diff mercurial/commands.py @ 45827:8d72e29ad1e0

errors: introduce InputError and use it from commands and cmdutil This patch introduces a `InputError` class and replaces many uses of `error.Abort` by it in `commands` and `cmdutil`. This is a part of https://www.mercurial-scm.org/wiki/ErrorCategoriesPlan. There will later be a different class for state errors (to raise e.g. when there's an unfinished operation). It's not always clear when one should report an input error and when it should be a state error. We can always adjust later if I got something wrong in this patch (but feel free to point out any you notice now). Differential Revision: https://phab.mercurial-scm.org/D9167
author Martin von Zweigbergk <martinvonz@google.com>
date Tue, 06 Oct 2020 22:36:15 -0700
parents d6279c43fc60
children 527ce85c2e60
line wrap: on
line diff
--- a/mercurial/commands.py	Wed Oct 21 19:00:16 2020 -0700
+++ b/mercurial/commands.py	Tue Oct 06 22:36:15 2020 -0700
@@ -189,7 +189,7 @@
     if not abortstate:
         raise error.Abort(_(b'no operation in progress'))
     if not abortstate.abortfunc:
-        raise error.Abort(
+        raise error.InputError(
             (
                 _(b"%s in progress but does not support 'hg abort'")
                 % (abortstate._opname)
@@ -418,7 +418,9 @@
     """
     opts = pycompat.byteskwargs(opts)
     if not pats:
-        raise error.Abort(_(b'at least one filename or pattern is required'))
+        raise error.InputError(
+            _(b'at least one filename or pattern is required')
+        )
 
     if opts.get(b'follow'):
         # --follow is deprecated and now just an alias for -f/--file
@@ -439,7 +441,7 @@
         and (not opts.get(b'changeset'))
         and (not opts.get(b'number'))
     ):
-        raise error.Abort(_(b'at least one of -n/-c is required for -l'))
+        raise error.InputError(_(b'at least one of -n/-c is required for -l'))
 
     rev = opts.get(b'rev')
     if rev:
@@ -650,18 +652,20 @@
         repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
     ctx = scmutil.revsingle(repo, rev)
     if not ctx:
-        raise error.Abort(_(b'no working directory: please specify a revision'))
+        raise error.InputError(
+            _(b'no working directory: please specify a revision')
+        )
     node = ctx.node()
     dest = cmdutil.makefilename(ctx, dest)
     if os.path.realpath(dest) == repo.root:
-        raise error.Abort(_(b'repository root cannot be destination'))
+        raise error.InputError(_(b'repository root cannot be destination'))
 
     kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
     prefix = opts.get(b'prefix')
 
     if dest == b'-':
         if kind == b'files':
-            raise error.Abort(_(b'cannot archive plain files to stdout'))
+            raise error.InputError(_(b'cannot archive plain files to stdout'))
         dest = cmdutil.makefileobj(ctx, dest)
         if not prefix:
             prefix = os.path.basename(repo.root) + b'-%h'
@@ -774,13 +778,13 @@
     opts = pycompat.byteskwargs(opts)
 
     if rev and node:
-        raise error.Abort(_(b"please specify just one revision"))
+        raise error.InputError(_(b"please specify just one revision"))
 
     if not rev:
         rev = node
 
     if not rev:
-        raise error.Abort(_(b"please specify a revision to backout"))
+        raise error.InputError(_(b"please specify a revision to backout"))
 
     date = opts.get(b'date')
     if date:
@@ -793,23 +797,27 @@
 
     op1, op2 = repo.dirstate.parents()
     if not repo.changelog.isancestor(node, op1):
-        raise error.Abort(_(b'cannot backout change that is not an ancestor'))
+        raise error.InputError(
+            _(b'cannot backout change that is not an ancestor')
+        )
 
     p1, p2 = repo.changelog.parents(node)
     if p1 == nullid:
-        raise error.Abort(_(b'cannot backout a change with no parents'))
+        raise error.InputError(_(b'cannot backout a change with no parents'))
     if p2 != nullid:
         if not opts.get(b'parent'):
-            raise error.Abort(_(b'cannot backout a merge changeset'))
+            raise error.InputError(_(b'cannot backout a merge changeset'))
         p = repo.lookup(opts[b'parent'])
         if p not in (p1, p2):
-            raise error.Abort(
+            raise error.InputError(
                 _(b'%s is not a parent of %s') % (short(p), short(node))
             )
         parent = p
     else:
         if opts.get(b'parent'):
-            raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
+            raise error.InputError(
+                _(b'cannot use --parent on non-merge changeset')
+            )
         parent = p1
 
     # the backout should appear on the same branch
@@ -1001,7 +1009,7 @@
         else:
             reset = True
     elif extra:
-        raise error.Abort(_(b'incompatible arguments'))
+        raise error.InputError(_(b'incompatible arguments'))
 
     incompatibles = {
         b'--bad': bad,
@@ -1015,7 +1023,7 @@
     enabled = [x for x in incompatibles if incompatibles[x]]
 
     if len(enabled) > 1:
-        raise error.Abort(
+        raise error.InputError(
             _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
         )
 
@@ -1236,7 +1244,7 @@
         opts, b'inactive', [b'delete', b'list']
     )
     if not names and action in {b'add', b'delete'}:
-        raise error.Abort(_(b"bookmark name required"))
+        raise error.InputError(_(b"bookmark name required"))
 
     if action in {b'add', b'delete', b'rename', b'inactive'}:
         with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
@@ -1245,9 +1253,11 @@
                 bookmarks.delete(repo, tr, names)
             elif action == b'rename':
                 if not names:
-                    raise error.Abort(_(b"new bookmark name required"))
+                    raise error.InputError(_(b"new bookmark name required"))
                 elif len(names) > 1:
-                    raise error.Abort(_(b"only one new bookmark name allowed"))
+                    raise error.InputError(
+                        _(b"only one new bookmark name allowed")
+                    )
                 oldname = repo._bookmarks.expandname(opts[b'rename'])
                 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
             elif action == b'add':
@@ -1323,7 +1333,9 @@
 
     if not opts.get(b'clean') and not label:
         if revs:
-            raise error.Abort(_(b"no branch name specified for the revisions"))
+            raise error.InputError(
+                _(b"no branch name specified for the revisions")
+            )
         ui.write(b"%s\n" % repo.dirstate.branch())
         return
 
@@ -1340,7 +1352,7 @@
 
             if not opts.get(b'force') and label in repo.branchmap():
                 if label not in [p.branch() for p in repo[None].parents()]:
-                    raise error.Abort(
+                    raise error.InputError(
                         _(b'a branch of the same name already exists'),
                         # i18n: "it" refers to an existing branch
                         hint=_(b"use 'hg update' to switch to it"),
@@ -1542,7 +1554,7 @@
         revstrings = opts[b'rev']
         revs = scmutil.revrange(repo, revstrings)
         if revstrings and not revs:
-            raise error.Abort(_(b'no commits to bundle'))
+            raise error.InputError(_(b'no commits to bundle'))
 
     bundletype = opts.get(b'type', b'bzip2').lower()
     try:
@@ -1550,7 +1562,7 @@
             repo, bundletype, strict=False
         )
     except error.UnsupportedBundleSpecification as e:
-        raise error.Abort(
+        raise error.InputError(
             pycompat.bytestr(e),
             hint=_(b"see 'hg help bundlespec' for supported values for --type"),
         )
@@ -1558,14 +1570,14 @@
 
     # Packed bundles are a pseudo bundle format for now.
     if cgversion == b's1':
-        raise error.Abort(
+        raise error.InputError(
             _(b'packed bundles cannot be produced by "hg bundle"'),
             hint=_(b"use 'hg debugcreatestreamclonebundle'"),
         )
 
     if opts.get(b'all'):
         if dest:
-            raise error.Abort(
+            raise error.InputError(
                 _(b"--all is incompatible with specifying a destination")
             )
         if opts.get(b'base'):
@@ -1580,7 +1592,7 @@
 
     if base:
         if dest:
-            raise error.Abort(
+            raise error.InputError(
                 _(b"--base is incompatible with specifying a destination")
             )
         common = [repo[rev].node() for rev in base]
@@ -2034,11 +2046,13 @@
         extra[b'close'] = b'1'
 
         if repo[b'.'].closesbranch():
-            raise error.Abort(
+            raise error.InputError(
                 _(b'current revision is already a branch closing head')
             )
         elif not bheads:
-            raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
+            raise error.InputError(
+                _(b'branch "%s" has no heads to close') % branch
+            )
         elif (
             branch == repo[b'.'].branch()
             and repo[b'.'].node() not in bheads
@@ -2048,17 +2062,19 @@
                 b'use --force-close-branch to close branch from a non-head'
                 b' changeset'
             )
-            raise error.Abort(_(b'can only close branch heads'), hint=hint)
+            raise error.InputError(_(b'can only close branch heads'), hint=hint)
         elif opts.get(b'amend'):
             if (
                 repo[b'.'].p1().branch() != branch
                 and repo[b'.'].p2().branch() != branch
             ):
-                raise error.Abort(_(b'can only close branch heads'))
+                raise error.InputError(_(b'can only close branch heads'))
 
     if opts.get(b'amend'):
         if ui.configbool(b'ui', b'commitsubrepos'):
-            raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
+            raise error.InputError(
+                _(b'cannot amend with ui.commitsubrepos enabled')
+            )
 
         old = repo[b'.']
         rewriteutil.precheck(repo, [old.rev()], b'amend')
@@ -2200,17 +2216,19 @@
         cmdutil.check_at_most_one_arg(opts, *editopts[1:])
         if opts.get(b'local'):
             if not repo:
-                raise error.Abort(_(b"can't use --local outside a repository"))
+                raise error.InputError(
+                    _(b"can't use --local outside a repository")
+                )
             paths = [repo.vfs.join(b'hgrc')]
         elif opts.get(b'global'):
             paths = rcutil.systemrcpath()
         elif opts.get(b'shared'):
             if not repo.shared():
-                raise error.Abort(
+                raise error.InputError(
                     _(b"repository is not shared; can't use --shared")
                 )
                 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
-                    raise error.Abort(
+                    raise error.InputError(
                         _(
                             b"share safe feature not unabled; "
                             b"unable to edit shared source repository config"
@@ -2241,7 +2259,7 @@
         editor = ui.geteditor()
         ui.system(
             b"%s \"%s\"" % (editor, f),
-            onerr=error.Abort,
+            onerr=error.InputError,
             errprefix=_(b"edit failed"),
             blockedtag=b'config_edit',
         )
@@ -2649,7 +2667,7 @@
 
     if bookmark:
         if bookmark not in repo._bookmarks:
-            raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
+            raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
 
         revs = scmutil.bookmarkrevs(repo, bookmark)
     else:
@@ -2660,7 +2678,7 @@
         revs = scmutil.revrange(repo, changesets)
 
     if not revs:
-        raise error.Abort(_(b"export requires at least one changeset"))
+        raise error.InputError(_(b"export requires at least one changeset"))
     if len(revs) > 1:
         ui.note(_(b'exporting patches:\n'))
     else:
@@ -2825,7 +2843,7 @@
 
     opts = pycompat.byteskwargs(opts)
     if not pats:
-        raise error.Abort(_(b'no files specified'))
+        raise error.InputError(_(b'no files specified'))
 
     m = scmutil.match(repo[None], pats, opts)
     dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
@@ -3052,7 +3070,7 @@
     elif opts.get(b'continue'):
         cont = True
         if revs:
-            raise error.Abort(_(b"can't specify --continue and revisions"))
+            raise error.InputError(_(b"can't specify --continue and revisions"))
         # read in unfinished revisions
         if graftstate.exists():
             statedata = cmdutil.readgraftstate(repo, graftstate)
@@ -3072,7 +3090,7 @@
             cmdutil.wrongtooltocontinue(repo, _(b'graft'))
     else:
         if not revs:
-            raise error.Abort(_(b'no revisions specified'))
+            raise error.InputError(_(b'no revisions specified'))
         cmdutil.checkunfinished(repo)
         cmdutil.bailifchanged(repo)
         revs = scmutil.revrange(repo, revs)
@@ -3090,7 +3108,7 @@
     if not revs:
         return -1
     if basectx is not None and len(revs) != 1:
-        raise error.Abort(_(b'only one revision allowed with --base '))
+        raise error.InputError(_(b'only one revision allowed with --base '))
 
     # Don't check in the --continue case, in effect retaining --force across
     # --continues. That's because without --force, any revisions we decided to
@@ -3765,7 +3783,7 @@
 
     opts = pycompat.byteskwargs(opts)
     if not repo and not source:
-        raise error.Abort(
+        raise error.InputError(
             _(b"there is no Mercurial repository here (.hg not found)")
         )
 
@@ -3784,7 +3802,7 @@
 
     if not repo:
         if num or branch or tags:
-            raise error.Abort(
+            raise error.InputError(
                 _(b"can't query remote revision number, branch, or tags")
             )
         if not rev and revs:
@@ -4056,7 +4074,7 @@
     cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
     opts = pycompat.byteskwargs(opts)
     if not patch1:
-        raise error.Abort(_(b'need at least one patch to import'))
+        raise error.InputError(_(b'need at least one patch to import'))
 
     patches = (patch1,) + patches
 
@@ -4069,11 +4087,11 @@
     try:
         sim = float(opts.get(b'similarity') or 0)
     except ValueError:
-        raise error.Abort(_(b'similarity must be a number'))
+        raise error.InputError(_(b'similarity must be a number'))
     if sim < 0 or sim > 100:
-        raise error.Abort(_(b'similarity must be between 0 and 100'))
+        raise error.InputError(_(b'similarity must be between 0 and 100'))
     if sim and not update:
-        raise error.Abort(_(b'cannot use --similarity with --bypass'))
+        raise error.InputError(_(b'cannot use --similarity with --bypass'))
 
     base = opts[b"base"]
     msgs = []
@@ -4130,7 +4148,7 @@
                         break
 
                 if not haspatch:
-                    raise error.Abort(_(b'%s: no diffs found') % patchurl)
+                    raise error.InputError(_(b'%s: no diffs found') % patchurl)
 
             if msgs:
                 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
@@ -4586,11 +4604,11 @@
     linerange = opts.get(b'line_range')
 
     if linerange and not opts.get(b'follow'):
-        raise error.Abort(_(b'--line-range requires --follow'))
+        raise error.InputError(_(b'--line-range requires --follow'))
 
     if linerange and pats:
         # TODO: take pats as patterns with no line-range filter
-        raise error.Abort(
+        raise error.InputError(
             _(b'FILE arguments are not compatible with --line-range option')
         )
 
@@ -4652,7 +4670,7 @@
 
     if opts.get(b'all'):
         if rev or node:
-            raise error.Abort(_(b"can't specify a revision with --all"))
+            raise error.InputError(_(b"can't specify a revision with --all"))
 
         res = set()
         for rev in repo:
@@ -4667,7 +4685,7 @@
         return
 
     if rev and node:
-        raise error.Abort(_(b"please specify just one revision"))
+        raise error.InputError(_(b"please specify just one revision"))
 
     if not node:
         node = rev
@@ -4754,11 +4772,11 @@
                 hint=state.hint(),
             )
         if node:
-            raise error.Abort(_(b"cannot specify a node with --abort"))
+            raise error.InputError(_(b"cannot specify a node with --abort"))
         return hg.abortmerge(repo.ui, repo)
 
     if opts.get(b'rev') and node:
-        raise error.Abort(_(b"please specify just one revision"))
+        raise error.InputError(_(b"please specify just one revision"))
     if not node:
         node = opts.get(b'rev')
 
@@ -4766,7 +4784,7 @@
         ctx = scmutil.revsingle(repo, node)
     else:
         if ui.configbool(b'commands', b'merge.require-rev'):
-            raise error.Abort(
+            raise error.InputError(
                 _(
                     b'configuration requires specifying revision to merge '
                     b'with'
@@ -4775,7 +4793,9 @@
         ctx = repo[destutil.destmerge(repo)]
 
     if ctx.node() is None:
-        raise error.Abort(_(b'merging with the working copy has no effect'))
+        raise error.InputError(
+            _(b'merging with the working copy has no effect')
+        )
 
     if opts.get(b'preview'):
         # find nodes that are ancestors of p2 but not of p1
@@ -4968,7 +4988,7 @@
     if file_:
         m = scmutil.match(ctx, (file_,), opts)
         if m.anypats() or len(m.files()) != 1:
-            raise error.Abort(_(b'can only specify an explicit filename'))
+            raise error.InputError(_(b'can only specify an explicit filename'))
         file_ = m.files()[0]
         filenodes = []
         for cp in ctx.parents():
@@ -4979,7 +4999,7 @@
             except error.LookupError:
                 pass
         if not filenodes:
-            raise error.Abort(_(b"'%s' not found in manifest!") % file_)
+            raise error.InputError(_(b"'%s' not found in manifest!") % file_)
         p = []
         for fn in filenodes:
             fctx = repo.filectx(file_, fileid=fn)
@@ -5121,7 +5141,7 @@
     for idx, name in enumerate(phases.cmdphasenames):
         if opts[name]:
             if targetphase is not None:
-                raise error.Abort(_(b'only one phase can be specified'))
+                raise error.InputError(_(b'only one phase can be specified'))
             targetphase = idx
 
     # look for specified revision
@@ -5144,7 +5164,7 @@
         with repo.lock(), repo.transaction(b"phase") as tr:
             # set phase
             if not revs:
-                raise error.Abort(_(b'empty revision set'))
+                raise error.InputError(_(b'empty revision set'))
             nodes = [repo[r].node() for r in revs]
             # moving revision from public to draft may hide them
             # We have to check result on an unfiltered repository
@@ -5287,7 +5307,7 @@
     ):
         msg = _(b'update destination required by configuration')
         hint = _(b'use hg pull followed by hg update DEST')
-        raise error.Abort(msg, hint=hint)
+        raise error.InputError(msg, hint=hint)
 
     source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
     ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
@@ -5326,7 +5346,9 @@
             for b in opts.get(b'bookmark', []):
                 b = repo._bookmarks.expandname(b)
                 if b not in remotebookmarks:
-                    raise error.Abort(_(b'remote bookmark %s not found!') % b)
+                    raise error.InputError(
+                        _(b'remote bookmark %s not found!') % b
+                    )
                 nodes.append(remotebookmarks[b])
             for i, rev in enumerate(revs):
                 node = fnodes[i].result()
@@ -5515,7 +5537,7 @@
     if revs:
         revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
         if not revs:
-            raise error.Abort(
+            raise error.InputError(
                 _(b"specified revisions evaluate to an empty set"),
                 hint=_(b"use different revision arguments"),
             )
@@ -5526,11 +5548,11 @@
         revs = scmutil.revrange(repo, [expr])
         revs = [repo[rev].node() for rev in revs]
         if not revs:
-            raise error.Abort(
+            raise error.InputError(
                 _(b'default push revset for path evaluates to an empty set')
             )
     elif ui.configbool(b'commands', b'push.require-revs'):
-        raise error.Abort(
+        raise error.InputError(
             _(b'no revisions specified to push'),
             hint=_(b'did you mean "hg push -r ."?'),
         )
@@ -5659,7 +5681,7 @@
     after, force = opts.get(b'after'), opts.get(b'force')
     dryrun = opts.get(b'dry_run')
     if not pats and not after:
-        raise error.Abort(_(b'no files specified'))
+        raise error.InputError(_(b'no files specified'))
 
     m = scmutil.match(repo[None], pats, opts)
     subrepos = opts.get(b'subrepos')
@@ -5789,16 +5811,16 @@
 
     actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
     if actioncount > 1:
-        raise error.Abort(_(b"too many actions specified"))
+        raise error.InputError(_(b"too many actions specified"))
     elif actioncount == 0 and ui.configbool(
         b'commands', b'resolve.explicit-re-merge'
     ):
         hint = _(b'use --mark, --unmark, --list or --re-merge')
-        raise error.Abort(_(b'no action specified'), hint=hint)
+        raise error.InputError(_(b'no action specified'), hint=hint)
     if pats and all:
-        raise error.Abort(_(b"can't specify --all and patterns"))
+        raise error.InputError(_(b"can't specify --all and patterns"))
     if not (all or pats or show or mark or unmark):
-        raise error.Abort(
+        raise error.InputError(
             _(b'no files or directories specified'),
             hint=b'use --all to re-merge all unresolved files',
         )
@@ -6082,7 +6104,7 @@
     parent, p2 = repo.dirstate.parents()
     if not opts.get(b'rev') and p2 != nullid:
         # revert after merge is a trap for new users (issue2915)
-        raise error.Abort(
+        raise error.InputError(
             _(b'uncommitted merge with no revision specified'),
             hint=_(b"use 'hg update' or see 'hg help revert'"),
         )
@@ -6105,7 +6127,7 @@
                 b"uncommitted merge, use --all to discard all changes,"
                 b" or 'hg update -C .' to abort the merge"
             )
-            raise error.Abort(msg, hint=hint)
+            raise error.InputError(msg, hint=hint)
         dirty = any(repo.status())
         node = ctx.node()
         if node != parent:
@@ -6129,7 +6151,7 @@
             hint = _(b"uncommitted changes, use --all to discard all changes")
         else:
             hint = _(b"use --all to revert all files")
-        raise error.Abort(msg, hint=hint)
+        raise error.InputError(msg, hint=hint)
 
     return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
 
@@ -6339,7 +6361,7 @@
     cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
     opts = pycompat.byteskwargs(opts)
     if opts[b"print_url"] and ui.verbose:
-        raise error.Abort(_(b"cannot use --print-url with --verbose"))
+        raise error.InputError(_(b"cannot use --print-url with --verbose"))
 
     if opts[b"stdio"]:
         if repo is None:
@@ -6466,7 +6488,7 @@
         if opts.get(opt):
             for i, allowable in allowables:
                 if opts[i] and opt not in allowable:
-                    raise error.Abort(
+                    raise error.InputError(
                         _(
                             b"options '--%s' and '--%s' may not be "
                             b"used together"
@@ -6477,7 +6499,9 @@
 
     if checkopt(b'cleanup'):
         if pats:
-            raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
+            raise error.InputError(
+                _(b"cannot specify names when using '--cleanup'")
+            )
         return shelvemod.cleanupcmd(ui, repo)
     elif checkopt(b'delete'):
         return shelvemod.deletecmd(ui, repo, pats)
@@ -6643,7 +6667,7 @@
 
     if revs and terse:
         msg = _(b'cannot use --terse with --rev')
-        raise error.Abort(msg)
+        raise error.InputError(msg)
     elif change:
         repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
         ctx2 = scmutil.revsingle(repo, change, None)
@@ -7114,11 +7138,11 @@
         rev_ = b"."
         names = [t.strip() for t in (name1,) + names]
         if len(names) != len(set(names)):
-            raise error.Abort(_(b'tag names must be unique'))
+            raise error.InputError(_(b'tag names must be unique'))
         for n in names:
             scmutil.checknewlabel(repo, n, b'tag')
             if not n:
-                raise error.Abort(
+                raise error.InputError(
                     _(b'tag names cannot consist entirely of whitespace')
                 )
         if opts.get(b'rev'):
@@ -7134,16 +7158,20 @@
                 if repo.tagtype(n) == b'global':
                     alltags = tagsmod.findglobaltags(ui, repo)
                     if alltags[n][0] == nullid:
-                        raise error.Abort(_(b"tag '%s' is already removed") % n)
+                        raise error.InputError(
+                            _(b"tag '%s' is already removed") % n
+                        )
                 if not repo.tagtype(n):
-                    raise error.Abort(_(b"tag '%s' does not exist") % n)
+                    raise error.InputError(_(b"tag '%s' does not exist") % n)
                 if repo.tagtype(n) != expectedtype:
                     if expectedtype == b'global':
-                        raise error.Abort(
+                        raise error.InputError(
                             _(b"tag '%s' is not a global tag") % n
                         )
                     else:
-                        raise error.Abort(_(b"tag '%s' is not a local tag") % n)
+                        raise error.InputError(
+                            _(b"tag '%s' is not a local tag") % n
+                        )
             rev_ = b'null'
             if not message:
                 # we don't translate commit messages
@@ -7151,7 +7179,7 @@
         elif not opts.get(b'force'):
             for n in names:
                 if n in repo.tags():
-                    raise error.Abort(
+                    raise error.InputError(
                         _(b"tag '%s' already exists (use -f to force)") % n
                     )
         if not opts.get(b'local'):
@@ -7160,7 +7188,7 @@
                 raise error.Abort(_(b'uncommitted merge'))
             bheads = repo.branchheads()
             if not opts.get(b'force') and bheads and p1 not in bheads:
-                raise error.Abort(
+                raise error.InputError(
                     _(
                         b'working directory is not at a branch head '
                         b'(use -f to force)'
@@ -7192,7 +7220,7 @@
             not opts.get(b'remove')
             and scmutil.revsingle(repo, rev_).rev() == nullrev
         ):
-            raise error.Abort(_(b"cannot tag null revision"))
+            raise error.InputError(_(b"cannot tag null revision"))
 
         tagsmod.tag(
             repo,
@@ -7324,7 +7352,7 @@
             f = hg.openpath(ui, fname)
             gen = exchange.readbundle(ui, f, fname)
             if isinstance(gen, streamclone.streamcloneapplier):
-                raise error.Abort(
+                raise error.InputError(
                     _(
                         b'packed bundles cannot be applied with '
                         b'"hg unbundle"'
@@ -7519,11 +7547,11 @@
     check = opts.get('check')
     merge = opts.get('merge')
     if rev and node:
-        raise error.Abort(_(b"please specify just one revision"))
+        raise error.InputError(_(b"please specify just one revision"))
 
     if ui.configbool(b'commands', b'update.requiredest'):
         if not node and not rev and not date:
-            raise error.Abort(
+            raise error.InputError(
                 _(b'you must specify a destination'),
                 hint=_(b'for example: hg update ".::"'),
             )
@@ -7532,7 +7560,7 @@
         rev = node
 
     if date and rev is not None:
-        raise error.Abort(_(b"you can't specify a revision and a date"))
+        raise error.InputError(_(b"you can't specify a revision and a date"))
 
     updatecheck = None
     if check: