diff --git a/docs/usage_general.rst.inc b/docs/usage_general.rst.inc index 0788c78bb..2a32c60c6 100644 --- a/docs/usage_general.rst.inc +++ b/docs/usage_general.rst.inc @@ -203,19 +203,22 @@ Some automatic "answerers" (if set, they automatically answer confirmation quest allowed). So please test your scripts interactively before making them a non-interactive script. Directories and files: - BORG_KEYS_DIR - Default to '~/.config/borg/keys'. This directory contains keys for encrypted repositories. - BORG_KEY_FILE - When set, use the given filename as repository key file. + BORG_BASE_DIR + Default to '$HOME', '~$USER', '~' (in that order)'. + If we refer to ~ below, we in fact mean BORG_BASE_DIR. + BORG_CONFIG_DIR + Default to '~/.config/borg'. This directory contains the whole config directories. + BORG_CACHE_DIR + Default to '~/.cache/borg'. This directory contains the local cache and might need a lot + of space for dealing with big repositories. BORG_SECURITY_DIR Default to '~/.config/borg/security'. This directory contains information borg uses to track its usage of NONCES ("numbers used once" - usually in encryption context) and other security relevant data. - BORG_CACHE_DIR - Default to '~/.cache/borg'. This directory contains the local cache and might need a lot - of space for dealing with big repositories). - BORG_CONFIG_DIR - Default to '~/.config/borg'. This directory contains the whole config directories. + BORG_KEYS_DIR + Default to '~/.config/borg/keys'. This directory contains keys for encrypted repositories. + BORG_KEY_FILE + When set, use the given filename as repository key file. Building: BORG_OPENSSL_PREFIX diff --git a/src/borg/helpers/fs.py b/src/borg/helpers/fs.py index eab9714d5..543429409 100644 --- a/src/borg/helpers/fs.py +++ b/src/borg/helpers/fs.py @@ -12,18 +12,22 @@ from .process import prepare_subprocess_env from ..constants import * # NOQA -def get_home_dir(): - """Get user's home directory while preferring a possibly set HOME - environment variable +def get_base_dir(): + """Get home directory / base directory for borg: + + - BORG_BASE_DIR, if set + - HOME, if set + - ~$USER, if USER is set + - ~ """ + base_dir = os.environ.get('BORG_BASE_DIR') or os.environ.get('HOME') # os.path.expanduser() behaves differently for '~' and '~someuser' as # parameters: when called with an explicit username, the possibly set # environment variable HOME is no longer respected. So we have to check if # it is set and only expand the user's home directory if HOME is unset. - if os.environ.get('HOME', ''): - return os.environ.get('HOME') - else: - return os.path.expanduser('~%s' % os.environ.get('USER', '')) + if not base_dir: + base_dir = os.path.expanduser('~%s' % os.environ.get('USER', '')) + return base_dir def get_keys_dir(): @@ -49,7 +53,7 @@ def get_security_dir(repository_id=None): def get_cache_dir(): """Determine where to repository keys and cache""" - xdg_cache = os.environ.get('XDG_CACHE_HOME', os.path.join(get_home_dir(), '.cache')) + xdg_cache = os.environ.get('XDG_CACHE_HOME', os.path.join(get_base_dir(), '.cache')) cache_dir = os.environ.get('BORG_CACHE_DIR', os.path.join(xdg_cache, 'borg')) if not os.path.exists(cache_dir): os.makedirs(cache_dir) @@ -66,7 +70,7 @@ def get_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')) + xdg_config = os.environ.get('XDG_CONFIG_HOME', os.path.join(get_base_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) diff --git a/src/borg/remote.py b/src/borg/remote.py index 81067881f..622b5ad12 100644 --- a/src/borg/remote.py +++ b/src/borg/remote.py @@ -22,7 +22,7 @@ from .compress import LZ4 from .constants import * # NOQA from .helpers import Error, IntegrityError from .helpers import bin_to_hex -from .helpers import get_home_dir +from .helpers import get_base_dir from .helpers import get_limited_unpacker from .helpers import hostname_is_unique from .helpers import replace_placeholders @@ -323,9 +323,9 @@ class RepositoryServer: # pragma: no cover path = os.fsdecode(path) # Leading slash is always present with URI (ssh://), but not with short-form (who@host:path). if path.startswith('/~/'): # /~/x = path x relative to home dir - path = os.path.join(get_home_dir(), path[3:]) + path = os.path.join(get_base_dir(), path[3:]) elif path.startswith('~/'): - path = os.path.join(get_home_dir(), path[2:]) + path = os.path.join(get_base_dir(), path[2:]) elif path.startswith('/~'): # /~username/x = relative to "user" home dir path = os.path.expanduser(path[1:]) elif path.startswith('~'): diff --git a/src/borg/testsuite/helpers.py b/src/borg/testsuite/helpers.py index 8d191974e..222115d2a 100644 --- a/src/borg/testsuite/helpers.py +++ b/src/borg/testsuite/helpers.py @@ -17,7 +17,7 @@ from ..helpers import Buffer 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, get_config_dir +from ..helpers import get_base_dir, 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 @@ -467,6 +467,20 @@ class TestParseTimestamp(BaseTestCase): self.assert_equal(parse_timestamp('2015-04-19T20:25:00'), datetime(2015, 4, 19, 20, 25, 0, 0, timezone.utc)) +def test_get_base_dir(monkeypatch): + """test that get_base_dir respects environment""" + monkeypatch.delenv('BORG_BASE_DIR', raising=False) + monkeypatch.delenv('HOME', raising=False) + monkeypatch.delenv('USER', raising=False) + assert get_base_dir() == os.path.expanduser('~') + monkeypatch.setenv('USER', 'root') + assert get_base_dir() == os.path.expanduser('~root') + monkeypatch.setenv('HOME', '/var/tmp/home') + assert get_base_dir() == '/var/tmp/home' + monkeypatch.setenv('BORG_BASE_DIR', '/var/tmp/base') + assert get_base_dir() == '/var/tmp/base' + + def test_get_config_dir(monkeypatch): """test that get_config_dir respects environment""" monkeypatch.delenv('BORG_CONFIG_DIR', raising=False) diff --git a/src/borg/upgrader.py b/src/borg/upgrader.py index 1044f649e..4e3fe576f 100644 --- a/src/borg/upgrader.py +++ b/src/borg/upgrader.py @@ -6,7 +6,7 @@ import time from .crypto.key import KeyfileKey, KeyfileNotFoundError from .constants import REPOSITORY_README from .helpers import ProgressIndicatorPercent -from .helpers import get_home_dir, get_keys_dir, get_cache_dir +from .helpers import get_base_dir, get_keys_dir, get_cache_dir from .locking import Lock from .logger import create_logger from .repository import Repository, MAGIC @@ -188,7 +188,7 @@ class AtticRepositoryUpgrader(Repository): """ # copy of attic's get_cache_dir() attic_cache_dir = os.environ.get('ATTIC_CACHE_DIR', - os.path.join(get_home_dir(), + os.path.join(get_base_dir(), '.cache', 'attic')) attic_cache_dir = os.path.join(attic_cache_dir, self.id_str) borg_cache_dir = os.path.join(get_cache_dir(), self.id_str) @@ -249,7 +249,7 @@ class AtticKeyfileKey(KeyfileKey): def get_keys_dir(): """Determine where to repository keys and cache""" return os.environ.get('ATTIC_KEYS_DIR', - os.path.join(get_home_dir(), '.attic', 'keys')) + os.path.join(get_base_dir(), '.attic', 'keys')) @classmethod def find_key_file(cls, repository): @@ -309,7 +309,7 @@ class Borg0xxKeyfileKey(KeyfileKey): @staticmethod def get_keys_dir(): return os.environ.get('BORG_KEYS_DIR', - os.path.join(get_home_dir(), '.borg', 'keys')) + os.path.join(get_base_dir(), '.borg', 'keys')) @classmethod def find_key_file(cls, repository):