Skip to content

Commit 09d06ff

Browse files
committed
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
1 parent ec8985a commit 09d06ff

File tree

9 files changed

+151
-53
lines changed

9 files changed

+151
-53
lines changed

cmd/cmd.go

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"asdf/internal/plugins"
2020
"asdf/internal/resolve"
2121
"asdf/internal/shims"
22+
"asdf/internal/toolversions"
2223
"asdf/internal/versions"
2324

2425
"github.com/urfave/cli/v2"
@@ -175,6 +176,15 @@ func Execute(version string) {
175176
return reshimCommand(logger, args.Get(0), args.Get(1))
176177
},
177178
},
179+
{
180+
Name: "where",
181+
Action: func(cCtx *cli.Context) error {
182+
tool := cCtx.Args().Get(0)
183+
version := cCtx.Args().Get(1)
184+
185+
return whereCommand(logger, tool, version)
186+
},
187+
},
178188
{
179189
Name: "which",
180190
Action: func(cCtx *cli.Context) error {
@@ -265,7 +275,7 @@ func getVersionInfo(conf config.Config, plugin plugins.Plugin, currentDir string
265275
installed := false
266276
if found {
267277
firstVersion := toolversion.Versions[0]
268-
versionType, version := versions.ParseString(firstVersion)
278+
versionType, version := toolversions.Parse(firstVersion)
269279
installed = installs.IsInstalled(conf, plugin, versionType, version)
270280
}
271281
return toolversion, found, installed
@@ -663,8 +673,68 @@ func whichCommand(logger *log.Logger, command string) error {
663673
return nil
664674
}
665675

676+
func whereCommand(logger *log.Logger, tool, version string) error {
677+
conf, err := config.LoadConfig()
678+
if err != nil {
679+
logger.Printf("error loading config: %s", err)
680+
return err
681+
}
682+
683+
currentDir, err := os.Getwd()
684+
if err != nil {
685+
logger.Printf("unable to get current directory: %s", err)
686+
return err
687+
}
688+
689+
plugin := plugins.New(conf, tool)
690+
err = plugin.Exists()
691+
if err != nil {
692+
if _, ok := err.(plugins.PluginMissing); ok {
693+
logger.Printf("No such plugin: %s", tool)
694+
}
695+
return err
696+
}
697+
698+
versionType, parsedVersion := toolversions.Parse(version)
699+
700+
if version == "" {
701+
// resolve version
702+
toolversions, found, err := resolve.Version(conf, plugin, currentDir)
703+
if err != nil {
704+
fmt.Printf("err %#+v\n", err)
705+
return err
706+
}
707+
708+
if found && len(toolversions.Versions) > 0 && installs.IsInstalled(conf, plugin, "version", toolversions.Versions[0]) {
709+
installPath := installs.InstallPath(conf, plugin, "version", toolversions.Versions[0])
710+
logger.Printf("%s", installPath)
711+
return nil
712+
}
713+
714+
// not found
715+
msg := fmt.Sprintf("No version is set for %s; please run `asdf <global | shell | local> %s <version>`", tool, tool)
716+
logger.Print(msg)
717+
return errors.New(msg)
718+
}
719+
720+
if version == "system" {
721+
logger.Printf("System version is selected")
722+
return errors.New("System version is selected")
723+
}
724+
725+
if !installs.IsInstalled(conf, plugin, versionType, parsedVersion) {
726+
logger.Printf("Version not installed")
727+
return errors.New("Version not installed")
728+
}
729+
730+
installPath := installs.InstallPath(conf, plugin, versionType, parsedVersion)
731+
logger.Printf("%s", installPath)
732+
733+
return nil
734+
}
735+
666736
func reshimToolVersion(conf config.Config, tool, version string, out io.Writer, errOut io.Writer) error {
667-
versionType, version := versions.ParseString(version)
737+
versionType, version := toolversions.Parse(version)
668738
return shims.GenerateForVersion(conf, plugins.New(conf, tool), versionType, version, out, errOut)
669739
}
670740

internal/help/help.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010

1111
"asdf/internal/config"
1212
"asdf/internal/plugins"
13-
"asdf/internal/versions"
13+
"asdf/internal/toolversions"
1414
)
1515

1616
//go:embed help.txt
@@ -80,7 +80,7 @@ func writePluginHelp(conf config.Config, toolName, toolVersion string, writer io
8080
}
8181

8282
if toolVersion != "" {
83-
versionType, version := versions.ParseString(toolVersion)
83+
versionType, version := toolversions.Parse(toolVersion)
8484
env["ASDF_INSTALL_VERSION"] = version
8585
env["ASDF_INSTALL_TYPE"] = versionType
8686
}

internal/installs/installs.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
"asdf/internal/config"
1212
"asdf/internal/plugins"
13+
"asdf/internal/toolversions"
1314
)
1415

1516
const (
@@ -45,15 +46,17 @@ func InstallPath(conf config.Config, plugin plugins.Plugin, versionType, version
4546
if versionType == "path" {
4647
return version
4748
}
48-
return filepath.Join(pluginInstallPath(conf, plugin), version)
49+
50+
return filepath.Join(pluginInstallPath(conf, plugin), toolversions.FormatForFS(versionType, version))
4951
}
5052

5153
// DownloadPath returns the download path for a particular plugin and version
5254
func DownloadPath(conf config.Config, plugin plugins.Plugin, versionType, version string) string {
5355
if versionType == "path" {
5456
return ""
5557
}
56-
return filepath.Join(conf.DataDir, dataDirDownloads, plugin.Name, version)
58+
59+
return filepath.Join(conf.DataDir, dataDirDownloads, plugin.Name, toolversions.FormatForFS(versionType, version))
5760
}
5861

5962
// IsInstalled checks if a specific version of a tool is installed

internal/toolversions/toolversions.go

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
// Package toolversions handles reading and writing tools and versions from
2-
// asdf's .tool-versions files
2+
// asdf's .tool-versions files. It also handles parsing version strings from
3+
// .tool-versions files and command line arguments.
34
package toolversions
45

56
import (
7+
"fmt"
68
"os"
79
"slices"
810
"strings"
@@ -81,6 +83,39 @@ func Unique(versions []ToolVersions) (uniques []ToolVersions) {
8183
return uniques
8284
}
8385

86+
// Parse parses a version string into versionType and version components
87+
func Parse(version string) (string, string) {
88+
segments := strings.Split(version, ":")
89+
if len(segments) >= 1 {
90+
remainder := strings.Join(segments[1:], ":")
91+
switch segments[0] {
92+
case "ref":
93+
return "ref", remainder
94+
case "path":
95+
// This is for people who have the local source already compiled
96+
// Like those who work on the language, etc
97+
// We'll allow specifying path:/foo/bar/project in .tool-versions
98+
// And then use the binaries there
99+
return "path", remainder
100+
default:
101+
return "version", version
102+
}
103+
}
104+
105+
return "version", version
106+
}
107+
108+
// FormatForFS takes a versionType and version strings and generate a version
109+
// string suitable for the file system
110+
func FormatForFS(versionType, version string) string {
111+
switch versionType {
112+
case "ref":
113+
return fmt.Sprintf("ref-%s", version)
114+
default:
115+
return version
116+
}
117+
}
118+
84119
// readLines reads all the lines in a given file
85120
// removing spaces and comments which are marked by '#'
86121
func readLines(content string) (lines []string) {

internal/toolversions/toolversions_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,33 @@ func TestgetAllToolsAndVersionsInContent(t *testing.T) {
157157
})
158158
}
159159
}
160+
161+
func TestParse(t *testing.T) {
162+
t.Run("returns 'version', and unmodified version when passed semantic version", func(t *testing.T) {
163+
versionType, version := Parse("1.2.3")
164+
assert.Equal(t, versionType, "version")
165+
assert.Equal(t, version, "1.2.3")
166+
})
167+
168+
t.Run("returns 'ref' and reference version when passed a ref version", func(t *testing.T) {
169+
versionType, version := Parse("ref:abc123")
170+
assert.Equal(t, versionType, "ref")
171+
assert.Equal(t, version, "abc123")
172+
})
173+
174+
t.Run("returns 'ref' and empty string when passed 'ref:'", func(t *testing.T) {
175+
versionType, version := Parse("ref:")
176+
assert.Equal(t, versionType, "ref")
177+
assert.Equal(t, version, "")
178+
})
179+
}
180+
181+
func TestFormatForFS(t *testing.T) {
182+
t.Run("returns version when version type is not ref", func(t *testing.T) {
183+
assert.Equal(t, FormatForFS("version", "foobar"), "foobar")
184+
})
185+
186+
t.Run("returns version prefixed with 'ref-' when version type is ref", func(t *testing.T) {
187+
assert.Equal(t, FormatForFS("ref", "foobar"), "ref-foobar")
188+
})
189+
}

internal/versions/versions.go

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"asdf/internal/plugins"
1717
"asdf/internal/resolve"
1818
"asdf/internal/shims"
19+
"asdf/internal/toolversions"
1920
)
2021

2122
const (
@@ -131,7 +132,7 @@ func InstallOneVersion(conf config.Config, plugin plugins.Plugin, version string
131132
return UninstallableVersionError{versionType: "system"}
132133
}
133134

134-
versionType, version := ParseString(version)
135+
versionType, version := toolversions.Parse(version)
135136

136137
if versionType == "path" {
137138
return UninstallableVersionError{versionType: "path"}
@@ -306,25 +307,3 @@ func parseVersions(rawVersions string) []string {
306307
}
307308
return versions
308309
}
309-
310-
// ParseString parses a version string into versionType and version components
311-
func ParseString(version string) (string, string) {
312-
segments := strings.Split(version, ":")
313-
if len(segments) >= 1 {
314-
remainder := strings.Join(segments[1:], ":")
315-
switch segments[0] {
316-
case "ref":
317-
return "ref", remainder
318-
case "path":
319-
// This is for people who have the local source already compiled
320-
// Like those who work on the language, etc
321-
// We'll allow specifying path:/foo/bar/project in .tool-versions
322-
// And then use the binaries there
323-
return "path", remainder
324-
default:
325-
return "version", version
326-
}
327-
}
328-
329-
return "version", version
330-
}

internal/versions/versions_test.go

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -308,26 +308,6 @@ func TestLatest(t *testing.T) {
308308
})
309309
}
310310

311-
func TestParseString(t *testing.T) {
312-
t.Run("returns 'version', and unmodified version when passed semantic version", func(t *testing.T) {
313-
versionType, version := ParseString("1.2.3")
314-
assert.Equal(t, versionType, "version")
315-
assert.Equal(t, version, "1.2.3")
316-
})
317-
318-
t.Run("returns 'ref' and reference version when passed a ref version", func(t *testing.T) {
319-
versionType, version := ParseString("ref:abc123")
320-
assert.Equal(t, versionType, "ref")
321-
assert.Equal(t, version, "abc123")
322-
})
323-
324-
t.Run("returns 'ref' and empty string when passed 'ref:'", func(t *testing.T) {
325-
versionType, version := ParseString("ref:")
326-
assert.Equal(t, versionType, "ref")
327-
assert.Equal(t, version, "")
328-
})
329-
}
330-
331311
func TestAllVersions(t *testing.T) {
332312
pluginName := "list-all-test"
333313
conf, _ := generateConfig(t)

main_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,9 @@ func TestBatsTests(t *testing.T) {
9595
// runBatsFile(t, dir, "version_commands.bats")
9696
//})
9797

98-
//t.Run("where_command", func(t *testing.T) {
99-
// runBatsFile(t, dir, "where_command.bats")
100-
//})
98+
t.Run("where_command", func(t *testing.T) {
99+
runBatsFile(t, dir, "where_command.bats")
100+
})
101101

102102
t.Run("which_command", func(t *testing.T) {
103103
runBatsFile(t, dir, "which_command.bats")

test/where_command.bats

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ setup() {
88
install_dummy_version 1.0
99
install_dummy_version 2.1
1010
install_dummy_version ref-master
11+
cd "$HOME" || exit
1112
}
1213

1314
teardown() {

0 commit comments

Comments
 (0)