diff --git a/cmd/cmd.go b/cmd/cmd.go index d72ff071..86708f43 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -8,6 +8,7 @@ import ( "log" "os" "path/filepath" + "slices" "strings" "text/tabwriter" @@ -110,6 +111,13 @@ func Execute(version string) { return latestCommand(logger, all, tool, pattern) }, }, + { + Name: "list", + Action: func(cCtx *cli.Context) error { + args := cCtx.Args() + return listCommand(logger, args.Get(0), args.Get(1), args.Get(2)) + }, + }, { Name: "plugin", Action: func(_ *cli.Context) error { @@ -610,6 +618,142 @@ func latestCommand(logger *log.Logger, all bool, toolName, pattern string) (err return nil } +func listCommand(logger *log.Logger, first, second, third string) (err error) { + conf, err := config.LoadConfig() + if err != nil { + logger.Printf("error loading config: %s", err) + return err + } + + // Both listAllCommand and listLocalCommand need to be refactored and extracted + // out into another package. + if first == "all" { + return listAllCommand(logger, conf, second, third) + } + + return listLocalCommand(logger, conf, first, second) +} + +func listAllCommand(logger *log.Logger, conf config.Config, toolName, filter string) error { + if toolName == "" { + logger.Print("No plugin given") + os.Exit(1) + return nil + } + + plugin := plugins.New(conf, toolName) + var stdout strings.Builder + var stderr strings.Builder + + err := plugin.RunCallback("list-all", []string{}, map[string]string{}, &stdout, &stderr) + + if err != nil { + fmt.Printf("Plugin %s's list-all callback script failed with output:\n", plugin.Name) + // Print to stderr + os.Stderr.WriteString(stderr.String()) + os.Stderr.WriteString(stdout.String()) + + os.Exit(1) + return err + } + + versions := strings.Split(stdout.String(), " ") + + if filter != "" { + versions = filterByExactMatch(versions, filter) + } + + if len(versions) == 0 { + logger.Printf("No compatible versions available (%s %s)", plugin.Name, filter) + os.Exit(1) + return nil + } + + for _, version := range versions { + fmt.Printf("%s\n", version) + } + + return nil +} + +func filterByExactMatch(allVersions []string, pattern string) (versions []string) { + for _, version := range allVersions { + if strings.HasPrefix(version, pattern) { + versions = append(versions, version) + } + } + + return versions +} + +func listLocalCommand(logger *log.Logger, conf config.Config, pluginName, filter string) error { + currentDir, err := os.Getwd() + if err != nil { + logger.Printf("unable to get current directory: %s", err) + return err + } + + if pluginName != "" { + plugin := plugins.New(conf, pluginName) + versions, _ := installs.Installed(conf, plugin) + + if filter != "" { + versions = filterByExactMatch(versions, filter) + } + + if len(versions) == 0 { + logger.Printf("No compatible versions installed (%s %s)", plugin.Name, filter) + os.Exit(1) + return nil + } + + currentVersions, _, err := resolve.Version(conf, plugin, currentDir) + if err != nil { + os.Exit(1) + return err + } + + for _, version := range versions { + if slices.Contains(currentVersions.Versions, version) { + fmt.Printf(" *%s\n", version) + } else { + fmt.Printf(" %s\n", version) + } + } + return nil + } + + allPlugins, err := plugins.List(conf, false, false) + if err != nil { + logger.Printf("unable to list plugins due to error: %s", err) + return err + } + + for _, plugin := range allPlugins { + fmt.Printf("%s\n", plugin.Name) + versions, _ := installs.Installed(conf, plugin) + + if len(versions) > 0 { + currentVersions, _, err := resolve.Version(conf, plugin, currentDir) + if err != nil { + os.Exit(1) + return err + } + for _, version := range versions { + if slices.Contains(currentVersions.Versions, version) { + fmt.Printf(" *%s\n", version) + } else { + fmt.Printf(" %s\n", version) + } + } + } else { + fmt.Print(" No versions installed\n") + } + } + + return nil +} + func reshimCommand(logger *log.Logger, tool, version string) (err error) { conf, err := config.LoadConfig() if err != nil { diff --git a/main_test.go b/main_test.go index cd76d764..b128dc26 100644 --- a/main_test.go +++ b/main_test.go @@ -39,9 +39,9 @@ func TestBatsTests(t *testing.T) { runBatsFile(t, dir, "latest_command.bats") }) - //t.Run("list_command", func(t *testing.T) { - // runBatsFile(t, dir, "list_command.bats") - //}) + t.Run("list_command", func(t *testing.T) { + runBatsFile(t, dir, "list_command.bats") + }) t.Run("plugin_add_command", func(t *testing.T) { runBatsFile(t, dir, "plugin_add_command.bats") diff --git a/test/list_command.bats b/test/list_command.bats index f21f2cd1..2a235e96 100644 --- a/test/list_command.bats +++ b/test/list_command.bats @@ -76,36 +76,36 @@ teardown() { } @test "list_all_command lists available versions" { - run asdf list-all dummy + run asdf list all dummy [ $'1.0.0\n1.1.0\n2.0.0' = "$output" ] [ "$status" -eq 0 ] } @test "list_all_command with version filters available versions" { - run asdf list-all dummy 1 + run asdf list all dummy 1 [ $'1.0.0\n1.1.0' = "$output" ] [ "$status" -eq 0 ] } @test "list_all_command with an invalid version should return an error" { - run asdf list-all dummy 3 + run asdf list all dummy 3 [ "No compatible versions available (dummy 3)" = "$output" ] [ "$status" -eq 1 ] } @test "list_all_command fails when list-all script exits with non-zero code" { - run asdf list-all dummy-broken + run asdf list all dummy-broken [ "$status" -eq 1 ] [[ "$output" == "Plugin dummy-broken's list-all callback script failed with output:"* ]] } @test "list_all_command displays stderr then stdout when failing" { - run asdf list-all dummy-broken + run asdf list all dummy-broken [[ "$output" == *"List-all failed!"* ]] [[ "$output" == *"Attempting to list versions" ]] } @test "list_all_command ignores stderr when completing successfully" { - run asdf list-all dummy + run asdf list all dummy [[ "$output" != *"ignore this error"* ]] }