mirror of
https://github.com/asdf-vm/asdf.git
synced 2024-12-23 20:05:09 -07:00
feat(golang-rewrite): create asdf where
command
* Move `versions.ParseString` function to the toolversions package * Create `toolversions.FormatForFS` function * use new `toolversions.FormatForFS` function * Create `asdf where` command * Enable BATS tests for `asdf where` command
This commit is contained in:
parent
ec8985af8f
commit
09d06ff125
74
cmd/cmd.go
74
cmd/cmd.go
@ -19,6 +19,7 @@ import (
|
|||||||
"asdf/internal/plugins"
|
"asdf/internal/plugins"
|
||||||
"asdf/internal/resolve"
|
"asdf/internal/resolve"
|
||||||
"asdf/internal/shims"
|
"asdf/internal/shims"
|
||||||
|
"asdf/internal/toolversions"
|
||||||
"asdf/internal/versions"
|
"asdf/internal/versions"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
@ -175,6 +176,15 @@ func Execute(version string) {
|
|||||||
return reshimCommand(logger, args.Get(0), args.Get(1))
|
return reshimCommand(logger, args.Get(0), args.Get(1))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "where",
|
||||||
|
Action: func(cCtx *cli.Context) error {
|
||||||
|
tool := cCtx.Args().Get(0)
|
||||||
|
version := cCtx.Args().Get(1)
|
||||||
|
|
||||||
|
return whereCommand(logger, tool, version)
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "which",
|
Name: "which",
|
||||||
Action: func(cCtx *cli.Context) error {
|
Action: func(cCtx *cli.Context) error {
|
||||||
@ -265,7 +275,7 @@ func getVersionInfo(conf config.Config, plugin plugins.Plugin, currentDir string
|
|||||||
installed := false
|
installed := false
|
||||||
if found {
|
if found {
|
||||||
firstVersion := toolversion.Versions[0]
|
firstVersion := toolversion.Versions[0]
|
||||||
versionType, version := versions.ParseString(firstVersion)
|
versionType, version := toolversions.Parse(firstVersion)
|
||||||
installed = installs.IsInstalled(conf, plugin, versionType, version)
|
installed = installs.IsInstalled(conf, plugin, versionType, version)
|
||||||
}
|
}
|
||||||
return toolversion, found, installed
|
return toolversion, found, installed
|
||||||
@ -663,8 +673,68 @@ func whichCommand(logger *log.Logger, command string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func whereCommand(logger *log.Logger, tool, version string) error {
|
||||||
|
conf, err := config.LoadConfig()
|
||||||
|
if err != nil {
|
||||||
|
logger.Printf("error loading config: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
currentDir, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
logger.Printf("unable to get current directory: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin := plugins.New(conf, tool)
|
||||||
|
err = plugin.Exists()
|
||||||
|
if err != nil {
|
||||||
|
if _, ok := err.(plugins.PluginMissing); ok {
|
||||||
|
logger.Printf("No such plugin: %s", tool)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
versionType, parsedVersion := toolversions.Parse(version)
|
||||||
|
|
||||||
|
if version == "" {
|
||||||
|
// resolve version
|
||||||
|
toolversions, found, err := resolve.Version(conf, plugin, currentDir)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("err %#+v\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if found && len(toolversions.Versions) > 0 && installs.IsInstalled(conf, plugin, "version", toolversions.Versions[0]) {
|
||||||
|
installPath := installs.InstallPath(conf, plugin, "version", toolversions.Versions[0])
|
||||||
|
logger.Printf("%s", installPath)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// not found
|
||||||
|
msg := fmt.Sprintf("No version is set for %s; please run `asdf <global | shell | local> %s <version>`", tool, tool)
|
||||||
|
logger.Print(msg)
|
||||||
|
return errors.New(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
if version == "system" {
|
||||||
|
logger.Printf("System version is selected")
|
||||||
|
return errors.New("System version is selected")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !installs.IsInstalled(conf, plugin, versionType, parsedVersion) {
|
||||||
|
logger.Printf("Version not installed")
|
||||||
|
return errors.New("Version not installed")
|
||||||
|
}
|
||||||
|
|
||||||
|
installPath := installs.InstallPath(conf, plugin, versionType, parsedVersion)
|
||||||
|
logger.Printf("%s", installPath)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func reshimToolVersion(conf config.Config, tool, version string, out io.Writer, errOut io.Writer) error {
|
func reshimToolVersion(conf config.Config, tool, version string, out io.Writer, errOut io.Writer) error {
|
||||||
versionType, version := versions.ParseString(version)
|
versionType, version := toolversions.Parse(version)
|
||||||
return shims.GenerateForVersion(conf, plugins.New(conf, tool), versionType, version, out, errOut)
|
return shims.GenerateForVersion(conf, plugins.New(conf, tool), versionType, version, out, errOut)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
"asdf/internal/config"
|
"asdf/internal/config"
|
||||||
"asdf/internal/plugins"
|
"asdf/internal/plugins"
|
||||||
"asdf/internal/versions"
|
"asdf/internal/toolversions"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed help.txt
|
//go:embed help.txt
|
||||||
@ -80,7 +80,7 @@ func writePluginHelp(conf config.Config, toolName, toolVersion string, writer io
|
|||||||
}
|
}
|
||||||
|
|
||||||
if toolVersion != "" {
|
if toolVersion != "" {
|
||||||
versionType, version := versions.ParseString(toolVersion)
|
versionType, version := toolversions.Parse(toolVersion)
|
||||||
env["ASDF_INSTALL_VERSION"] = version
|
env["ASDF_INSTALL_VERSION"] = version
|
||||||
env["ASDF_INSTALL_TYPE"] = versionType
|
env["ASDF_INSTALL_TYPE"] = versionType
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
|
|
||||||
"asdf/internal/config"
|
"asdf/internal/config"
|
||||||
"asdf/internal/plugins"
|
"asdf/internal/plugins"
|
||||||
|
"asdf/internal/toolversions"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -45,7 +46,8 @@ func InstallPath(conf config.Config, plugin plugins.Plugin, versionType, version
|
|||||||
if versionType == "path" {
|
if versionType == "path" {
|
||||||
return version
|
return version
|
||||||
}
|
}
|
||||||
return filepath.Join(pluginInstallPath(conf, plugin), version)
|
|
||||||
|
return filepath.Join(pluginInstallPath(conf, plugin), toolversions.FormatForFS(versionType, version))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DownloadPath returns the download path for a particular plugin and version
|
// DownloadPath returns the download path for a particular plugin and version
|
||||||
@ -53,7 +55,8 @@ func DownloadPath(conf config.Config, plugin plugins.Plugin, versionType, versio
|
|||||||
if versionType == "path" {
|
if versionType == "path" {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return filepath.Join(conf.DataDir, dataDirDownloads, plugin.Name, version)
|
|
||||||
|
return filepath.Join(conf.DataDir, dataDirDownloads, plugin.Name, toolversions.FormatForFS(versionType, version))
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsInstalled checks if a specific version of a tool is installed
|
// IsInstalled checks if a specific version of a tool is installed
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
// Package toolversions handles reading and writing tools and versions from
|
// Package toolversions handles reading and writing tools and versions from
|
||||||
// asdf's .tool-versions files
|
// asdf's .tool-versions files. It also handles parsing version strings from
|
||||||
|
// .tool-versions files and command line arguments.
|
||||||
package toolversions
|
package toolversions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
@ -81,6 +83,39 @@ func Unique(versions []ToolVersions) (uniques []ToolVersions) {
|
|||||||
return uniques
|
return uniques
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse parses a version string into versionType and version components
|
||||||
|
func Parse(version string) (string, string) {
|
||||||
|
segments := strings.Split(version, ":")
|
||||||
|
if len(segments) >= 1 {
|
||||||
|
remainder := strings.Join(segments[1:], ":")
|
||||||
|
switch segments[0] {
|
||||||
|
case "ref":
|
||||||
|
return "ref", remainder
|
||||||
|
case "path":
|
||||||
|
// This is for people who have the local source already compiled
|
||||||
|
// Like those who work on the language, etc
|
||||||
|
// We'll allow specifying path:/foo/bar/project in .tool-versions
|
||||||
|
// And then use the binaries there
|
||||||
|
return "path", remainder
|
||||||
|
default:
|
||||||
|
return "version", version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "version", version
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatForFS takes a versionType and version strings and generate a version
|
||||||
|
// string suitable for the file system
|
||||||
|
func FormatForFS(versionType, version string) string {
|
||||||
|
switch versionType {
|
||||||
|
case "ref":
|
||||||
|
return fmt.Sprintf("ref-%s", version)
|
||||||
|
default:
|
||||||
|
return version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// readLines reads all the lines in a given file
|
// readLines reads all the lines in a given file
|
||||||
// removing spaces and comments which are marked by '#'
|
// removing spaces and comments which are marked by '#'
|
||||||
func readLines(content string) (lines []string) {
|
func readLines(content string) (lines []string) {
|
||||||
|
@ -157,3 +157,33 @@ func TestgetAllToolsAndVersionsInContent(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParse(t *testing.T) {
|
||||||
|
t.Run("returns 'version', and unmodified version when passed semantic version", func(t *testing.T) {
|
||||||
|
versionType, version := Parse("1.2.3")
|
||||||
|
assert.Equal(t, versionType, "version")
|
||||||
|
assert.Equal(t, version, "1.2.3")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("returns 'ref' and reference version when passed a ref version", func(t *testing.T) {
|
||||||
|
versionType, version := Parse("ref:abc123")
|
||||||
|
assert.Equal(t, versionType, "ref")
|
||||||
|
assert.Equal(t, version, "abc123")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("returns 'ref' and empty string when passed 'ref:'", func(t *testing.T) {
|
||||||
|
versionType, version := Parse("ref:")
|
||||||
|
assert.Equal(t, versionType, "ref")
|
||||||
|
assert.Equal(t, version, "")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFormatForFS(t *testing.T) {
|
||||||
|
t.Run("returns version when version type is not ref", func(t *testing.T) {
|
||||||
|
assert.Equal(t, FormatForFS("version", "foobar"), "foobar")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("returns version prefixed with 'ref-' when version type is ref", func(t *testing.T) {
|
||||||
|
assert.Equal(t, FormatForFS("ref", "foobar"), "ref-foobar")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
"asdf/internal/plugins"
|
"asdf/internal/plugins"
|
||||||
"asdf/internal/resolve"
|
"asdf/internal/resolve"
|
||||||
"asdf/internal/shims"
|
"asdf/internal/shims"
|
||||||
|
"asdf/internal/toolversions"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -131,7 +132,7 @@ func InstallOneVersion(conf config.Config, plugin plugins.Plugin, version string
|
|||||||
return UninstallableVersionError{versionType: "system"}
|
return UninstallableVersionError{versionType: "system"}
|
||||||
}
|
}
|
||||||
|
|
||||||
versionType, version := ParseString(version)
|
versionType, version := toolversions.Parse(version)
|
||||||
|
|
||||||
if versionType == "path" {
|
if versionType == "path" {
|
||||||
return UninstallableVersionError{versionType: "path"}
|
return UninstallableVersionError{versionType: "path"}
|
||||||
@ -306,25 +307,3 @@ func parseVersions(rawVersions string) []string {
|
|||||||
}
|
}
|
||||||
return versions
|
return versions
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseString parses a version string into versionType and version components
|
|
||||||
func ParseString(version string) (string, string) {
|
|
||||||
segments := strings.Split(version, ":")
|
|
||||||
if len(segments) >= 1 {
|
|
||||||
remainder := strings.Join(segments[1:], ":")
|
|
||||||
switch segments[0] {
|
|
||||||
case "ref":
|
|
||||||
return "ref", remainder
|
|
||||||
case "path":
|
|
||||||
// This is for people who have the local source already compiled
|
|
||||||
// Like those who work on the language, etc
|
|
||||||
// We'll allow specifying path:/foo/bar/project in .tool-versions
|
|
||||||
// And then use the binaries there
|
|
||||||
return "path", remainder
|
|
||||||
default:
|
|
||||||
return "version", version
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "version", version
|
|
||||||
}
|
|
||||||
|
@ -308,26 +308,6 @@ func TestLatest(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseString(t *testing.T) {
|
|
||||||
t.Run("returns 'version', and unmodified version when passed semantic version", func(t *testing.T) {
|
|
||||||
versionType, version := ParseString("1.2.3")
|
|
||||||
assert.Equal(t, versionType, "version")
|
|
||||||
assert.Equal(t, version, "1.2.3")
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("returns 'ref' and reference version when passed a ref version", func(t *testing.T) {
|
|
||||||
versionType, version := ParseString("ref:abc123")
|
|
||||||
assert.Equal(t, versionType, "ref")
|
|
||||||
assert.Equal(t, version, "abc123")
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("returns 'ref' and empty string when passed 'ref:'", func(t *testing.T) {
|
|
||||||
versionType, version := ParseString("ref:")
|
|
||||||
assert.Equal(t, versionType, "ref")
|
|
||||||
assert.Equal(t, version, "")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAllVersions(t *testing.T) {
|
func TestAllVersions(t *testing.T) {
|
||||||
pluginName := "list-all-test"
|
pluginName := "list-all-test"
|
||||||
conf, _ := generateConfig(t)
|
conf, _ := generateConfig(t)
|
||||||
|
@ -95,9 +95,9 @@ func TestBatsTests(t *testing.T) {
|
|||||||
// runBatsFile(t, dir, "version_commands.bats")
|
// runBatsFile(t, dir, "version_commands.bats")
|
||||||
//})
|
//})
|
||||||
|
|
||||||
//t.Run("where_command", func(t *testing.T) {
|
t.Run("where_command", func(t *testing.T) {
|
||||||
// runBatsFile(t, dir, "where_command.bats")
|
runBatsFile(t, dir, "where_command.bats")
|
||||||
//})
|
})
|
||||||
|
|
||||||
t.Run("which_command", func(t *testing.T) {
|
t.Run("which_command", func(t *testing.T) {
|
||||||
runBatsFile(t, dir, "which_command.bats")
|
runBatsFile(t, dir, "which_command.bats")
|
||||||
|
@ -8,6 +8,7 @@ setup() {
|
|||||||
install_dummy_version 1.0
|
install_dummy_version 1.0
|
||||||
install_dummy_version 2.1
|
install_dummy_version 2.1
|
||||||
install_dummy_version ref-master
|
install_dummy_version ref-master
|
||||||
|
cd "$HOME" || exit
|
||||||
}
|
}
|
||||||
|
|
||||||
teardown() {
|
teardown() {
|
||||||
|
Loading…
Reference in New Issue
Block a user