mirror of
https://github.com/asdf-vm/asdf.git
synced 2024-12-19 09:55:01 -07:00
feat(golang-rewrite): implement asdf plugin list all
command
* Enable `plugin_list_all_command.bats` tests * Create `PluginIndex.Get` method * Create `asdf plugin list all` subcommand * Extract plugin index repo URL into config package * Fix failing tests
This commit is contained in:
parent
5e542da7b5
commit
e7df5ff325
71
cmd/cmd.go
71
cmd/cmd.go
@ -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"
|
||||
@ -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",
|
||||
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
@ -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
|
||||
@ -62,6 +64,7 @@ func defaultConfig(dataDir, configFile string) *Config {
|
||||
DataDir: dataDir,
|
||||
ConfigFile: configFile,
|
||||
DefaultToolVersionsFilename: defaultToolVersionsFilenameDefault,
|
||||
PluginIndexURL: defaultPluginIndexURL,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ package pluginindex
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
@ -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)
|
||||
@ -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.
|
||||
@ -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
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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 {
|
||||
|
@ -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")
|
||||
|
@ -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"* ]]
|
||||
}
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
|
@ -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 "test@example.com"
|
||||
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() {
|
||||
@ -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"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user