Skip to content
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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: generalize HOMEDIR management and respect XDG_CONFIG_HOME, fixes #5807 #5813

Merged
merged 49 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
b90d19f
feat: respect xdg_config_home, fixes #5807
danepowell Feb 9, 2024
d0781e6
reword comment
danepowell Feb 12, 2024
9c433aa
update test
danepowell Feb 13, 2024
86343e4
fix tests
danepowell Feb 14, 2024
379f0b3
fix lint error
danepowell Feb 14, 2024
ce97ad2
Fix tests
danepowell Feb 14, 2024
293e18f
Make config directory optional, update docs
stasadev Apr 10, 2024
6b521a7
Move mutagen_data_directory
stasadev Apr 19, 2024
59b31df
refactor: there is no .ddev/.globalcommands
stasadev Apr 26, 2024
bb90f37
feat: remove old ~/.ddev_mutagen_data_directory
stasadev Apr 26, 2024
10e6df2
refactor: use $XDG_CONFIG_HOME for all platforms
stasadev Apr 26, 2024
54dbb0c
feat: add global_config_path to global_config.yaml
stasadev Apr 26, 2024
7ef5b20
refactor: use $XDG_CONFIG_HOME in tests
stasadev Apr 26, 2024
fd84eb2
Move MUTAGEN_DATA_DIRECTORY
stasadev Apr 26, 2024
899783d
Stop daemon in the previous MUTAGEN_DATA_DIRECTORY
stasadev Apr 26, 2024
32b6c3b
Check MUTAGEN_DATA_DIRECTORY explicitly before running Mutagen
stasadev Apr 26, 2024
be509ce
Use EnsureGlobalConfig to completely reset the config
stasadev Apr 26, 2024
ff50bf0
test: refactored test function
stasadev Apr 30, 2024
26b78eb
test: add more details for mutagen start/stop
stasadev Apr 30, 2024
6e2cf52
fix: use shorter path to MUTAGEN_DATA_DIRECTORY in XDG_CONFIG_HOME
stasadev Apr 30, 2024
4e22f52
fix: make XDG_CONFIG_HOME shorter for MUTAGEN_DATA_DIRECTORY
stasadev Apr 30, 2024
a108a30
test: check if Mutagen binary exists before running it
stasadev Apr 30, 2024
f5df0e4
test: use mutagen start/stop functions
stasadev May 1, 2024
600ba8f
Show MUTAGEN_DATA_DIRECTORY on daemon start error
stasadev May 1, 2024
f62a63d
Show warning if Mutagen socket path is too long
stasadev May 1, 2024
b566311
Do not copy global_config.yaml to the temp location
stasadev May 1, 2024
60616b2
test: add more details for mutagen start/stop
stasadev May 1, 2024
3303467
test: fix TestPoweroffOnNewVersion
stasadev May 1, 2024
e666838
Use shorter .ddev/.mdd for MUTAGEN_DATA_DIRECTORY
stasadev May 1, 2024
1801bfb
test: rename tmpXdgConfigHomeDir variable
stasadev May 2, 2024
692539b
test: add TestGetXdgConfigHomeDir
stasadev May 2, 2024
26839c9
docs: add more tips for ~/.ddev directory
stasadev May 2, 2024
5fa9fd0
@rfay's suggestions, thank you [skip ci]
stasadev May 6, 2024
df05920
feat: `ddev mutagen version` command
stasadev May 8, 2024
b958f1c
Revert "feat: add global_config_path to global_config.yaml"
stasadev May 8, 2024
394b665
feat: add global-ddev-dir to `ddev version`
stasadev May 8, 2024
9224d08
docs: update path for MUTAGEN_DATA_DIRECTORY
stasadev May 8, 2024
92064b4
refactor: use default XDG_CONFIG_HOME for Linux only
stasadev May 8, 2024
9efec6a
refactor: use function instead of env variable
stasadev May 8, 2024
9c5ab51
test: rename MoveGlobalDdevDir to CopyGlobalDdevDir
stasadev May 8, 2024
e5bd603
docs: `mutagen version` command
stasadev May 8, 2024
62fb36d
refactor: run mutagen length check only for Linux and macOS
stasadev May 8, 2024
632ff93
docs: add XDG to spelling check list
stasadev May 8, 2024
f360482
docs: remove trailing space
stasadev May 8, 2024
a3729bf
@rfay suggestions [skip ci]
stasadev May 20, 2024
69ad029
feat: create $XDG_CONFIG_HOME/ddev directory
stasadev May 20, 2024
cb5db44
feat: create $XDG_CONFIG_HOME/ddev directory
stasadev May 21, 2024
43951f8
test: fix TestCreateGlobalDdevDir
stasadev May 21, 2024
6f8f1a1
test: use XDG for TestConfigGitignore
stasadev May 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions .buildkite/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,13 @@ fi
# Make sure we start with mutagen daemon off.
unset MUTAGEN_DATA_DIRECTORY
if [ -f ~/.ddev/bin/mutagen -o -f ~/.ddev/bin/mutagen.exe ]; then
# This line can be removed when ~/.ddev/.mdd is well established in master, probably July 2024
MUTAGEN_DATA_DIRECTORY=~/.ddev_mutagen_data_directory/ ~/.ddev/bin/mutagen sync terminate -a || true
stasadev marked this conversation as resolved.
Show resolved Hide resolved
MUTAGEN_DATA_DIRECTORY=~/.ddev/.mdd/ ~/.ddev/bin/mutagen sync terminate -a || true
MUTAGEN_DATA_DIRECTORY=~/.mutagen ~/.ddev/bin/mutagen daemon stop || true
# This line can be removed when ~/.ddev/.mdd is well established in master, probably July 2024
MUTAGEN_DATA_DIRECTORY=~/.ddev_mutagen_data_directory/ ~/.ddev/bin/mutagen daemon stop || true
stasadev marked this conversation as resolved.
Show resolved Hide resolved
MUTAGEN_DATA_DIRECTORY=~/.ddev/.mdd/ ~/.ddev/bin/mutagen daemon stop || true
fi
if command -v killall >/dev/null ; then
killall mutagen || true
Expand Down
1 change: 1 addition & 0 deletions .spellcheckwordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ WSL2
WantedBy
Webhosting
XDebug
XDG
Xhprof
Zoho
XSym
Expand Down
32 changes: 9 additions & 23 deletions cmd/ddev/cmd/autocompletion_test.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package cmd

import (
"github.com/ddev/ddev/pkg/dockerutil"
"os"
"path/filepath"
"runtime"
"strings"
"testing"

"github.com/ddev/ddev/pkg/ddevapp"
"github.com/ddev/ddev/pkg/dockerutil"
"github.com/ddev/ddev/pkg/exec"
"github.com/ddev/ddev/pkg/fileutil"
"github.com/ddev/ddev/pkg/globalconfig"
"github.com/ddev/ddev/pkg/testcommon"
asrt "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -225,8 +227,7 @@ func TestAutocompletionForCustomCmds(t *testing.T) {
app, err := ddevapp.NewApp("", false)
assert.NoError(err)

tmpHome, _, err := makeTempHomeDir(app, t)
require.NoError(t, err)
tmpXdgConfigHomeDir := testcommon.CopyGlobalDdevDir(t)

testdataCustomCommandsDir := filepath.Join(origDir, "testdata", t.Name())

Expand All @@ -235,20 +236,13 @@ func TestAutocompletionForCustomCmds(t *testing.T) {
assert.NoError(err)
err = app.Stop(true, false)
assert.NoError(err)
// Stop the Mutagen daemon running in the bogus homedir
ddevapp.StopMutagenDaemon()
_ = os.RemoveAll(tmpHome)
testcommon.ResetGlobalDdevDir(t, tmpXdgConfigHomeDir)
_ = fileutil.PurgeDirectory(filepath.Join(site.Dir, ".ddev", "commands"))
})
err = app.Start()
require.NoError(t, err)

// We can't use the standard getGlobalDDevDir here because *our* global hasn't changed.
// It's changed via $HOME for the DDEV subprocess
err = os.MkdirAll(filepath.Join(tmpHome, ".ddev"), 0755)
assert.NoError(err)

tmpHomeGlobalCommandsDir := filepath.Join(tmpHome, ".ddev", "commands")
tmpHomeGlobalCommandsDir := filepath.Join(globalconfig.GetGlobalDdevDir(), "commands")
projectCommandsDir := app.GetConfigPath("commands")

// Remove existing commands
Expand Down Expand Up @@ -299,8 +293,7 @@ func TestAutocompleteTermsForCustomCmds(t *testing.T) {
app, err := ddevapp.NewApp("", false)
assert.NoError(err)

tmpHome, _, err := makeTempHomeDir(app, t)
require.NoError(t, err)
tmpXdgConfigHomeDir := testcommon.CopyGlobalDdevDir(t)

testdataCustomCommandsDir := filepath.Join(origDir, "testdata", t.Name())

Expand All @@ -309,20 +302,13 @@ func TestAutocompleteTermsForCustomCmds(t *testing.T) {
assert.NoError(err)
err = app.Stop(true, false)
assert.NoError(err)
// Stop the Mutagen daemon running in the bogus homedir
ddevapp.StopMutagenDaemon()
_ = os.RemoveAll(tmpHome)
testcommon.ResetGlobalDdevDir(t, tmpXdgConfigHomeDir)
_ = fileutil.PurgeDirectory(filepath.Join(site.Dir, ".ddev", "commands"))
})
err = app.Start()
require.NoError(t, err)

// We can't use the standard getGlobalDDevDir here because *our* global hasn't changed.
// It's changed via $HOME for the DDEV subprocess
err = os.MkdirAll(filepath.Join(tmpHome, ".ddev"), 0755)
assert.NoError(err)

tmpHomeGlobalCommandsDir := filepath.Join(tmpHome, ".ddev", "commands")
tmpHomeGlobalCommandsDir := filepath.Join(globalconfig.GetGlobalDdevDir(), "commands")
projectCommandsDir := app.GetConfigPath("commands")

// Remove existing commands
Expand Down
65 changes: 4 additions & 61 deletions cmd/ddev/cmd/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ func TestCustomCommands(t *testing.T) {
app, err := ddevapp.NewApp("", false)
assert.NoError(err)

tmpHome, origHome, err := makeTempHomeDir(app, t)
require.NoError(t, err)
tmpXdgConfigHomeDir := testcommon.CopyGlobalDdevDir(t)

testdataCustomCommandsDir := filepath.Join(origDir, "testdata", t.Name())

Expand All @@ -46,24 +45,18 @@ func TestCustomCommands(t *testing.T) {
assert.NoError(err)
err = app.Stop(true, false)
assert.NoError(err)
// Stop the Mutagen daemon running in the bogus homedir
ddevapp.StopMutagenDaemon()
testcommon.ResetGlobalDdevDir(t, tmpXdgConfigHomeDir)
runTime()
app.Type = origType
err = app.WriteConfig()
assert.NoError(err)
_ = os.RemoveAll(tmpHome)
_ = fileutil.PurgeDirectory(filepath.Join(site.Dir, ".ddev", "commands"))
})
// We must start the app before copying commands, so they don't get copied over
err = app.Start()
require.NoError(t, err)

// We can't use the standard getGlobalDDevDir here because *our* global hasn't changed.
// It's changed via $HOME for the DDEV subprocess
err = os.MkdirAll(filepath.Join(tmpHome, ".ddev"), 0755)
assert.NoError(err)
tmpHomeGlobalCommandsDir := filepath.Join(tmpHome, ".ddev", "commands")
tmpHomeGlobalCommandsDir := filepath.Join(globalconfig.GetGlobalDdevDir(), "commands")
err = os.RemoveAll(tmpHomeGlobalCommandsDir)
assert.NoError(err)

Expand All @@ -76,7 +69,7 @@ func TestCustomCommands(t *testing.T) {
assert.NoError(err)

// We need to run some assertions outside of the context of a project first
err = os.Chdir(tmpHome)
err = os.Chdir(tmpXdgConfigHomeDir)
require.NoError(t, err)

// Check that only global host commands with the XXX annotation display here
Expand Down Expand Up @@ -299,10 +292,6 @@ func TestCustomCommands(t *testing.T) {
assert.FileExists(filepath.Join(projectCommandsDir, f))
}

// Make sure we haven't accidentally created anything inappropriate in ~/.ddev
assert.False(fileutil.FileExists(filepath.Join(tmpHome, ".ddev", ".globalcommands")))
assert.False(fileutil.FileExists(filepath.Join(origHome, ".ddev", ".globalcommands")))
stasadev marked this conversation as resolved.
Show resolved Hide resolved

// Make sure that the old launch, mysql, and xdebug commands aren't in the project directory
for _, command := range []string{"db/mysql", "host/launch", "web/xdebug"} {
cmdPath := app.GetConfigPath(filepath.Join("commands", command))
Expand Down Expand Up @@ -535,49 +524,3 @@ func TestNpmYarnCommands(t *testing.T) {
require.NoError(t, err)
}
}

// makeTempHomeDir makes a temporary home directory named for the test being executed.
// Don't forget to run `ddevapp.StopMutagenDaemon()` and `os.RemoveAll(tmpHome)` in the
// test's cleanup function.
func makeTempHomeDir(app *ddevapp.DdevApp, t *testing.T) (string, string, error) {
// Before changing HOME, make sure that Mutagen is already running if we are using it,
// so we don't accidentally start it in the wrong directory
err := globalconfig.ReadGlobalConfig()
if err != nil {
return "", "", err
}
if globalconfig.DdevGlobalConfig.IsMutagenEnabled() {
out, err := exec.RunHostCommand(globalconfig.GetMutagenPath(), "daemon", "start")
if err != nil {
return "", "", fmt.Errorf("unable to run Mutagen daemon start, out='%s', err=%v", out, err)
}
}

// Must be stopped before changing homedir or Mutagen will lose track
// of sessions which are also tracked in the homedir.
err = app.Stop(true, false)
if err != nil {
return "", "", err
}

origHome, err := os.UserHomeDir()
require.NoError(t, err)
if runtime.GOOS == "windows" {
origHome = os.Getenv("USERPROFILE")
}

tmpHome := testcommon.CreateTmpDir(t.Name() + "-tempHome")

// Change the homedir temporarily
t.Setenv("HOME", tmpHome)
t.Setenv("USERPROFILE", tmpHome)
t.Setenv("DDEV_DEBUG", "")

// Make sure we have the .ddev/bin dir we need
err = fileutil.CopyDir(filepath.Join(origHome, ".ddev/bin"), filepath.Join(tmpHome, ".ddev/bin"))
if err != nil {
return "", "", err
}

return tmpHome, origHome, nil
}
12 changes: 7 additions & 5 deletions cmd/ddev/cmd/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package cmd

import (
"fmt"
copy2 "github.com/otiai10/copy"
"os"
"path/filepath"
"reflect"
Expand All @@ -16,6 +15,7 @@ import (
"github.com/ddev/ddev/pkg/globalconfig"
"github.com/ddev/ddev/pkg/nodeps"
"github.com/ddev/ddev/pkg/testcommon"
copy2 "github.com/otiai10/copy"
asrt "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"
Expand Down Expand Up @@ -651,6 +651,9 @@ func TestConfigGitignore(t *testing.T) {

origDir, _ := os.Getwd()

tmpXdgConfigHomeDir := testcommon.CopyGlobalDdevDir(t)
globalDdevDir := globalconfig.GetGlobalDdevDir()

// Create a temporary directory and switch to it.
testDir := testcommon.CreateTmpDir(t.Name())

Expand All @@ -664,8 +667,7 @@ func TestConfigGitignore(t *testing.T) {
assert.NoError(err)
err = os.Chdir(origDir)
assert.NoError(err)
_, err = exec.RunHostCommand("bash", "-c", fmt.Sprintf("rm -f ~/.ddev/commands/web/%s ~/.ddev/homeadditions/%s", t.Name(), t.Name()))
assert.NoError(err)
testcommon.ResetGlobalDdevDir(t, tmpXdgConfigHomeDir)
_ = os.RemoveAll(testDir)
})

Expand All @@ -682,10 +684,10 @@ func TestConfigGitignore(t *testing.T) {
out = strings.ReplaceAll(out, "new file: .ddev/config.yaml", "")
assert.NotContains(out, "new file:")

_, err = exec.RunHostCommand("bash", "-c", fmt.Sprintf("touch ~/.ddev/commands/web/%s ~/.ddev/homeadditions/%s", t.Name(), t.Name()))
_, err = exec.RunHostCommand("bash", "-c", fmt.Sprintf(`touch "/%s" "/%s"`, filepath.Join(globalDdevDir, "commands", "web", t.Name()), filepath.Join(globalDdevDir, "homeadditions", t.Name())))
assert.NoError(err)
if err != nil {
out, err = exec.RunHostCommand("bash", "-c", "ls -l ~/.ddev && ls -lR ~/.ddev/commands ~/.ddev/homeadditions")
out, err = exec.RunHostCommand("bash", "-c", fmt.Sprintf(`ls -l "/%s" && ls -lR "/%s" "/%s"`, globalDdevDir, filepath.Join(globalDdevDir, "commands"), filepath.Join(globalDdevDir, "homeadditions")))
assert.NoError(err)
t.Logf("Contents of global .ddev: \n=====\n%s\n====", out)
}
Expand Down
32 changes: 5 additions & 27 deletions cmd/ddev/cmd/homeadditions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@ import (
"path/filepath"
"testing"

"github.com/ddev/ddev/pkg/config/types"
"github.com/ddev/ddev/pkg/ddevapp"
"github.com/ddev/ddev/pkg/exec"
"github.com/ddev/ddev/pkg/fileutil"
"github.com/ddev/ddev/pkg/globalconfig"
"github.com/ddev/ddev/pkg/nodeps"
"github.com/ddev/ddev/pkg/testcommon"
asrt "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand All @@ -20,32 +18,18 @@ import (
// TestHomeadditions makes sure that extra files added to
// .ddev/homeadditions and ~/.ddev/homeadditions get added into the container's ~/
func TestHomeadditions(t *testing.T) {
if nodeps.PerformanceModeDefault == types.PerformanceModeMutagen ||
(globalconfig.DdevGlobalConfig.IsMutagenEnabled() &&
nodeps.PerformanceModeDefault != types.PerformanceModeNone) ||
nodeps.NoBindMountsDefault {
t.Skip("Skipping because this changes homedir and breaks Mutagen functionality")
}
assert := asrt.New(t)

origDir, _ := os.Getwd()
testdata := filepath.Join(origDir, "testdata", t.Name())

tmpHome := testcommon.CreateTmpDir(t.Name() + "tempHome")
// Change the homedir temporarily
t.Setenv("HOME", tmpHome)
t.Setenv("USERPROFILE", tmpHome)
tmpXdgConfigHomeDir := testcommon.CopyGlobalDdevDir(t)

tmpHomeGlobalHomeadditionsDir := filepath.Join(globalconfig.GetGlobalDdevDir(), "homeadditions")
err := os.RemoveAll(tmpHomeGlobalHomeadditionsDir)
assert.NoError(err)
site := TestSites[0]
projectHomeadditionsDir := filepath.Join(site.Dir, ".ddev", "homeadditions")

// We can't use the standard getGlobalDDevDir here because *our* global hasn't changed.
// It's changed via $HOME for the DDEV subprocess
err := os.MkdirAll(filepath.Join(tmpHome, ".ddev"), 0755)
assert.NoError(err)
tmpHomeGlobalHomeadditionsDir := filepath.Join(tmpHome, ".ddev", "homeadditions")
err = os.RemoveAll(tmpHomeGlobalHomeadditionsDir)
assert.NoError(err)
err = os.RemoveAll(projectHomeadditionsDir)
assert.NoError(err)
err = fileutil.CopyDir(filepath.Join(testdata, "global"), tmpHomeGlobalHomeadditionsDir)
Expand All @@ -55,16 +39,10 @@ func TestHomeadditions(t *testing.T) {
err = os.Chdir(site.Dir)
require.NoError(t, err)
t.Cleanup(func() {
_, err := os.Stat(globalconfig.GetMutagenPath())
if err == nil {
out, err := exec.RunHostCommand(DdevBin, "debug", "mutagen", "daemon", "stop")
assert.NoError(err, "mutagen daemon stop returned %s", string(out))
}

err = os.Chdir(origDir)
assert.NoError(err)
_ = fileutil.PurgeDirectory(projectHomeadditionsDir)
_ = os.RemoveAll(tmpHome)
testcommon.ResetGlobalDdevDir(t, tmpXdgConfigHomeDir)
})

// Before we can symlink global, need to make sure anything is already gone
Expand Down
66 changes: 66 additions & 0 deletions cmd/ddev/cmd/mutagen-version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package cmd

import (
"bytes"
"fmt"
"github.com/ddev/ddev/pkg/globalconfig"
"github.com/ddev/ddev/pkg/output"
"github.com/ddev/ddev/pkg/styles"
"github.com/ddev/ddev/pkg/versionconstants"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
"sort"
)

// MutagenVersionCmd implements the ddev mutagen version command
var MutagenVersionCmd = &cobra.Command{
Use: "version",
Short: "Display the version of the Mutagen binary and the location of its components.",
Example: `"ddev mutagen version"`,
Run: func(_ *cobra.Command, _ []string) {

v := make(map[string]string)
v["version"] = versionconstants.RequiredMutagenVersion
v["binary"] = globalconfig.GetMutagenPath()
v["enabled"] = fmt.Sprintf("%t", globalconfig.DdevGlobalConfig.IsMutagenEnabled())
v["MUTAGEN_DATA_DIRECTORY"] = globalconfig.GetMutagenDataDirectory()

var out bytes.Buffer
t := table.NewWriter()
t.SetOutputMirror(&out)

// Use simplest possible output
s := styles.GetTableStyle("default")
s.Options.SeparateRows = false
s.Options.SeparateFooter = false
s.Options.SeparateColumns = false
s.Options.SeparateHeader = false
s.Options.DrawBorder = false
t.SetStyle(s)

t.AppendHeader(table.Row{"Item", "Value"})

// Ensure "version" is always the first row
t.AppendRow(table.Row{"version", v["version"]})

keys := make([]string, 0, len(v))
for k := range v {
if k != "version" {
keys = append(keys, k)
}
}
sort.Strings(keys)

for _, label := range keys {
t.AppendRow(table.Row{
label, v[label],
})
}
t.Render()
output.UserOut.WithField("raw", v).Println(out.String())
},
}

func init() {
MutagenCmd.AddCommand(MutagenVersionCmd)
}