mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-04-27 14:57:41 +00:00
parent
63e9e55bbe
commit
c6e185d8a3
2 changed files with 96 additions and 26 deletions
|
|
@ -510,3 +510,63 @@ def test_partial_sync(tmpdir, runner, partial_sync):
|
||||||
assert not r.exception
|
assert not r.exception
|
||||||
assert baritem.exists()
|
assert baritem.exists()
|
||||||
assert fooitem.exists()
|
assert fooitem.exists()
|
||||||
|
|
||||||
|
|
||||||
|
def test_fetch_only_necessary_params(tmpdir, runner):
|
||||||
|
fetched_file = tmpdir.join('fetched_flag')
|
||||||
|
fetch_script = tmpdir.join('fetch_script')
|
||||||
|
fetch_script.write(dedent('''
|
||||||
|
set -e
|
||||||
|
touch "{}"
|
||||||
|
echo ".txt"
|
||||||
|
'''.format(str(fetched_file))))
|
||||||
|
|
||||||
|
runner.write_with_general(dedent('''
|
||||||
|
[pair foobar]
|
||||||
|
a = foo
|
||||||
|
b = bar
|
||||||
|
collections = null
|
||||||
|
|
||||||
|
[pair bambar]
|
||||||
|
a = bam
|
||||||
|
b = bar
|
||||||
|
collections = null
|
||||||
|
|
||||||
|
[storage foo]
|
||||||
|
type = filesystem
|
||||||
|
path = {path}
|
||||||
|
fileext = .txt
|
||||||
|
|
||||||
|
[storage bar]
|
||||||
|
type = filesystem
|
||||||
|
path = {path}
|
||||||
|
fileext = .txt
|
||||||
|
|
||||||
|
[storage bam]
|
||||||
|
type = filesystem
|
||||||
|
path = {path}
|
||||||
|
fileext.fetch = ["command", "sh", "{script}"]
|
||||||
|
'''.format(path=str(tmpdir.mkdir('bogus')), script=str(fetch_script))))
|
||||||
|
|
||||||
|
def fetched():
|
||||||
|
try:
|
||||||
|
fetched_file.remove()
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
r = runner.invoke(['discover'])
|
||||||
|
assert not r.exception
|
||||||
|
assert fetched()
|
||||||
|
|
||||||
|
r = runner.invoke(['sync', 'foobar'])
|
||||||
|
assert not r.exception
|
||||||
|
assert not fetched()
|
||||||
|
|
||||||
|
r = runner.invoke(['sync'])
|
||||||
|
assert not r.exception
|
||||||
|
assert fetched()
|
||||||
|
|
||||||
|
r = runner.invoke(['sync', 'bambar'])
|
||||||
|
assert not r.exception
|
||||||
|
assert fetched()
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ from . import cli_logger
|
||||||
from .fetchparams import expand_fetch_params
|
from .fetchparams import expand_fetch_params
|
||||||
from .utils import storage_class_from_config
|
from .utils import storage_class_from_config
|
||||||
from .. import PROJECT_HOME, exceptions
|
from .. import PROJECT_HOME, exceptions
|
||||||
from ..utils import expand_path
|
from ..utils import cached_property, expand_path
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from ConfigParser import RawConfigParser
|
from ConfigParser import RawConfigParser
|
||||||
|
|
@ -253,21 +253,30 @@ class PairConfig(object):
|
||||||
self.name_a = options.pop('a')
|
self.name_a = options.pop('a')
|
||||||
self.name_b = options.pop('b')
|
self.name_b = options.pop('b')
|
||||||
|
|
||||||
self.config_a = self._config.get_storage_args(self.name_a)
|
self._partial_sync = options.pop('partial_sync', None)
|
||||||
self.config_b = self._config.get_storage_args(self.name_b)
|
|
||||||
|
|
||||||
self._set_conflict_resolution(options)
|
|
||||||
self._set_partial_sync(options)
|
|
||||||
self._set_collections(options)
|
|
||||||
self.metadata = options.pop('metadata', None) or ()
|
self.metadata = options.pop('metadata', None) or ()
|
||||||
|
|
||||||
|
self.conflict_resolution = \
|
||||||
|
self._process_conflict_resolution_param(
|
||||||
|
options.pop('conflict_resolution', None))
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.collections = options.pop('collections')
|
||||||
|
except KeyError:
|
||||||
|
raise ValueError(
|
||||||
|
'collections parameter missing.\n\n'
|
||||||
|
'As of 0.9.0 this parameter has no default anymore. '
|
||||||
|
'Set `collections = null` explicitly in your pair config.'
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
_validate_collections_param(self.collections)
|
||||||
|
|
||||||
if options:
|
if options:
|
||||||
raise ValueError('Unknown options: {}'.format(', '.join(options)))
|
raise ValueError('Unknown options: {}'.format(', '.join(options)))
|
||||||
|
|
||||||
def _set_conflict_resolution(self, options):
|
def _process_conflict_resolution_param(self, conflict_resolution):
|
||||||
conflict_resolution = options.pop('conflict_resolution', None)
|
|
||||||
if conflict_resolution in (None, 'a wins', 'b wins'):
|
if conflict_resolution in (None, 'a wins', 'b wins'):
|
||||||
self.conflict_resolution = conflict_resolution
|
return conflict_resolution
|
||||||
elif isinstance(conflict_resolution, list) and \
|
elif isinstance(conflict_resolution, list) and \
|
||||||
len(conflict_resolution) > 1 and \
|
len(conflict_resolution) > 1 and \
|
||||||
conflict_resolution[0] == 'command':
|
conflict_resolution[0] == 'command':
|
||||||
|
|
@ -282,12 +291,25 @@ class PairConfig(object):
|
||||||
ui_worker = get_ui_worker()
|
ui_worker = get_ui_worker()
|
||||||
return ui_worker.put(inner)
|
return ui_worker.put(inner)
|
||||||
|
|
||||||
self.conflict_resolution = resolve
|
return resolve
|
||||||
else:
|
else:
|
||||||
raise ValueError('Invalid value for `conflict_resolution`.')
|
raise ValueError('Invalid value for `conflict_resolution`.')
|
||||||
|
|
||||||
def _set_partial_sync(self, options):
|
# The following parameters are lazily evaluated because evaluating
|
||||||
partial_sync = options.pop('partial_sync', None)
|
# self.config_a would expand all `x.fetch` parameters. This is costly and
|
||||||
|
# unnecessary if the pair is not actually synced.
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def config_a(self):
|
||||||
|
return self._config.get_storage_args(self.name_a)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def config_b(self):
|
||||||
|
return self._config.get_storage_args(self.name_b)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def partial_sync(self):
|
||||||
|
partial_sync = self._partial_sync
|
||||||
if partial_sync is not None:
|
if partial_sync is not None:
|
||||||
cls_a, _ = storage_class_from_config(self.config_a)
|
cls_a, _ = storage_class_from_config(self.config_a)
|
||||||
cls_b, _ = storage_class_from_config(self.config_b)
|
cls_b, _ = storage_class_from_config(self.config_b)
|
||||||
|
|
@ -305,19 +327,7 @@ class PairConfig(object):
|
||||||
if partial_sync not in ('ignore', 'revert', 'error'):
|
if partial_sync not in ('ignore', 'revert', 'error'):
|
||||||
raise ValueError('Invalid value for `partial_sync`.')
|
raise ValueError('Invalid value for `partial_sync`.')
|
||||||
|
|
||||||
self.partial_sync = partial_sync
|
return partial_sync
|
||||||
|
|
||||||
def _set_collections(self, options):
|
|
||||||
try:
|
|
||||||
self.collections = options.pop('collections')
|
|
||||||
except KeyError:
|
|
||||||
raise ValueError(
|
|
||||||
'collections parameter missing.\n\n'
|
|
||||||
'As of 0.9.0 this parameter has no default anymore. '
|
|
||||||
'Set `collections = null` explicitly in your pair config.'
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
_validate_collections_param(self.collections)
|
|
||||||
|
|
||||||
|
|
||||||
class CollectionConfig(object):
|
class CollectionConfig(object):
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue