comparison mercurial/bundle2.py @ 34152:21c2df59a1da

bundle2: move exception handling into part iterator As part of separating the part iteration logic from the part handling logic, let's move the exception handling to the part iterator class. Differential Revision: https://phab.mercurial-scm.org/D705
author Durham Goode <durham@fb.com>
date Wed, 13 Sep 2017 20:39:01 -0700
parents 550343626bb2
children 8e0358024a36
comparison
equal deleted inserted replaced
34151:550343626bb2 34152:21c2df59a1da
346 op = bundleoperation(repo, lambda: tr) 346 op = bundleoperation(repo, lambda: tr)
347 _processchangegroup(op, unbundler, tr, source, url, **kwargs) 347 _processchangegroup(op, unbundler, tr, source, url, **kwargs)
348 return op 348 return op
349 349
350 class partiterator(object): 350 class partiterator(object):
351 def __init__(self, repo, unbundler): 351 def __init__(self, repo, op, unbundler):
352 self.repo = repo 352 self.repo = repo
353 self.op = op
353 self.unbundler = unbundler 354 self.unbundler = unbundler
354 self.iterator = None 355 self.iterator = None
355 self.count = 0 356 self.count = 0
356 357
357 def __enter__(self): 358 def __enter__(self):
361 self.count = count 362 self.count = count
362 yield p 363 yield p
363 self.iterator = func() 364 self.iterator = func()
364 return self.iterator 365 return self.iterator
365 366
366 def __exit__(self, type, value, tb): 367 def __exit__(self, type, exc, tb):
367 if not self.iterator: 368 if not self.iterator:
368 return 369 return
370
371 if exc:
372 # Any exceptions seeking to the end of the bundle at this point are
373 # almost certainly related to the underlying stream being bad.
374 # And, chances are that the exception we're handling is related to
375 # getting in that bad state. So, we swallow the seeking error and
376 # re-raise the original error.
377 seekerror = False
378 try:
379 for part in self.iterator:
380 # consume the bundle content
381 part.seek(0, 2)
382 except Exception:
383 seekerror = True
384
385 # Small hack to let caller code distinguish exceptions from bundle2
386 # processing from processing the old format. This is mostly needed
387 # to handle different return codes to unbundle according to the type
388 # of bundle. We should probably clean up or drop this return code
389 # craziness in a future version.
390 exc.duringunbundle2 = True
391 salvaged = []
392 replycaps = None
393 if self.op.reply is not None:
394 salvaged = self.op.reply.salvageoutput()
395 replycaps = self.op.reply.capabilities
396 exc._replycaps = replycaps
397 exc._bundle2salvagedoutput = salvaged
398
399 # Re-raising from a variable loses the original stack. So only use
400 # that form if we need to.
401 if seekerror:
402 raise exc
369 403
370 self.repo.ui.debug('bundle2-input-bundle: %i parts total\n' % 404 self.repo.ui.debug('bundle2-input-bundle: %i parts total\n' %
371 self.count) 405 self.count)
372 406
373 def processbundle(repo, unbundler, transactiongetter=None, op=None): 407 def processbundle(repo, unbundler, transactiongetter=None, op=None):
400 else: 434 else:
401 msg.append(' with-transaction') 435 msg.append(' with-transaction')
402 msg.append('\n') 436 msg.append('\n')
403 repo.ui.debug(''.join(msg)) 437 repo.ui.debug(''.join(msg))
404 438
405 with partiterator(repo, unbundler) as parts: 439 with partiterator(repo, op, unbundler) as parts:
406 part = None 440 for part in parts:
407 try: 441 _processpart(op, part)
408 for part in parts:
409 _processpart(op, part)
410 except Exception as exc:
411 # Any exceptions seeking to the end of the bundle at this point are
412 # almost certainly related to the underlying stream being bad.
413 # And, chances are that the exception we're handling is related to
414 # getting in that bad state. So, we swallow the seeking error and
415 # re-raise the original error.
416 seekerror = False
417 try:
418 for part in parts:
419 # consume the bundle content
420 part.seek(0, 2)
421 except Exception:
422 seekerror = True
423
424 # Small hack to let caller code distinguish exceptions from bundle2
425 # processing from processing the old format. This is mostly needed
426 # to handle different return codes to unbundle according to the type
427 # of bundle. We should probably clean up or drop this return code
428 # craziness in a future version.
429 exc.duringunbundle2 = True
430 salvaged = []
431 replycaps = None
432 if op.reply is not None:
433 salvaged = op.reply.salvageoutput()
434 replycaps = op.reply.capabilities
435 exc._replycaps = replycaps
436 exc._bundle2salvagedoutput = salvaged
437
438 # Re-raising from a variable loses the original stack. So only use
439 # that form if we need to.
440 if seekerror:
441 raise exc
442 else:
443 raise
444 442
445 return op 443 return op
446 444
447 def _processchangegroup(op, cg, tr, source, url, **kwargs): 445 def _processchangegroup(op, cg, tr, source, url, **kwargs):
448 ret = cg.apply(op.repo, tr, source, url, **kwargs) 446 ret = cg.apply(op.repo, tr, source, url, **kwargs)