github.com/danhper/asdf-exec@v0.1.3-0.20230723223931-b71340b83071/version_manager.go (about) 1 package main 2 3 import ( 4 "io/ioutil" 5 "os" 6 "os/exec" 7 "path" 8 "strings" 9 ) 10 11 const ( 12 toolVersionsFile string = ".tool-versions" 13 legacyFileNamesScript string = "list-legacy-filenames" 14 parseLegacyFileScript string = "parse-legacy-file" 15 ) 16 17 var legacyFileNamesCache = make(map[string][]string) 18 19 // ParseVersion parses the raw version 20 func ParseVersion(rawVersions string) []string { 21 var versions []string 22 for _, version := range strings.Split(rawVersions, " ") { 23 version = strings.TrimSpace(version) 24 if len(version) > 0 { 25 versions = append(versions, version) 26 } 27 } 28 return versions 29 } 30 31 // FindVersionsInEnv returns the version from the environment if present 32 func FindVersionsInEnv(plugin string) ([]string, bool) { 33 envVariableName := "ASDF_" + strings.ToUpper(plugin) + "_VERSION" 34 versionString := os.Getenv(envVariableName) 35 if versionString == "" { 36 return nil, false 37 } 38 return ParseVersion(versionString), true 39 } 40 41 // GetLegacyFilenames retrieves the legacy filenames of the plugin 42 func GetLegacyFilenames(plugin string) ([]string, error) { 43 pluginPath := GetPluginPath(plugin) 44 listFilenames := path.Join(pluginPath, "bin", legacyFileNamesScript) 45 if _, err := os.Stat(listFilenames); err != nil { 46 return []string{}, nil 47 } 48 result, err := exec.Command("bash", listFilenames).Output() 49 if err != nil { 50 return nil, err 51 } 52 return strings.Split(string(result), " "), nil 53 } 54 55 // GetVersionsFromLegacyfile returns the versions in the legacy file 56 func GetVersionsFromLegacyfile(plugin string, legacyFilepath string) (versions []string, err error) { 57 pluginPath := GetPluginPath(plugin) 58 parseScriptPath := path.Join(pluginPath, "bin", parseLegacyFileScript) 59 60 var rawVersions []byte 61 if _, err := os.Stat(parseScriptPath); err == nil { 62 rawVersions, err = exec.Command("bash", parseScriptPath, legacyFilepath).Output() 63 } else { 64 rawVersions, err = ioutil.ReadFile(legacyFilepath) 65 } 66 if err != nil { 67 return nil, err 68 } 69 70 for _, version := range strings.Split(string(rawVersions), " ") { 71 versions = append(versions, strings.TrimSpace(version)) 72 } 73 return 74 } 75 76 // FindVersionsInLegacyFile returns the version from the legacy file if found 77 func FindVersionsInLegacyFile(dir string, plugin string) (versions []string, found bool, err error) { 78 var legacyFileNames []string 79 if names, ok := legacyFileNamesCache[plugin]; ok { 80 legacyFileNames = names 81 } else { 82 legacyFileNames, err = GetLegacyFilenames(plugin) 83 if err != nil { 84 return 85 } 86 legacyFileNamesCache[plugin] = legacyFileNames 87 } 88 for _, filename := range legacyFileNames { 89 filename = strings.TrimSpace(filename) 90 filepath := path.Join(dir, filename) 91 if _, err := os.Stat(filepath); err == nil { 92 versions, err := GetVersionsFromLegacyfile(plugin, filepath) 93 if len(versions) == 0 || (len(versions) == 1 && versions[0] == "") { 94 return nil, false, nil 95 } 96 return versions, err == nil, err 97 } 98 } 99 return nil, false, nil 100 } 101 102 // FindVersionsInDir returns the version from the current directory 103 func FindVersionsInDir(dir string, plugin string, config Config) ([]string, bool, error) { 104 filepath := path.Join(dir, toolVersionsFile) 105 if _, err := os.Stat(filepath); err == nil { 106 versions, found, err := FindVersionsInToolFile(filepath, plugin) 107 if found || err != nil { 108 return versions, found, err 109 } 110 } 111 if config.LegacyVersionFile { 112 return FindVersionsInLegacyFile(dir, plugin) 113 114 } 115 return nil, false, nil 116 } 117 118 // FindVersionsInToolFileContent returns the version of a plugin from the toolsfile content 119 func FindVersionsInToolFileContent(plugin string, content string) ([]string, bool) { 120 for _, line := range ReadLines(content) { 121 tokens := strings.SplitN(line, " ", 2) 122 if strings.TrimSpace(tokens[0]) == plugin { 123 return ParseVersion(tokens[1]), true 124 } 125 } 126 return nil, false 127 } 128 129 // FindVersionsInToolFile returns the version of a plugin from the toolsfile at the given path 130 func FindVersionsInToolFile(filepath string, plugin string) ([]string, bool, error) { 131 content, err := ioutil.ReadFile(filepath) 132 if err != nil { 133 return nil, false, err 134 } 135 versions, found := FindVersionsInToolFileContent(plugin, string(content)) 136 return versions, found, nil 137 } 138 139 // FindVersions returns the current versions for the plugin 140 func FindVersions(plugin string, config Config) ([]string, bool, error) { 141 version, found := FindVersionsInEnv(plugin) 142 dir, err := os.Getwd() 143 if err != nil { 144 return nil, false, err 145 } 146 for !found { 147 version, found, err = FindVersionsInDir(dir, plugin, config) 148 if err != nil { 149 return nil, false, err 150 } 151 nextDir := path.Dir(dir) 152 if nextDir == dir { 153 break 154 } 155 dir = nextDir 156 } 157 if !found { 158 homeToolsFile := path.Join(os.Getenv("HOME"), toolVersionsFile) 159 if _, err := os.Stat(homeToolsFile); err == nil { 160 version, found, err = FindVersionsInToolFile(homeToolsFile, plugin) 161 } 162 } 163 return version, found, err 164 }