Skip to content

Commit

Permalink
add backward-compatible lookup for pre-existing config file
Browse files Browse the repository at this point in the history
  • Loading branch information
jsuchan-reef committed Nov 23, 2023
1 parent 7994ec5 commit 0471968
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 21 deletions.
38 changes: 27 additions & 11 deletions b2sdk/account_info/sqlite_account_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,16 @@ def __init__(self, file_name=None, last_upgrade_to_run=None, profile: str | None
If ``profile`` arg is provided:
* ``${XDG_CONFIG_HOME_ENV_VAR}/b2/db-<profile>.sqlite`` on XDG-compatible OSes (Linux)
* ``{B2_ACCOUNT_INFO_PROFILE_FILE}`` if it already exists
* ``${XDG_CONFIG_HOME_ENV_VAR}/b2/db-<profile>.sqlite`` on XDG-compatible OSes (Linux, BSD)
* ``{B2_ACCOUNT_INFO_PROFILE_FILE}``
Otherwise:
* ``file_name``, if truthy
* ``{B2_ACCOUNT_INFO_ENV_VAR}`` env var's value, if set
* ``{B2_ACCOUNT_INFO_DEFAULT_FILE}``, if it exists
* ``${XDG_CONFIG_HOME_ENV_VAR}/b2/account_info`` on XDG-compatible OSes (Linux)
* ``{B2_ACCOUNT_INFO_DEFAULT_FILE}``, if it already exists
* ``${XDG_CONFIG_HOME_ENV_VAR}/b2/account_info`` on XDG-compatible OSes (Linux, BSD)
* ``{B2_ACCOUNT_INFO_DEFAULT_FILE}``, as default
If the directory ``${XDG_CONFIG_HOME_ENV_VAR}/b2`` does not exist (and is needed), it is created.
Expand Down Expand Up @@ -91,12 +92,26 @@ def __init__(self, file_name=None, last_upgrade_to_run=None, profile: str | None
)
)

@classmethod
def get_xdg_config_path(cls, home_dir: str = '~') -> str | None:
"""
Return XDG config path if the OS is XDG-compatible (Linux, BSD), None otherwise.
If $XDG_CONFIG_HOME is empty but the OS is XDG compliant, fallback to ~/.config as expected by XDG standard.
"""
xdg_config_home = os.getenv(XDG_CONFIG_HOME_ENV_VAR)
if xdg_config_home or sys.platform.startswith(('linux', 'freebsd', 'openbsd', 'netbsd')):
config_path = xdg_config_home or os.path.join(home_dir, '.config')
return os.path.expanduser(config_path)
return None

@classmethod
def _get_user_account_info_path(cls, file_name: str | None = None, profile: str | None = None):
if profile and not B2_ACCOUNT_INFO_PROFILE_NAME_REGEXP.match(profile):
raise ValueError(f'Invalid profile name: {profile}')

xdg_compatible_os = sys.platform in ('linux',) or 'bsd' in sys.platform
profile_file = B2_ACCOUNT_INFO_PROFILE_FILE.format(profile=profile) if profile else None
xdg_config_path = cls.get_xdg_config_path()

if file_name:
if profile:
Expand All @@ -109,16 +124,17 @@ def _get_user_account_info_path(cls, file_name: str | None = None, profile: str
format(B2_ACCOUNT_INFO_ENV_VAR)
)
user_account_info_path = os.environ[B2_ACCOUNT_INFO_ENV_VAR]
elif os.path.exists(os.path.expanduser(B2_ACCOUNT_INFO_DEFAULT_FILE)) and not profile:
elif not profile and os.path.exists(os.path.expanduser(B2_ACCOUNT_INFO_DEFAULT_FILE)):
user_account_info_path = B2_ACCOUNT_INFO_DEFAULT_FILE
elif xdg_compatible_os:
# if following env. variable not present, fallback to ~/.config as expected by XDG standard
config_home = os.getenv(XDG_CONFIG_HOME_ENV_VAR) or os.path.expanduser('~/.config')
elif profile and os.path.exists(profile_file):
user_account_info_path = profile_file
elif xdg_config_path:
os.makedirs(os.path.join(xdg_config_path, 'b2'), mode=0o755, exist_ok=True)

file_name = f'db-{profile}.sqlite' if profile else 'account_info'
user_account_info_path = os.path.join(config_home, 'b2', file_name)
os.makedirs(os.path.join(config_home, 'b2'), mode=0o755, exist_ok=True)
user_account_info_path = os.path.join(xdg_config_path, 'b2', file_name)
elif profile:
user_account_info_path = B2_ACCOUNT_INFO_PROFILE_FILE.format(profile=profile)
user_account_info_path = profile_file
else:
user_account_info_path = B2_ACCOUNT_INFO_DEFAULT_FILE

Expand Down
2 changes: 1 addition & 1 deletion changelog.d/b2cli958.changed.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Breaking change: on XDG compatible OSes, the config file lookup path has now changed to `$XDG_CONFIG_HOME` (with fallback to `~/.config/` in absence of given env. variable).
On XDG compatible OSes (Linux, BSD), the profile file is now created in `$XDG_CONFIG_HOME` (with a fallback to `~/.config/` in absence of given env. variable).
26 changes: 20 additions & 6 deletions test/unit/account_info/test_account_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,29 +415,43 @@ def _make_sqlite_account_info(self, env=None, last_upgrade_to_run=None):
)

def test_uses_default(self):
xdg_config_path = SqliteAccountInfo.get_xdg_config_path(self.test_home)

account_info = self._make_sqlite_account_info(
env={
'HOME': self.test_home,
'USERPROFILE': self.test_home,
'HOME':
self.test_home,
'USERPROFILE':
self.test_home,
XDG_CONFIG_HOME_ENV_VAR:
bool(xdg_config_path) and os.path.join(self.test_home, '.config'),
}
)
actual_path = os.path.abspath(account_info.filename)
assert os.path.join(self.test_home, '.b2_account_info') == actual_path

if xdg_config_path:
expected_path = os.path.join(xdg_config_path, 'b2', 'account_info')
else:
expected_path = os.path.join(self.test_home, '.b2_account_info')
assert expected_path == os.path.abspath(account_info.filename)

def test_uses_xdg_config_home(self, apiver):
is_xdg_os = bool(SqliteAccountInfo.get_xdg_config_path())
with WindowsSafeTempDir() as d:
account_info = self._make_sqlite_account_info(
env={
'HOME': self.test_home,
'USERPROFILE': self.test_home,
XDG_CONFIG_HOME_ENV_VAR: d,
# pass the env. variable on XDG-like OS only
XDG_CONFIG_HOME_ENV_VAR: is_xdg_os and d,
}
)
if apiver in ['v0', 'v1']:
expected_path = os.path.abspath(os.path.join(self.test_home, '.b2_account_info'))
else:
elif is_xdg_os:
assert os.path.exists(os.path.join(d, 'b2'))
expected_path = os.path.abspath(os.path.join(d, 'b2', 'account_info'))
else:
expected_path = os.path.abspath(os.path.join(self.test_home, '.b2_account_info'))
actual_path = os.path.abspath(account_info.filename)
assert expected_path == actual_path

Expand Down
18 changes: 15 additions & 3 deletions test/unit/account_info/test_sqlite_account_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,15 @@ def test_profile_and_xdg_config_env_var(self, monkeypatch):
os.path.join('~', 'custom', 'b2', 'db-secondary.sqlite')
)

def test_profile(self):
def test_profile(self, monkeypatch):
xdg_config_path = SqliteAccountInfo.get_xdg_config_path()
if xdg_config_path:
expected_path = (xdg_config_path, 'b2', 'db-foo.sqlite')
else:
expected_path = ('~', '.b2db-foo.sqlite')

account_info_path = SqliteAccountInfo._get_user_account_info_path(profile='foo')
assert account_info_path == os.path.expanduser(os.path.join('~', '.b2db-foo.sqlite'))
assert account_info_path == os.path.expanduser(os.path.join(*expected_path))

def test_file_name(self):
account_info_path = SqliteAccountInfo._get_user_account_info_path(
Expand Down Expand Up @@ -129,5 +135,11 @@ def test_xdg_config_env_var(self, monkeypatch):
)

def test_default_file(self):
xdg_config_path = SqliteAccountInfo.get_xdg_config_path()
if xdg_config_path:
expected_path = os.path.join(xdg_config_path, 'b2', 'account_info')
else:
expected_path = B2_ACCOUNT_INFO_DEFAULT_FILE

account_info_path = SqliteAccountInfo._get_user_account_info_path()
assert account_info_path == os.path.expanduser(B2_ACCOUNT_INFO_DEFAULT_FILE)
assert account_info_path == os.path.expanduser(expected_path)

0 comments on commit 0471968

Please sign in to comment.