-
Notifications
You must be signed in to change notification settings - Fork 0
feat(config:install): improve destination directory detection #48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
7af2018
fcf4366
981da87
e659507
55a5230
39aa209
3ea3489
8b2797f
92ed971
5b5349b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,57 +13,175 @@ import ( | |
| func TestFindConfigDir(t *testing.T) { | ||
| tempDir := t.TempDir() | ||
|
|
||
| t.Run("XDG_CONFIG_HOME exists", func(t *testing.T) { | ||
| switch runtime.GOOS { | ||
| case "windows", "darwin", "ios", "plan9": | ||
| t.Run("XDG_CONFIG_HOME set", func(t *testing.T) { | ||
| if runtime.GOOS == "plan9" { | ||
| t.Skip() | ||
| } | ||
| err := os.Setenv("XDG_CONFIG_HOME", tempDir) | ||
| require.NoError(t, err) | ||
| defer os.Unsetenv("XDG_CONFIG_HOME") | ||
|
|
||
| err = os.Mkdir(filepath.Join(tempDir, subDir), 0o755) | ||
| require.NoError(t, err) | ||
| t.Setenv("XDG_CONFIG_HOME", tempDir) | ||
|
|
||
| result, err := FindConfigDir() | ||
| assert.NoError(t, err) | ||
| assert.Equal(t, filepath.Join(tempDir, subDir), result) | ||
| }) | ||
|
|
||
| t.Run("XDG_CONFIG_HOME honored even when target does not yet exist", func(t *testing.T) { | ||
| if runtime.GOOS == "plan9" { | ||
| t.Skip() | ||
| } | ||
| nonExistent := filepath.Join(tempDir, "does-not-exist-yet") | ||
| t.Setenv("XDG_CONFIG_HOME", nonExistent) | ||
|
|
||
| result, err := FindConfigDir() | ||
| assert.NoError(t, err) | ||
| assert.Equal(t, filepath.Join(nonExistent, subDir), result) | ||
| }) | ||
|
|
||
| t.Run("HOME fallback", func(t *testing.T) { | ||
| err := os.Setenv("HOME", tempDir) | ||
| require.NoError(t, err) | ||
| defer os.Unsetenv("HOME") | ||
| t.Setenv("XDG_CONFIG_HOME", "") | ||
| t.Setenv("HOME", tempDir) | ||
|
|
||
| result, err := FindConfigDir() | ||
| assert.NoError(t, err) | ||
| assert.Equal(t, filepath.Join(tempDir, homeSubDir), result) | ||
| // On platforms where os.UserConfigDir resolves to an existing directory under the test | ||
| // HOME, that directory wins. | ||
| ucd, ucdErr := os.UserConfigDir() | ||
| isDir, _ := isExistingDirectory(ucd) | ||
| if ucdErr == nil && isDir { | ||
| assert.Equal(t, filepath.Join(ucd, subDir), result) | ||
| } else { | ||
| assert.Equal(t, filepath.Join(tempDir, homeSubDir), result) | ||
|
miguelsanchez-upsun marked this conversation as resolved.
|
||
| } | ||
| }) | ||
| } | ||
|
|
||
| func TestFindBinDir(t *testing.T) { | ||
| tempDir := t.TempDir() | ||
| if runtime.GOOS == "windows" { | ||
| t.Skip("path setup in this test is unix-style") | ||
| } | ||
|
Comment on lines
+58
to
+60
|
||
|
|
||
| err := os.Setenv("HOME", tempDir) | ||
| require.NoError(t, err) | ||
| defer os.Unsetenv("HOME") | ||
| originalExecFn := executableFn | ||
| t.Cleanup(func() { executableFn = originalExecFn }) | ||
|
|
||
| result, err := FindBinDir() | ||
| assert.NoError(t, err) | ||
| assert.Equal(t, filepath.Join(tempDir, homeSubDir, "bin"), result) | ||
| setExe := func(p string) { executableFn = func() (string, error) { return p, nil } } | ||
|
|
||
| var standardDir string | ||
| if runtime.GOOS == "windows" { | ||
| standardDir = filepath.Join("AppData", "Local", "Programs") | ||
| } else { | ||
| standardDir = filepath.Join(".local", "bin") | ||
| } | ||
| err = os.Setenv("PATH", os.Getenv("PATH")+string(os.PathListSeparator)+filepath.Join(tempDir, standardDir)) | ||
| require.NoError(t, err) | ||
| t.Run("home fallback when nothing on PATH", func(t *testing.T) { | ||
| tempDir := t.TempDir() | ||
| t.Setenv("HOME", tempDir) | ||
| t.Setenv("PATH", "/nonexistent/dir") | ||
| t.Setenv("XDG_BIN_HOME", "") | ||
| setExe(filepath.Join(tempDir, "exe")) | ||
|
|
||
| result, err = FindBinDir() | ||
| assert.NoError(t, err) | ||
| assert.Equal(t, filepath.Join(tempDir, standardDir), result) | ||
| result, err := FindBinDir() | ||
| assert.NoError(t, err) | ||
| assert.Equal(t, filepath.Join(tempDir, homeSubDir, "bin"), result) | ||
| }) | ||
|
|
||
| t.Run("allowlist fallback picks first writable PATH entry", func(t *testing.T) { | ||
| tempDir := t.TempDir() | ||
| localBin := filepath.Join(tempDir, ".local", "bin") | ||
| require.NoError(t, os.MkdirAll(localBin, 0o755)) | ||
| t.Setenv("HOME", tempDir) | ||
| t.Setenv("PATH", localBin) | ||
| t.Setenv("XDG_BIN_HOME", "") | ||
| setExe(filepath.Join(tempDir, "build", "exe")) | ||
|
|
||
| result, err := FindBinDir() | ||
| assert.NoError(t, err) | ||
| assert.Equal(t, localBin, result) | ||
| }) | ||
|
|
||
| t.Run("source-dir match on allowlist co-locates", func(t *testing.T) { | ||
| tempDir := t.TempDir() | ||
| sourceBin := filepath.Join(tempDir, "bin") | ||
| higherPriorityBin := filepath.Join(tempDir, ".local", "bin") | ||
| require.NoError(t, os.MkdirAll(sourceBin, 0o755)) | ||
| require.NoError(t, os.MkdirAll(higherPriorityBin, 0o755)) | ||
| t.Setenv("HOME", tempDir) | ||
| t.Setenv("PATH", higherPriorityBin+string(os.PathListSeparator)+sourceBin) | ||
| t.Setenv("XDG_BIN_HOME", "") | ||
| setExe(filepath.Join(sourceBin, "exe")) | ||
|
|
||
| result, err := FindBinDir() | ||
| assert.NoError(t, err) | ||
| assert.Equal(t, sourceBin, result) | ||
| }) | ||
|
|
||
| t.Run("symlinked source dir is co-located via allowlist", func(t *testing.T) { | ||
| tempDir := t.TempDir() | ||
| shimBin := filepath.Join(tempDir, "shim", "bin") | ||
| realBin := filepath.Join(tempDir, "real", "bin") | ||
| require.NoError(t, os.MkdirAll(shimBin, 0o755)) | ||
| require.NoError(t, os.MkdirAll(realBin, 0o755)) | ||
| realExe := filepath.Join(realBin, "exe") | ||
| require.NoError(t, os.WriteFile(realExe, []byte("#!/bin/sh\n"), 0o600)) | ||
| require.NoError(t, os.Symlink(realExe, filepath.Join(shimBin, "exe"))) | ||
|
|
||
| higherPriorityBin := filepath.Join(tempDir, ".local", "bin") | ||
| require.NoError(t, os.MkdirAll(higherPriorityBin, 0o755)) | ||
| t.Setenv("HOME", tempDir) | ||
| t.Setenv("PATH", higherPriorityBin+string(os.PathListSeparator)+shimBin) | ||
| // XDG_BIN_HOME pulls shimBin onto the allowlist; the running exe lives outside the | ||
| // allowlist but is reachable via a symlink from shimBin, so co-location should still | ||
| // pick shimBin. | ||
| t.Setenv("XDG_BIN_HOME", shimBin) | ||
| setExe(realExe) | ||
|
|
||
| result, err := FindBinDir() | ||
| assert.NoError(t, err) | ||
| assert.Equal(t, shimBin, result) | ||
| }) | ||
|
|
||
| t.Run("nvm-style source dir is not selected", func(t *testing.T) { | ||
| tempDir := t.TempDir() | ||
| nvmBin := filepath.Join(tempDir, ".nvm", "versions", "node", "v20.0.0", "bin") | ||
| localBin := filepath.Join(tempDir, ".local", "bin") | ||
| require.NoError(t, os.MkdirAll(nvmBin, 0o755)) | ||
| require.NoError(t, os.MkdirAll(localBin, 0o755)) | ||
| t.Setenv("HOME", tempDir) | ||
| t.Setenv("PATH", nvmBin+string(os.PathListSeparator)+localBin) | ||
| t.Setenv("XDG_BIN_HOME", "") | ||
| setExe(filepath.Join(nvmBin, "upsun")) | ||
|
|
||
| result, err := FindBinDir() | ||
| assert.NoError(t, err) | ||
| assert.Equal(t, localBin, result) | ||
| }) | ||
|
|
||
| t.Run("XDG_BIN_HOME is honored", func(t *testing.T) { | ||
| tempDir := t.TempDir() | ||
| xdgBin := filepath.Join(tempDir, "xdg-bin") | ||
| require.NoError(t, os.MkdirAll(xdgBin, 0o755)) | ||
| t.Setenv("HOME", tempDir) | ||
| t.Setenv("XDG_BIN_HOME", xdgBin) | ||
| t.Setenv("PATH", xdgBin) | ||
| setExe(filepath.Join(tempDir, "exe")) | ||
|
|
||
| result, err := FindBinDir() | ||
| assert.NoError(t, err) | ||
| assert.Equal(t, xdgBin, result) | ||
| }) | ||
|
|
||
| t.Run("non-writable PATH entry is skipped", func(t *testing.T) { | ||
| if os.Geteuid() == 0 { | ||
| t.Skip("running as root; cannot create a non-writable directory") | ||
| } | ||
| tempDir := t.TempDir() | ||
| readOnlyBin := filepath.Join(tempDir, ".local", "bin") | ||
| writableBin := filepath.Join(tempDir, "bin") | ||
| require.NoError(t, os.MkdirAll(readOnlyBin, 0o755)) | ||
| require.NoError(t, os.MkdirAll(writableBin, 0o755)) | ||
| require.NoError(t, os.Chmod(readOnlyBin, 0o555)) | ||
| t.Cleanup(func() { _ = os.Chmod(readOnlyBin, 0o755) }) | ||
|
|
||
| t.Setenv("HOME", tempDir) | ||
| t.Setenv("PATH", readOnlyBin+string(os.PathListSeparator)+writableBin) | ||
| t.Setenv("XDG_BIN_HOME", "") | ||
| setExe(filepath.Join(tempDir, "exe")) | ||
|
|
||
| result, err := FindBinDir() | ||
| assert.NoError(t, err) | ||
| assert.Equal(t, writableBin, result) | ||
| }) | ||
| } | ||
|
|
||
| func TestFSHelpers(t *testing.T) { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.