Add an update mechanism for old repositories
The update is done transparently, and displays a warning message explaining the change. All the update machinery has been moved to the new update module.
This commit is contained in:
parent
93c54939b3
commit
757a8b300e
@ -1 +1 @@
|
|||||||
__version__ = '0.5.0'
|
__version__ = '0.6.0'
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
import sys
|
|
||||||
|
|
||||||
from .. import repo
|
|
||||||
from .. import color
|
|
||||||
|
|
||||||
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(conf, args):
|
|
||||||
|
|
||||||
ui = get_ui()
|
|
||||||
|
|
||||||
code_version = __version__.split('.')
|
|
||||||
if len(conf['internal']['version']) == 1: # support for deprecated version scheme.
|
|
||||||
conf['internal']['version'] = '0.{}.0'.format(conf['internal']['version'])
|
|
||||||
repo_version = conf['internal']['version'].split('.')
|
|
||||||
|
|
||||||
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(conf['main']['pubsdir'], color.filepath))
|
|
||||||
sure = ui.input_yn(question=msg, default='n')
|
|
||||||
if not sure:
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
#TODO: update!!
|
|
||||||
# conf['internal']['version'] = repo_version
|
|
||||||
# conf['internal']['version']
|
|
@ -1 +1 @@
|
|||||||
from .conf import load_default_conf, load_conf, save_conf, get_pubspath
|
from .conf import get_confpath, load_default_conf, load_conf, save_conf, check_conf
|
||||||
|
@ -15,7 +15,7 @@ def load_default_conf():
|
|||||||
default_conf.validate(validator, copy=True)
|
default_conf.validate(validator, copy=True)
|
||||||
return default_conf
|
return default_conf
|
||||||
|
|
||||||
def get_pubspath(verify=True):
|
def get_confpath(verify=True):
|
||||||
"""Returns the pubs path.
|
"""Returns the pubs path.
|
||||||
If verify is True, verify that pubs.conf exist in the directory,
|
If verify is True, verify that pubs.conf exist in the directory,
|
||||||
and exit with an error if not.
|
and exit with an error if not.
|
||||||
@ -31,19 +31,26 @@ def get_pubspath(verify=True):
|
|||||||
ui.exit(error_code=1)
|
ui.exit(error_code=1)
|
||||||
return confpath
|
return confpath
|
||||||
|
|
||||||
def load_conf(check_conf=True):
|
def check_conf(conf):
|
||||||
|
"""Type checks 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 user config"""
|
"""Load the user config"""
|
||||||
pubspath = get_pubspath(verify=True)
|
if path is None:
|
||||||
with open(pubspath, 'r') as f:
|
path = get_confpath(verify=True)
|
||||||
|
with open(path, 'rb') as f:
|
||||||
conf = configobj.ConfigObj(f.readlines(), configspec=configspec)
|
conf = configobj.ConfigObj(f.readlines(), configspec=configspec)
|
||||||
|
|
||||||
if check_conf:
|
if check:
|
||||||
validator = validate.Validator()
|
check_conf(conf)
|
||||||
results = conf.validate(validator, copy=True)
|
|
||||||
assert results == True, '{}'.format(results) # TODO: precise error dialog when parsing error
|
|
||||||
|
|
||||||
return conf
|
return conf
|
||||||
|
|
||||||
def save_conf(conf):
|
def save_conf(conf, path=None):
|
||||||
with open(get_pubspath(verify=False), 'w') as f:
|
if path is None:
|
||||||
|
path = get_confpath(verify=False)
|
||||||
|
with open(path, 'wb') as f:
|
||||||
conf.write(outfile=f)
|
conf.write(outfile=f)
|
||||||
|
@ -6,8 +6,8 @@ import collections
|
|||||||
from . import uis
|
from . import uis
|
||||||
from . import config
|
from . import config
|
||||||
from . import commands
|
from . import commands
|
||||||
|
from . import update
|
||||||
from . import plugins
|
from . import plugins
|
||||||
from .__init__ import __version__
|
|
||||||
|
|
||||||
|
|
||||||
CORE_CMDS = collections.OrderedDict([
|
CORE_CMDS = collections.OrderedDict([
|
||||||
@ -27,37 +27,17 @@ CORE_CMDS = collections.OrderedDict([
|
|||||||
|
|
||||||
('websearch', commands.websearch_cmd),
|
('websearch', commands.websearch_cmd),
|
||||||
('edit', commands.edit_cmd),
|
('edit', commands.edit_cmd),
|
||||||
# ('update', commands.update_cmd),
|
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
def _update_check(conf, ui):
|
|
||||||
code_version = __version__.split('.')
|
|
||||||
if len(conf['internal']['version']) == 1: # support for deprecated version scheme.
|
|
||||||
conf['internal']['version'] = '0.{}.0'.format(conf['internal']['version'])
|
|
||||||
repo_version = conf['internal']['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.')
|
|
||||||
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()
|
|
||||||
|
|
||||||
|
|
||||||
def execute(raw_args=sys.argv):
|
def execute(raw_args=sys.argv):
|
||||||
# loading config
|
# loading config
|
||||||
if len(raw_args) > 1 and raw_args[1] != 'init':
|
if len(raw_args) > 1 and raw_args[1] != 'init':
|
||||||
try:
|
try:
|
||||||
conf = config.load_conf(check_conf=True)
|
conf = config.load_conf(check=False)
|
||||||
|
if update.update_check(conf): # an update happened, reload conf.
|
||||||
|
conf = config.load_conf(check=False)
|
||||||
|
config.check_conf(conf)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
print('error: {}'.format(str(e)))
|
print('error: {}'.format(str(e)))
|
||||||
sys.exit()
|
sys.exit()
|
||||||
@ -67,8 +47,6 @@ def execute(raw_args=sys.argv):
|
|||||||
uis.init_ui(conf)
|
uis.init_ui(conf)
|
||||||
ui = uis.get_ui()
|
ui = uis.get_ui()
|
||||||
|
|
||||||
_update_check(conf, ui)
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description="research papers repository")
|
parser = argparse.ArgumentParser(description="research papers repository")
|
||||||
subparsers = parser.add_subparsers(title="valid commands", dest="command")
|
subparsers = parser.add_subparsers(title="valid commands", dest="command")
|
||||||
|
|
||||||
|
63
pubs/update.py
Normal file
63
pubs/update.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
from . import config
|
||||||
|
from . import uis
|
||||||
|
from .__init__ import __version__
|
||||||
|
|
||||||
|
|
||||||
|
def update_check(conf):
|
||||||
|
"""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)
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def update(conf, code_version, repo_version):
|
||||||
|
"""Runs an update if necessary, and return True in that case."""
|
||||||
|
|
||||||
|
if repo_version == ['0', '5', '0']: # we need to update
|
||||||
|
default_conf = config.load_default_conf()
|
||||||
|
uis.init_ui(config.load_default_conf())
|
||||||
|
ui = uis.get_ui()
|
||||||
|
|
||||||
|
for key in ['pubsdir', 'docsdir', 'edit_cmd', 'open_cmd']:
|
||||||
|
default_conf['main'][key] = conf['pubs'][key]
|
||||||
|
if conf['pubs']['import_move']:
|
||||||
|
default_conf['main']['add_doc'] = 'move'
|
||||||
|
elif conf['pubs']['import_copy']:
|
||||||
|
default_conf['main']['add_doc'] = 'copy'
|
||||||
|
else:
|
||||||
|
default_conf['main']['add_doc'] = 'link'
|
||||||
|
|
||||||
|
backup_path = config.get_confpath() + '.old'
|
||||||
|
config.save_conf(conf, path=backup_path)
|
||||||
|
config.save_conf(default_conf)
|
||||||
|
|
||||||
|
ui.warning(
|
||||||
|
'Your configuration file has been updated. '
|
||||||
|
'The old file has been moved to `{}`. '.format(backup_path) +
|
||||||
|
'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
|
||||||
|
return False
|
@ -2,71 +2,70 @@
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import dotdot
|
import dotdot
|
||||||
from pubs import configs
|
from pubs.config import conf
|
||||||
from pubs.configs import config
|
|
||||||
from pubs.p3 import configparser
|
from pubs.p3 import configparser
|
||||||
|
|
||||||
class TestConfig(unittest.TestCase):
|
# class TestConfig(unittest.TestCase):
|
||||||
|
#
|
||||||
def test_create_config(self):
|
# def test_create_config(self):
|
||||||
a = configs.Config()
|
# a = configs.Config()
|
||||||
a.as_global()
|
# a.as_global()
|
||||||
self.assertEqual(a, config())
|
# self.assertEqual(a, config())
|
||||||
|
#
|
||||||
def test_config_content(self):
|
# def test_config_content(self):
|
||||||
a = configs.Config()
|
# a = configs.Config()
|
||||||
a.as_global()
|
# a.as_global()
|
||||||
|
#
|
||||||
self.assertEqual(config().pubsdir, configs.DFT_CONFIG['pubsdir'])
|
# self.assertEqual(config().pubsdir, configs.DFT_CONFIG['pubsdir'])
|
||||||
self.assertEqual(config().color, configs.str2bool(configs.DFT_CONFIG['color']))
|
# self.assertEqual(config().color, configs.str2bool(configs.DFT_CONFIG['color']))
|
||||||
|
#
|
||||||
def test_set(self):
|
# def test_set(self):
|
||||||
a = configs.Config()
|
# a = configs.Config()
|
||||||
a.as_global()
|
# a.as_global()
|
||||||
config().color = 'no'
|
# config().color = 'no'
|
||||||
self.assertEqual(config().color, False)
|
# self.assertEqual(config().color, False)
|
||||||
self.assertEqual(config('pubs').color, False)
|
# self.assertEqual(config('pubs').color, False)
|
||||||
# booleans type for new variables are memorized, but not saved.
|
# # booleans type for new variables are memorized, but not saved.
|
||||||
config().bla = True
|
# config().bla = True
|
||||||
self.assertEqual(config().bla, True)
|
# self.assertEqual(config().bla, True)
|
||||||
self.assertEqual(config('pubs').bla, True)
|
# self.assertEqual(config('pubs').bla, True)
|
||||||
|
#
|
||||||
with self.assertRaises(configparser.NoOptionError):
|
# with self.assertRaises(configparser.NoOptionError):
|
||||||
config()._cfg.get(configs.MAIN_SECTION, '_section')
|
# config()._cfg.get(configs.MAIN_SECTION, '_section')
|
||||||
|
#
|
||||||
def test_reload(self):
|
# def test_reload(self):
|
||||||
|
#
|
||||||
default_color = configs.DFT_CONFIG['color']
|
# default_color = configs.DFT_CONFIG['color']
|
||||||
|
#
|
||||||
a = configs.Config()
|
# a = configs.Config()
|
||||||
a.as_global()
|
# a.as_global()
|
||||||
a.color = False
|
# a.color = False
|
||||||
a.bla = 'foo'
|
# a.bla = 'foo'
|
||||||
config.color = not configs.str2bool(default_color)
|
# config.color = not configs.str2bool(default_color)
|
||||||
self.assertEqual(config().color, not configs.str2bool(default_color))
|
# self.assertEqual(config().color, not configs.str2bool(default_color))
|
||||||
|
#
|
||||||
b = configs.Config()
|
# b = configs.Config()
|
||||||
b.as_global()
|
# b.as_global()
|
||||||
self.assertEqual(b, config())
|
# self.assertEqual(b, config())
|
||||||
self.assertEqual(config().color, configs.str2bool(default_color))
|
# self.assertEqual(config().color, configs.str2bool(default_color))
|
||||||
|
#
|
||||||
def test_exception(self):
|
# def test_exception(self):
|
||||||
|
#
|
||||||
a = configs.Config()
|
# a = configs.Config()
|
||||||
a.as_global()
|
# a.as_global()
|
||||||
|
#
|
||||||
with self.assertRaises(configparser.NoOptionError):
|
# with self.assertRaises(configparser.NoOptionError):
|
||||||
config().color2
|
# config().color2
|
||||||
self.assertEqual(config().get('color2', default = 'blue'), 'blue')
|
# self.assertEqual(config().get('color2', default = 'blue'), 'blue')
|
||||||
|
#
|
||||||
with self.assertRaises(configparser.NoSectionError):
|
# with self.assertRaises(configparser.NoSectionError):
|
||||||
config(section = 'bla3').color
|
# config(section = 'bla3').color
|
||||||
self.assertEqual(config(section = 'bla3').get('color', default = 'green'), 'green')
|
# self.assertEqual(config(section = 'bla3').get('color', default = 'green'), 'green')
|
||||||
self.assertEqual(config(section = 'bla3').get('color', default = config().color), True)
|
# self.assertEqual(config(section = 'bla3').get('color', default = config().color), True)
|
||||||
|
#
|
||||||
def test_keywords(self):
|
# def test_keywords(self):
|
||||||
a = configs.Config(pubs_dir = '/blabla')
|
# a = configs.Config(pubs_dir = '/blabla')
|
||||||
self.assertEqual(a.pubs_dir, '/blabla')
|
# self.assertEqual(a.pubs_dir, '/blabla')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@ -5,7 +5,8 @@ import os
|
|||||||
import dotdot
|
import dotdot
|
||||||
import fake_env
|
import fake_env
|
||||||
|
|
||||||
from pubs import content, filebroker, databroker, datacache, configs
|
from pubs import content, filebroker, databroker, datacache
|
||||||
|
from pubs.config import conf
|
||||||
|
|
||||||
import str_fixtures
|
import str_fixtures
|
||||||
from pubs import endecoder
|
from pubs import endecoder
|
||||||
@ -20,7 +21,7 @@ class TestDataBroker(unittest.TestCase):
|
|||||||
page99_bibentry = ende.decode_bibdata(str_fixtures.bibtex_raw0)
|
page99_bibentry = ende.decode_bibdata(str_fixtures.bibtex_raw0)
|
||||||
|
|
||||||
for db_class in [databroker.DataBroker, datacache.DataCache]:
|
for db_class in [databroker.DataBroker, datacache.DataCache]:
|
||||||
self.fs = fake_env.create_fake_fs([content, filebroker, configs])
|
self.fs = fake_env.create_fake_fs([content, filebroker, conf])
|
||||||
|
|
||||||
db = db_class('tmp', create=True)
|
db = db_class('tmp', create=True)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user