Merge pull request #37 from pubs/feat/new_config
feat/new_config: better, more robust, more flexible configurationmain
commit
76be98a900
@ -1 +1 @@
|
||||
__version__ = '0.5.0'
|
||||
__version__ = '0.6.0'
|
||||
|
@ -0,0 +1,36 @@
|
||||
from .. import uis
|
||||
from .. import config
|
||||
from .. import content
|
||||
|
||||
|
||||
def parser(subparsers):
|
||||
parser = subparsers.add_parser('conf',
|
||||
help='open the configuration in an editor')
|
||||
return parser
|
||||
|
||||
|
||||
def command(conf, args):
|
||||
uis.init_ui(conf)
|
||||
ui = uis.get_ui()
|
||||
|
||||
while True:
|
||||
# get modif from user
|
||||
content.edit_file(conf['main']['edit_cmd'], config.get_confpath())
|
||||
|
||||
new_conf = config.load_conf(check=False)
|
||||
try:
|
||||
config.check_conf(new_conf)
|
||||
ui.message('The configuration file was updated.')
|
||||
break
|
||||
except AssertionError: # TODO better error message
|
||||
ui.error('Error reading the modified configuration file.')
|
||||
options = ['edit_again', 'abort']
|
||||
choice = options[ui.input_choice(
|
||||
options, ['e', 'a'],
|
||||
question=('Edit again or abort? If you abort, the changes will be reverted.')
|
||||
)]
|
||||
|
||||
if choice == 'abort':
|
||||
config.save_conf(conf)
|
||||
ui.message('The changes have been reverted.')
|
||||
break
|
@ -1,37 +0,0 @@
|
||||
import sys
|
||||
|
||||
from .. import repo
|
||||
from .. import color
|
||||
from ..configs import config
|
||||
from ..uis import get_ui
|
||||
from ..__init__ import __version__
|
||||
|
||||
def parser(subparsers):
|
||||
parser = subparsers.add_parser('update', help='update the repository to the lastest format')
|
||||
return parser
|
||||
|
||||
|
||||
def command(args):
|
||||
|
||||
ui = get_ui()
|
||||
|
||||
code_version = __version__
|
||||
repo_version = int(config().version)
|
||||
|
||||
if repo_version == code_version:
|
||||
ui.message('Your pubs repository is up-to-date.')
|
||||
sys.exit(0)
|
||||
elif repo_version > code_version:
|
||||
ui.message('Your repository was generated with an newer version of pubs.\n'
|
||||
'You should not use pubs until you install the newest version.')
|
||||
sys.exit(0)
|
||||
else:
|
||||
msg = ("You should backup the pubs directory {} before continuing."
|
||||
"Continue ?").format(color.dye_out(config().papers_dir, color.filepath))
|
||||
sure = ui.input_yn(question=msg, default='n')
|
||||
if not sure:
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
# config().version = repo_version
|
||||
# config().save()
|
@ -0,0 +1,2 @@
|
||||
from .conf import get_confpath, load_default_conf, load_conf, save_conf, check_conf
|
||||
from .conf import default_open_cmd, default_edit_cmd
|
@ -0,0 +1,102 @@
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
|
||||
|
||||
import configobj
|
||||
import validate
|
||||
|
||||
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)
|
||||
validator = validate.Validator()
|
||||
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.
|
||||
"""
|
||||
confpath = DFT_CONFIG_PATH
|
||||
if 'PUBSCONF' in os.environ:
|
||||
confpath = os.path.abspath(os.path.expanduser(os.environ['PUBSCONF']))
|
||||
if verify:
|
||||
if not os.path.isfile(confpath):
|
||||
from .. import uis
|
||||
ui = uis.get_ui()
|
||||
ui.error('configuration file not found at `{}`'.format(confpath))
|
||||
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 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':
|
||||
return 'open'
|
||||
elif platform.system() == 'Linux':
|
||||
return 'xdg-open'
|
||||
elif platform.system() == 'Windows':
|
||||
return 'start'
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def which(cmd):
|
||||
try:
|
||||
return shutil.which(cmd) # available in python 3.3
|
||||
except AttributeError:
|
||||
for path in ['.'] + os.environ["PATH"].split(os.pathsep):
|
||||
filepath = os.path.join(path.strip('"'), cmd)
|
||||
if os.path.isfile(path) and os.access(path, os.X_OK):
|
||||
return filepath
|
||||
return None
|
||||
|
||||
|
||||
def default_edit_cmd():
|
||||
"""Find an available editor"""
|
||||
if 'EDITOR' in os.environ:
|
||||
return os.environ['EDITOR']
|
||||
elif platform.system() == 'Darwin' or 'Linux':
|
||||
for editor in ['vim', 'nano', 'emacs', 'vi']:
|
||||
if which(editor) is not None:
|
||||
return editor
|
||||
elif platform.system() == 'Windows':
|
||||
return 'Notepad.exe | Out-Null' # wait for notepad to close
|
||||
else:
|
||||
return None
|
@ -0,0 +1,86 @@
|
||||
from .. import __version__
|
||||
|
||||
configspec = """
|
||||
[main]
|
||||
|
||||
# Where the pubs repository files (bibtex, metadata, notes) are located
|
||||
pubsdir = string(default='~/pubs')
|
||||
|
||||
# Where the documents files are located (default: $(pubsdir)/doc/)
|
||||
docsdir = string(default="docsdir://")
|
||||
|
||||
# Specify if a document should be copied or moved in the docdir, or only
|
||||
# linked when adding a publication.
|
||||
doc_add = option('copy', 'move', 'link', default='move')
|
||||
|
||||
# the command to use when opening document files
|
||||
open_cmd = string(default=None)
|
||||
|
||||
# which editor to use when editing bibtex files.
|
||||
# if using a graphical editor, use the --wait or --block option, i.e.:
|
||||
# "atom --wait"
|
||||
# "kate --block"
|
||||
edit_cmd = string(default=None)
|
||||
|
||||
|
||||
[formating]
|
||||
|
||||
# Enable bold formatting, if the terminal supports it.
|
||||
bold = boolean(default=True)
|
||||
|
||||
# Enable italics, if the terminal supports it.
|
||||
italics = boolean(default=True)
|
||||
|
||||
# Enable colors, if the terminal supports it.
|
||||
color = boolean(default=True)
|
||||
|
||||
|
||||
[theme]
|
||||
|
||||
# Here you can define the color theme used by pubs, if enabled in the
|
||||
# 'formating' section. Predefined theme are available at:
|
||||
# https://github.com/pubs/pubs/blob/master/theme.md
|
||||
|
||||
# Available colors are: 'black', 'red', 'green', 'yellow', 'blue', 'purple',
|
||||
# 'cyan', and 'grey'. Bold colors are available by prefixing 'b' in front of
|
||||
# the color name ('bblack', 'bred', etc.), italic colors by prefixing 'i',
|
||||
# and bold italic by prefixing 'bi'. Finally, 'bold', 'italic' and
|
||||
# 'bolditalic' can be used to apply formatting without changing the color.
|
||||
# For no color, use an empty string ''
|
||||
|
||||
# messages
|
||||
ok = string(default='green')
|
||||
warning = string(default='yellow')
|
||||
error = string(default='red')
|
||||
|
||||
# ui elements
|
||||
filepath = string(default='bold')
|
||||
citekey = string(default='purple')
|
||||
tag = string(default='cyan')
|
||||
|
||||
# bibliographic fields
|
||||
author = string(default='bold')
|
||||
title = string(default='')
|
||||
publisher = string(default='italic')
|
||||
year = string(default='bold')
|
||||
volume = string(default='bold')
|
||||
pages = string(default='')
|
||||
|
||||
|
||||
[plugins]
|
||||
# comma-separated list of the plugins to load
|
||||
active = list(default=list())
|
||||
|
||||
[[alias]]
|
||||
# new subcommands can be defined, e.g.:
|
||||
# print = open --with lp
|
||||
# evince = open --with evince
|
||||
|
||||
# shell commands can also be defined, by prefixing them with a bang `!`, e.g:
|
||||
# count = !pubs list -k | wc -l
|
||||
|
||||
[internal]
|
||||
# The version of this configuration file. Do not edit.
|
||||
version = string(min=5, default='{}')
|
||||
|
||||
""".format(__version__).split('\n')
|
@ -1,112 +0,0 @@
|
||||
import os
|
||||
import sys
|
||||
import collections
|
||||
|
||||
from .p3 import configparser, ConfigParser, _read_config
|
||||
|
||||
from .content import check_file, _open
|
||||
from . import __version__
|
||||
|
||||
# constant stuff (DFT = DEFAULT)
|
||||
|
||||
MAIN_SECTION = 'pubs'
|
||||
DFT_CONFIG_PATH = os.path.expanduser('~/.pubsrc')
|
||||
try:
|
||||
DFT_EDIT_CMD = os.environ['EDITOR']
|
||||
except KeyError:
|
||||
DFT_EDIT_CMD = 'vi'
|
||||
|
||||
DFT_PLUGINS = ''
|
||||
|
||||
DFT_CONFIG = collections.OrderedDict([
|
||||
('pubsdir', os.path.expanduser('~/.pubs')),
|
||||
('docsdir', ''),
|
||||
('import_copy', True),
|
||||
('import_move', False),
|
||||
('color', True),
|
||||
('version', __version__),
|
||||
('version_warning', True),
|
||||
('open_cmd', 'open'),
|
||||
('edit_cmd', DFT_EDIT_CMD),
|
||||
('plugins', DFT_PLUGINS)
|
||||
])
|
||||
|
||||
BOOLEANS = {'import_copy', 'import_move', 'color', 'version_warning'}
|
||||
|
||||
|
||||
# package-shared config that can be accessed using :
|
||||
# from configs import config
|
||||
_config = None
|
||||
|
||||
|
||||
def config(section=MAIN_SECTION):
|
||||
if _config is None:
|
||||
raise ValueError('not config instanciated yet')
|
||||
_config._section = section
|
||||
return _config
|
||||
|
||||
|
||||
class Config(object):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
object.__setattr__(self, '_section', MAIN_SECTION) # active section
|
||||
object.__setattr__(self, '_cfg', ConfigParser())
|
||||
|
||||
self._cfg.add_section(self._section)
|
||||
for name, value in DFT_CONFIG.items():
|
||||
self._cfg.set(self._section, name, str(value))
|
||||
|
||||
for name, value in kwargs.items():
|
||||
self.__setattr__(name, value)
|
||||
|
||||
def as_global(self):
|
||||
global _config
|
||||
_config = self
|
||||
|
||||
def load(self, path=DFT_CONFIG_PATH):
|
||||
if not check_file(path, fail=False):
|
||||
raise IOError(("The configuration file {} does not exist."
|
||||
" Did you run 'pubs init' ?").format(path))
|
||||
b_flag = ''
|
||||
if sys.version_info[0] == 2: # HACK, FIXME please
|
||||
b_flag = 'b'
|
||||
with _open(path, 'r{}+'.format(b_flag)) as f:
|
||||
_read_config(self._cfg, f)
|
||||
return self
|
||||
|
||||
def save(self, path=DFT_CONFIG_PATH):
|
||||
b_flag = ''
|
||||
if sys.version_info[0] == 2: # HACK, FIXME please
|
||||
b_flag = 'b'
|
||||
with _open(path, 'w{}+'.format(b_flag)) as f:
|
||||
self._cfg.write(f)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
if name in ('_cfg', '_section'):
|
||||
object.__setattr__(self, name, value)
|
||||
else:
|
||||
if type(value) is bool:
|
||||
BOOLEANS.add(name)
|
||||
self._cfg.set(self._section, name, str(value))
|
||||
|
||||
def __getattr__(self, name):
|
||||
value = self._cfg.get(self._section, name)
|
||||
if name in BOOLEANS:
|
||||
value = str2bool(value)
|
||||
return value
|
||||
|
||||
def get(self, name, default=None):
|
||||
try:
|
||||
return self.__getattr__(name)
|
||||
except (configparser.NoOptionError, configparser.NoSectionError):
|
||||
return default
|
||||
|
||||
def items(self):
|
||||
for name, value in self._cfg.items(self._section):
|
||||
if name in BOOLEANS:
|
||||
value = str2bool(value)
|
||||
yield name, value
|
||||
|
||||
|
||||
def str2bool(s):
|
||||
return str(s).lower() in ('yes', 'true', 't', 'y', '1')
|
@ -1,92 +1,85 @@
|
||||
import sys
|
||||
|
||||
import argparse
|
||||
import collections
|
||||
|
||||
from . import uis
|
||||
from . import configs
|
||||
from . import config
|
||||
from . import commands
|
||||
from . import update
|
||||
from . import plugins
|
||||
from .__init__ import __version__
|
||||
|
||||
|
||||
CORE_CMDS = collections.OrderedDict([
|
||||
('init', commands.init_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),
|
||||
|
||||
('export', commands.export_cmd),
|
||||
('import', commands.import_cmd),
|
||||
|
||||
('websearch', commands.websearch_cmd),
|
||||
('edit', commands.edit_cmd),
|
||||
# ('update', commands.update_cmd),
|
||||
])
|
||||
|
||||
|
||||
def _update_check(config, ui):
|
||||
if config.version_warning:
|
||||
code_version = __version__.split('.')
|
||||
if len(config.version) == 1: # support for deprecated version scheme.
|
||||
config.version = '0.{}.0'.format(config.version)
|
||||
repo_version = config.version.split('.')
|
||||
|
||||
if repo_version > code_version:
|
||||
ui.warning(
|
||||
'your repository was generated with an newer version'
|
||||
' of pubs (v{}) than the one you are using (v{}).'
|
||||
'\n'.format(repo_version, code_version) +
|
||||
'You should not use pubs until you install the '
|
||||
'newest version. (use version_warning in you pubsrc '
|
||||
'to bypass this error)')
|
||||
sys.exit()
|
||||
elif repo_version < code_version:
|
||||
ui.message(
|
||||
'warning: your repository version (v{})'.format(repo_version)
|
||||
+ 'must be updated to version {}.\n'.format(code_version)
|
||||
+ "run 'pubs update'.")
|
||||
sys.exit()
|
||||
('init', commands.init_cmd),
|
||||
('conf', commands.conf_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),
|
||||
|
||||
('export', commands.export_cmd),
|
||||
('import', commands.import_cmd),
|
||||
|
||||
('websearch', commands.websearch_cmd),
|
||||
('edit', commands.edit_cmd),
|
||||
])
|
||||
|
||||
|
||||
def execute(raw_args=sys.argv):
|
||||
# loading config
|
||||
config = configs.Config()
|
||||
if len(raw_args) > 1 and raw_args[1] != 'init':
|
||||
|
||||
conf_parser = argparse.ArgumentParser(prog="pubs", add_help=False)
|
||||
conf_parser.add_argument("-c", "--config", help="path to config file",
|
||||
type=str, metavar="FILE")
|
||||
#conf_parser.add_argument("-u", "--update", help="update config if needed",
|
||||
# default=False, action='store_true')
|
||||
top_args, remaining_args = conf_parser.parse_known_args(raw_args[1:])
|
||||
|
||||
if top_args.config:
|
||||
conf_path = top_args.config
|
||||
else:
|
||||
conf_path = config.get_confpath(verify=False) # will be checked on load
|
||||
|
||||
# Loading config
|
||||
if len(remaining_args) > 0 and remaining_args[0] != 'init':
|
||||
try:
|
||||
config.load()
|
||||
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()
|
||||
config.as_global()
|
||||
else:
|
||||
conf = config.load_default_conf()
|
||||
conf.filename = conf_path
|
||||
|
||||
uis.init_ui(config)
|
||||
uis.init_ui(conf)
|
||||
ui = uis.get_ui()
|
||||
|
||||
_update_check(config, ui)
|
||||
|
||||
parser = argparse.ArgumentParser(description="research papers repository")
|
||||
parser = argparse.ArgumentParser(description="research papers repository",
|
||||
prog="pubs", add_help=True)
|
||||
parser.add_argument('--version', action='version', version=__version__)
|
||||
subparsers = parser.add_subparsers(title="valid commands", dest="command")
|
||||
subparsers.required = True
|
||||
|
||||
cmd_funcs = collections.OrderedDict()
|
||||
# Populate the parser with core commands
|
||||
for cmd_name, cmd_mod in CORE_CMDS.items():
|
||||
cmd_mod.parser(subparsers)
|
||||
cmd_funcs[cmd_name] = cmd_mod.command
|
||||
cmd_parser = cmd_mod.parser(subparsers)
|
||||
cmd_parser.set_defaults(func=cmd_mod.command)
|
||||
|
||||
# Extend with plugin commands
|
||||
plugins.load_plugins(ui, config.plugins.split())
|
||||
plugins.load_plugins(conf, ui)
|
||||
for p in plugins.get_plugins().values():
|
||||
cmd_funcs.update(p.get_commands(subparsers))
|
||||
|
||||
args = parser.parse_args(raw_args[1:])
|
||||
args.prog = parser.prog # Hack: there might be a better way...
|
||||
cmd = args.command
|
||||
del args.command
|
||||
p.update_parser(subparsers)
|
||||
|
||||
cmd_funcs[cmd](args)
|
||||
# Parse and run appropriate command
|
||||
args = parser.parse_args(remaining_args)
|
||||
args.prog = "pubs" # FIXME?
|
||||
args.func(conf, args)
|
||||
|
@ -0,0 +1,106 @@
|
||||
import shutil
|
||||
|
||||
import io
|
||||
from . import config
|
||||
from . import uis
|
||||
from . import color
|
||||
from .__init__ import __version__
|
||||
|
||||
|
||||
def update_check(conf, path=None):
|
||||
"""Runs an update if necessary, and return True in that case."""
|
||||
|
||||
code_version = __version__.split('.')
|
||||
try:
|
||||
repo_version = conf['internal']['version'].split('.')
|
||||
except KeyError:
|
||||
repo_version = ['0', '5', '0']
|
||||
|
||||
if repo_version > code_version:
|
||||
uis.init_ui(config.load_default_conf())
|
||||
ui = uis.get_ui()
|
||||
|
||||
ui.warning(
|
||||
'Your repository was generated with an newer version'
|
||||
' of pubs (v{}) than the one you are using (v{}).'
|
||||
'\n'.format(repo_version, code_version) +
|
||||
'You should not use pubs until you install the '
|
||||
'newest version.')
|
||||
sys.exit()
|
||||
|
||||
elif repo_version <= code_version:
|
||||
return update(conf, code_version, repo_version, path=path)
|
||||
|
||||
return False
|
||||
|
||||
def update(conf, code_version, repo_version, path=None):
|
||||
"""Runs an update if necessary, and return True in that case."""
|
||||
if path is None:
|
||||
path = config.get_confpath()
|
||||
|
||||
if repo_version == ['0', '5', '0']: # we need to update
|
||||
default_conf = config.load_default_conf()
|
||||
|
||||
for key in ['pubsdir', 'docsdir', 'edit_cmd', 'open_cmd']:
|
||||
if key in conf['pubs']:
|
||||
default_conf['main'][key] = conf['pubs'][key]
|
||||
if conf.get('import_move'):
|
||||
default_conf['main']['add_doc'] = 'move'
|
||||
elif conf.get('import_copy'):
|
||||
default_conf['main']['add_doc'] = 'copy'
|
||||
else:
|
||||
default_conf['main']['add_doc'] = 'link'
|
||||
|
||||
backup_path = path + '.old'
|
||||
shutil.move(path, backup_path)
|
||||
config.save_conf(default_conf)
|
||||
|
||||
uis.init_ui(default_conf)
|
||||
ui = uis.get_ui()
|
||||
ui.warning(
|
||||
'Your configuration file has been updated. '
|
||||
'Your old configuration has been moved to `{}`. '.format(color.dye_out(backup_path, 'filepath')) +
|
||||
'Some, but not all, of your settings has been transferred '
|
||||
'to the new file.\n'
|
||||
'You can inspect and modify your configuration '
|
||||
' using the `pubs config` command.'
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
# continuous update while configuration is stabilizing
|
||||
if repo_version == ['0', '6', '0'] and repo_version < code_version:
|
||||
default_conf = config.load_default_conf()
|
||||
for section_name, section in conf.items():
|
||||
for key, value in section.items():
|
||||
try:
|
||||
default_conf[section_name][key]
|
||||
default_conf[section_name][key] = value
|
||||
except KeyError:
|
||||
pass
|
||||
# we don't update plugins
|
||||
for section_name, section in conf['plugins'].items():
|
||||
default_conf[section_name]['plugins'][section_name] = section
|
||||
|
||||
|
||||
# comparing potential changes
|
||||
with open(path, 'r') as f:
|
||||
old_conf_text = f.read()
|
||||
new_conf_text = io.BytesIO()
|
||||
default_conf.write(outfile=new_conf_text)
|
||||
|
||||
if new_conf_text.getvalue() != old_conf_text:
|
||||
|
||||
backup_path = path + '.old'
|
||||
shutil.move(path, backup_path)
|
||||
default_conf.filename = path
|
||||
config.save_conf(default_conf)
|
||||
|
||||
uis.init_ui(default_conf)
|
||||
ui = uis.get_ui()
|
||||
ui.warning('Your configuration file has been updated.\n'
|
||||
'Your old configuration has been moved to `{}`.'.format(color.dye_out(backup_path, 'filepath')))
|
||||
|
||||
return True
|
||||
|
||||
return False
|
@ -0,0 +1,84 @@
|
||||
import unittest
|
||||
|
||||
import dotdot
|
||||
|
||||
import pubs
|
||||
from pubs import config
|
||||
from pubs.plugs.alias.alias import (Alias, AliasPlugin, CommandAlias,
|
||||
ShellAlias)
|
||||
|
||||
|
||||
def to_args(arg_str):
|
||||
o = lambda: None # Dirty hack
|
||||
o.prog = 'pubs'
|
||||
o.arguments = arg_str.split(' ')
|
||||
return o
|
||||
|
||||
|
||||
class FakeExecuter(object):
|
||||
|
||||
called = None
|
||||
executed = None
|
||||
|
||||
def call(self, obj, shell=None):
|
||||
self.called = obj
|
||||
|
||||
def execute(self, obj):
|
||||
self.executed = obj
|
||||
|
||||
|
||||
class AliasTestCase(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.subprocess = FakeExecuter()
|
||||
pubs.plugs.alias.alias.subprocess = self.subprocess
|
||||
self.cmd_execute = FakeExecuter()
|
||||
pubs.plugs.alias.alias.execute = self.cmd_execute.execute
|
||||
|
||||
def testAlias(self):
|
||||
alias = Alias.create_alias('print', 'open -w lpppp')
|
||||
alias.command(None, to_args('CiteKey'))
|
||||
self.assertIsNone(self.subprocess.called)
|
||||
self.assertEqual(self.cmd_execute.executed,
|
||||
['pubs', 'open', '-w', 'lpppp', 'CiteKey'])
|
||||
|
||||
def testShellAlias(self):
|
||||
"""This actually just test that subprocess.call is called.
|
||||
"""
|
||||
alias = Alias.create_alias('count', '!pubs list -k | wc -l')
|
||||
alias.command(None, to_args(''))
|
||||
self.assertIsNone(self.cmd_execute.executed)
|
||||
self.assertIsNotNone(self.subprocess.called)
|
||||
|
||||
|
||||
class AliasPluginTestCase(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.conf = config.load_default_conf()
|
||||
self.conf['plugins']['active'] = ['alias']
|
||||
|
||||
def testAliasPluginCreated(self):
|
||||
self.plugin = AliasPlugin(self.conf)
|
||||
|
||||
def testAliasPluginOneCommnand(self):
|
||||
self.conf['plugins']['alias'] = {'print': 'open -w lpppp'}
|
||||
self.plugin = AliasPlugin(self.conf)
|
||||
self.assertEqual(len(self.plugin.aliases), 1)
|
||||
self.assertEqual(type(self.plugin.aliases[0]), CommandAlias)
|
||||
self.assertEqual(self.plugin.aliases[0].name, 'print')
|
||||
self.assertEqual(self.plugin.aliases[0].definition, 'open -w lpppp')
|
||||
|
||||
def testAliasPluginOneShell(self):
|
||||
self.conf['plugins']['alias'] = {'count': '!pubs list -k | wc -l'}
|
||||
self.plugin = AliasPlugin(self.conf)
|
||||
self.assertEqual(len(self.plugin.aliases), 1)
|
||||
self.assertEqual(type(self.plugin.aliases[0]), ShellAlias)
|
||||
self.assertEqual(self.plugin.aliases[0].name, 'count')
|
||||
self.assertEqual(self.plugin.aliases[0].definition,
|
||||
'pubs list -k | wc -l')
|
||||
|
||||
def testAliasPluginTwoCommnands(self):
|
||||
self.conf['plugins']['alias'] = {'print': 'open -w lpppp',
|
||||
'count': '!pubs list -k | wc -l'}
|
||||
self.plugin = AliasPlugin(self.conf)
|
||||
self.assertEqual(len(self.plugin.aliases), 2)
|
Loading…
Reference in new issue