-
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 #50 from asdf-vm/tb/version-file-parsing
feat(golang-rewrite): version file parsing
- Loading branch information
Showing
2 changed files
with
189 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
// Package toolversions handles reading and writing tools and versions from | ||
// asdf's .tool-versions files | ||
package toolversions | ||
|
||
import ( | ||
"os" | ||
"strings" | ||
) | ||
|
||
// ToolVersions represents a tool along with versions specified for it | ||
type ToolVersions struct { | ||
Name string | ||
Versions []string | ||
} | ||
|
||
// FindToolVersions looks up a tool version in a tool versions file and if found | ||
// returns a slice of versions for it. | ||
func FindToolVersions(filepath, toolName string) (versions []string, found bool, err error) { | ||
content, err := os.ReadFile(filepath) | ||
if err != nil { | ||
return versions, false, err | ||
} | ||
|
||
versions, found = findToolVersionsInContent(string(content), toolName) | ||
return versions, found, nil | ||
} | ||
|
||
func findToolVersionsInContent(content, toolName string) (versions []string, found bool) { | ||
toolVersions := getAllToolsAndVersionsInContent(content) | ||
for _, tool := range toolVersions { | ||
if tool.Name == toolName { | ||
return tool.Versions, true | ||
} | ||
} | ||
|
||
return versions, found | ||
} | ||
|
||
// GetAllToolsAndVersions returns a list of all tools and associated versions | ||
// contained in a .tool-versions file | ||
func GetAllToolsAndVersions(filepath string) (toolVersions []ToolVersions, err error) { | ||
content, err := os.ReadFile(filepath) | ||
if err != nil { | ||
return toolVersions, err | ||
} | ||
|
||
toolVersions = getAllToolsAndVersionsInContent(string(content)) | ||
return toolVersions, nil | ||
} | ||
|
||
func getAllToolsAndVersionsInContent(content string) (toolVersions []ToolVersions) { | ||
for _, line := range readLines(content) { | ||
tokens := parseLine(line) | ||
newTool := ToolVersions{Name: tokens[0], Versions: tokens[1:]} | ||
toolVersions = append(toolVersions, newTool) | ||
} | ||
|
||
return toolVersions | ||
} | ||
|
||
// readLines reads all the lines in a given file | ||
// removing spaces and comments which are marked by '#' | ||
func readLines(content string) (lines []string) { | ||
for _, line := range strings.Split(content, "\n") { | ||
line = strings.SplitN(line, "#", 2)[0] | ||
line = strings.TrimSpace(line) | ||
if len(line) > 0 { | ||
lines = append(lines, line) | ||
} | ||
} | ||
return | ||
} | ||
|
||
func parseLine(line string) (tokens []string) { | ||
for _, token := range strings.Split(line, " ") { | ||
token = strings.TrimSpace(token) | ||
if len(token) > 0 { | ||
tokens = append(tokens, token) | ||
} | ||
} | ||
|
||
return tokens | ||
} |
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,106 @@ | ||
package toolversions | ||
|
||
import ( | ||
"os" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestGetAllToolsAndVersions(t *testing.T) { | ||
t.Run("returns error when non-existant file", func(t *testing.T) { | ||
toolVersions, err := GetAllToolsAndVersions("non-existant-file") | ||
assert.Error(t, err) | ||
assert.Empty(t, toolVersions) | ||
}) | ||
|
||
t.Run("returns list of tool versions when populated file", func(t *testing.T) { | ||
toolVersionsPath := filepath.Join(t.TempDir(), ".tool-versions") | ||
file, err := os.Create(toolVersionsPath) | ||
assert.Nil(t, err) | ||
defer file.Close() | ||
file.WriteString("ruby 2.0.0") | ||
|
||
toolVersions, err := GetAllToolsAndVersions(toolVersionsPath) | ||
assert.Nil(t, err) | ||
expected := []ToolVersions{{Name: "ruby", Versions: []string{"2.0.0"}}} | ||
assert.Equal(t, expected, toolVersions) | ||
}) | ||
} | ||
|
||
func TestFindToolVersions(t *testing.T) { | ||
t.Run("returns error when non-existant file", func(t *testing.T) { | ||
versions, found, err := FindToolVersions("non-existant-file", "nonexistant-tool") | ||
assert.Error(t, err) | ||
assert.False(t, found) | ||
assert.Empty(t, versions) | ||
}) | ||
|
||
t.Run("returns list of versions and found true when file contains tool versions", func(t *testing.T) { | ||
toolVersionsPath := filepath.Join(t.TempDir(), ".tool-versions") | ||
file, err := os.Create(toolVersionsPath) | ||
assert.Nil(t, err) | ||
defer file.Close() | ||
file.WriteString("ruby 2.0.0") | ||
|
||
versions, found, err := FindToolVersions(toolVersionsPath, "ruby") | ||
assert.Nil(t, err) | ||
assert.True(t, found) | ||
assert.Equal(t, []string{"2.0.0"}, versions) | ||
}) | ||
} | ||
|
||
func TestfindToolVersionsInContent(t *testing.T) { | ||
t.Run("returns empty list with found false when empty content", func(t *testing.T) { | ||
versions, found := findToolVersionsInContent("", "ruby") | ||
assert.False(t, found) | ||
assert.Empty(t, versions) | ||
}) | ||
|
||
t.Run("returns empty list with found false when tool not found", func(t *testing.T) { | ||
versions, found := findToolVersionsInContent("lua 5.4.5", "ruby") | ||
assert.False(t, found) | ||
assert.Empty(t, versions) | ||
}) | ||
|
||
t.Run("returns list of versions with found true when tool found", func(t *testing.T) { | ||
versions, found := findToolVersionsInContent("lua 5.4.5 5.4.6\nruby 2.0.0", "lua") | ||
assert.True(t, found) | ||
assert.Equal(t, []string{"5.4.5", "5.4.6"}, versions) | ||
}) | ||
} | ||
|
||
func TestgetAllToolsAndVersionsInContent(t *testing.T) { | ||
tests := []struct { | ||
desc string | ||
input string | ||
want []ToolVersions | ||
}{ | ||
{ | ||
desc: "returns empty list with found true and no error when empty content", | ||
input: "", | ||
want: []ToolVersions{}, | ||
}, | ||
{ | ||
desc: "returns list with one tool when single tool in content", | ||
input: "lua 5.4.5 5.4.6", | ||
want: []ToolVersions{{Name: "lua", Versions: []string{"5.4.5", "5.4.6"}}}, | ||
}, | ||
{ | ||
desc: "returns list with multiple tools when multiple tools in content", | ||
input: "lua 5.4.5 5.4.6\nruby 2.0.0", | ||
want: []ToolVersions{ | ||
{Name: "lua", Versions: []string{"5.4.5", "5.4.6"}}, | ||
{Name: "ruby", Versions: []string{"2.0.0"}}, | ||
}, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.desc, func(t *testing.T) { | ||
toolsAndVersions := getAllToolsAndVersionsInContent(tt.input) | ||
assert.Equal(t, tt.want, toolsAndVersions) | ||
}) | ||
} | ||
} |