-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #70 from asdf-vm/tb/asdf-help-command
feat(golang-rewrite): implement `asdf help` command
- Loading branch information
Showing
9 changed files
with
396 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
// Package help contains functions responsible for generating help output for | ||
// asdf and asdf plugins. | ||
package help | ||
|
||
import ( | ||
_ "embed" | ||
"fmt" | ||
"io" | ||
"os" | ||
|
||
"asdf/internal/config" | ||
"asdf/internal/plugins" | ||
"asdf/internal/versions" | ||
) | ||
|
||
//go:embed help.txt | ||
var helpText string | ||
|
||
const quote = "\"Late but latest\"\n-- Rajinikanth" | ||
|
||
// Print help output to STDOUT | ||
func Print(asdfVersion string) error { | ||
return Write(asdfVersion, os.Stdout) | ||
} | ||
|
||
// PrintTool write tool help output to STDOUT | ||
func PrintTool(conf config.Config, toolName string) error { | ||
return WriteToolHelp(conf, toolName, os.Stdout, os.Stderr) | ||
} | ||
|
||
// PrintToolVersion write help for specific tool version to STDOUT | ||
func PrintToolVersion(conf config.Config, toolName, toolVersion string) error { | ||
return WriteToolVersionHelp(conf, toolName, toolVersion, os.Stdout, os.Stderr) | ||
} | ||
|
||
// Write help output to an io.Writer | ||
func Write(asdfVersion string, writer io.Writer) error { | ||
_, err := writer.Write([]byte(fmt.Sprintf("version: %s", asdfVersion))) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
_, err = writer.Write([]byte(helpText)) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
_, err = writer.Write([]byte("\n")) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
_, err = writer.Write([]byte(quote)) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
_, err = writer.Write([]byte("\n")) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// WriteToolHelp output to an io.Writer | ||
func WriteToolHelp(conf config.Config, toolName string, writer io.Writer, errWriter io.Writer) error { | ||
return writePluginHelp(conf, toolName, "", writer, errWriter) | ||
} | ||
|
||
// WriteToolVersionHelp output to an io.Writer | ||
func WriteToolVersionHelp(conf config.Config, toolName, toolVersion string, writer io.Writer, errWriter io.Writer) error { | ||
return writePluginHelp(conf, toolName, toolVersion, writer, errWriter) | ||
} | ||
|
||
func writePluginHelp(conf config.Config, toolName, toolVersion string, writer io.Writer, errWriter io.Writer) error { | ||
plugin := plugins.New(conf, toolName) | ||
env := map[string]string{ | ||
"ASDF_INSTALL_PATH": plugin.Dir, | ||
} | ||
|
||
if toolVersion != "" { | ||
versionType, version := versions.ParseString(toolVersion) | ||
env["ASDF_INSTALL_VERSION"] = version | ||
env["ASDF_INSTALL_TYPE"] = versionType | ||
} | ||
|
||
if err := plugin.Exists(); err != nil { | ||
errWriter.Write([]byte(fmt.Sprintf("No plugin named %s\n", plugin.Name))) | ||
return err | ||
} | ||
|
||
err := plugin.RunCallback("help.overview", []string{}, env, writer, errWriter) | ||
if _, ok := err.(plugins.NoCallbackError); ok { | ||
// No such callback, print err msg | ||
errWriter.Write([]byte(fmt.Sprintf("No documentation for plugin %s\n", plugin.Name))) | ||
return err | ||
} | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
err = plugin.RunCallback("help.deps", []string{}, env, writer, errWriter) | ||
if _, ok := err.(plugins.NoCallbackError); !ok { | ||
return err | ||
} | ||
|
||
err = plugin.RunCallback("help.config", []string{}, env, writer, errWriter) | ||
if _, ok := err.(plugins.NoCallbackError); !ok { | ||
return err | ||
} | ||
|
||
err = plugin.RunCallback("help.links", []string{}, env, writer, errWriter) | ||
if _, ok := err.(plugins.NoCallbackError); !ok { | ||
return err | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
MANAGE PLUGINS | ||
asdf plugin add <name> [<git-url>] Add a plugin from the plugin repo OR, | ||
add a Git repo as a plugin by | ||
specifying the name and repo url | ||
asdf plugin list [--urls] [--refs] List installed plugins. Optionally show | ||
git urls and git-ref | ||
asdf plugin list all List plugins registered on asdf-plugins | ||
repository with URLs | ||
asdf plugin remove <name> Remove plugin and package versions | ||
asdf plugin update <name> [<git-ref>] Update a plugin to latest commit on | ||
default branch or a particular git-ref | ||
asdf plugin update --all Update all plugins to latest commit on | ||
default branch | ||
|
||
|
||
MANAGE TOOLS | ||
asdf current Display current version set or being | ||
used for all packages | ||
asdf current <name> Display current version set or being | ||
used for package | ||
asdf global <name> <version> Set the package global version | ||
asdf global <name> latest[:<version>] Set the package global version to the | ||
latest provided version | ||
asdf help <name> [<version>] Output documentation for plugin and tool | ||
asdf install Install all the package versions listed | ||
in the .tool-versions file | ||
asdf install <name> Install one tool at the version | ||
specified in the .tool-versions file | ||
asdf install <name> <version> Install a specific version of a package | ||
asdf install <name> latest[:<version>] Install the latest stable version of a | ||
package, or with optional version, | ||
install the latest stable version that | ||
begins with the given string | ||
asdf latest <name> [<version>] Show latest stable version of a package | ||
asdf latest --all Show latest stable version of all the | ||
packages and if they are installed | ||
asdf list <name> [version] List installed versions of a package and | ||
optionally filter the versions | ||
asdf list all <name> [<version>] List all versions of a package and | ||
optionally filter the returned versions | ||
asdf local <name> <version> Set the package local version | ||
asdf local <name> latest[:<version>] Set the package local version to the | ||
latest provided version | ||
asdf shell <name> <version> Set the package version to | ||
`ASDF_${LANG}_VERSION` in the current shell | ||
asdf uninstall <name> <version> Remove a specific version of a package | ||
asdf where <name> [<version>] Display install path for an installed | ||
or current version | ||
asdf which <command> Display the path to an executable | ||
|
||
|
||
UTILS | ||
asdf exec <command> [args...] Executes the command shim for current version | ||
asdf env <command> [util] Runs util (default: `env`) inside the | ||
environment used for command shim execution. | ||
asdf info Print OS, Shell and ASDF debug information. | ||
asdf version Print the currently installed version of ASDF | ||
asdf reshim <name> <version> Recreate shims for version of a package | ||
asdf shim-versions <command> List the plugins and versions that | ||
provide a command | ||
asdf update Update asdf to the latest stable release | ||
asdf update --head Update asdf to the latest on the master branch | ||
|
||
RESOURCES | ||
GitHub: https://github.com/asdf-vm/asdf | ||
Docs: https://asdf-vm.com |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package help | ||
|
||
import ( | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
"testing" | ||
|
||
"asdf/internal/config" | ||
"asdf/internal/plugins" | ||
"asdf/repotest" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
const ( | ||
version = "0.15.0" | ||
testPluginName = "lua" | ||
) | ||
|
||
func TestWrite(t *testing.T) { | ||
testDataDir := t.TempDir() | ||
err := os.MkdirAll(filepath.Join(testDataDir, "plugins"), 0o777) | ||
assert.Nil(t, err) | ||
|
||
var stdout strings.Builder | ||
|
||
err = Write(version, &stdout) | ||
assert.Nil(t, err) | ||
output := stdout.String() | ||
|
||
// Simple format assertions | ||
assert.Contains(t, output, "version: ") | ||
assert.Contains(t, output, "MANAGE PLUGINS\n") | ||
assert.Contains(t, output, "MANAGE TOOLS\n") | ||
assert.Contains(t, output, "UTILS\n") | ||
assert.Contains(t, output, "RESOURCES\n") | ||
} | ||
|
||
func TestWriteToolHelp(t *testing.T) { | ||
conf, plugin := generateConfig(t) | ||
|
||
t.Run("when plugin implements all help callbacks", func(t *testing.T) { | ||
var stdout strings.Builder | ||
var stderr strings.Builder | ||
|
||
err := WriteToolHelp(conf, plugin.Name, &stdout, &stderr) | ||
|
||
assert.Nil(t, err) | ||
assert.Empty(t, stderr.String()) | ||
expected := "Dummy plugin documentation\n\nDummy plugin is a plugin only used for unit tests\n" | ||
assert.Equal(t, stdout.String(), expected) | ||
}) | ||
|
||
t.Run("when plugin does not have help.overview callback", func(t *testing.T) { | ||
var stdout strings.Builder | ||
var stderr strings.Builder | ||
plugin := installPlugin(t, conf, "dummy_legacy_plugin", "legacy-plugin") | ||
|
||
err := WriteToolHelp(conf, plugin.Name, &stdout, &stderr) | ||
|
||
assert.EqualError(t, err, "Plugin named legacy-plugin does not have a callback named help.overview") | ||
assert.Empty(t, stdout.String()) | ||
assert.Equal(t, stderr.String(), "No documentation for plugin legacy-plugin\n") | ||
}) | ||
|
||
t.Run("when plugin does not exist", func(t *testing.T) { | ||
var stdout strings.Builder | ||
var stderr strings.Builder | ||
|
||
err := WriteToolHelp(conf, "non-existent", &stdout, &stderr) | ||
|
||
assert.EqualError(t, err, "Plugin named non-existent not installed") | ||
assert.Empty(t, stdout.String()) | ||
assert.Equal(t, stderr.String(), "No plugin named non-existent\n") | ||
}) | ||
} | ||
|
||
func TestWriteToolVersionHelp(t *testing.T) { | ||
conf, plugin := generateConfig(t) | ||
|
||
t.Run("when plugin implements all help callbacks", func(t *testing.T) { | ||
var stdout strings.Builder | ||
var stderr strings.Builder | ||
|
||
err := WriteToolVersionHelp(conf, plugin.Name, "1.2.3", &stdout, &stderr) | ||
|
||
assert.Nil(t, err) | ||
assert.Empty(t, stderr.String()) | ||
expected := "Dummy plugin documentation\n\nDummy plugin is a plugin only used for unit tests\n\nDetails specific for version 1.2.3\n" | ||
assert.Equal(t, stdout.String(), expected) | ||
}) | ||
|
||
t.Run("when plugin does not have help.overview callback", func(t *testing.T) { | ||
var stdout strings.Builder | ||
var stderr strings.Builder | ||
plugin := installPlugin(t, conf, "dummy_legacy_plugin", "legacy-plugin") | ||
|
||
err := WriteToolVersionHelp(conf, plugin.Name, "1.2.3", &stdout, &stderr) | ||
|
||
assert.EqualError(t, err, "Plugin named legacy-plugin does not have a callback named help.overview") | ||
assert.Empty(t, stdout.String()) | ||
assert.Equal(t, stderr.String(), "No documentation for plugin legacy-plugin\n") | ||
}) | ||
|
||
t.Run("when plugin does not exist", func(t *testing.T) { | ||
var stdout strings.Builder | ||
var stderr strings.Builder | ||
|
||
err := WriteToolVersionHelp(conf, "non-existent", "1.2.3", &stdout, &stderr) | ||
|
||
assert.EqualError(t, err, "Plugin named non-existent not installed") | ||
assert.Empty(t, stdout.String()) | ||
assert.Equal(t, stderr.String(), "No plugin named non-existent\n") | ||
}) | ||
} | ||
|
||
func generateConfig(t *testing.T) (config.Config, plugins.Plugin) { | ||
t.Helper() | ||
testDataDir := t.TempDir() | ||
conf, err := config.LoadConfig() | ||
assert.Nil(t, err) | ||
conf.DataDir = testDataDir | ||
|
||
return conf, installPlugin(t, conf, "dummy_plugin", testPluginName) | ||
} | ||
|
||
func installPlugin(t *testing.T, conf config.Config, fixture, pluginName string) plugins.Plugin { | ||
_, err := repotest.InstallPlugin(fixture, conf.DataDir, pluginName) | ||
assert.Nil(t, err) | ||
|
||
return plugins.New(conf, pluginName) | ||
} |
Oops, something went wrong.