Evaluate partial_sync lazily

Fix #516
This commit is contained in:
Markus Unterwaditzer 2016-10-10 16:33:28 +02:00
parent 63e9e55bbe
commit c6e185d8a3
2 changed files with 96 additions and 26 deletions

View file

@ -510,3 +510,63 @@ def test_partial_sync(tmpdir, runner, partial_sync):
assert not r.exception
assert baritem.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()

View file

@ -9,7 +9,7 @@ from . import cli_logger
from .fetchparams import expand_fetch_params
from .utils import storage_class_from_config
from .. import PROJECT_HOME, exceptions
from ..utils import expand_path
from ..utils import cached_property, expand_path
try:
from ConfigParser import RawConfigParser
@ -253,21 +253,30 @@ class PairConfig(object):
self.name_a = options.pop('a')
self.name_b = options.pop('b')
self.config_a = self._config.get_storage_args(self.name_a)
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._partial_sync = options.pop('partial_sync', None)
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:
raise ValueError('Unknown options: {}'.format(', '.join(options)))
def _set_conflict_resolution(self, options):
conflict_resolution = options.pop('conflict_resolution', None)
def _process_conflict_resolution_param(self, conflict_resolution):
if conflict_resolution in (None, 'a wins', 'b wins'):
self.conflict_resolution = conflict_resolution
return conflict_resolution
elif isinstance(conflict_resolution, list) and \
len(conflict_resolution) > 1 and \
conflict_resolution[0] == 'command':
@ -282,12 +291,25 @@ class PairConfig(object):
ui_worker = get_ui_worker()
return ui_worker.put(inner)
self.conflict_resolution = resolve
return resolve
else:
raise ValueError('Invalid value for `conflict_resolution`.')
def _set_partial_sync(self, options):
partial_sync = options.pop('partial_sync', None)
# The following parameters are lazily evaluated because evaluating
# 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:
cls_a, _ = storage_class_from_config(self.config_a)
cls_b, _ = storage_class_from_config(self.config_b)
@ -305,19 +327,7 @@ class PairConfig(object):
if partial_sync not in ('ignore', 'revert', 'error'):
raise ValueError('Invalid value for `partial_sync`.')
self.partial_sync = 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)
return partial_sync
class CollectionConfig(object):