Repository: Jguer/yay (Go)

Issue:
yay creates a folder named ~ in the current directory
### Affected Version

yay v11.2.0 - libalpm v13.0.1

### Describe the bug

`yay` is creating a directory named `~` containing the sub directories `.cache/yay`  in whatever directory you execute it.

### Reproduction Steps

1. Create a directory or use an existing directory
2. Run `yay -Syu` to update pacman cache
3. Run `ls` and see a folder named `~` exists

### Expected behavior

The `yay` command uses the .cache directory in $HOME

### Output

<!--
Include the FULL output of any relevant commands/configs
The current yay config can be printed with `yay -Pg`
Paste services are only needed for excessive output (>500 lines)
-->

```sh
dmills in 🌐 dmills-remote in /tmp 
❯ mkdir yay
dmills in 🌐 dmills-remote in /tmp 
❯ cd yay
dmills in 🌐 dmills-remote in /tmp/yay 
❯ yay -Syu
[sudo] password for dmills: 
:: Synchronizing package databases...
 core is up to date
 extra is up to date
 community is up to date
 multilib is up to date
 endeavouros is up to date
:: Starting full system upgrade...
warning: openssh: ignoring package upgrade (8.8p1-1 => 9.0p1-1)
 there is nothing to do
:: Searching databases for updates...
:: Searching AUR for updates...
 -> openssh: ignoring package upgrade (8.8p1-1 => 9.0p1-1)
 -> Missing AUR Packages:  celt
 -> Flagged Out Of Date AUR Packages:  vmware-ovftool
 there is nothing to do
dmills in 🌐 dmills-remote in /tmp/yay 
❯ ls -lh
Permissions Size User   Date Modified Name
drwxr-xr-x     - dmills 19 Jul 12:46  ~
dmills in 🌐 dmills-remote in /tmp/yay 
❯ ls -lhT
Permissions Size User   Date Modified Name
drwxr-xr-x     - dmills 19 Jul 12:46  .
drwxr-xr-x     - dmills 19 Jul 12:46  └── ~
```



Discussion:
can't reproduce, can you share your `~/.config/yay/config.json`? 

EDIT: as well if `AURDEST` is present as a env var?
AURDEST is unset

I haven't made any changes to my config it started happening as much as I can tell after a recent update.

```json
{
        "aururl": "https://aur.archlinux.org",
        "buildDir": "~/.cache/yay",
        "absdir": "~/.cache/yay/abs",
        "editor": "",
        "editorflags": "",
        "makepkgbin": "makepkg",
        "makepkgconf": "",
        "pacmanbin": "pacman",
        "pacmanconf": "/etc/pacman.conf",
        "redownload": "no",
        "rebuild": "no",
        "answerclean": "",
        "answerdiff": "",
        "answeredit": "",
        "answerupgrade": "",
        "gitbin": "git",
        "gpgbin": "gpg",
        "gpgflags": "",
        "mflags": "",
        "sortby": "votes",
        "searchby": "name-desc",
        "gitflags": "",
        "removemake": "ask",
        "sudobin": "sudo",
        "sudoflags": "",
        "requestsplitn": 150,
        "sortmode": 0,
        "completionrefreshtime": 7,
        "sudoloop": false,
        "timeupdate": false,
        "devel": false,
        "cleanAfter": false,
        "provides": true,
        "pgpfetch": true,
        "upgrademenu": true,
        "cleanmenu": false,
        "diffmenu": false,
        "editmenu": false,
        "combinedupgrade": false,
        "useask": false,
        "batchinstall": false
}
```
I'm not sure how the dirs got set to ~ but it appears it must not be expanding that



Patch:
diff --git a/pkg/settings/config.go b/pkg/settings/config.go
index ec665406d..89a2a858b 100644
--- a/pkg/settings/config.go
+++ b/pkg/settings/config.go
@@ -115,21 +115,21 @@ func (c *Configuration) Save(configPath string) error {
 func (c *Configuration) expandEnv() {
 	c.AURURL = os.ExpandEnv(c.AURURL)
 	c.AURRPCURL = os.ExpandEnv(c.AURRPCURL)
-	c.BuildDir = os.ExpandEnv(c.BuildDir)
-	c.Editor = os.ExpandEnv(c.Editor)
+	c.BuildDir = expandEnvOrHome(c.BuildDir)
+	c.Editor = expandEnvOrHome(c.Editor)
 	c.EditorFlags = os.ExpandEnv(c.EditorFlags)
-	c.MakepkgBin = os.ExpandEnv(c.MakepkgBin)
-	c.MakepkgConf = os.ExpandEnv(c.MakepkgConf)
-	c.PacmanBin = os.ExpandEnv(c.PacmanBin)
-	c.PacmanConf = os.ExpandEnv(c.PacmanConf)
+	c.MakepkgBin = expandEnvOrHome(c.MakepkgBin)
+	c.MakepkgConf = expandEnvOrHome(c.MakepkgConf)
+	c.PacmanBin = expandEnvOrHome(c.PacmanBin)
+	c.PacmanConf = expandEnvOrHome(c.PacmanConf)
 	c.GpgFlags = os.ExpandEnv(c.GpgFlags)
 	c.MFlags = os.ExpandEnv(c.MFlags)
 	c.GitFlags = os.ExpandEnv(c.GitFlags)
 	c.SortBy = os.ExpandEnv(c.SortBy)
 	c.SearchBy = os.ExpandEnv(c.SearchBy)
-	c.GitBin = os.ExpandEnv(c.GitBin)
-	c.GpgBin = os.ExpandEnv(c.GpgBin)
-	c.SudoBin = os.ExpandEnv(c.SudoBin)
+	c.GitBin = expandEnvOrHome(c.GitBin)
+	c.GpgBin = expandEnvOrHome(c.GpgBin)
+	c.SudoBin = expandEnvOrHome(c.SudoBin)
 	c.SudoFlags = os.ExpandEnv(c.SudoFlags)
 	c.ReDownload = os.ExpandEnv(c.ReDownload)
 	c.ReBuild = os.ExpandEnv(c.ReBuild)
@@ -140,6 +140,15 @@ func (c *Configuration) expandEnv() {
 	c.RemoveMake = os.ExpandEnv(c.RemoveMake)
 }
 
+func expandEnvOrHome(path string) string {
+	path = os.ExpandEnv(path)
+	if strings.HasPrefix(path, "~/") {
+		path = filepath.Join(os.Getenv("HOME"), path[2:])
+	}
+
+	return path
+}
+
 func (c *Configuration) String() string {
 	var buf bytes.Buffer
 	enc := json.NewEncoder(&buf)


Test patch:
diff --git a/pkg/settings/config_test.go b/pkg/settings/config_test.go
index 4384476c9..82cc6fe6f 100644
--- a/pkg/settings/config_test.go
+++ b/pkg/settings/config_test.go
@@ -75,6 +75,39 @@ func TestNewConfigAURDEST(t *testing.T) {
 	assert.NoError(t, err)
 }
 
+// Test tilde expansion in AURDEST
+func TestNewConfigAURDESTTildeExpansion(t *testing.T) {
+	configDir := t.TempDir()
+	err := os.MkdirAll(filepath.Join(configDir, "yay"), 0o755)
+	assert.NoError(t, err)
+
+	t.Setenv("XDG_CONFIG_HOME", configDir)
+
+	homeDir := t.TempDir()
+	cacheDir := t.TempDir()
+
+	config := map[string]string{"BuildDir": filepath.Join(cacheDir, "test-other-dir")}
+	t.Setenv("AURDEST", "~/test-build-dir")
+	t.Setenv("HOME", homeDir)
+
+	f, err := os.Create(filepath.Join(configDir, "yay", "config.json"))
+	assert.NoError(t, err)
+
+	defer f.Close()
+
+	configJSON, _ := json.Marshal(config)
+	_, err = f.WriteString(string(configJSON))
+	assert.NoError(t, err)
+
+	newConfig, err := NewConfig("v1.0.0")
+	assert.NoError(t, err)
+
+	assert.Equal(t, filepath.Join(homeDir, "test-build-dir"), newConfig.BuildDir)
+
+	_, err = os.Stat(filepath.Join(homeDir, "test-build-dir"))
+	assert.NoError(t, err)
+}
+
 // GIVEN default config
 // WHEN setPrivilegeElevator gets called
 // THEN sudobin should stay as "sudo" (given sudo exists)