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:
Markus Unterwaditzer 2014-10-08 22:03:04 +02:00
parent 8bb25e3fb2
commit 2d62c8716b
2 changed files with 68 additions and 1 deletions

View file

@ -228,3 +228,62 @@ def test_verbosity(tmpdir):
)
assert result.exception
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

View file

@ -300,9 +300,11 @@ def _create_app():
@click.option('--force-delete', multiple=True,
help=('Disable data-loss protection for the given pairs. '
'Can be passed multiple times'))
@click.option('--fail-fast', is_flag=True,
help='Exit immediately on first error.')
@click.pass_context
@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
synchronized.
@ -359,6 +361,12 @@ def _create_app():
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):
sys.exit(1)