diff --git a/cmd/cmd.go b/cmd/cmd.go index 29e00c01..1eb201ed 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -2,6 +2,7 @@ package cmd import ( + "errors" "log" "os" @@ -115,17 +116,23 @@ func pluginAddCommand(_ *cli.Context, conf config.Config, logger *log.Logger, pl // Maybe one day switch this to show the generated help // cli.ShowSubcommandHelp(cCtx) return cli.Exit("usage: asdf plugin add []", 1) - } else if pluginRepo == "" { - // add from plugin repo - // TODO: implement - return cli.Exit("Not implemented yet", 1) } err := plugins.Add(conf, pluginName, pluginRepo) if err != nil { - logger.Printf("error adding plugin: %s", err) + logger.Printf("%s", err) + + var existsErr plugins.PluginAlreadyExists + if errors.As(err, &existsErr) { + os.Exit(0) + return nil + } + + os.Exit(1) + return nil } + os.Exit(0) return nil } diff --git a/main_test.go b/main_test.go index 5fc40222..b5260be9 100644 --- a/main_test.go +++ b/main_test.go @@ -130,7 +130,7 @@ func TestBatsTests(t *testing.T) { // cmd.Stderr = &stderr // // Add dir to asdf test variables -// asdfTestHome := fmt.Sprintf("HOME=%s", dir) +// asdfTestHome := fmt.Sprintf("BASE_DIR=%s", dir) // asdfBinPath := fmt.Sprintf("ASDF_BIN=%s", dir) // cmd.Env = []string{asdfBinPath, asdfTestHome} diff --git a/pluginindex/pluginindex.go b/pluginindex/pluginindex.go index e35a187d..5859bbea 100644 --- a/pluginindex/pluginindex.go +++ b/pluginindex/pluginindex.go @@ -28,6 +28,12 @@ type PluginIndex struct { updateDurationMinutes int } +// Build returns a complete PluginIndex struct with default values set +func Build(dataDir string, URL string, disableUpdate bool, updateDurationMinutes int) PluginIndex { + directory := filepath.Join(dataDir, pluginIndexDir) + return New(directory, URL, disableUpdate, updateDurationMinutes, &git.Repo{Directory: directory}) +} + // New initializes a new PluginIndex instance with the options passed in. func New(directory, url string, disableUpdate bool, updateDurationMinutes int, repo git.Repoer) PluginIndex { return PluginIndex{ @@ -134,7 +140,7 @@ func readPlugin(dir, name string) (string, error) { pluginInfo, err := ini.Load(filename) if err != nil { - return "", fmt.Errorf("no such plugin found in plugin index: %s", name) + return "", fmt.Errorf("plugin %s not found in repository", name) } return pluginInfo.Section("").Key("repository").String(), nil diff --git a/pluginindex/pluginindex_test.go b/pluginindex/pluginindex_test.go index 1b74e2c6..5768f5e6 100644 --- a/pluginindex/pluginindex_test.go +++ b/pluginindex/pluginindex_test.go @@ -114,7 +114,7 @@ func TestGetPluginSourceURL(t *testing.T) { dir := t.TempDir() pluginIndex := New(dir, realIndexURL, false, 10, &MockIndex{Directory: dir}) url, err := pluginIndex.GetPluginSourceURL("foobar") - assert.EqualError(t, err, "no such plugin found in plugin index: foobar") + assert.EqualError(t, err, "plugin foobar not found in repository") assert.Equal(t, url, "") }) diff --git a/plugins/plugins.go b/plugins/plugins.go index 71ffd382..8eea7123 100644 --- a/plugins/plugins.go +++ b/plugins/plugins.go @@ -10,12 +10,29 @@ import ( "asdf/config" "asdf/git" + "asdf/pluginindex" ) +// NewPluginAlreadyExists generates a new PluginAlreadyExists error instance for +// a particular plugin +func NewPluginAlreadyExists(plugin string) PluginAlreadyExists { + return PluginAlreadyExists{plugin: plugin} +} + +// PluginAlreadyExists is an error returned when the specified plugin already +// exists +type PluginAlreadyExists struct { + plugin string +} + +func (e PluginAlreadyExists) Error() string { + return fmt.Sprintf(pluginAlreadyExistsMsg, e.plugin) +} + const ( - dataDirPlugins = "plugins" - invalidPluginNameMsg = "'%q' is invalid. Name may only contain lowercase letters, numbers, '_', and '-'" - pluginAlreadyExists = "plugin named %q already added" + dataDirPlugins = "plugins" + invalidPluginNameMsg = "%s is invalid. Name may only contain lowercase letters, numbers, '_', and '-'" + pluginAlreadyExistsMsg = "Plugin named %s already added" ) // Plugin struct represents an asdf plugin to all asdf code. The name and dir @@ -96,7 +113,7 @@ func Add(config config.Config, pluginName, pluginURL string) error { } if exists { - return fmt.Errorf(pluginAlreadyExists, pluginName) + return NewPluginAlreadyExists(pluginName) } pluginDir := PluginDirectory(config.DataDir, pluginName) @@ -105,6 +122,30 @@ func Add(config config.Config, pluginName, pluginURL string) error { return fmt.Errorf("unable to create plugin directory: %w", err) } + if pluginURL == "" { + // Ignore error here as the default value is fine + disablePluginIndex, _ := config.DisablePluginShortNameRepository() + + if disablePluginIndex { + return fmt.Errorf("Short-name plugin repository is disabled") + } + + lastCheckDuration := 0 + // We don't care about errors here as we can use the default value + checkDuration, _ := config.PluginRepositoryLastCheckDuration() + + if !checkDuration.Never { + lastCheckDuration = checkDuration.Every + } + + index := pluginindex.Build(config.DataDir, "https://github.com/asdf-vm/asdf-plugins.git", false, lastCheckDuration) + var err error + pluginURL, err = index.GetPluginSourceURL(pluginName) + if err != nil { + return fmt.Errorf("error fetching plugin URL: %s", err) + } + } + return git.NewRepo(pluginDir).Clone(pluginURL) } diff --git a/plugins/plugins_test.go b/plugins/plugins_test.go index 233cf1b1..37baed42 100644 --- a/plugins/plugins_test.go +++ b/plugins/plugins_test.go @@ -107,7 +107,7 @@ func TestAdd(t *testing.T) { t.Fatal("expected error got nil") } - expectedErrMsg := "plugin named \"lua\" already added" + expectedErrMsg := "Plugin named lua already added" if !strings.Contains(err.Error(), expectedErrMsg) { t.Errorf("Expected an error with message %v", expectedErrMsg) } diff --git a/staticcheck.conf b/staticcheck.conf new file mode 100644 index 00000000..606faa6d --- /dev/null +++ b/staticcheck.conf @@ -0,0 +1 @@ +checks = ["all", "-ST1005"] diff --git a/test/test_helpers.bash b/test/test_helpers.bash index 510aef2a..eceda964 100644 --- a/test/test_helpers.bash +++ b/test/test_helpers.bash @@ -7,19 +7,18 @@ bats_require_minimum_version 1.7.0 setup_asdf_dir() { if [ "$BATS_TEST_NAME" = 'test_shim_exec_should_use_path_executable_when_specified_version_path-3a-3cpath-3e' ]; then - BASE_DIR="$HOME/asdf_with_no_spaces/" + BASE_DIR="$BASE_DIR/asdf_with_no_spaces" else - BASE_DIR="$HOME/asdf with spaces/" + BASE_DIR="$BASE_DIR/w space${BATS_TEST_NAME}" fi # We don't call mktemp anymore so we need to create this sub directory manually mkdir "$BASE_DIR" # HOME is now defined by the Golang test code in main_test.go - #HOME="$BASE_DIR/home" - ASDF_DIR="$BASE_DIR/.asdf" - ASDF_DATA_DIR="$BASE_DIR/.asdf" - export ASDF_DATA_DIR + HOME="$BASE_DIR/home" + export HOME + ASDF_DIR="$HOME/.asdf" mkdir -p "$ASDF_DIR/plugins" mkdir -p "$ASDF_DIR/installs" mkdir -p "$ASDF_DIR/shims" @@ -27,6 +26,9 @@ setup_asdf_dir() { # ASDF_BIN is now defined by the Golang test code in main_test.go #ASDF_BIN="$(dirname "$BATS_TEST_DIRNAME")/bin" + ASDF_DATA_DIR="$BASE_DIR/.asdf" + export ASDF_DATA_DIR + # shellcheck disable=SC2031,SC2153 PATH="$ASDF_BIN:$ASDF_DIR/shims:$PATH" }