diff --git a/pubs/config/conf.py b/pubs/config/conf.py index aefeda2..6c41e21 100644 --- a/pubs/config/conf.py +++ b/pubs/config/conf.py @@ -2,6 +2,7 @@ import os import platform import shutil + import configobj import validate @@ -10,6 +11,7 @@ from .spec import configspec DFT_CONFIG_PATH = os.path.expanduser('~/.pubsrc') + def load_default_conf(): """Load the default configuration""" default_conf = configobj.ConfigObj(configspec=configspec) @@ -17,6 +19,7 @@ def load_default_conf(): default_conf.validate(validator, copy=True) return default_conf + def get_confpath(verify=True): """Return the configuration filepath If verify is True, verify that the file exists and exit with an error if not. @@ -32,31 +35,36 @@ def get_confpath(verify=True): ui.exit(error_code=1) return confpath + def check_conf(conf): """Type check a configuration""" validator = validate.Validator() results = conf.validate(validator, copy=True) assert results == True, '{}'.format(results) # TODO: precise error dialog when parsing error + def load_conf(check=True, path=None): """Load the configuration""" if path is None: path = get_confpath(verify=True) with open(path, 'rb') as f: conf = configobj.ConfigObj(f.readlines(), configspec=configspec) - if check: check_conf(conf) - + conf.filename = path return conf + def save_conf(conf, path=None): """Save the configuration.""" - if path is None: - path = get_confpath(verify=False) - with open(path, 'wb') as f: + if path is not None: + conf.filename = path + elif conf.filename is None: + conf.filename = get_confpath(verify=False) + with open(conf.filename, 'wb') as f: conf.write(outfile=f) + def default_open_cmd(): """Chooses the default command to open documents""" if platform.system() == 'Darwin': @@ -68,6 +76,7 @@ def default_open_cmd(): else: return None + def which(cmd): try: return shutil.which(cmd) # available in python 3.3 @@ -78,6 +87,7 @@ def which(cmd): return filepath return None + def default_edit_cmd(): """Find an available editor""" if 'EDITOR' in os.environ: diff --git a/pubs/pubs_cmd.py b/pubs/pubs_cmd.py index 3b2fc53..a98d629 100644 --- a/pubs/pubs_cmd.py +++ b/pubs/pubs_cmd.py @@ -1,57 +1,68 @@ import sys - import argparse import collections - from . import uis from . import config from . import commands from . import update from . import plugins - +from .__init__ import __version__ CORE_CMDS = collections.OrderedDict([ - ('init', commands.init_cmd), - ('conf', commands.conf_cmd), + ('init', commands.init_cmd), + ('conf', commands.conf_cmd), - ('add', commands.add_cmd), - ('rename', commands.rename_cmd), - ('remove', commands.remove_cmd), - ('list', commands.list_cmd), + ('add', commands.add_cmd), + ('rename', commands.rename_cmd), + ('remove', commands.remove_cmd), + ('list', commands.list_cmd), - ('attach', commands.attach_cmd), - ('open', commands.open_cmd), - ('tag', commands.tag_cmd), - ('note', commands.note_cmd), + ('attach', commands.attach_cmd), + ('open', commands.open_cmd), + ('tag', commands.tag_cmd), + ('note', commands.note_cmd), - ('export', commands.export_cmd), - ('import', commands.import_cmd), + ('export', commands.export_cmd), + ('import', commands.import_cmd), - ('websearch', commands.websearch_cmd), - ('edit', commands.edit_cmd), - ]) + ('websearch', commands.websearch_cmd), + ('edit', commands.edit_cmd), +]) def execute(raw_args=sys.argv): + + conf_parser = argparse.ArgumentParser(add_help=False) + conf_parser.add_argument("-c", "--config", help="path to config file", + type=str, metavar="FILE") + args, remaining_args = conf_parser.parse_known_args(raw_args[1:]) + + if args.config: + conf_path = args.config + else: + conf_path = config.get_confpath(verify=False) # will be checked on load + # loading config - if len(raw_args) > 1 and raw_args[1] != 'init': + if len(remaining_args) > 0 and remaining_args[0] != 'init': try: - conf = config.load_conf(check=False) - if update.update_check(conf): # an update happened, reload conf. - conf = config.load_conf(check=False) + conf = config.load_conf(path=conf_path, check=False) + if update.update_check(conf, path=conf.filename): # an update happened, reload conf. + conf = config.load_conf(path=conf_path, check=False) config.check_conf(conf) except IOError as e: print('error: {}'.format(str(e))) sys.exit() else: conf = config.load_default_conf() + conf.filename = conf_path uis.init_ui(conf) ui = uis.get_ui() - parser = argparse.ArgumentParser(description="research papers repository") + parser = argparse.ArgumentParser(parents=[conf_parser], + description="research papers repository", + prog="pubs", version=__version__, add_help=True) subparsers = parser.add_subparsers(title="valid commands", dest="command") - cmd_funcs = collections.OrderedDict() for cmd_name, cmd_mod in CORE_CMDS.items(): cmd_mod.parser(subparsers) @@ -62,7 +73,7 @@ def execute(raw_args=sys.argv): for p in plugins.get_plugins().values(): cmd_funcs.update(p.get_commands(subparsers)) - args = parser.parse_args(raw_args[1:]) + args = parser.parse_args(remaining_args) args.prog = parser.prog # Hack: there might be a better way... cmd = args.command del args.command diff --git a/pubs/uis.py b/pubs/uis.py index c0c472d..a08126f 100644 --- a/pubs/uis.py +++ b/pubs/uis.py @@ -6,6 +6,7 @@ import codecs from .content import editor_input from . import color +from . import config from .p3 import _get_raw_stdout, _get_raw_stderr, input, ustr @@ -30,7 +31,7 @@ def _get_encoding(conf): def get_ui(): if _ui is None: - return PrintUI() # no editor support. (#FIXME?) + return PrintUI(config.load_default_conf()) # no editor support. (#FIXME?) return _ui diff --git a/tests/test_usecase.py b/tests/test_usecase.py index 9ec2b3e..1dd9f7d 100644 --- a/tests/test_usecase.py +++ b/tests/test_usecase.py @@ -59,6 +59,7 @@ class CommandTestCase(unittest.TestCase): def setUp(self): self.fs = fake_env.create_fake_fs([content, filebroker, conf, init_cmd, import_cmd, configobj, update]) self.default_pubs_dir = self.fs['os'].path.expanduser('~/.pubs') + self.default_conf_path = self.fs['os'].path.expanduser('~/.pubsrc') def execute_cmds(self, cmds, capture_output=CAPTURE_OUTPUT): """ Execute a list of commands, and capture their output @@ -509,8 +510,21 @@ class TestUsecase(DataCommandTestCase): 'pubs attach --move Page99 data/pagerank.pdf' ] self.execute_cmds(cmds) + self.assertTrue(self.fs['os'].path.isfile(self.default_conf_path)) self.assertFalse(self.fs['os'].path.exists('/data/pagerank.pdf')) + def test_alternate_config(self): + alt_conf = self.fs['os'].path.expanduser('~/.alt_conf') + cmds = ['pubs -c ' + alt_conf + ' init', + 'pubs --config ' + alt_conf + ' import data/ Page99', + 'pubs list -c ' + alt_conf + ] + outs = self.execute_cmds(cmds) + # check if pubs works as expected + self.assertEqual(1 + 1, len(outs[-1].split('\n'))) + # check whether we actually changed the config file + self.assertFalse(self.fs['os'].path.isfile(self.default_conf_path)) + self.assertTrue(self.fs['os'].path.isfile(alt_conf)) if __name__ == '__main__': unittest.main()