mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-03-25 08:55:50 +00:00
Fix #63
This commit is contained in:
parent
dce438d758
commit
1f85b4db6f
2 changed files with 36 additions and 21 deletions
|
|
@ -14,7 +14,7 @@ import sys
|
|||
import argvard
|
||||
|
||||
from .storage import storage_names
|
||||
from .sync import sync, StorageEmpty
|
||||
from .sync import sync, StorageEmpty, SyncConflict
|
||||
from .utils import expand_path, parse_options, split_dict, get_class_init_args
|
||||
|
||||
import vdirsyncer.log as log
|
||||
|
|
@ -29,6 +29,7 @@ except ImportError:
|
|||
cli_logger = log.get(__name__)
|
||||
|
||||
PROJECT_HOME = 'https://github.com/untitaker/vdirsyncer'
|
||||
DOCS_HOME = 'https://vdirsyncer.readthedocs.org/en/latest'
|
||||
|
||||
|
||||
class CliError(RuntimeError):
|
||||
|
|
@ -296,16 +297,30 @@ def sync_collection(config_a, config_b, pair_name, collection, pair_options,
|
|||
force_delete=status_name in force_delete
|
||||
)
|
||||
except StorageEmpty as e:
|
||||
raise CliError(
|
||||
'{collection_description}: Storage "{side}" ({storage}) was '
|
||||
'completely emptied. Use "--force-delete {status_name}" to '
|
||||
'synchronize that emptyness to the other side, or delete the '
|
||||
'status by yourself to restore the items from the non-empty '
|
||||
'side.'.format(
|
||||
collection_description=collection_description,
|
||||
cli_logger.critical(
|
||||
'{collection}: Storage "{side}" ({storage}) was completely '
|
||||
'emptied. Use "--force-delete {status_name}" to synchronize that '
|
||||
'emptyness to the other side, or delete the status by yourself to '
|
||||
'restore the items from the non-empty side.'.format(
|
||||
collection=collection_description,
|
||||
side='a' if e.empty_storage is a else 'b',
|
||||
storage=e.empty_storage,
|
||||
status_name=status_name
|
||||
)
|
||||
)
|
||||
except SyncConflict as e:
|
||||
cli_logger.critical(
|
||||
'{collection}: One item changed on both sides. Resolve this '
|
||||
'conflict manually, or by setting the `conflict_resolution` '
|
||||
'parameter in your config file.\n'
|
||||
'See also {docs}/api.html#pair-section\n'
|
||||
'Item ID: {e.ident}\n'
|
||||
'Item href on side A: {e.href_a}\n'
|
||||
'Item href on side B: {e.href_b}\n'
|
||||
.format(collection=collection_description, e=e, docs=DOCS_HOME)
|
||||
)
|
||||
except Exception:
|
||||
cli_logger.exception('Unhandled exception occured while syncing {}.'
|
||||
.format(collection_description))
|
||||
|
||||
save_status(general['status_path'], status_name, status)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@ sync_logger = log.get(__name__)
|
|||
class SyncError(exceptions.Error):
|
||||
'''Errors related to synchronization.'''
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.__dict__.update(kwargs)
|
||||
super(SyncError, self).__init__(*args)
|
||||
|
||||
|
||||
class SyncConflict(SyncError):
|
||||
'''
|
||||
|
|
@ -39,10 +43,6 @@ class StorageEmpty(SyncError):
|
|||
The first argument is the empty storage.
|
||||
'''
|
||||
|
||||
@property
|
||||
def empty_storage(self):
|
||||
return self.args[0]
|
||||
|
||||
|
||||
def prepare_list(storage, href_to_status):
|
||||
rv = {}
|
||||
|
|
@ -63,7 +63,7 @@ def prepare_list(storage, href_to_status):
|
|||
props['item'] = item
|
||||
props['ident'] = item.ident
|
||||
if props['etag'] != etag:
|
||||
raise SyncConflict('Etag changed during sync.')
|
||||
raise SyncError('Etag changed during sync.')
|
||||
|
||||
return rv
|
||||
|
||||
|
|
@ -101,7 +101,7 @@ def sync(storage_a, storage_b, status, conflict_resolution=None,
|
|||
list_b = prepare_list(storage_b, b_href_to_status)
|
||||
|
||||
if bool(list_a) != bool(list_b) and status and not force_delete:
|
||||
raise StorageEmpty(storage_b if list_a else storage_a)
|
||||
raise StorageEmpty(empty_storage=(storage_b if list_a else storage_a))
|
||||
|
||||
a_ident_to_href = dict((x['ident'], href) for href, x in iteritems(list_a))
|
||||
b_ident_to_href = dict((x['ident'], href) for href, x in iteritems(list_b))
|
||||
|
|
@ -185,15 +185,15 @@ def action_conflict_resolve(ident):
|
|||
.format(ident))
|
||||
a_storage, list_a, a_ident_to_href = storages['a']
|
||||
b_storage, list_b, b_ident_to_href = storages['b']
|
||||
a_href = a_ident_to_href[ident]
|
||||
b_href = b_ident_to_href[ident]
|
||||
a_meta = list_a[a_href]
|
||||
b_meta = list_b[b_href]
|
||||
if a_meta['item'].raw == b_meta['item'].raw:
|
||||
href_a = a_ident_to_href[ident]
|
||||
href_b = b_ident_to_href[ident]
|
||||
meta_a = list_a[href_a]
|
||||
meta_b = list_b[href_b]
|
||||
if meta_a['item'].raw == meta_b['item'].raw:
|
||||
sync_logger.info('...same content on both sides.')
|
||||
status[ident] = a_href, a_meta['etag'], b_href, b_meta['etag']
|
||||
status[ident] = href_a, meta_a['etag'], href_b, meta_b['etag']
|
||||
elif conflict_resolution is None:
|
||||
raise SyncConflict()
|
||||
raise SyncConflict(ident=ident, href_a=href_a, href_b=href_b)
|
||||
elif conflict_resolution == 'a wins':
|
||||
sync_logger.info('...{} wins.'.format(a_storage))
|
||||
action_update(ident, 'a', 'b')(storages, status,
|
||||
|
|
|
|||
Loading…
Reference in a new issue