Repository: borgbackup/borg

Issue:
add BORG_CONFIG_DIR
from the mailing list:

> I've read them BORG_CACHE_DIR is OK but I see no way to relocate the ".config/borg" directory in its *entirety*!
>
> If I read the docs correctly, I can only relocate *parts* of ".config" with BORG_KEYS_DIR and BORG_SECURITY_DIR but there are other files besides these on the ".config/borg" directory.
>
> I'd really like a BORG_CONFIG_DIR variable to relocate the *whole* config dir. I want everything in ONE predictable place, especially stuff related to backups which is a really critical process in my PoV.



Discussion:
Hmm, I see `.config/borg/key-nonces` on my machine, but all from 2016.

Didn't find `key-nonces` in the borg source (master branch).
Was it moved to `.config/borg/security/<repoid>/nonce`?

Update: see https://github.com/borgbackup/borg/pull/1888/files

@ThomasWaldmann Can I pick this up?
sure, thanks! Make a PR against master.

The stuff is in helpers/fs.py and you can have a look at how the other BORG_*_DIR variables work, just do it in a similar way.
@narendravardi did you work on this issue yet or do you have questions?
@ThomasWaldmann This is what the changes I have made.

Included a function which would create 'BORG_CONFIG_DIR' and map this to '.config/borg' path in helpers/fs.py
I am looking at other files where BORG_*_DIR are used in the repo for making changes.

Is this what is expected? Please correct me if I am wrong. 
Just have a look at the other similar env vars and do it in same way.
To discuss / code review, make a PR, so you can get feedback based on your code.

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
@@ -29,8 +29,7 @@ def get_home_dir():
 def get_keys_dir():
     """Determine where to repository keys and cache"""
 
-    xdg_config = os.environ.get('XDG_CONFIG_HOME', os.path.join(get_home_dir(), '.config'))
-    keys_dir = os.environ.get('BORG_KEYS_DIR', os.path.join(xdg_config, 'borg', 'keys'))
+    keys_dir = os.environ.get('BORG_KEYS_DIR', os.path.join(get_config_dir(), 'keys'))
     if not os.path.exists(keys_dir):
         os.makedirs(keys_dir)
         os.chmod(keys_dir, stat.S_IRWXU)
@@ -39,8 +38,7 @@ def get_keys_dir():
 
 def get_security_dir(repository_id=None):
     """Determine where to store local security information."""
-    xdg_config = os.environ.get('XDG_CONFIG_HOME', os.path.join(get_home_dir(), '.config'))
-    security_dir = os.environ.get('BORG_SECURITY_DIR', os.path.join(xdg_config, 'borg', 'security'))
+    security_dir = os.environ.get('BORG_SECURITY_DIR', os.path.join(get_config_dir(), 'security'))
     if repository_id:
         security_dir = os.path.join(security_dir, repository_id)
     if not os.path.exists(security_dir):
@@ -66,6 +64,16 @@ def get_cache_dir():
     return cache_dir
 
 
+def get_config_dir():
+    """Determine where to store whole config"""
+    xdg_config = os.environ.get('XDG_CONFIG_HOME', os.path.join(get_home_dir(), '.config'))
+    config_dir = os.environ.get('BORG_CONFIG_DIR', os.path.join(xdg_config, 'borg'))
+    if not os.path.exists(config_dir):
+        os.makedirs(config_dir)
+        os.chmod(config_dir, stat.S_IRWXU)
+    return config_dir
+
+
 def dir_is_cachedir(path):
     """Determines whether the specified path is a cache directory (and
     therefore should potentially be excluded from the backup) according to
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
@@ -18,7 +18,7 @@
 from ..helpers import partial_format, format_file_size, parse_file_size, format_timedelta, format_line, PlaceholderError, replace_placeholders
 from ..helpers import make_path_safe, clean_lines
 from ..helpers import interval, prune_within, prune_split
-from ..helpers import get_cache_dir, get_keys_dir, get_security_dir
+from ..helpers import get_cache_dir, get_keys_dir, get_security_dir, get_config_dir
 from ..helpers import is_slow_msgpack
 from ..helpers import yes, TRUISH, FALSISH, DEFAULTISH
 from ..helpers import StableDict, int_to_bigint, bigint_to_int, bin_to_hex
@@ -447,6 +447,17 @@ def test(self):
         self.assert_equal(parse_timestamp('2015-04-19T20:25:00'), datetime(2015, 4, 19, 20, 25, 0, 0, timezone.utc))
 
 
+def test_get_config_dir(monkeypatch):
+    """test that get_config_dir respects environment"""
+    monkeypatch.delenv('BORG_CONFIG_DIR', raising=False)
+    monkeypatch.delenv('XDG_CONFIG_HOME', raising=False)
+    assert get_config_dir() == os.path.join(os.path.expanduser('~'), '.config', 'borg')
+    monkeypatch.setenv('XDG_CONFIG_HOME', '/var/tmp/.config')
+    assert get_config_dir() == os.path.join('/var/tmp/.config', 'borg')
+    monkeypatch.setenv('BORG_CONFIG_DIR', '/var/tmp')
+    assert get_config_dir() == '/var/tmp'
+
+
 def test_get_cache_dir(monkeypatch):
     """test that get_cache_dir respects environment"""
     monkeypatch.delenv('BORG_CACHE_DIR', raising=False)


Test patch: