Skip to content

Commit f1d5fb7

Browse files
committed
Recursively find defined plugins
1 parent 92640f8 commit f1d5fb7

File tree

3 files changed

+105
-39
lines changed

3 files changed

+105
-39
lines changed

internal/resolve/resolve.go

Lines changed: 90 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package resolve
55

66
import (
77
"fmt"
8+
"iter"
89
"os"
910
"path"
1011
"strings"
@@ -21,54 +22,100 @@ type ToolVersions struct {
2122
Source string
2223
}
2324

25+
// AllVersions takes a set of plugins and a directory and resolves all tools to one or more
26+
// versions. This includes tools without a corresponding plugin.
27+
func AllVersions(conf config.Config, plugins []plugins.Plugin, directory string) (versions map[string]ToolVersions, err error) {
28+
resolvedToolVersions := map[string]ToolVersions{}
29+
for _, plugin := range plugins {
30+
version, envVariableName, found := findVersionsInEnv(plugin.Name)
31+
if found {
32+
resolvedToolVersions[plugin.Name] = ToolVersions{Versions: version, Source: envVariableName}
33+
}
34+
}
35+
36+
for iterDir := range iterDirectories(conf, directory) {
37+
for _, plugin := range plugins {
38+
if _, isPluginResolved := resolvedToolVersions[plugin.Name]; !isPluginResolved {
39+
version, found, err := findLegacyVersionsInDir(conf, plugin, iterDir)
40+
if err != nil {
41+
return versions, err
42+
}
43+
if found {
44+
resolvedToolVersions[plugin.Name] = version
45+
}
46+
}
47+
}
48+
49+
filepath := path.Join(iterDir, conf.DefaultToolVersionsFilename)
50+
if _, err = os.Stat(filepath); err == nil {
51+
if allVersions, err := toolversions.GetAllToolsAndVersions(filepath); err == nil {
52+
for _, v := range allVersions {
53+
if _, isPluginResolved := resolvedToolVersions[v.Name]; !isPluginResolved {
54+
resolvedToolVersions[v.Name] = ToolVersions{Versions: v.Versions, Source: conf.DefaultToolVersionsFilename, Directory: iterDir}
55+
}
56+
}
57+
}
58+
}
59+
}
60+
return resolvedToolVersions, nil
61+
}
62+
2463
// Version takes a plugin and a directory and resolves the tool to one or more
25-
// versions.
64+
// versions. Only returns results for the provided plugin.
2665
func Version(conf config.Config, plugin plugins.Plugin, directory string) (versions ToolVersions, found bool, err error) {
2766
version, envVariableName, found := findVersionsInEnv(plugin.Name)
2867
if found {
2968
return ToolVersions{Versions: version, Source: envVariableName}, true, nil
3069
}
3170

32-
for !found {
33-
versions, found, err = findVersionsInDir(conf, plugin, directory)
71+
for iterDir := range iterDirectories(conf, directory) {
72+
versions, found, err = findVersionsInDir(conf, plugin, iterDir)
3473
if err != nil {
3574
return versions, false, err
3675
}
76+
if found {
77+
return versions, found, err
78+
}
79+
}
80+
return versions, found, err
81+
}
3782

38-
nextDir := path.Dir(directory)
39-
// If current dir and next dir are the same it means we've reached `/` and
40-
// have no more parent directories to search.
41-
if nextDir == directory {
42-
// If no version found, try current users home directory. I'd like to
43-
// eventually remove this feature.
44-
homeDir, osErr := os.UserHomeDir()
45-
if osErr != nil {
83+
func iterDirectories(conf config.Config, directory string) iter.Seq[string] {
84+
return func(yield func(string) bool) {
85+
if !yield(directory) {
86+
return
87+
}
88+
iterDir := directory
89+
for {
90+
nextDir := path.Dir(iterDir)
91+
// If current dir and next dir are the same it means we've reached `/` and
92+
// have no more parent directories to search.
93+
if nextDir == iterDir {
4694
break
4795
}
48-
49-
versions, found, err = findVersionsInDir(conf, plugin, homeDir)
50-
break
96+
if !yield(iterDir) {
97+
return
98+
}
99+
iterDir = nextDir
100+
}
101+
// If no version found, try current users home directory. I'd like to
102+
// eventually remove this feature.
103+
homeDir := conf.Home
104+
// homeDir, osErr := os.UserHomeDir()
105+
if homeDir != "" {
106+
if !yield(homeDir) {
107+
return
108+
}
51109
}
52-
directory = nextDir
53110
}
54-
55-
return versions, found, err
56111
}
57112

58113
func findVersionsInDir(conf config.Config, plugin plugins.Plugin, directory string) (versions ToolVersions, found bool, err error) {
59-
legacyFiles, err := conf.LegacyVersionFile()
60-
if err != nil {
114+
versions, found, err = findLegacyVersionsInDir(conf, plugin, directory)
115+
if found || err != nil {
61116
return versions, found, err
62117
}
63118

64-
if legacyFiles {
65-
versions, found, err := findVersionsInLegacyFile(plugin, directory)
66-
67-
if found || err != nil {
68-
return versions, found, err
69-
}
70-
}
71-
72119
filepath := path.Join(directory, conf.DefaultToolVersionsFilename)
73120

74121
if _, err = os.Stat(filepath); err == nil {
@@ -81,6 +128,22 @@ func findVersionsInDir(conf config.Config, plugin plugins.Plugin, directory stri
81128
return versions, found, nil
82129
}
83130

131+
func findLegacyVersionsInDir(conf config.Config, plugin plugins.Plugin, directory string) (versions ToolVersions, found bool, err error) {
132+
legacyFiles, err := conf.LegacyVersionFile()
133+
if err != nil {
134+
return versions, found, err
135+
}
136+
137+
if legacyFiles {
138+
versions, found, err := findVersionsInLegacyFile(plugin, directory)
139+
140+
if found || err != nil {
141+
return versions, found, err
142+
}
143+
}
144+
return versions, false, nil
145+
}
146+
84147
// findVersionsInEnv returns the version from the environment if present
85148
func findVersionsInEnv(pluginName string) ([]string, string, bool) {
86149
envVariableName := variableVersionName(pluginName)

internal/versions/versions.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"fmt"
88
"io"
99
"os"
10-
"path"
1110
"regexp"
1211
"strings"
1312

@@ -84,27 +83,30 @@ func InstallAll(conf config.Config, dir string, stdOut io.Writer, stdErr io.Writ
8483
return []error{fmt.Errorf("unable to list plugins: %w", err)}
8584
}
8685

87-
toolNames := map[string]bool{}
88-
filepath := path.Join(dir, conf.DefaultToolVersionsFilename)
89-
toolVersions, err := toolversions.GetAllToolsAndVersions(filepath)
90-
if err == nil {
91-
for _, version := range toolVersions {
92-
toolNames[version.Name] = true
93-
}
86+
toolVersions, err := resolve.AllVersions(conf, plugins, dir)
87+
if err != nil {
88+
return []error{fmt.Errorf("unable to resolve versions: %w", err)}
9489
}
9590

9691
// Ideally we should install these in the order they are specified in the
9792
// closest .tool-versions file, but for now that is too complicated to
9893
// implement.
9994
for _, plugin := range plugins {
100-
delete(toolNames, plugin.Name)
101-
err := Install(conf, plugin, dir, stdOut, stdErr)
102-
if err != nil {
95+
if toolVersion, isPluginResolved := toolVersions[plugin.Name]; isPluginResolved {
96+
delete(toolVersions, plugin.Name)
97+
for _, version := range toolVersion.Versions {
98+
err := InstallOneVersion(conf, plugin, version, false, stdOut, stdErr)
99+
if err != nil {
100+
failures = append(failures, err)
101+
}
102+
}
103+
} else {
104+
err := NoVersionSetError{toolName: plugin.Name}
103105
failures = append(failures, err)
104106
}
105107
}
106108

107-
for toolName := range toolNames {
109+
for toolName := range toolVersions {
108110
err = MissingPluginError{toolName: toolName}
109111
failures = append(failures, err)
110112
}

internal/versions/versions_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,7 @@ func generateConfig(t *testing.T) (config.Config, plugins.Plugin) {
485485
conf, err := config.LoadConfig()
486486
assert.Nil(t, err)
487487
conf.DataDir = testDataDir
488+
conf.Home = testDataDir
488489

489490
_, err = repotest.InstallPlugin("dummy_plugin", testDataDir, testPluginName)
490491
assert.Nil(t, err)

0 commit comments

Comments
 (0)