Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/cmdutil.py @ 48411:6a454e7053a1
errors: return more detailed errors when failing to parse or apply patch
This patch adds subclasses of `PatchError` so we can distinguish
between failure to parse a patch from failure to apply it. It updates
the callers to raise either `InputError` or `StateError` depending on
which type of error occurred.
Differential Revision: https://phab.mercurial-scm.org/D11824
author | Martin von Zweigbergk <martinvonz@google.com> |
---|---|
date | Fri, 19 Nov 2021 12:57:53 -0800 |
parents | c62e4397eb28 |
children | 220506bb213e |
comparison
equal
deleted
inserted
replaced
48410:7e6488aa1261 | 48411:6a454e7053a1 |
---|---|
520 match = scmutil.match(repo[None], pats) | 520 match = scmutil.match(repo[None], pats) |
521 | 521 |
522 # 1. filter patch, since we are intending to apply subset of it | 522 # 1. filter patch, since we are intending to apply subset of it |
523 try: | 523 try: |
524 chunks, newopts = filterfn(ui, original_headers, match) | 524 chunks, newopts = filterfn(ui, original_headers, match) |
525 except error.PatchError as err: | 525 except error.PatchParseError as err: |
526 raise error.InputError(_(b'error parsing patch: %s') % err) | 526 raise error.InputError(_(b'error parsing patch: %s') % err) |
527 except error.PatchApplicationError as err: | |
528 raise error.StateError(_(b'error applying patch: %s') % err) | |
527 opts.update(newopts) | 529 opts.update(newopts) |
528 | 530 |
529 # We need to keep a backup of files that have been newly added and | 531 # We need to keep a backup of files that have been newly added and |
530 # modified during the recording process because there is a previous | 532 # modified during the recording process because there is a previous |
531 # version without the edit in the workdir. We also will need to restore | 533 # version without the edit in the workdir. We also will need to restore |
606 if dopatch: | 608 if dopatch: |
607 try: | 609 try: |
608 ui.debug(b'applying patch\n') | 610 ui.debug(b'applying patch\n') |
609 ui.debug(fp.getvalue()) | 611 ui.debug(fp.getvalue()) |
610 patch.internalpatch(ui, repo, fp, 1, eolmode=None) | 612 patch.internalpatch(ui, repo, fp, 1, eolmode=None) |
611 except error.PatchError as err: | 613 except error.PatchParseError as err: |
612 raise error.InputError(pycompat.bytestr(err)) | 614 raise error.InputError(pycompat.bytestr(err)) |
615 except error.PatchApplicationError as err: | |
616 raise error.StateError(pycompat.bytestr(err)) | |
613 del fp | 617 del fp |
614 | 618 |
615 # 4. We prepared working directory according to filtered | 619 # 4. We prepared working directory according to filtered |
616 # patch. Now is the time to delegate the job to | 620 # patch. Now is the time to delegate the job to |
617 # commit/qrefresh or the like! | 621 # commit/qrefresh or the like! |
2018 prefix=prefix, | 2022 prefix=prefix, |
2019 files=files, | 2023 files=files, |
2020 eolmode=None, | 2024 eolmode=None, |
2021 similarity=sim / 100.0, | 2025 similarity=sim / 100.0, |
2022 ) | 2026 ) |
2023 except error.PatchError as e: | 2027 except error.PatchParseError as e: |
2028 raise error.InputError(pycompat.bytestr(e)) | |
2029 except error.PatchApplicationError as e: | |
2024 if not partial: | 2030 if not partial: |
2025 raise error.Abort(pycompat.bytestr(e)) | 2031 raise error.StateError(pycompat.bytestr(e)) |
2026 if partial: | 2032 if partial: |
2027 rejects = True | 2033 rejects = True |
2028 | 2034 |
2029 files = list(files) | 2035 files = list(files) |
2030 if nocommit: | 2036 if nocommit: |
2077 strip, | 2083 strip, |
2078 prefix, | 2084 prefix, |
2079 files, | 2085 files, |
2080 eolmode=None, | 2086 eolmode=None, |
2081 ) | 2087 ) |
2082 except error.PatchError as e: | 2088 except error.PatchParseError as e: |
2083 raise error.Abort(stringutil.forcebytestr(e)) | 2089 raise error.InputError(stringutil.forcebytestr(e)) |
2090 except error.PatchApplicationError as e: | |
2091 raise error.StateError(stringutil.forcebytestr(e)) | |
2084 if opts.get(b'exact'): | 2092 if opts.get(b'exact'): |
2085 editor = None | 2093 editor = None |
2086 else: | 2094 else: |
2087 editor = getcommiteditor(editform=b'import.bypass') | 2095 editor = getcommiteditor(editform=b'import.bypass') |
2088 memctx = context.memctx( | 2096 memctx = context.memctx( |
3672 repo.ui, original_headers, match, operation=operation | 3680 repo.ui, original_headers, match, operation=operation |
3673 ) | 3681 ) |
3674 if operation == b'discard': | 3682 if operation == b'discard': |
3675 chunks = patch.reversehunks(chunks) | 3683 chunks = patch.reversehunks(chunks) |
3676 | 3684 |
3677 except error.PatchError as err: | 3685 except error.PatchParseError as err: |
3678 raise error.Abort(_(b'error parsing patch: %s') % err) | 3686 raise error.InputError(_(b'error parsing patch: %s') % err) |
3687 except error.PatchApplicationError as err: | |
3688 raise error.StateError(_(b'error applying patch: %s') % err) | |
3679 | 3689 |
3680 # FIXME: when doing an interactive revert of a copy, there's no way of | 3690 # FIXME: when doing an interactive revert of a copy, there's no way of |
3681 # performing a partial revert of the added file, the only option is | 3691 # performing a partial revert of the added file, the only option is |
3682 # "remove added file <name> (Yn)?", so we don't need to worry about the | 3692 # "remove added file <name> (Yn)?", so we don't need to worry about the |
3683 # alsorestore value. Ideally we'd be able to partially revert | 3693 # alsorestore value. Ideally we'd be able to partially revert |
3708 dopatch = fp.tell() | 3718 dopatch = fp.tell() |
3709 fp.seek(0) | 3719 fp.seek(0) |
3710 if dopatch: | 3720 if dopatch: |
3711 try: | 3721 try: |
3712 patch.internalpatch(repo.ui, repo, fp, 1, eolmode=None) | 3722 patch.internalpatch(repo.ui, repo, fp, 1, eolmode=None) |
3713 except error.PatchError as err: | 3723 except error.PatchParseError as err: |
3714 raise error.Abort(pycompat.bytestr(err)) | 3724 raise error.InputError(pycompat.bytestr(err)) |
3725 except error.PatchApplicationError as err: | |
3726 raise error.StateError(pycompat.bytestr(err)) | |
3715 del fp | 3727 del fp |
3716 else: | 3728 else: |
3717 for f in actions[b'revert'][0]: | 3729 for f in actions[b'revert'][0]: |
3718 prntstatusmsg(b'revert', f) | 3730 prntstatusmsg(b'revert', f) |
3719 checkout(f) | 3731 checkout(f) |