Use XDG_CONFIG_HOME for user configuration directory, if set. (Thanks to floli.)

This commit is contained in:
Dan Helfman 2018-06-19 22:32:13 -07:00
parent f42aa0a6f2
commit a0f6256b63
5 changed files with 57 additions and 11 deletions

2
NEWS
View File

@ -1,5 +1,5 @@
1.2.1.dev0 1.2.1.dev0
* * Support for XDG_CONFIG_HOME environment variable for specifying alternate user ~/.config/ path.
1.2.0 1.2.0
* #61: Support for Borg --list option via borgmatic command-line to list all archives. * #61: Support for Borg --list option via borgmatic command-line to list all archives.

View File

@ -24,6 +24,8 @@ def parse_arguments(*arguments):
Given command-line arguments with which this script was invoked, parse the arguments and return Given command-line arguments with which this script was invoked, parse the arguments and return
them as an ArgumentParser instance. them as an ArgumentParser instance.
''' '''
config_paths = collect.get_default_config_paths()
parser = ArgumentParser( parser = ArgumentParser(
description= description=
''' '''
@ -36,8 +38,8 @@ def parse_arguments(*arguments):
'-c', '--config', '-c', '--config',
nargs='+', nargs='+',
dest='config_paths', dest='config_paths',
default=collect.DEFAULT_CONFIG_PATHS, default=config_paths,
help='Configuration filenames or directories, defaults to: {}'.format(' '.join(collect.DEFAULT_CONFIG_PATHS)), help='Configuration filenames or directories, defaults to: {}'.format(' '.join(config_paths)),
) )
parser.add_argument( parser.add_argument(
'--excludes', '--excludes',

View File

@ -1,11 +1,21 @@
import os import os
DEFAULT_CONFIG_PATHS = [ def get_default_config_paths():
'/etc/borgmatic/config.yaml', '''
'/etc/borgmatic.d', Based on the value of the XDG_CONFIG_HOME and HOME environment variables, return a list of
os.path.expanduser('~/.config/borgmatic/config.yaml'), default configuration paths. This includes both system-wide configuration and configuration in
] the current user's home directory.
'''
user_config_directory = (
os.getenv('XDG_CONFIG_HOME') or os.path.expandvars(os.path.join('$HOME', '.config'))
)
return [
'/etc/borgmatic/config.yaml',
'/etc/borgmatic.d',
'%s/borgmatic/config.yaml' % user_config_directory,
]
def collect_config_filenames(config_paths): def collect_config_filenames(config_paths):
@ -18,7 +28,7 @@ def collect_config_filenames(config_paths):
configuration paths. However, skip a default config path if it's missing, so the user doesn't configuration paths. However, skip a default config path if it's missing, so the user doesn't
have to create a default config path unless they need it. have to create a default config path unless they need it.
''' '''
real_default_config_paths = set(map(os.path.realpath, DEFAULT_CONFIG_PATHS)) real_default_config_paths = set(map(os.path.realpath, get_default_config_paths()))
for path in config_paths: for path in config_paths:
exists = os.path.exists(path) exists = os.path.exists(path)

View File

@ -7,14 +7,19 @@ from borgmatic.commands import borgmatic as module
def test_parse_arguments_with_no_arguments_uses_defaults(): def test_parse_arguments_with_no_arguments_uses_defaults():
config_paths = ['default']
flexmock(module.collect).should_receive('get_default_config_paths').and_return(config_paths)
parser = module.parse_arguments() parser = module.parse_arguments()
assert parser.config_paths == module.collect.DEFAULT_CONFIG_PATHS assert parser.config_paths == config_paths
assert parser.excludes_filename == None assert parser.excludes_filename == None
assert parser.verbosity is None assert parser.verbosity is None
def test_parse_arguments_with_path_arguments_overrides_defaults(): def test_parse_arguments_with_path_arguments_overrides_defaults():
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
parser = module.parse_arguments('--config', 'myconfig', '--excludes', 'myexcludes') parser = module.parse_arguments('--config', 'myconfig', '--excludes', 'myexcludes')
assert parser.config_paths == ['myconfig'] assert parser.config_paths == ['myconfig']
@ -23,6 +28,8 @@ def test_parse_arguments_with_path_arguments_overrides_defaults():
def test_parse_arguments_with_multiple_config_paths_parses_as_list(): def test_parse_arguments_with_multiple_config_paths_parses_as_list():
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
parser = module.parse_arguments('--config', 'myconfig', 'otherconfig') parser = module.parse_arguments('--config', 'myconfig', 'otherconfig')
assert parser.config_paths == ['myconfig', 'otherconfig'] assert parser.config_paths == ['myconfig', 'otherconfig']
@ -30,14 +37,19 @@ def test_parse_arguments_with_multiple_config_paths_parses_as_list():
def test_parse_arguments_with_verbosity_flag_overrides_default(): def test_parse_arguments_with_verbosity_flag_overrides_default():
config_paths = ['default']
flexmock(module.collect).should_receive('get_default_config_paths').and_return(config_paths)
parser = module.parse_arguments('--verbosity', '1') parser = module.parse_arguments('--verbosity', '1')
assert parser.config_paths == module.collect.DEFAULT_CONFIG_PATHS assert parser.config_paths == config_paths
assert parser.excludes_filename == None assert parser.excludes_filename == None
assert parser.verbosity == 1 assert parser.verbosity == 1
def test_parse_arguments_with_no_actions_defaults_to_all_actions_enabled(): def test_parse_arguments_with_no_actions_defaults_to_all_actions_enabled():
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
parser = module.parse_arguments() parser = module.parse_arguments()
assert parser.prune is True assert parser.prune is True
@ -46,6 +58,8 @@ def test_parse_arguments_with_no_actions_defaults_to_all_actions_enabled():
def test_parse_arguments_with_prune_action_leaves_other_actions_disabled(): def test_parse_arguments_with_prune_action_leaves_other_actions_disabled():
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
parser = module.parse_arguments('--prune') parser = module.parse_arguments('--prune')
assert parser.prune is True assert parser.prune is True
@ -54,6 +68,8 @@ def test_parse_arguments_with_prune_action_leaves_other_actions_disabled():
def test_parse_arguments_with_multiple_actions_leaves_other_action_disabled(): def test_parse_arguments_with_multiple_actions_leaves_other_action_disabled():
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
parser = module.parse_arguments('--create', '--check') parser = module.parse_arguments('--create', '--check')
assert parser.prune is False assert parser.prune is False
@ -62,5 +78,7 @@ def test_parse_arguments_with_multiple_actions_leaves_other_action_disabled():
def test_parse_arguments_with_invalid_arguments_exits(): def test_parse_arguments_with_invalid_arguments_exits():
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
with pytest.raises(SystemExit): with pytest.raises(SystemExit):
module.parse_arguments('--posix-me-harder') module.parse_arguments('--posix-me-harder')

View File

@ -3,6 +3,22 @@ from flexmock import flexmock
from borgmatic.config import collect as module from borgmatic.config import collect as module
def test_get_default_config_paths_includes_absolute_user_config_path():
flexmock(module.os, environ={'XDG_CONFIG_HOME': None, 'HOME': '/home/user'})
config_paths = module.get_default_config_paths()
assert '/home/user/.config/borgmatic/config.yaml' in config_paths
def test_get_default_config_paths_prefers_xdg_config_home_for_user_config_path():
flexmock(module.os, environ={'XDG_CONFIG_HOME': '/home/user/.etc', 'HOME': '/home/user'})
config_paths = module.get_default_config_paths()
assert '/home/user/.etc/borgmatic/config.yaml' in config_paths
def test_collect_config_filenames_collects_given_files(): def test_collect_config_filenames_collects_given_files():
config_paths = ('config.yaml', 'other.yaml') config_paths = ('config.yaml', 'other.yaml')
flexmock(module.os.path).should_receive('isdir').and_return(False) flexmock(module.os.path).should_receive('isdir').and_return(False)