feat: support .python-version to set version (#12)
* feat: add support for defining version via .python-version * test: coverage for .python-version support * fix: double-printing due to untrimmed .python-version read
This commit is contained in:
parent
d6bce67296
commit
3ccf410f17
3 changed files with 110 additions and 4 deletions
|
@ -104,8 +104,10 @@ func Where(args []string, flags Flags, currentState State) error {
|
|||
selectedVersion, _ := DetermineSelectedPythonVersion(currentState)
|
||||
|
||||
var printedPath string
|
||||
|
||||
if selectedVersion == "SYSTEM" {
|
||||
_, printedPath = DetermineSystemPython()
|
||||
_, sysPath := DetermineSystemPython()
|
||||
printedPath = fmt.Sprintf("%s (system)", sysPath)
|
||||
} else {
|
||||
tag := VersionStringToStruct(selectedVersion)
|
||||
printedPath = GetStatePath("runtimes", fmt.Sprintf("py-%s", selectedVersion), "bin", fmt.Sprintf("python%s", tag.MajorMinor()))
|
||||
|
|
|
@ -1,17 +1,52 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SearchForPythonVersionFile crawls up to the system root to find any
|
||||
// .python-version file that could set the current version.
|
||||
func SearchForPythonVersionFile() (string, bool) {
|
||||
currentPath, _ := os.Getwd()
|
||||
var versionFound string
|
||||
for {
|
||||
content, err := ioutil.ReadFile(path.Join(currentPath, ".python-version"))
|
||||
|
||||
if err == nil {
|
||||
versionFound = strings.TrimSpace(string(content))
|
||||
break
|
||||
}
|
||||
|
||||
nextPath := path.Dir(currentPath)
|
||||
|
||||
if currentPath == nextPath {
|
||||
break
|
||||
}
|
||||
|
||||
currentPath = nextPath
|
||||
}
|
||||
|
||||
return versionFound, versionFound != ""
|
||||
}
|
||||
|
||||
// DetermineSelectedPythonVersion returns the Python runtime version that should be
|
||||
// used according to v.
|
||||
//
|
||||
// By default, 'SYSTEM' is returned, which signals that the non-v-managed Python
|
||||
// runtime is used.
|
||||
// First, v will look in the current directory and all its parents for a .python-version
|
||||
// file that would indicate which version is preferred. If none are found, the global
|
||||
// user-defined version (via `v use <version>`) is used. If there is none, the system
|
||||
// Python version is used.
|
||||
func DetermineSelectedPythonVersion(currentState State) (string, error) {
|
||||
pythonFileVersion, pythonFileVersionFound := SearchForPythonVersionFile()
|
||||
|
||||
if pythonFileVersionFound {
|
||||
return pythonFileVersion, nil
|
||||
}
|
||||
|
||||
if len(currentState.GlobalVersion) != 0 {
|
||||
return currentState.GlobalVersion, nil
|
||||
}
|
||||
|
@ -27,8 +62,11 @@ func DetermineSystemPython() (string, string) {
|
|||
pathWithoutShims := slices.DeleteFunc(strings.Split(currentPathEnv, ":"), func(element string) bool {
|
||||
return element == GetStatePath("shims")
|
||||
})
|
||||
|
||||
// FIXME: This should be set through RunCommand instead.
|
||||
os.Setenv("PATH", strings.Join(pathWithoutShims, ":"))
|
||||
defer os.Setenv("PATH", currentPathEnv)
|
||||
|
||||
whichOut, _ := RunCommand([]string{"which", "python"}, GetStatePath(), true)
|
||||
versionOut, _ := RunCommand([]string{"python", "--version"}, GetStatePath(), true)
|
||||
|
||||
|
|
|
@ -16,6 +16,10 @@ import (
|
|||
func SetupAndCleanupEnvironment(t *testing.T) func() {
|
||||
os.Setenv("V_ROOT", t.TempDir())
|
||||
|
||||
temporaryWd := t.TempDir()
|
||||
|
||||
os.Chdir(temporaryWd)
|
||||
|
||||
return func() {
|
||||
os.Unsetenv("V_ROOT")
|
||||
}
|
||||
|
@ -43,6 +47,26 @@ func TestDetermineSystemPythonGetsUnshimmedPythonRuntime(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestDetermineSelectedPythonVersionUsesPythonVersionFileIfFound(t *testing.T) {
|
||||
defer SetupAndCleanupEnvironment(t)()
|
||||
|
||||
// Writing a mock user-defined state.
|
||||
mockState := State{GlobalVersion: "1.0.0"}
|
||||
statePath := GetStatePath("state.json")
|
||||
stateData, _ := json.Marshal(mockState)
|
||||
ioutil.WriteFile(statePath, stateData, 0750)
|
||||
|
||||
temporaryWd := t.TempDir()
|
||||
os.Chdir(temporaryWd)
|
||||
ioutil.WriteFile(path.Join(temporaryWd, ".python-version"), []byte("1.2.3"), 0750)
|
||||
|
||||
version, err := DetermineSelectedPythonVersion(ReadState())
|
||||
|
||||
if err != nil || version != "1.2.3" {
|
||||
t.Errorf("Expected version to be %s, got %s instead.", "1.2.3", version)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetermineSelectedPythonVersionGetsUserDefinedVersion(t *testing.T) {
|
||||
defer SetupAndCleanupEnvironment(t)()
|
||||
|
||||
|
@ -60,7 +84,7 @@ func TestDetermineSelectedPythonVersionGetsUserDefinedVersion(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDetermineSelectedPythonVersionDefaultsToSystem(t *testing.T) {
|
||||
defer SetupAndCleanupEnvironment(t)
|
||||
defer SetupAndCleanupEnvironment(t)()
|
||||
|
||||
version, err := DetermineSelectedPythonVersion(ReadState())
|
||||
|
||||
|
@ -68,3 +92,45 @@ func TestDetermineSelectedPythonVersionDefaultsToSystem(t *testing.T) {
|
|||
t.Errorf("Expected version to be 'SYSTEM', got %s instead.", version)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchForPythonVersionFileFindsFileInCwd(t *testing.T) {
|
||||
defer SetupAndCleanupEnvironment(t)()
|
||||
|
||||
temporaryWd := t.TempDir()
|
||||
os.Chdir(temporaryWd)
|
||||
ioutil.WriteFile(path.Join(temporaryWd, ".python-version"), []byte("1.2.3"), 0750)
|
||||
|
||||
versionFound, found := SearchForPythonVersionFile()
|
||||
|
||||
if versionFound != "1.2.3" || !found {
|
||||
t.Errorf("Expected \"1.2.3\", found %s", versionFound)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchForPythonVersionFileFindsFileInParents(t *testing.T) {
|
||||
defer SetupAndCleanupEnvironment(t)()
|
||||
|
||||
temporaryWd := t.TempDir()
|
||||
|
||||
ioutil.WriteFile(path.Join(temporaryWd, ".python-version"), []byte("1.2.3"), 0750)
|
||||
os.Mkdir(path.Join(temporaryWd, "child"), 0750)
|
||||
os.Chdir(path.Join(temporaryWd, "child"))
|
||||
|
||||
versionFound, found := SearchForPythonVersionFile()
|
||||
|
||||
if versionFound != "1.2.3" || !found {
|
||||
t.Errorf("Expected \"1.2.3\", found %s", versionFound)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestSearchForPythonVersionFileReturnsOnRootIfNoneFound(t *testing.T) {
|
||||
defer SetupAndCleanupEnvironment(t)()
|
||||
|
||||
versionFound, found := SearchForPythonVersionFile()
|
||||
|
||||
if versionFound != "" || found {
|
||||
t.Errorf("Did not expect any result, found %s.", versionFound)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue