mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-04-27 14:57:41 +00:00
Continue syncing pairs if one pair crashes
Fix #121 Vdirsyncer used to exit as a whole when one pair failed to synchronize due to connection errors. The new behavior actually tries to synchronize other pairs before exiting with a nonzero status code. The old behavior can be restored with the --fail-fast flag.
This commit is contained in:
parent
8bb25e3fb2
commit
2d62c8716b
2 changed files with 68 additions and 1 deletions
|
|
@ -228,3 +228,62 @@ def test_verbosity(tmpdir):
|
||||||
)
|
)
|
||||||
assert result.exception
|
assert result.exception
|
||||||
assert 'invalid verbosity value' in result.output.lower()
|
assert 'invalid verbosity value' in result.output.lower()
|
||||||
|
|
||||||
|
|
||||||
|
def test_fail_fast(tmpdir):
|
||||||
|
runner = CliRunner()
|
||||||
|
config_file = tmpdir.join('config')
|
||||||
|
config_file.write(dedent('''
|
||||||
|
[general]
|
||||||
|
status_path = {status}
|
||||||
|
processes = 1
|
||||||
|
|
||||||
|
[storage a1]
|
||||||
|
type = filesystem
|
||||||
|
fileext = .txt
|
||||||
|
path = {a1}
|
||||||
|
|
||||||
|
[storage a2]
|
||||||
|
type = filesystem
|
||||||
|
fileext = .txt
|
||||||
|
path = {a2}
|
||||||
|
create = False
|
||||||
|
|
||||||
|
[storage b1]
|
||||||
|
type = filesystem
|
||||||
|
fileext = .txt
|
||||||
|
path = {b1}
|
||||||
|
|
||||||
|
[storage b2]
|
||||||
|
type = filesystem
|
||||||
|
fileext = .txt
|
||||||
|
path = {b2}
|
||||||
|
|
||||||
|
[pair a]
|
||||||
|
a = a1
|
||||||
|
b = a2
|
||||||
|
|
||||||
|
[pair b]
|
||||||
|
a = b1
|
||||||
|
b = b2
|
||||||
|
''').format(
|
||||||
|
status=str(tmpdir.mkdir('status')),
|
||||||
|
a1=str(tmpdir.mkdir('a1')),
|
||||||
|
a2=str(tmpdir.join('a2')),
|
||||||
|
b1=str(tmpdir.mkdir('b1')),
|
||||||
|
b2=str(tmpdir.mkdir('b2'))
|
||||||
|
))
|
||||||
|
|
||||||
|
result = runner.invoke(cli.app, ['sync', 'a', 'b'],
|
||||||
|
env={'VDIRSYNCER_CONFIG': str(config_file)})
|
||||||
|
lines = result.output.splitlines()
|
||||||
|
assert 'Syncing a' in lines
|
||||||
|
assert 'Syncing b' in lines
|
||||||
|
assert result.exception
|
||||||
|
|
||||||
|
result = runner.invoke(cli.app, ['sync', '--fail-fast', 'a', 'b'],
|
||||||
|
env={'VDIRSYNCER_CONFIG': str(config_file)})
|
||||||
|
lines = result.output.splitlines()
|
||||||
|
assert 'Syncing a' in lines
|
||||||
|
assert 'Syncing b' not in lines
|
||||||
|
assert result.exception
|
||||||
|
|
|
||||||
|
|
@ -300,9 +300,11 @@ def _create_app():
|
||||||
@click.option('--force-delete', multiple=True,
|
@click.option('--force-delete', multiple=True,
|
||||||
help=('Disable data-loss protection for the given pairs. '
|
help=('Disable data-loss protection for the given pairs. '
|
||||||
'Can be passed multiple times'))
|
'Can be passed multiple times'))
|
||||||
|
@click.option('--fail-fast', is_flag=True,
|
||||||
|
help='Exit immediately on first error.')
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
@catch_errors
|
@catch_errors
|
||||||
def sync(ctx, pairs, force_delete):
|
def sync(ctx, pairs, force_delete, fail_fast):
|
||||||
'''
|
'''
|
||||||
Synchronize the given pairs. If no pairs are given, all will be
|
Synchronize the given pairs. If no pairs are given, all will be
|
||||||
synchronized.
|
synchronized.
|
||||||
|
|
@ -359,6 +361,12 @@ def _create_app():
|
||||||
|
|
||||||
rv = p.imap_unordered(_sync_collection, actions)
|
rv = p.imap_unordered(_sync_collection, actions)
|
||||||
|
|
||||||
|
if not fail_fast:
|
||||||
|
# exhaust iterator before calling all(...), which would return
|
||||||
|
# after it encounters a False item.
|
||||||
|
# In other words, all(rv) fails fast.
|
||||||
|
rv = list(rv)
|
||||||
|
|
||||||
if not all(rv):
|
if not all(rv):
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue