Repository: borgbackup/borg

Issue:
wrong cache directories
From a discussion post:

> I noticed that with borg 2 the cache directories do *not* contain the 
> name borg which is a bit annoying and i would prefer the old behaviour.
> 
> Borg 1.2 
> /home/dietmar/.cache/borg/0a2cb8f22adaa78a1863b028f3d1629393ef0fdd99b3b61c11d871de9eaaee8b/README
> 
> Borg 2.0.0b5 
> /home/dietmar/.cache/fa673b73240ed3b75ba947fd98787fdf8ecd17204323e4a10c2754cdcc5fd547/README

this is likely due to us switching to `platformdirs` library and the related api change.

config directories need also checking, there might be the same issue.



Discussion:
Likely the issue happened on Linux.

It looks OK on macOS:
- config: `/Users/tw/Library/Application Support/borg`
- cache: `/Users/username/Library/Caches/borg`

Hi. I would like to look into this. First step for me I guess would be replicating it on my device. (and looking at the relevant code)

Could you mention the email thread subject so I can read more?
https://github.com/borgbackup/borg/discussions/7392#discussioncomment-5316914 see there.
I suppose #7300 (mentioned earlier) , #7332 are related to this. Am going afk now.
Will check again tomorrow. (if it's still open :)


I think this might be the offending line https://github.com/borgbackup/borg/blob/270b705248a6a23a2842697b114aec446f6b99fd/src/borg/helpers/fs.py#L145-L146

`join_base_dir(".config", legacy=legacy)` should instead be `join_base_dir(".config", "borg", legacy=legacy)`


For comparison:

https://github.com/borgbackup/borg/blob/1.2.3/src/borg/helpers/fs.py#L105

Yes, I think you maybe discovered an issue there (but that is only for the case when BORG_BASE_DIR is used, which is not the default use case).

Also the tests need checking and extending - we have tests whether the new code behaves compatible to the old (1.2.x) code except for expected exceptions.
I am running https://github.com/borgbackup/borg/commit/8027c7b2847fc3feb764fd643c07614186f0e5af  to test. I can't seem to replicate the behavior mentioned above. I get the usual `~/.cache/borg` dir.

Ubuntu 20.04

Will try the exact release.  ...

Same on release `borg 2.0.0b5` :pouting_face: :thinking: 
I tried  `platformdirs.user_config_dir("borg")` with platformdirs version 3.1.0 on Ubuntu 20.04, and it gives the expected "/home/user/.config/borg" value. 

Similarly on Fedora. 

So at-least on these two (and other Linux distros), `platformdirs` may not be the culprit. 
Just ran manual testing on 1.2.3 vs 2.0.0b5, both with the BORG_BASE_DIR set. Can confirm the difference in behavior. 
The later version looses borg subdir

```
(borg-env):/tmp$ tree -a -L 2 borg1.2.3/
borg1.2.3/
|-- .cache
|   `-- borg
`-- .config
    `-- borg
```

```
(borg-env):/tmp$ tree -a -L 2 borg2/    
borg2/
|-- .cache
|   |-- CACHEDIR.TAG
|   `-- df4e4ae7737b68eeb241f01fc1bffee4f5fdda570a238815d05a2f2f1b756eaa
`-- .config
    `-- security

```

Seems like that is the issue here. 

Will look into the tests. 

Resolving patch:
diff --git a/src/borg/helpers/fs.py b/src/borg/helpers/fs.py
--- a/src/borg/helpers/fs.py
+++ b/src/borg/helpers/fs.py
@@ -106,7 +106,7 @@ def get_cache_dir(*, legacy=False):
         cache_dir = os.environ.get("BORG_CACHE_DIR", os.path.join(cache_home, "borg"))
     else:
         cache_dir = os.environ.get(
-            "BORG_CACHE_DIR", join_base_dir(".cache", legacy=legacy) or platformdirs.user_cache_dir("borg")
+            "BORG_CACHE_DIR", join_base_dir(".cache", "borg", legacy=legacy) or platformdirs.user_cache_dir("borg")
         )
 
     # Create path if it doesn't exist yet
@@ -143,7 +143,7 @@ def get_config_dir(*, legacy=False):
         config_dir = os.environ.get("BORG_CONFIG_DIR", os.path.join(config_home, "borg"))
     else:
         config_dir = os.environ.get(
-            "BORG_CONFIG_DIR", join_base_dir(".config", legacy=legacy) or platformdirs.user_config_dir("borg")
+            "BORG_CONFIG_DIR", join_base_dir(".config", "borg", legacy=legacy) or platformdirs.user_config_dir("borg")
         )
 
     # Create path if it doesn't exist yet
diff --git a/src/borg/testsuite/helpers.py b/src/borg/testsuite/helpers.py
--- a/src/borg/testsuite/helpers.py
+++ b/src/borg/testsuite/helpers.py
@@ -635,19 +635,20 @@ def test_get_config_dir(monkeypatch):
 
 def test_get_config_dir_compat(monkeypatch):
     """test that it works the same for legacy and for non-legacy implementation"""
+    monkeypatch.delenv("BORG_CONFIG_DIR", raising=False)
     monkeypatch.delenv("BORG_BASE_DIR", raising=False)
+    monkeypatch.delenv("XDG_CONFIG_HOME", raising=False)
     if not is_darwin and not is_win32:
-        monkeypatch.delenv("BORG_CONFIG_DIR", raising=False)
-        monkeypatch.delenv("XDG_CONFIG_HOME", raising=False)
         # fails on macOS: assert '/Users/tw/Library/Application Support/borg' == '/Users/tw/.config/borg'
         # fails on win32 MSYS2 (but we do not need legacy compat there).
         assert get_config_dir(legacy=False) == get_config_dir(legacy=True)
-    if not is_darwin and not is_win32:
-        monkeypatch.setenv("XDG_CONFIG_HOME", "/var/tmp/.config1")
-        # fails on macOS: assert '/Users/tw/Library/Application Support/borg' == '/var/tmp/.config1/borg'
+        monkeypatch.setenv("XDG_CONFIG_HOME", "/var/tmp/xdg.config.d")
+        # fails on macOS: assert '/Users/tw/Library/Application Support/borg' == '/var/tmp/xdg.config.d'
         # fails on win32 MSYS2 (but we do not need legacy compat there).
         assert get_config_dir(legacy=False) == get_config_dir(legacy=True)
-    monkeypatch.setenv("BORG_CONFIG_DIR", "/var/tmp/.config2")
+    monkeypatch.setenv("BORG_BASE_DIR", "/var/tmp/base")
+    assert get_config_dir(legacy=False) == get_config_dir(legacy=True)
+    monkeypatch.setenv("BORG_CONFIG_DIR", "/var/tmp/borg.config.d")
     assert get_config_dir(legacy=False) == get_config_dir(legacy=True)
 
 
@@ -675,6 +676,25 @@ def test_get_cache_dir(monkeypatch):
         assert get_cache_dir() == "/var/tmp"
 
 
+def test_get_cache_dir_compat(monkeypatch):
+    """test that it works the same for legacy and for non-legacy implementation"""
+    monkeypatch.delenv("BORG_CACHE_DIR", raising=False)
+    monkeypatch.delenv("BORG_BASE_DIR", raising=False)
+    monkeypatch.delenv("XDG_CACHE_HOME", raising=False)
+    if not is_darwin and not is_win32:
+        # fails on macOS: assert '/Users/tw/Library/Caches/borg' == '/Users/tw/.cache/borg'
+        # fails on win32 MSYS2 (but we do not need legacy compat there).
+        assert get_cache_dir(legacy=False) == get_cache_dir(legacy=True)
+        # fails on macOS: assert '/Users/tw/Library/Caches/borg' == '/var/tmp/xdg.cache.d'
+        # fails on win32 MSYS2 (but we do not need legacy compat there).
+        monkeypatch.setenv("XDG_CACHE_HOME", "/var/tmp/xdg.cache.d")
+        assert get_cache_dir(legacy=False) == get_cache_dir(legacy=True)
+    monkeypatch.setenv("BORG_BASE_DIR", "/var/tmp/base")
+    assert get_cache_dir(legacy=False) == get_cache_dir(legacy=True)
+    monkeypatch.setenv("BORG_CACHE_DIR", "/var/tmp/borg.cache.d")
+    assert get_cache_dir(legacy=False) == get_cache_dir(legacy=True)
+
+
 def test_get_keys_dir(monkeypatch):
     """test that get_keys_dir respects environment"""
     monkeypatch.delenv("BORG_BASE_DIR", raising=False)


Test patch: