mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-04-27 14:57:41 +00:00
Add CLI for partial_sync
This commit is contained in:
parent
8ca5446e02
commit
827299ef24
4 changed files with 76 additions and 2 deletions
|
|
@ -101,6 +101,13 @@ Pair Section
|
||||||
|
|
||||||
Vdirsyncer never attempts to "automatically merge" the two items.
|
Vdirsyncer never attempts to "automatically merge" the two items.
|
||||||
|
|
||||||
|
- ``partial_sync``: Assume A is read-only, B not. If you change items on B,
|
||||||
|
vdirsyncer can't sync the changes to A. What should happen instead?
|
||||||
|
|
||||||
|
- ``error``: An error is shown.
|
||||||
|
- ``ignore``: The change is ignored.
|
||||||
|
- ``revert`` (default): The change is reverted on next sync.
|
||||||
|
|
||||||
- ``metadata``: Metadata keys that should be synchronized when ``vdirsyncer
|
- ``metadata``: Metadata keys that should be synchronized when ``vdirsyncer
|
||||||
metasync`` is executed. Example::
|
metasync`` is executed. Example::
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -449,3 +449,64 @@ def test_conflict_resolution(tmpdir, runner, resolution, expect_foo,
|
||||||
|
|
||||||
assert fooitem.read() == expect_foo
|
assert fooitem.read() == expect_foo
|
||||||
assert baritem.read() == expect_bar
|
assert baritem.read() == expect_bar
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('partial_sync', ['error', 'ignore', 'revert', None])
|
||||||
|
def test_partial_sync(tmpdir, runner, partial_sync):
|
||||||
|
runner.write_with_general(dedent('''
|
||||||
|
[pair foobar]
|
||||||
|
a = foo
|
||||||
|
b = bar
|
||||||
|
collections = null
|
||||||
|
{partial_sync}
|
||||||
|
|
||||||
|
[storage foo]
|
||||||
|
type = filesystem
|
||||||
|
fileext = .txt
|
||||||
|
path = {base}/foo
|
||||||
|
|
||||||
|
[storage bar]
|
||||||
|
type = filesystem
|
||||||
|
read_only = true
|
||||||
|
fileext = .txt
|
||||||
|
path = {base}/bar
|
||||||
|
'''.format(
|
||||||
|
partial_sync=('partial_sync = {}\n'.format(partial_sync)
|
||||||
|
if partial_sync else ''),
|
||||||
|
base=str(tmpdir)
|
||||||
|
)))
|
||||||
|
|
||||||
|
foo = tmpdir.mkdir('foo')
|
||||||
|
bar = tmpdir.mkdir('bar')
|
||||||
|
|
||||||
|
foo.join('other.txt').write('UID:other')
|
||||||
|
bar.join('other.txt').write('UID:other')
|
||||||
|
|
||||||
|
baritem = bar.join('lol.txt')
|
||||||
|
baritem.write('UID:lol')
|
||||||
|
|
||||||
|
r = runner.invoke(['discover'])
|
||||||
|
assert not r.exception
|
||||||
|
|
||||||
|
r = runner.invoke(['sync'])
|
||||||
|
assert not r.exception
|
||||||
|
|
||||||
|
fooitem = foo.join('lol.txt')
|
||||||
|
fooitem.remove()
|
||||||
|
|
||||||
|
r = runner.invoke(['sync'])
|
||||||
|
|
||||||
|
if partial_sync == 'error':
|
||||||
|
assert r.exception
|
||||||
|
assert 'Attempted change' in r.output
|
||||||
|
elif partial_sync == 'ignore':
|
||||||
|
assert baritem.exists()
|
||||||
|
r = runner.invoke(['sync'])
|
||||||
|
assert not r.exception
|
||||||
|
assert baritem.exists()
|
||||||
|
else:
|
||||||
|
assert baritem.exists()
|
||||||
|
r = runner.invoke(['sync'])
|
||||||
|
assert not r.exception
|
||||||
|
assert baritem.exists()
|
||||||
|
assert fooitem.exists()
|
||||||
|
|
|
||||||
|
|
@ -254,6 +254,7 @@ class PairConfig(object):
|
||||||
self.options = options
|
self.options = options
|
||||||
|
|
||||||
self._set_conflict_resolution()
|
self._set_conflict_resolution()
|
||||||
|
self._set_partial_sync()
|
||||||
self._set_collections()
|
self._set_collections()
|
||||||
|
|
||||||
def _set_conflict_resolution(self):
|
def _set_conflict_resolution(self):
|
||||||
|
|
@ -278,6 +279,11 @@ class PairConfig(object):
|
||||||
else:
|
else:
|
||||||
raise ValueError('Invalid value for `conflict_resolution`.')
|
raise ValueError('Invalid value for `conflict_resolution`.')
|
||||||
|
|
||||||
|
def _set_partial_sync(self):
|
||||||
|
self.partial_sync = self.options.pop('partial_sync', 'revert')
|
||||||
|
if self.partial_sync not in ('ignore', 'revert', 'error'):
|
||||||
|
raise ValueError('Invalid value for `partial_sync`.')
|
||||||
|
|
||||||
def _set_collections(self):
|
def _set_collections(self):
|
||||||
try:
|
try:
|
||||||
collections = self.options['collections']
|
collections = self.options['collections']
|
||||||
|
|
|
||||||
|
|
@ -68,8 +68,8 @@ def sync_collection(wq, collection, general, force_delete):
|
||||||
a, b, status,
|
a, b, status,
|
||||||
conflict_resolution=pair.conflict_resolution,
|
conflict_resolution=pair.conflict_resolution,
|
||||||
force_delete=force_delete,
|
force_delete=force_delete,
|
||||||
error_callback=error_callback
|
error_callback=error_callback,
|
||||||
|
partial_sync=pair.partial_sync
|
||||||
)
|
)
|
||||||
|
|
||||||
save_status(general['status_path'], pair.name, collection.name,
|
save_status(general['status_path'], pair.name, collection.name,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue