diff --git a/internal/controller/common.go b/internal/controller/common.go index 71b065c7..aff8d4ee 100644 --- a/internal/controller/common.go +++ b/internal/controller/common.go @@ -102,6 +102,7 @@ func NewAtlasExec(dir string, c *Cloud, home string) (AtlasExec, error) { return nil, err } env := atlasexec.NewOSEnviron() + cacheHome := "" // If DATA_DIR is set, create a resource-specific directory and set HOME. if dataDir := os.Getenv(envDataDir); dataDir != "" { homeDir := filepath.Join(dataDir, home) @@ -109,10 +110,19 @@ func NewAtlasExec(dir string, c *Cloud, home string) (AtlasExec, error) { return nil, fmt.Errorf("creating resource home directory: %w", err) } env["HOME"] = homeDir - } else if env["HOME"] == "" { + cacheHome = filepath.Join(homeDir, ".cache") + } else if env["HOME"] == "" || env["HOME"] == "/" { // Ensure HOME is set to a safe default when not provided by the environment // and no DATA_DIR-based home directory is configured. env["HOME"] = "/tmp" + cacheHome = "/tmp/.cache" + } + if cacheHome != "" { + if err := os.MkdirAll(cacheHome, 0755); err != nil { + return nil, fmt.Errorf("creating cache directory: %w", err) + } + env["XDG_CACHE_HOME"] = cacheHome + env["GOCACHE"] = filepath.Join(cacheHome, "go-build") } if c != nil && c.Token != "" { env["ATLAS_TOKEN"] = c.Token diff --git a/internal/controller/common_test.go b/internal/controller/common_test.go index a775b8d4..3a28c608 100644 --- a/internal/controller/common_test.go +++ b/internal/controller/common_test.go @@ -15,12 +15,18 @@ package controller import ( + "context" + "os" + "path/filepath" "reflect" + "strings" "testing" "time" + "ariga.io/atlas/atlasexec" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclwrite" + "github.com/stretchr/testify/require" ) func Test_mergeBlocks(t *testing.T) { @@ -303,3 +309,89 @@ func Test_backoffDelayAt(t *testing.T) { }) } } + +func TestNewAtlasExec_HomeAndCache(t *testing.T) { + tests := []struct { + name string + homeEnv string + dataDir string + resourceHome string + wantHome string + wantCache string + }{ + { + name: "data dir overrides home root", + homeEnv: "/", + dataDir: "data", + resourceHome: "ns/name", + wantHome: "data/ns/name", + wantCache: "data/ns/name/.cache", + }, + { + name: "empty home falls back to tmp", + homeEnv: "", + resourceHome: "ignored", + wantHome: "/tmp", + wantCache: "/tmp/.cache", + }, + { + name: "root home falls back to tmp", + homeEnv: "/", + resourceHome: "ignored", + wantHome: "/tmp", + wantCache: "/tmp/.cache", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tmp := t.TempDir() + capture := filepath.Join(tmp, "env.txt") + path := filepath.Join(tmp, "atlas") + script := `#!/bin/sh +{ + printf 'HOME=%s\n' "${HOME}" + printf 'XDG_CACHE_HOME=%s\n' "${XDG_CACHE_HOME}" + printf 'GOCACHE=%s\n' "${GOCACHE}" +} > "${CAPTURE_ENV}" +printf '{"Org":"test"}' +` + require.NoError(t, os.WriteFile(path, []byte(script), 0755)) + t.Setenv("PATH", tmp+string(os.PathListSeparator)+os.Getenv("PATH")) + t.Setenv("CAPTURE_ENV", capture) + t.Setenv("HOME", tt.homeEnv) + if tt.dataDir == "" { + t.Setenv(envDataDir, "") + } else { + dataDir := filepath.Join(tmp, tt.dataDir) + require.NoError(t, os.MkdirAll(dataDir, 0755)) + t.Setenv(envDataDir, dataDir) + tt.wantHome = filepath.Join(tmp, tt.wantHome) + tt.wantCache = filepath.Join(tmp, tt.wantCache) + } + exec, err := NewAtlasExec(tmp, nil, tt.resourceHome) + require.NoError(t, err) + _, err = exec.WhoAmI(context.Background(), &atlasexec.WhoAmIParams{}) + require.NoError(t, err) + require.DirExists(t, tt.wantCache) + if tt.dataDir != "" { + require.DirExists(t, tt.wantHome) + } + data, err := os.ReadFile(capture) + require.NoError(t, err) + got := make(map[string]string) + for _, line := range strings.Split(strings.TrimSpace(string(data)), "\n") { + if line == "" { + continue + } + k, v, ok := strings.Cut(line, "=") + require.True(t, ok) + got[k] = v + } + require.Equal(t, map[string]string{ + "HOME": tt.wantHome, + "XDG_CACHE_HOME": tt.wantCache, + "GOCACHE": filepath.Join(tt.wantCache, "go-build"), + }, got) + }) + } +}