github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/cf/commands/pluginrepo/add_plugin_repo.go (about)

     1  package pluginrepo
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"net"
     9  	"net/http"
    10  	"net/url"
    11  	"strings"
    12  
    13  	"code.cloudfoundry.org/cli/cf/commandregistry"
    14  	"code.cloudfoundry.org/cli/cf/configuration/coreconfig"
    15  	"code.cloudfoundry.org/cli/cf/flags"
    16  	"code.cloudfoundry.org/cli/cf/models"
    17  	"code.cloudfoundry.org/cli/cf/requirements"
    18  	"code.cloudfoundry.org/cli/cf/terminal"
    19  
    20  	clipr "code.cloudfoundry.org/cli-plugin-repo/web"
    21  
    22  	. "code.cloudfoundry.org/cli/cf/i18n"
    23  )
    24  
    25  type AddPluginRepo struct {
    26  	ui     terminal.UI
    27  	config coreconfig.ReadWriter
    28  }
    29  
    30  func init() {
    31  	commandregistry.Register(&AddPluginRepo{})
    32  }
    33  
    34  func (cmd *AddPluginRepo) MetaData() commandregistry.CommandMetadata {
    35  	return commandregistry.CommandMetadata{
    36  		Name:        "add-plugin-repo",
    37  		Description: T("Add a new plugin repository"),
    38  		Usage: []string{
    39  			T(`CF_NAME add-plugin-repo REPO_NAME URL`),
    40  		},
    41  		Examples: []string{
    42  			"CF_NAME add-plugin-repo PrivateRepo https://myprivaterepo.com/repo/",
    43  		},
    44  		TotalArgs: 2,
    45  	}
    46  }
    47  
    48  func (cmd *AddPluginRepo) Requirements(requirementsFactory requirements.Factory, fc flags.FlagContext) ([]requirements.Requirement, error) {
    49  	if len(fc.Args()) != 2 {
    50  		cmd.ui.Failed(T("Incorrect Usage. Requires REPO_NAME and URL as arguments\n\n") + commandregistry.Commands.CommandUsage("add-plugin-repo"))
    51  		return nil, fmt.Errorf("Incorrect usage: %d arguments of %d required", len(fc.Args()), 2)
    52  	}
    53  
    54  	reqs := []requirements.Requirement{}
    55  	return reqs, nil
    56  }
    57  
    58  func (cmd *AddPluginRepo) SetDependency(deps commandregistry.Dependency, pluginCall bool) commandregistry.Command {
    59  	cmd.ui = deps.UI
    60  	cmd.config = deps.Config
    61  	return cmd
    62  }
    63  
    64  func (cmd *AddPluginRepo) Execute(c flags.FlagContext) error {
    65  	cmd.ui.Say("")
    66  	repoURL := strings.ToLower(c.Args()[1])
    67  	repoName := strings.Trim(c.Args()[0], " ")
    68  
    69  	err := cmd.checkIfRepoExists(repoName, repoURL)
    70  	if err != nil {
    71  		return err
    72  	}
    73  
    74  	repoURL, err = cmd.verifyURL(repoURL)
    75  	if err != nil {
    76  		return err
    77  	}
    78  
    79  	resp, err := http.Get(repoURL)
    80  	if err != nil {
    81  		if urlErr, ok := err.(*url.Error); ok {
    82  			if opErr, opErrOk := urlErr.Err.(*net.OpError); opErrOk {
    83  				if opErr.Op == "dial" {
    84  					return errors.New(T("There is an error performing request on '{{.RepoURL}}': {{.Error}}\n{{.Tip}}", map[string]interface{}{
    85  						"RepoURL": repoURL,
    86  						"Error":   err.Error(),
    87  						"Tip":     T("TIP: If you are behind a firewall and require an HTTP proxy, verify the https_proxy environment variable is correctly set. Else, check your network connection."),
    88  					}))
    89  				}
    90  			}
    91  		}
    92  		return errors.New(T("There is an error performing request on '{{.RepoURL}}': ", map[string]interface{}{
    93  			"RepoURL": repoURL,
    94  		}, err.Error()))
    95  	}
    96  	defer resp.Body.Close()
    97  
    98  	if resp.StatusCode == 404 {
    99  		return errors.New(repoURL + T(" is not responding. Please make sure it is a valid plugin repo."))
   100  	}
   101  
   102  	body, err := ioutil.ReadAll(resp.Body)
   103  	if err != nil {
   104  		return errors.New(T("Error reading response from server: ") + err.Error())
   105  	}
   106  
   107  	result := clipr.PluginsJson{}
   108  	err = json.Unmarshal(body, &result)
   109  	if err != nil {
   110  		return errors.New(T("Error processing data from server: ") + err.Error())
   111  	}
   112  
   113  	if result.Plugins == nil {
   114  		return errors.New(T(`"Plugins" object not found in the responded data.`))
   115  	}
   116  
   117  	cmd.config.SetPluginRepo(models.PluginRepo{
   118  		Name: c.Args()[0],
   119  		URL:  c.Args()[1],
   120  	})
   121  
   122  	cmd.ui.Ok()
   123  	cmd.ui.Say(repoURL + T(" added as '") + c.Args()[0] + "'")
   124  	cmd.ui.Say("")
   125  	return nil
   126  }
   127  
   128  func (cmd AddPluginRepo) checkIfRepoExists(repoName, repoURL string) error {
   129  	repos := cmd.config.PluginRepos()
   130  	for _, repo := range repos {
   131  		if strings.ToLower(repo.Name) == strings.ToLower(repoName) {
   132  			return errors.New(T(`Plugin repo named "{{.repoName}}" already exists, please use another name.`, map[string]interface{}{"repoName": repoName}))
   133  		} else if repo.URL == repoURL {
   134  			return errors.New(repo.URL + ` (` + repo.Name + T(`) already exists.`))
   135  		}
   136  	}
   137  	return nil
   138  }
   139  
   140  func (cmd AddPluginRepo) verifyURL(repoURL string) (string, error) {
   141  	if !strings.HasPrefix(repoURL, "http://") && !strings.HasPrefix(repoURL, "https://") {
   142  		return "", errors.New(T("{{.URL}} is not a valid url, please provide a url, e.g. https://your_repo.com", map[string]interface{}{"URL": repoURL}))
   143  	}
   144  
   145  	if strings.HasSuffix(repoURL, "/") {
   146  		repoURL = repoURL + "list"
   147  	} else {
   148  		repoURL = repoURL + "/list"
   149  	}
   150  
   151  	return repoURL, nil
   152  }