Skip to content

Commit

Permalink
Merge pull request #89 from asdf-vm/tb/plugin-list-all-tests
Browse files Browse the repository at this point in the history
feat(golang-rewrite): implement `asdf plugin list all` command
  • Loading branch information
Stratus3D authored Dec 9, 2024
2 parents 8fbf47d + 2596d37 commit 4ccc757
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 13 deletions.
71 changes: 71 additions & 0 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"asdf/internal/hook"
"asdf/internal/info"
"asdf/internal/installs"
"asdf/internal/pluginindex"
"asdf/internal/plugins"
"asdf/internal/resolve"
"asdf/internal/shims"
Expand Down Expand Up @@ -173,6 +174,14 @@ func Execute(version string) {
Action: func(cCtx *cli.Context) error {
return pluginListCommand(cCtx, logger)
},
Subcommands: []*cli.Command{
{
Name: "all",
Action: func(_ *cli.Context) error {
return pluginListAllCommand(logger)
},
},
},
},
{
Name: "remove",
Expand Down Expand Up @@ -628,6 +637,68 @@ func pluginListCommand(cCtx *cli.Context, logger *log.Logger) error {
return nil
}

func pluginListAllCommand(logger *log.Logger) error {
conf, err := config.LoadConfig()
if err != nil {
logger.Printf("error loading config: %s", err)
return err
}

disableRepo, err := conf.DisablePluginShortNameRepository()
if err != nil {
logger.Printf("unable to check config")
return err
}
if disableRepo {
logger.Printf("Short-name plugin repository is disabled")
os.Exit(1)
return nil
}

lastCheckDuration := 0
// We don't care about errors here as we can use the default value
checkDuration, _ := conf.PluginRepositoryLastCheckDuration()

if !checkDuration.Never {
lastCheckDuration = checkDuration.Every
}

index := pluginindex.Build(conf.DataDir, conf.PluginIndexURL, false, lastCheckDuration)
availablePlugins, err := index.Get()
if err != nil {
logger.Printf("error loading plugin index: %s", err)
return err
}

installedPlugins, err := plugins.List(conf, true, false)
if err != nil {
logger.Printf("error loading plugin list: %s", err)
return err
}

w := tabwriter.NewWriter(os.Stdout, 15, 0, 1, ' ', 0)
for _, availablePlugin := range availablePlugins {
if pluginInstalled(availablePlugin, installedPlugins) {
fmt.Fprintf(w, "%s\t\t*%s\n", availablePlugin.Name, availablePlugin.URL)
} else {
fmt.Fprintf(w, "%s\t\t%s\n", availablePlugin.Name, availablePlugin.URL)
}
}
w.Flush()

return nil
}

func pluginInstalled(plugin pluginindex.Plugin, installedPlugins []plugins.Plugin) bool {
for _, installedPlugin := range installedPlugins {
if installedPlugin.Name == plugin.Name && installedPlugin.URL == plugin.URL {
return true
}
}

return false
}

func infoCommand(conf config.Config, version string) error {
return info.Print(conf, version)
}
Expand Down
5 changes: 4 additions & 1 deletion internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const (
dataDirDefault = "~/.asdf"
configFileDefault = "~/.asdfrc"
defaultToolVersionsFilenameDefault = ".tool-versions"
defaultPluginIndexURL = "https://github.com/asdf-vm/asdf-plugins.git"
)

/* PluginRepoCheckDuration represents the remote plugin repo check duration
Expand All @@ -40,7 +41,8 @@ type Config struct {
DataDir string `env:"ASDF_DATA_DIR, overwrite"`
ForcePrepend bool `env:"ASDF_FORCE_PREPEND, overwrite"`
// Field that stores the settings struct if it is loaded
Settings Settings
Settings Settings
PluginIndexURL string
}

// Settings is a struct that stores config values from the asdfrc file
Expand All @@ -62,6 +64,7 @@ func defaultConfig(dataDir, configFile string) *Config {
DataDir: dataDir,
ConfigFile: configFile,
DefaultToolVersionsFilename: defaultToolVersionsFilenameDefault,
PluginIndexURL: defaultPluginIndexURL,
}
}

Expand Down
37 changes: 37 additions & 0 deletions internal/pluginindex/pluginindex.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package pluginindex

import (
"fmt"
"io/fs"
"os"
"path/filepath"
"time"
Expand All @@ -28,6 +29,12 @@ type PluginIndex struct {
updateDurationMinutes int
}

// Plugin represents a plugin listed on a plugin index.
type Plugin struct {
Name string
URL string
}

// 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)
Expand All @@ -45,6 +52,16 @@ func New(directory, url string, disableUpdate bool, updateDurationMinutes int, r
}
}

// Get returns a slice of all available plugins
func (p PluginIndex) Get() (plugins []Plugin, err error) {
_, err = p.Refresh()
if err != nil {
return plugins, err
}

return getPlugins(p.directory)
}

// Refresh may update the plugin repo if it hasn't been updated in longer
// than updateDurationMinutes. If the plugin repo needs to be updated the
// repo will be invoked to perform the actual Git pull.
Expand Down Expand Up @@ -145,3 +162,23 @@ func readPlugin(dir, name string) (string, error) {

return pluginInfo.Section("").Key("repository").String(), nil
}

func getPlugins(dir string) (plugins []Plugin, err error) {
files, err := os.ReadDir(filepath.Join(dir, "plugins"))
if _, ok := err.(*fs.PathError); ok {
return plugins, nil
}

for _, file := range files {
if !file.IsDir() {
url, err := readPlugin(dir, file.Name())
if err != nil {
return plugins, err
}

plugins = append(plugins, Plugin{Name: file.Name(), URL: url})
}
}

return plugins, err
}
11 changes: 11 additions & 0 deletions internal/pluginindex/pluginindex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,17 @@ func writeMockPluginFile(dir, pluginName, pluginURL string) error {
return nil
}

func TestGet(t *testing.T) {
t.Run("returns populated slice of plugins when plugins exist in directory", func(t *testing.T) {
dir := t.TempDir()

pluginIndex := New(dir, mockIndexURL, true, 0, &MockIndex{Directory: dir})
plugins, err := pluginIndex.Get()
assert.Nil(t, err)
assert.Equal(t, plugins, []Plugin{{Name: "elixir", URL: "https://github.com/asdf-vm/asdf-elixir.git"}})
})
}

func TestGetPluginSourceURL(t *testing.T) {
t.Run("with Git returns a plugin url when provided name of existing plugin", func(t *testing.T) {
dir := t.TempDir()
Expand Down
2 changes: 1 addition & 1 deletion internal/plugins/plugins.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ func Add(config config.Config, pluginName, pluginURL string) error {
lastCheckDuration = checkDuration.Every
}

index := pluginindex.Build(config.DataDir, "https://github.com/asdf-vm/asdf-plugins.git", false, lastCheckDuration)
index := pluginindex.Build(config.DataDir, config.PluginIndexURL, false, lastCheckDuration)
var err error
pluginURL, err = index.GetPluginSourceURL(pluginName)
if err != nil {
Expand Down
6 changes: 3 additions & 3 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ func TestBatsTests(t *testing.T) {
// runBatsFile(t, dir, "plugin_extension_command.bats")
//})

//t.Run("plugin_list_all_command", func(t *testing.T) {
// runBatsFile(t, dir, "plugin_list_all_command.bats")
//})
t.Run("plugin_list_all_command", func(t *testing.T) {
runBatsFile(t, dir, "plugin_list_all_command.bats")
})

t.Run("plugin_remove_command", func(t *testing.T) {
runBatsFile(t, dir, "plugin_remove_command.bats")
Expand Down
10 changes: 4 additions & 6 deletions test/plugin_list_all_command.bats
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,13 @@ teardown() {
@test "plugin_list_all should sync repo when check_duration set to 0" {
export ASDF_CONFIG_DEFAULT_FILE="$HOME/.asdfrc"
echo 'plugin_repository_last_check_duration = 0' >"$ASDF_CONFIG_DEFAULT_FILE"
local expected_plugin_repo_sync="updating plugin repository..."
local expected_plugins_list="\
bar http://example.com/bar
dummy *http://example.com/dummy
dummy http://example.com/dummy
foo http://example.com/foo"

run asdf plugin list all
[ "$status" -eq 0 ]
[[ "$output" == *"$expected_plugin_repo_sync"* ]]
[[ "$output" == *"$expected_plugins_list"* ]]
}

Expand All @@ -43,7 +41,7 @@ foo http://example.com/foo"
echo 'plugin_repository_last_check_duration = 10' >"$ASDF_CONFIG_DEFAULT_FILE"
local expected="\
bar http://example.com/bar
dummy *http://example.com/dummy
dummy http://example.com/dummy
foo http://example.com/foo"

run asdf plugin list all
Expand All @@ -56,7 +54,7 @@ foo http://example.com/foo"
echo 'plugin_repository_last_check_duration = never' >"$ASDF_CONFIG_DEFAULT_FILE"
local expected="\
bar http://example.com/bar
dummy *http://example.com/dummy
dummy http://example.com/dummy
foo http://example.com/foo"

run asdf plugin list all
Expand All @@ -67,7 +65,7 @@ foo http://example.com/foo"
@test "plugin_list_all list all plugins in the repository" {
local expected="\
bar http://example.com/bar
dummy *http://example.com/dummy
dummy http://example.com/dummy
foo http://example.com/foo"

run asdf plugin list all
Expand Down
8 changes: 6 additions & 2 deletions test/test_helpers.bash
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,13 @@ install_mock_plugin_repo() {

init_git_repo() {
location="$1"
remote="${2:-"https://asdf-vm.com/fake-repo"}"
git -C "${location}" init -q
git -C "${location}" config user.name "Test"
git -C "${location}" config user.email "[email protected]"
git -C "${location}" add -A
git -C "${location}" commit -q -m "asdf ${plugin_name} plugin"
git -C "${location}" remote add origin "https://asdf-vm.com/fake-repo"
git -C "${location}" remote add origin "$remote"
}

install_mock_plugin_version() {
Expand Down Expand Up @@ -127,6 +128,9 @@ clean_asdf_dir() {
}

setup_repo() {
cp -r "$BATS_TEST_DIRNAME/fixtures/dummy_plugins_repo" "$ASDF_DIR/repository"
cp -r "$BATS_TEST_DIRNAME/fixtures/dummy_plugins_repo" "$ASDF_DIR/plugin-index"
cp -r "$BATS_TEST_DIRNAME/fixtures/dummy_plugins_repo" "$ASDF_DIR/plugin-index-2"
init_git_repo "$ASDF_DIR/plugin-index-2"
init_git_repo "$ASDF_DIR/plugin-index" "$ASDF_DIR/plugin-index-2"
touch "$(asdf_dir)/tmp/repo-updated"
}

0 comments on commit 4ccc757

Please sign in to comment.