diff --git a/setup.py b/setup.py index d9d994d..c952670 100644 --- a/setup.py +++ b/setup.py @@ -25,5 +25,5 @@ setup( entry_points={ 'console_scripts': ['vdirsyncer = vdirsyncer.cli:main'] }, - install_requires=['argvard'] + install_requires=['argvard', 'requests'] ) diff --git a/vdirsyncer/cli.py b/vdirsyncer/cli.py index 17462b6..3c52f41 100644 --- a/vdirsyncer/cli.py +++ b/vdirsyncer/cli.py @@ -8,21 +8,69 @@ ''' import os +import sys +import json import ConfigParser -from vdirsyncer.sync import sync_classes +from vdirsyncer.sync import sync +from vdirsyncer.storage.caldav import CaldavStorage +from vdirsyncer.storage.filesystem import FilesystemStorage +from vdirsyncer.utils import expand_path +import argvard -def _path(p): - p = os.path.expanduser(p) - p = os.path.abspath(p) - return p +storage_names = { + 'caldav': CaldavStorage, + 'filesystem': FilesystemStorage +} def get_config_parser(env): - fname = env.get('VDIRSYNCER_CONFIG', _path('~/.vdirsyncer/config')) - c = ConfigParser.SafeConfigParser() + fname = env.get('VDIRSYNCER_CONFIG', expand_path('~/.vdirsyncer/config')) + c = ConfigParser.RawConfigParser() c.read(fname) - return dict((c, c.items(c)) for c in c.sections()) + pairs = {} + storages = {} + for section in c.sections(): + if section.startswith('storage '): + name = section[len('storage '):] + storages.setdefault(name, {}).update(c.items(section)) + elif section.startswith('pair '): + name = section[len('pair '):] + options = dict(c.items(section)) + pairs[name] = a, b = (options.pop('a'), options.pop('b')) + storages.setdefault(a, {}).update(options) + storages.setdefault(b, {}).update(options) + elif section == 'general': + general = dict(c.items(section)) + else: + raise RuntimeError('Unknown section: {}'.format(section)) + + return general, pairs, storages + + +def load_status(basepath, pair_name): + full_path = os.path.join(expand_path(basepath), pair_name) + if not os.path.exists(full_path): + return {} + with open(full_path) as f: + return dict(json.loads(line) for line in f) + + +def save_status(basepath, pair_name, status): + full_path = os.path.join(expand_path(basepath), pair_name) + with open(full_path, 'w+') as f: + for k, v in status.items(): + json.dump((k, v), f) + + +def storage_instance_from_config(config): + config = dict(config) + cls = storage_names[config.pop('type')] + try: + return cls(**config) + except TypeError: + print(config) + raise def main(): @@ -32,16 +80,40 @@ def main(): def _main(env, file_cfg): + general, all_pairs, all_storages = file_cfg app = argvard.Argvard() - sync = argvard.Command() - @sync_command.main('[accounts...]') - def sync_main(accounts=None): - if accounts is None: - accounts = list(file_cfg.keys()) - for account in accounts: - account_cfg = dict(file_cfg[account]) - del account_cfg['type'] - syncer = sync_classes[account_cfg['type']](**account_cfg) - syncer.run() + @app.main() + def app_main(context): + print("heY") + + sync_command = argvard.Command() + + + @sync_command.main('[pairs...]') + def sync_main(context, pairs=None): + if pairs is None: + pairs = list(all_pairs) + actions = [] + for pair_name in pairs: + try: + a, b = all_pairs[pair_name] + except KeyError: + print('Pair not found: {}'.format(pair_name)) + print(file_cfg) + sys.exit(1) + a = storage_instance_from_config(all_storages[a]) + b = storage_instance_from_config(all_storages[b]) + + def x(a=a, b=b, pair_name=pair_name): + status = load_status(general['status_path'], pair_name) + sync(a, b, status) + save_status(general['status_path'], pair_name, status) + actions.append(x) + + for action in actions: + action() + + app.register_command('sync', sync_command) + app() diff --git a/vdirsyncer/storage/caldav.py b/vdirsyncer/storage/caldav.py index af76272..6ff796f 100644 --- a/vdirsyncer/storage/caldav.py +++ b/vdirsyncer/storage/caldav.py @@ -82,7 +82,7 @@ class CaldavStorage(Storage): if self._session is None: self._session = requests.session() assert '/' not in item - path = self.url + item + url = self.url + item return self._session.request(method, url, data=data, headers=headers, **self._settings) @staticmethod diff --git a/vdirsyncer/storage/filesystem.py b/vdirsyncer/storage/filesystem.py index 2a39222..410680e 100644 --- a/vdirsyncer/storage/filesystem.py +++ b/vdirsyncer/storage/filesystem.py @@ -10,6 +10,7 @@ import os from vdirsyncer.storage.base import Storage, Item import vdirsyncer.exceptions as exceptions +from vdirsyncer.utils import expand_path class FilesystemStorage(Storage): @@ -22,7 +23,7 @@ class FilesystemStorage(Storage): ''' :param path: Absolute path to a *collection* inside a vdir. ''' - self.path = path + self.path = expand_path(path) self.fileext = fileext super(FilesystemStorage, self).__init__(**kwargs) diff --git a/vdirsyncer/utils.py b/vdirsyncer/utils.py new file mode 100644 index 0000000..7f48a8e --- /dev/null +++ b/vdirsyncer/utils.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +''' + vdirsyncer.utils + ~~~~~~~~~~~~~~~~ + + :copyright: (c) 2014 Markus Unterwaditzer + :license: MIT, see LICENSE for more details. +''' + +import os + +def expand_path(p): + p = os.path.expanduser(p) + p = os.path.abspath(p) + return p