From 2c04b98c60d87ff5442820fc084364748a4a15e8 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 22 Oct 2026 13:15:44 -0400 Subject: [PATCH] style: use `import error` everywhere Align with Google style guides and `import error` as a module rather than import classes out of it. Change-Id: I8686fbe7887bd6ceac7a07877af63934f0d0ddd2 Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/647563 Commit-Queue: Mike Frysinger Reviewed-by: Gavin Mak Reviewed-by: Insaf Latypov Tested-by: Mike Frysinger --- command.py | 12 +-- editor.py | 8 +- fetch.py | 4 +- git_command.py | 9 +- git_config.py | 15 +-- hooks.py | 18 ++-- main.py | 52 ++++----- manifest_xml.py | 114 ++++++++++---------- project.py | 172 +++++++++++++++--------------- repo_logging.py | 4 +- subcmds/abandon.py | 7 +- subcmds/checkout.py | 15 ++- subcmds/cherry_pick.py | 14 +-- subcmds/download.py | 14 ++- subcmds/grep.py | 20 ++-- subcmds/help.py | 4 +- subcmds/init.py | 7 +- subcmds/rebase.py | 4 +- subcmds/selfupdate.py | 4 +- subcmds/start.py | 10 +- subcmds/sync.py | 63 +++++------ subcmds/upload.py | 8 +- subcmds/wipe.py | 7 +- tests/test_project.py | 2 +- tests/test_repo_logging.py | 6 +- tests/test_subcmds_cherry_pick.py | 6 +- tests/test_subcmds_rebase.py | 4 +- tests/test_subcmds_sync.py | 48 ++++----- tests/test_subcmds_upload.py | 11 +- 29 files changed, 321 insertions(+), 341 deletions(-) diff --git a/command.py b/command.py index 7f60834ad..5124d7458 100644 --- a/command.py +++ b/command.py @@ -19,9 +19,7 @@ import os import re from typing import List, Optional, TYPE_CHECKING -from error import InvalidProjectGroupsError -from error import NoSuchProjectError -from error import RepoExitError +import error from event_log import EventLog import progress @@ -48,7 +46,7 @@ WORKER_BATCH_SIZE = 32 DEFAULT_LOCAL_JOBS = min(os.cpu_count(), 8) -class UsageError(RepoExitError): +class UsageError(error.RepoExitError): """Exception thrown with invalid command usage.""" @@ -526,16 +524,16 @@ class Command: projects = [project] if not projects: - raise NoSuchProjectError(arg) + raise error.NoSuchProjectError(arg) for project in projects: if not missing_ok and not project.Exists: - raise NoSuchProjectError( + raise error.NoSuchProjectError( "%s (%s)" % (arg, project.RelPath(local=not all_manifests)) ) if not matches_groups(project): - raise InvalidProjectGroupsError(arg) + raise error.InvalidProjectGroupsError(arg) result.extend(projects) diff --git a/editor.py b/editor.py index 359cff938..5b8f08a7b 100644 --- a/editor.py +++ b/editor.py @@ -18,7 +18,7 @@ import subprocess import sys import tempfile -from error import EditorError +import error import platform_utils @@ -104,9 +104,11 @@ least one of these before using this command.""", # noqa: E501 try: rc = subprocess.Popen(args, shell=shell).wait() except OSError as e: - raise EditorError(f"editor failed, {str(e)}: {editor} {path}") + raise error.EditorError( + f"editor failed, {str(e)}: {editor} {path}" + ) if rc != 0: - raise EditorError( + raise error.EditorError( "editor failed with exit status %d: %s %s" % (rc, editor, path) ) diff --git a/fetch.py b/fetch.py index 509a0fcbd..7e9a528b4 100644 --- a/fetch.py +++ b/fetch.py @@ -19,10 +19,10 @@ import sys from urllib.parse import urlparse from urllib.request import urlopen -from error import RepoExitError +import error -class FetchFileError(RepoExitError): +class FetchFileError(error.RepoExitError): """Exit error when fetch_file fails.""" diff --git a/git_command.py b/git_command.py index abaf6a565..9558a9aeb 100644 --- a/git_command.py +++ b/git_command.py @@ -20,8 +20,7 @@ import subprocess import sys from typing import Any, Optional -from error import GitError -from error import RepoExitError +import error from git_trace2_event_log_base import BaseEventLog import platform_utils from repo_logging import RepoLogger @@ -604,14 +603,14 @@ class GitCommand: return self.rc -class GitRequireError(RepoExitError): +class GitRequireError(error.RepoExitError): """Error raised when git version is unavailable or invalid.""" def __init__(self, message, exit_code: int = INVALID_GIT_EXIT_CODE): super().__init__(message, exit_code=exit_code) -class GitCommandError(GitError): +class GitCommandError(error.GitError): """ Error raised from a failed git command. Note that GitError can refer to any Git related error (e.g. branch not @@ -691,7 +690,7 @@ class GitCommandError(GitError): return string -class GitPopenCommandError(GitError): +class GitPopenCommandError(error.GitError): """ Error raised when subprocess.Popen fails for a GitCommand """ diff --git a/git_config.py b/git_config.py index 5117422c3..756e9c2d5 100644 --- a/git_config.py +++ b/git_config.py @@ -26,8 +26,7 @@ from typing import Union import urllib.error import urllib.request -from error import GitError -from error import UploadError +import error from git_command import GitCommand from git_refs import R_CHANGES from git_refs import R_HEADS @@ -479,7 +478,7 @@ class GitConfig: if p.Wait() == 0: return p.stdout else: - raise GitError(f"git {' '.join(command)}: {p.stderr}") + raise error.GitError(f"git {' '.join(command)}: {p.stderr}") class RepoConfig(GitConfig): @@ -717,11 +716,13 @@ class Remote: userEmail, host, port ) except urllib.error.HTTPError as e: - raise UploadError(f"{self.review}: {str(e)}") + raise error.UploadError(f"{self.review}: {str(e)}") except urllib.error.URLError as e: - raise UploadError(f"{self.review}: {str(e)}") + raise error.UploadError(f"{self.review}: {str(e)}") except http.client.HTTPException as e: - raise UploadError(f"{self.review}: {e.__class__.__name__}") + raise error.UploadError( + f"{self.review}: {e.__class__.__name__}" + ) REVIEW_CACHE[u] = self._review_url return self._review_url + self.projectname @@ -747,7 +748,7 @@ class Remote: if not rev.startswith(R_HEADS): return rev - raise GitError( + raise error.GitError( "%s: remote %s does not have %s" % (self.projectname, self.name, rev) ) diff --git a/hooks.py b/hooks.py index af3134d5e..b910b34a8 100644 --- a/hooks.py +++ b/hooks.py @@ -19,7 +19,7 @@ import sys import traceback import urllib.parse -from error import HookError +import error from git_refs import HEAD @@ -228,7 +228,7 @@ class RepoHook: # For anything else, we'll assume no approval. if self._abort_if_user_denies: - raise HookError( + raise error.HookError( "You must allow the %s hook or use --no-verify." % self._hook_type ) @@ -326,14 +326,16 @@ class RepoHook: try: exec(compile(data, self._script_fullpath, "exec"), context) except Exception: - raise HookError( + raise error.HookError( "%s\nFailed to import %s hook; see traceback above." % (traceback.format_exc(), self._hook_type) ) # Running the script should have defined a main() function. if "main" not in context: - raise HookError('Missing main() in: "%s"' % self._script_fullpath) + raise error.HookError( + 'Missing main() in: "%s"' % self._script_fullpath + ) # Call the main function in the hook. If the hook should cause the # build to fail, it will raise an Exception. We'll catch that convert @@ -341,7 +343,7 @@ class RepoHook: try: context["main"](**kwargs) except Exception: - raise HookError( + raise error.HookError( "%s\nFailed to run main() for %s hook; see traceback " "above." % (traceback.format_exc(), self._hook_type) ) @@ -394,7 +396,7 @@ class RepoHook: if interp: prog = os.path.basename(interp) if prog.startswith("python2"): - raise HookError("Python 2 is not supported") + raise error.HookError("Python 2 is not supported") # Run the hook by importing directly. self._ExecuteHookViaImport(data, context, **kwargs) @@ -406,7 +408,7 @@ class RepoHook: def _CheckHook(self): # Bail with a nice error if we can't find the hook. if not os.path.isfile(self._script_fullpath): - raise HookError( + raise error.HookError( "Couldn't find repo hook: %s" % self._script_fullpath ) @@ -473,7 +475,7 @@ class RepoHook: % (self._hook_type, str(e)), file=sys.stderr, ) - except HookError as e: + except error.HookError as e: passed = False print("ERROR: %s" % str(e), file=sys.stderr) diff --git a/main.py b/main.py index 49093c505..818a4744b 100755 --- a/main.py +++ b/main.py @@ -45,17 +45,7 @@ from color import SetDefaultColoring from command import InteractiveCommand from command import MirrorSafeCommand from editor import Editor -from error import DownloadError -from error import InvalidProjectGroupsError -from error import ManifestInvalidRevisionError -from error import ManifestParseError -from error import NoManifestException -from error import NoSuchProjectError -from error import RepoChangedException -from error import RepoError -from error import RepoExitError -from error import RepoUnhandledExceptionError -from error import SilentRepoExitError +import error import event_log from git_command import user_agent from git_config import RepoConfig @@ -435,7 +425,7 @@ class _Repo: try: copts, cargs = cmd.OptionParser.parse_args(argv) copts = cmd.ReadEnvironmentOptions(copts) - except NoManifestException as e: + except error.NoManifestException as e: logger.error("error: in `%s`: %s", " ".join([name] + argv), e) logger.error( "error: manifest missing or unreadable -- please run init" @@ -511,23 +501,23 @@ class _Repo: KeyboardInterrupt, SystemExit, Exception, - RepoExitError, + error.RepoExitError, ) as e: ok = isinstance(e, SystemExit) and not e.code exception_name = type(e).__name__ - if isinstance(e, RepoUnhandledExceptionError): + if isinstance(e, error.RepoUnhandledExceptionError): exception_name = type(e.error).__name__ - if isinstance(e, RepoExitError): + if isinstance(e, error.RepoExitError): aggregated_errors = e.aggregate_errors or [] - for error in aggregated_errors: + for err in aggregated_errors: project = None - if isinstance(error, RepoError): - project = error.project + if isinstance(err, error.RepoError): + project = err.project error_info = json.dumps( { - "ErrorType": type(error).__name__, + "ErrorType": type(err).__name__, "Project": str(project), - "Message": str(error), + "Message": str(err), } ) git_trace2_event_log.ErrorEvent( @@ -542,24 +532,24 @@ class _Repo: try: execute_command() except ( - DownloadError, - ManifestInvalidRevisionError, - ManifestParseError, - NoManifestException, + error.DownloadError, + error.ManifestInvalidRevisionError, + error.ManifestParseError, + error.NoManifestException, ) as e: logger.error("error: in `%s`: %s", " ".join([name] + argv), e) - if isinstance(e, NoManifestException): + if isinstance(e, error.NoManifestException): logger.error( "error: manifest missing or unreadable -- please run init" ) result = e.exit_code - except NoSuchProjectError as e: + except error.NoSuchProjectError as e: if e.name: logger.error("error: project %s not found", e.name) else: logger.error("error: no project in current directory") result = e.exit_code - except InvalidProjectGroupsError as e: + except error.InvalidProjectGroupsError as e: if e.name: logger.error( "error: project group must be enabled for project %s", @@ -578,7 +568,7 @@ class _Repo: except KeyboardInterrupt: result = KEYBOARD_INTERRUPT_EXIT raise - except RepoExitError as e: + except error.RepoExitError as e: result = e.exit_code raise except Exception: @@ -949,14 +939,14 @@ def _Main(argv): SetTraceToStderr() result = repo._Run(name, gopts, argv) or 0 - except RepoExitError as e: - if not isinstance(e, SilentRepoExitError): + except error.RepoExitError as e: + if not isinstance(e, error.SilentRepoExitError): logger.log_aggregated_errors(e) result = e.exit_code except KeyboardInterrupt: print("aborted by user", file=sys.stderr) result = KEYBOARD_INTERRUPT_EXIT - except RepoChangedException as rce: + except error.RepoChangedException as rce: # If repo changed, re-exec ourselves. argv = list(sys.argv) argv.extend(rce.extra_args) diff --git a/manifest_xml.py b/manifest_xml.py index c3d6fe011..590e6b6d1 100644 --- a/manifest_xml.py +++ b/manifest_xml.py @@ -21,9 +21,7 @@ import sys import urllib.parse import xml.dom.minidom -from error import ManifestInvalidPathError -from error import ManifestInvalidRevisionError -from error import ManifestParseError +import error from git_config import GitConfig from git_refs import HEAD from git_refs import R_HEADS @@ -114,7 +112,9 @@ def XmlInt(node, attr, default=None): try: return int(value) except ValueError: - raise ManifestParseError(f'manifest: invalid {attr}="{value}" integer') + raise error.ManifestParseError( + f'manifest: invalid {attr}="{value}" integer' + ) def normalize_url(url: str) -> str: @@ -290,7 +290,7 @@ class _XmlSubmanifest: self.annotations = [] outer_client = parent._outer_client or parent if self.remote and not self.project: - raise ManifestParseError( + raise error.ManifestParseError( f"Submanifest {name}: must specify project when remote is " "given." ) @@ -424,7 +424,7 @@ class XmlManifest: # This avoids a trailing os.path.sep when submanifest_path is empty. self.topdir = os.path.join(self.topdir, submanifest_path) if manifest_file != os.path.abspath(manifest_file): - raise ManifestParseError("manifest_file must be abspath") + raise error.ManifestParseError("manifest_file must be abspath") self.manifestFile = manifest_file if not outer_client or outer_client == self: # manifestFileOverrides only exists in the outer_client's manifest, @@ -438,7 +438,9 @@ class XmlManifest: if submanifest_path and not outer_client: # If passing a submanifest_path, there must be an outer_client. - raise ManifestParseError(f"Bad call to {self.__class__.__name__}") + raise error.ManifestParseError( + f"Bad call to {self.__class__.__name__}" + ) # If self._outer_client is None, this is not a checkout that supports # multi-tree. @@ -477,7 +479,7 @@ class XmlManifest: if path is None: path = os.path.join(self.manifestProject.worktree, name) if not os.path.isfile(path): - raise ManifestParseError("manifest %s not found" % name) + raise error.ManifestParseError("manifest %s not found" % name) self._load_local_manifests = load_local_manifests self._outer_client.manifestFileOverrides[self.path_prefix] = path @@ -863,7 +865,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md elif child.nodeName in MULTI_ELEMENTS: ret.setdefault(child.nodeName, []).append(element) else: - raise ManifestParseError( + raise error.ManifestParseError( f'Unhandled element "{child.nodeName}"' ) @@ -1188,7 +1190,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md def _Load(self, initial_client=None, submanifest_depth=0): if submanifest_depth > MAX_SUBMANIFEST_DEPTH: - raise ManifestParseError( + raise error.ManifestParseError( "maximum submanifest depth %d exceeded." % MAX_SUBMANIFEST_DEPTH ) if not self._loaded: @@ -1260,7 +1262,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md try: self._ParseManifest(nodes) - except ManifestParseError as e: + except error.ManifestParseError as e: # There was a problem parsing, unload ourselves in case they # catch this error and try again later, we will show the # correct error @@ -1322,10 +1324,12 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md try: root = xml.dom.minidom.parse(path) except (OSError, xml.parsers.expat.ExpatError) as e: - raise ManifestParseError(f"error parsing manifest {path}: {e}") + raise error.ManifestParseError( + f"error parsing manifest {path}: {e}" + ) if not root or not root.childNodes: - raise ManifestParseError(f"no root node in {path}") + raise error.ManifestParseError(f"no root node in {path}") for manifest in root.childNodes: if ( @@ -1334,7 +1338,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md ): break else: - raise ManifestParseError(f"no in {path}") + raise error.ManifestParseError(f"no in {path}") nodes = [] for node in manifest.childNodes: @@ -1351,7 +1355,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md if restrict_includes: msg = self._CheckLocalPath(name) if msg: - raise ManifestInvalidPathError( + raise error.ManifestInvalidPathError( f' invalid "name": {name}: {msg}' ) include_groups = (parent_groups or set()).copy() @@ -1361,7 +1365,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md ) fp = os.path.join(include_root, name) if not os.path.isfile(fp): - raise ManifestParseError( + raise error.ManifestParseError( "include [%s/]%s doesn't exist or isn't a file" % (include_root, name) ) @@ -1373,10 +1377,10 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md ) # should isolate this to the exact exception, but that's # tricky. actual parsing implementation may vary. - except (RuntimeError, ManifestParseError): + except (RuntimeError, error.ManifestParseError): raise except Exception as e: - raise ManifestParseError( + raise error.ManifestParseError( f"failed parsing included manifest {name}: {e}" ) else: @@ -1400,7 +1404,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md if remote: if remote.name in self._remotes: if remote != self._remotes[remote.name]: - raise ManifestParseError( + raise error.ManifestParseError( "remote %s already exists with different " "attributes" % (remote.name) ) @@ -1416,7 +1420,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md if self._default is None: self._default = new_default elif not emptyDefault and new_default != self._default: - raise ManifestParseError( + raise error.ManifestParseError( "duplicate default in %s" % (self.manifestFile) ) @@ -1430,7 +1434,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md if submanifest: if submanifest.name in self._submanifests: if submanifest != self._submanifests[submanifest.name]: - raise ManifestParseError( + raise error.ManifestParseError( "submanifest %s already exists with different " "attributes" % (submanifest.name) ) @@ -1441,7 +1445,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md for node in itertools.chain(*node_list): if node.nodeName == "notice": if self._notice is not None: - raise ManifestParseError( + raise error.ManifestParseError( "duplicate notice in %s" % (self.manifestFile) ) self._notice = self._ParseNotice(node) @@ -1451,7 +1455,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md url = self._reqatt(node, "url") helper = node.getAttribute("helper") or None if self._manifest_server is not None: - raise ManifestParseError( + raise error.ManifestParseError( "duplicate manifest-server in %s" % (self.manifestFile) ) self._manifest_server = url @@ -1460,18 +1464,18 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md def recursively_add_projects(project): projects = self._projects.setdefault(project.name, []) if project.relpath is None: - raise ManifestParseError( + raise error.ManifestParseError( "missing path for %s in %s" % (project.name, self.manifestFile) ) if project.relpath in self._paths: - raise ManifestParseError( + raise error.ManifestParseError( "duplicate path %s in %s" % (project.relpath, self.manifestFile) ) for tree in submanifest_paths: if project.relpath.startswith(tree): - raise ManifestParseError( + raise error.ManifestParseError( "project %s conflicts with submanifest path %s" % (project.relpath, tree) ) @@ -1491,7 +1495,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md name = self._reqatt(node, "name") if name not in self._projects: - raise ManifestParseError( + raise error.ManifestParseError( "extend-project element specifies non-existent " "project: %s" % name ) @@ -1513,7 +1517,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md named_projects = self._projects[name] if dest_path and not path and len(named_projects) > 1: - raise ManifestParseError( + raise error.ManifestParseError( "extend-project cannot use dest-path when " "matching multiple projects: %s" % name ) @@ -1570,7 +1574,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md if node.nodeName == "repo-hooks": # Only one project can be the hooks project if repo_hooks_project is not None: - raise ManifestParseError( + raise error.ManifestParseError( "duplicate repo-hooks in %s" % (self.manifestFile) ) @@ -1584,7 +1588,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md name = self._reqatt(node, "name") # There can only be one superproject. if self._superproject: - raise ManifestParseError( + raise error.ManifestParseError( "duplicate superproject in %s" % (self.manifestFile) ) remote_name = node.getAttribute("remote") @@ -1593,7 +1597,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md else: remote = self._get_remote(node) if remote is None: - raise ManifestParseError( + raise error.ManifestParseError( "no remote for superproject %s within %s" % (name, self.manifestFile) ) @@ -1601,7 +1605,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md if not revision: revision = self._default.revisionExpr if not revision: - raise ManifestParseError( + raise error.ManifestParseError( "no revision for superproject %s within %s" % (name, self.manifestFile) ) @@ -1624,7 +1628,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md # Name or path needed. if not name and not path: - raise ManifestParseError( + raise error.ManifestParseError( "remove-project must have name and/or path" ) @@ -1669,14 +1673,14 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md repo_hooks_project = None if not removed_project and not XmlBool(node, "optional", False): - raise ManifestParseError( + raise error.ManifestParseError( "remove-project element specifies non-existent " "project: %s" % node.toxml() ) if failed_revision_changes: fail_string = "\n".join(failed_revision_changes) - raise ManifestParseError( + raise error.ManifestParseError( f"detected base-revision mismatch, updates needed:\n" f"{fail_string}", ) @@ -1687,12 +1691,12 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md try: repo_hooks_projects = self._projects[repo_hooks_project] except KeyError: - raise ManifestParseError( + raise error.ManifestParseError( "project %s not found for repo-hooks" % (repo_hooks_project) ) if len(repo_hooks_projects) != 1: - raise ManifestParseError( + raise error.ManifestParseError( "internal error parsing repo-hooks in %s" % (self.manifestFile) ) @@ -1704,7 +1708,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md name = None m_url = m.GetRemote().url if m_url.endswith("/.git"): - raise ManifestParseError("refusing to mirror %s" % m_url) + raise error.ManifestParseError("refusing to mirror %s" % m_url) if self._default and self._default.remote: url = self._default.remote.resolvedFetchUrl @@ -1789,14 +1793,14 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md d.sync_j = XmlInt(node, "sync-j", None) if d.sync_j is not None and d.sync_j <= 0: - raise ManifestParseError( + raise error.ManifestParseError( '%s: sync-j must be greater than 0, not "%s"' % (self.manifestFile, d.sync_j) ) d.sync_j_max = XmlInt(node, "sync-j-max", None) if d.sync_j_max is not None and d.sync_j_max <= 0: - raise ManifestParseError( + raise error.ManifestParseError( '%s: sync-j-max must be greater than 0, not "%s"' % (self.manifestFile, d.sync_j_max) ) @@ -1872,20 +1876,20 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md if revision: msg = self._CheckLocalPath(revision.split("/")[-1]) if msg: - raise ManifestInvalidPathError( + raise error.ManifestInvalidPathError( ' invalid "revision": %s: %s' % (revision, msg) ) else: msg = self._CheckLocalPath(name) if msg: - raise ManifestInvalidPathError( + raise error.ManifestInvalidPathError( f' invalid "name": {name}: {msg}' ) else: msg = self._CheckLocalPath(path) if msg: - raise ManifestInvalidPathError( + raise error.ManifestInvalidPathError( f' invalid "path": {path}: {msg}' ) @@ -1920,7 +1924,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md name = self._reqatt(node, "name") msg = self._CheckLocalPath(name, dir_ok=True) if msg: - raise ManifestInvalidPathError( + raise error.ManifestInvalidPathError( f' invalid "name": {name}: {msg}' ) if parent: @@ -1930,7 +1934,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md if remote is None: remote = self._default.remote if remote is None: - raise ManifestParseError( + raise error.ManifestParseError( f"no remote for project {name} within {self.manifestFile}" ) @@ -1938,7 +1942,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md if not revisionExpr: revisionExpr = self._default.revisionExpr if not revisionExpr: - raise ManifestParseError( + raise error.ManifestParseError( "no revision for project %s within %s" % (name, self.manifestFile) ) @@ -1951,7 +1955,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md # Project.Sync_LocalHalf. msg = self._CheckLocalPath(path, dir_ok=True, cwd_dot_ok=True) if msg: - raise ManifestInvalidPathError( + raise error.ManifestInvalidPathError( f' invalid "path": {path}: {msg}' ) @@ -1962,7 +1966,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md clone_depth = XmlInt(node, "clone-depth") if clone_depth is not None and clone_depth <= 0: - raise ManifestParseError( + raise error.ManifestParseError( '%s: clone-depth must be greater than 0, not "%s"' % (self.manifestFile, clone_depth) ) @@ -2256,7 +2260,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md # It is relative to the top of the repo client checkout. msg = cls._CheckLocalPath(dest) if msg: - raise ManifestInvalidPathError( + raise error.ManifestInvalidPathError( f'<{element}> invalid "dest": {dest}: {msg}' ) @@ -2267,7 +2271,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md src, dir_ok=is_linkfile, cwd_dot_ok=is_linkfile ) if msg: - raise ManifestInvalidPathError( + raise error.ManifestInvalidPathError( f'<{element}> invalid "src": {src}: {msg}' ) @@ -2296,10 +2300,10 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md value = self._reqatt(node, "value") try: keep = self._reqatt(node, "keep").lower() - except ManifestParseError: + except error.ManifestParseError: keep = "true" if keep != "true" and keep != "false": - raise ManifestParseError( + raise error.ManifestParseError( 'optional "keep" attribute must be ' '"true" or "false"' ) element.AddAnnotation(name, value, keep) @@ -2311,7 +2315,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md v = self._remotes.get(name) if not v: - raise ManifestParseError( + raise error.ManifestParseError( f"remote {name} not defined in {self.manifestFile}" ) return v @@ -2322,7 +2326,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md """ v = node.getAttribute(attname) if not v: - raise ManifestParseError( + raise error.ManifestParseError( "no %s in <%s> within %s" % (attname, node.nodeName, self.manifestFile) ) @@ -2360,7 +2364,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md try: fromRevId = fromProj.GetCommitRevisionId() toRevId = toProj.GetCommitRevisionId() - except ManifestInvalidRevisionError: + except error.ManifestInvalidRevisionError: diff["unreachable"].append((fromProj, toProj)) else: if fromRevId != toRevId: diff --git a/project.py b/project.py index 6a186aa1d..f890071a8 100644 --- a/project.py +++ b/project.py @@ -33,15 +33,7 @@ from typing import Any, Dict, List, NamedTuple, Optional, Tuple import urllib.parse from color import Coloring -from error import DownloadError -from error import GitAuthError -from error import GitError -from error import ManifestInvalidPathError -from error import ManifestInvalidRevisionError -from error import ManifestParseError -from error import NoManifestException -from error import RepoError -from error import UploadError +import error import fetch from git_command import git_require from git_command import GitCommand @@ -83,11 +75,11 @@ class SyncNetworkHalfResult(NamedTuple): return not self.error -class SyncNetworkHalfError(RepoError): +class SyncNetworkHalfError(error.RepoError): """Failure trying to sync.""" -class DeleteWorktreeError(RepoError): +class DeleteWorktreeError(error.RepoError): """Failure to delete worktree.""" def __init__( @@ -226,7 +218,7 @@ class ReviewableBranch: self._commit_cache = self.project.bare_git.rev_list( *args, log_as_error=self.base_exists ) - except GitError: + except error.GitError: # We weren't able to probe the commits for this branch. Was it # tracking a branch that no longer exists? If so, return no # commits. Otherwise, rethrow the error as we don't know what's @@ -270,7 +262,7 @@ class ReviewableBranch: self.project.bare_git.rev_parse("--verify", not_rev(self.base)) # If we're still here, the base branch exists. self._base_exists = True - except GitError: + except error.GitError: # If we failed to verify, the base branch doesn't exist. self._base_exists = False @@ -392,19 +384,19 @@ def _SafeExpandPath(base, subpath, skipfinal=False): path = base for part in components: if part in {".", ".."}: - raise ManifestInvalidPathError( + raise error.ManifestInvalidPathError( f'{subpath}: "{part}" not allowed in paths' ) path = os.path.join(path, part) if platform_utils.islink(path): - raise ManifestInvalidPathError( + raise error.ManifestInvalidPathError( f"{path}: traversing symlinks not allow" ) if os.path.exists(path): if not os.path.isfile(path) and not platform_utils.isdir(path): - raise ManifestInvalidPathError( + raise error.ManifestInvalidPathError( f"{path}: only regular files & directories allowed" ) @@ -431,11 +423,11 @@ class _CopyFile(NamedTuple): dest = _SafeExpandPath(self.topdir, self.dest) if platform_utils.isdir(src): - raise ManifestInvalidPathError( + raise error.ManifestInvalidPathError( f"{self.src}: copying from directory not supported" ) if platform_utils.isdir(dest): - raise ManifestInvalidPathError( + raise error.ManifestInvalidPathError( f"{self.dest}: copying to directory not allowed" ) @@ -714,7 +706,7 @@ class Project: try: lrev = "" if self.manifest.IsMirror else self.GetRevisionId() - except ManifestInvalidRevisionError: + except error.ManifestInvalidRevisionError: lrev = "" setenv("REPO_LREV", lrev) setenv("REPO_RREV", self.revisionExpr) @@ -788,7 +780,7 @@ class Project: """ try: b = self._GetHead() - except NoManifestException: + except error.NoManifestException: # If the local checkout is in a bad state, don't barf. Let the # callers process this like the head is unreadable. return None @@ -862,7 +854,7 @@ class Project: try: self.work_git.update_index("-q", *args, log_as_error=False) return - except GitError: + except error.GitError: pass # Exit code 1 means there are modified files, which is okay. @@ -908,7 +900,11 @@ class Project: ahead_behind=ahead_behind, show_stash=show_stash, ) - except (GitError, ValueError, git_status.UnsupportedStatusError) as e: + except ( + error.GitError, + ValueError, + git_status.UnsupportedStatusError, + ) as e: logger.warning( "project %s: porcelain v2 status failed; using legacy " "status: %s", @@ -970,7 +966,7 @@ class Project: is_dirty = self._IsDirtyLegacy(consider_untracked=True) try: head = self.work_git.rev_parse(HEAD) - except GitError: + except error.GitError: head = None return is_dirty, head @@ -1252,7 +1248,7 @@ class Project: left, right = left_right[0].split() behind = int(left) ahead = int(right) - except (GitError, IndexError, ValueError): + except (error.GitError, IndexError, ValueError): pass return ahead, behind @@ -1378,7 +1374,7 @@ class Project: try: p = GitCommand(self, cmd, capture_stdout=True, capture_stderr=True) p.Wait() - except GitError as e: + except error.GitError as e: out.nl() out.project("project %s/" % self.RelPath(local)) out.nl() @@ -1401,7 +1397,7 @@ class Project: if all_refs is None: try: return self.bare_git.rev_parse(key) - except GitError: + except error.GitError: return None else: try: @@ -1494,16 +1490,16 @@ class Project: if branch is None: branch = self.CurrentBranch if branch is None: - raise GitError("not currently on a branch", project=self.name) + raise error.GitError("not currently on a branch", project=self.name) branch = self.GetBranch(branch) if not branch.LocalMerge: - raise GitError( + raise error.GitError( "branch %s does not track a remote" % branch.name, project=self.name, ) if not branch.remote.review: - raise GitError( + raise error.GitError( "remote %s has no review url" % branch.remote.name, project=self.name, ) @@ -1511,7 +1507,7 @@ class Project: # Basic validity check on label syntax. for label in labels: if not re.match(r"^.+[+-][0-9]+$", label): - raise UploadError( + raise error.UploadError( f'invalid label syntax "{label}": labels use forms like ' "CodeReview+1 or Verified-1", project=self.name, @@ -1530,7 +1526,7 @@ class Project: url = branch.remote.ReviewUrl(self.UserEmail, validate_certs) if url is None: - raise UploadError("review not configured", project=self.name) + raise error.UploadError("review not configured", project=self.name) cmd = ["push", "--progress"] if dryrun: cmd.append("-n") @@ -1693,7 +1689,7 @@ class Project: try: local_head = self.bare_git.rev_parse("HEAD") - except GitError: + except error.GitError: local_head = None if target_hash == local_head: @@ -1717,7 +1713,7 @@ class Project: ) if int(local_commits[0]) > 0: return False - except (GitError, IndexError, ValueError): + except (error.GitError, IndexError, ValueError): return False if self._HasDirtyOrStash(): @@ -1768,7 +1764,7 @@ class Project: try: self._FetchArchive(tarpath, cwd=topdir) - except GitError as e: + except error.GitError as e: logger.error("error: %s", e) return SyncNetworkHalfResult(False, e) @@ -1821,7 +1817,7 @@ class Project: self._CheckDirReference(self.objdir, self.gitdir) self._UpdateHooks(quiet=quiet) - except GitError as e: + except error.GitError as e: if not force_sync: raise e # Let _InitGitDir fix the issue, force_sync is always True here. @@ -1916,7 +1912,7 @@ class Project: project=self.name, ), ) - except RepoError as e: + except error.RepoError as e: return SyncNetworkHalfResult( remote_fetched, e, @@ -1961,7 +1957,7 @@ class Project: project=self.name, ), ) - except RepoError as e: + except error.RepoError as e: return SyncNetworkHalfResult( remote_fetched, e, @@ -1987,7 +1983,7 @@ class Project: if p.Wait() != 0: return SyncNetworkHalfResult( remote_fetched, - GitError( + error.GitError( "Unable to repack alternates", project=self.name ), ) @@ -2035,7 +2031,7 @@ class Project: return head try: return self.work_git.rev_parse("HEAD") - except GitError: + except error.GitError: pass return None @@ -2058,8 +2054,8 @@ class Project: try: return self.bare_git.ResolveCommit(rev) - except GitError: - raise ManifestInvalidRevisionError( + except error.GitError: + raise error.ManifestInvalidRevisionError( f"revision {self.revisionExpr} in {self.name} not found" ) @@ -2243,7 +2239,7 @@ class Project: _checkout() if submodules: self._SyncSubmodules(quiet=True) - except (GitError, LocalSyncFail) as e: + except (error.GitError, LocalSyncFail) as e: fail(e) return self._CopyAndLinkFiles() @@ -2270,7 +2266,7 @@ class Project: _checkout() if submodules: self._SyncSubmodules(quiet=True) - except (GitError, LocalSyncFail) as e: + except (error.GitError, LocalSyncFail) as e: fail(e) return self._CopyAndLinkFiles() @@ -2287,7 +2283,7 @@ class Project: ) # Skip the published logic. pub = False - except GitError: + except error.GitError: pub = self.WasPublished(branch.name, all_refs) if pub: @@ -2403,7 +2399,7 @@ class Project: if submodules: self._SyncSubmodules(quiet=True) self._CopyAndLinkFiles() - except (GitError, LocalSyncFail) as e: + except (error.GitError, LocalSyncFail) as e: fail(e) return else: @@ -2478,7 +2474,7 @@ class Project: is_corrupted = False try: is_dirty = self.IsDirty() - except GitError: + except error.GitError: is_corrupted = True rel_path = self.RelPath(local=False) @@ -2541,7 +2537,7 @@ class Project: ) if fullpath == needle: platform_utils.rmtree(os.path.join(configs, name)) - except GitError as e: + except error.GitError as e: logger.warning( "warning: %s: Failed to list worktrees, skipping worktree " "cleanup: %s", @@ -2903,7 +2899,7 @@ class Project: bare=True, gitdir=gitdir, ) - except GitError: + except error.GitError: return [], [], [] if p.Wait() != 0: return [], [], [] @@ -2925,7 +2921,7 @@ class Project: if p.Wait() != 0: return [], [], [] gitmodules_lines = p.stdout.split("\n") - except GitError: + except error.GitError: return [], [], [] finally: platform_utils.remove(temp_gitmodules_path) @@ -2971,7 +2967,7 @@ class Project: bare=True, gitdir=gitdir, ) - except GitError: + except error.GitError: return [] if p.Wait() != 0: return [] @@ -2985,7 +2981,7 @@ class Project: try: rev = self.GetRevisionId() - except (GitError, ManifestInvalidRevisionError): + except (error.GitError, error.ManifestInvalidRevisionError): # The git repo may be outdated (i.e. not fetched yet) and querying # its submodules using the revision may not work; so return here. return [] @@ -3015,7 +3011,7 @@ class Project: "--", log_as_error=False, ) - except (GitError, ManifestInvalidRevisionError): + except (error.GitError, error.ManifestInvalidRevisionError): return None return { @@ -3154,7 +3150,7 @@ class Project: log_as_error=False, ) return True - except GitError: + except error.GitError: # There is no such persistent revision. We have to fetch it. return False @@ -3283,12 +3279,12 @@ class Project: if not IsId(self.revisionExpr): try: ref_name = self.GetRemote().ToLocal(self.revisionExpr) - except GitError as e: + except error.GitError as e: logger.error("error: Failed to resolve tracking ref: %s", e) return False try: resolved_ref = self.bare_git.ResolveCommit(ref_name) - except GitError: + except error.GitError: logger.error( "error: Postcondition failed: %s does not resolve to a " "commit in object store", @@ -3315,7 +3311,7 @@ class Project: repo_trev, ) return False - except GitError: + except error.GitError: logger.error( "error: Postcondition failed: FETCH_HEAD does not resolve to " "a commit in object store" @@ -3644,7 +3640,7 @@ class Project: "interactive authentication.", file=output_redir, ) - raise GitAuthError(gitcmd.stdout) + raise error.GitAuthError(gitcmd.stdout) break elif current_branch_only and is_sha1 and ret == 128: # Exit code 128 means "couldn't find the ref you asked for"; @@ -3893,7 +3889,7 @@ class Project: cmd.append("--") if GitCommand(self, cmd).Wait() != 0: if self._allrefs: - raise GitError( + raise error.GitError( f"{self.name} checkout {rev} ", project=self.name ) @@ -3907,7 +3903,7 @@ class Project: cmd.append("--") if GitCommand(self, cmd).Wait() != 0: if self._allrefs: - raise GitError( + raise error.GitError( f"{self.name} cherry-pick {rev} ", project=self.name ) @@ -3925,7 +3921,9 @@ class Project: cmd.append("--") if GitCommand(self, cmd).Wait() != 0: if self._allrefs: - raise GitError(f"{self.name} revert {rev} ", project=self.name) + raise error.GitError( + f"{self.name} revert {rev} ", project=self.name + ) def _ResetHard(self, rev, quiet=True): cmd = ["reset", "--hard"] @@ -3933,7 +3931,7 @@ class Project: cmd.append("-q") cmd.append(rev) if GitCommand(self, cmd).Wait() != 0: - raise GitError( + raise error.GitError( f"{self.name} reset --hard {rev} ", project=self.name ) @@ -3942,7 +3940,7 @@ class Project: if quiet: cmd.append("-q") if GitCommand(self, cmd).Wait() != 0: - raise GitError( + raise error.GitError( "%s submodule update --init --recursive " % self.name, project=self.name, ) @@ -3987,7 +3985,9 @@ class Project: cmd.extend(["--onto", onto]) cmd.append(upstream) if GitCommand(self, cmd).Wait() != 0: - raise GitError(f"{self.name} rebase {upstream} ", project=self.name) + raise error.GitError( + f"{self.name} rebase {upstream} ", project=self.name + ) def _FastForward(self, head: str, quiet: bool = True) -> None: cmd = ["merge", "--no-stat", "--ff-only"] @@ -3995,7 +3995,7 @@ class Project: cmd.append("-q") cmd.append(head) if GitCommand(self, cmd).Wait() != 0: - raise GitError( + raise error.GitError( f"{self.name} merge --ff-only {head}", project=self.name ) @@ -4057,7 +4057,7 @@ class Project: head_tree = self.work_git.rev_parse( "-q", "--verify", "HEAD^{tree}", log_as_error=False ) - except GitError: + except error.GitError: head_tree = None if head_tree: @@ -4101,7 +4101,7 @@ class Project: head_oid = self.work_git.rev_parse( "-q", "--verify", "HEAD", log_as_error=False ) - except GitError: + except error.GitError: head_oid = None env = os.environ.copy() @@ -4137,7 +4137,7 @@ class Project: new_head_oid = self.work_git.rev_parse( "-q", "--verify", "HEAD", log_as_error=False ) - except GitError: + except error.GitError: new_head_oid = None if new_head != head or new_head_oid != head_oid: @@ -4220,7 +4220,7 @@ class Project: ) try: self._CheckDirReference(self.objdir, curr_gitdir) - except GitError as e: + except error.GitError as e: if force_sync: try: rm_dirs = ( @@ -4390,7 +4390,7 @@ class Project: try: os.link(stock_hook, dst) except OSError: - raise GitError( + raise error.GitError( self._get_symlink_error_message(), project=self.name ) else: @@ -4502,7 +4502,7 @@ class Project: destdir, srcdir, ) - raise GitError( + raise error.GitError( "--force-sync not enabled; cannot overwrite a local " "work tree. If you're comfortable with the " "possibility of losing the work tree's git metadata," @@ -4554,7 +4554,7 @@ class Project: except OSError as e: if e.errno == errno.EPERM: - raise DownloadError(self._get_symlink_error_message()) + raise error.DownloadError(self._get_symlink_error_message()) else: raise @@ -4660,7 +4660,7 @@ class Project: cmd = ["read-tree", "--reset", "-u", "-v", HEAD] try: if GitCommand(self, cmd).Wait() != 0: - raise GitError( + raise error.GitError( "Cannot initialize work tree for " + self.name, project=self.name, ) @@ -4703,7 +4703,7 @@ class Project: with open(dotgit) as fp: setting = fp.read() if not setting.startswith("gitdir:"): - raise GitError( + raise error.GitError( f"'.git' in {self.worktree} must start with 'gitdir:'", project=self.name, ) @@ -4731,7 +4731,7 @@ class Project: gitdir = os.path.dirname(os.path.realpath(path)) break else: - raise GitError( + raise error.GitError( f"{dotgit}: unsupported checkout state", project=project ) @@ -4792,7 +4792,7 @@ class Project: f"{dotgit_path}: unknown file; please file a bug" ) if unknown_paths: - raise GitError( + raise error.GitError( "Aborting migration: " + "\n".join(unknown_paths), project=project, ) @@ -4892,7 +4892,7 @@ class Project: ) if log.Wait() == 0: return log.stdout - except GitError: + except error.GitError: # worktree may not exist if groups changed for example. In that # case, try in gitdir instead. if not os.path.exists(self.worktree): @@ -5076,13 +5076,13 @@ class Project: try: return self.symbolic_ref("-q", HEAD, log_as_error=False) - except GitError: + except error.GitError: pass try: # If symbolic-ref fails, try to treat as detached HEAD. return self.rev_parse(HEAD) - except GitError as e: + except error.GitError as e: logger.warning( "project %s: unparseable HEAD; trying to recover.\n" "Check that HEAD ref in .git/HEAD is valid. The error " @@ -5094,7 +5094,7 @@ class Project: # Fallback to direct file reading for compatibility with broken # repos, e.g. if HEAD points to an unborn branch. if not path: - raise NoManifestException( + raise error.NoManifestException( self._project.RelPath(local=False), str(e) ) try: @@ -5103,11 +5103,11 @@ class Project: ) as fd: ref = self._ParseHead(fd.readline()) except OSError: - raise NoManifestException( + raise error.NoManifestException( self._project.RelPath(local=False), str(e) ) if not ref: - raise NoManifestException( + raise error.NoManifestException( self._project.RelPath(local=False), str(e) ) return ref @@ -5118,7 +5118,7 @@ class Project: if git_require((2, 30, 0)): cmdv.append("--end-of-options") elif revision.startswith("-"): - raise GitError( + raise error.GitError( f"invalid revision: {revision}", project=self._project.name, ) @@ -5233,7 +5233,7 @@ class Project: return runner -class LocalSyncFail(RepoError): +class LocalSyncFail(error.RepoError): """Default error when there is an Sync_LocalHalf error.""" @@ -5287,7 +5287,7 @@ class _Later: if not self.quiet: out.nl() return True - except (GitError, LocalSyncFail) as e: + except (error.GitError, LocalSyncFail) as e: syncbuf.fail(self.project, e) out.nl() return False @@ -6137,7 +6137,7 @@ class ManifestProject(MetaProject): if is_new or self.CurrentBranch is None: try: self.StartBranch("default") - except GitError as e: + except error.GitError as e: msg = str(e) logger.error( "fatal: cannot create default in manifest %s", msg @@ -6159,7 +6159,7 @@ class ManifestProject(MetaProject): try: self.manifest.Link(manifest_name) - except ManifestParseError as e: + except error.ManifestParseError as e: logger.error("fatal: manifest '%s' not available", manifest_name) logger.error("fatal: %s", e) return False diff --git a/repo_logging.py b/repo_logging.py index 639382a29..a736106fc 100644 --- a/repo_logging.py +++ b/repo_logging.py @@ -17,7 +17,7 @@ import logging from color import Coloring -from error import RepoExitError +import error SEPARATOR = "=" * 80 @@ -71,7 +71,7 @@ class RepoLogger(logging.Logger): handler.setFormatter(_LogColoringFormatter(config)) self.addHandler(handler) - def log_aggregated_errors(self, err: RepoExitError): + def log_aggregated_errors(self, err: error.RepoExitError) -> None: """Print all aggregated logs.""" self.error(SEPARATOR) diff --git a/subcmds/abandon.py b/subcmds/abandon.py index b266900c0..1350c86e6 100644 --- a/subcmds/abandon.py +++ b/subcmds/abandon.py @@ -18,8 +18,7 @@ import itertools from command import Command from command import DEFAULT_LOCAL_JOBS -from error import RepoError -from error import RepoExitError +import error from git_command import IsValidBranchName from progress import Progress from repo_logging import RepoLogger @@ -28,7 +27,7 @@ from repo_logging import RepoLogger logger = RepoLogger(__file__) -class AbandonError(RepoExitError): +class AbandonError(error.RepoExitError): """Exit error when abandon command fails.""" @@ -82,7 +81,7 @@ It is equivalent to "git branch -D ". status = None try: status = project.AbandonBranch(name) - except RepoError as e: + except error.RepoError as e: status = False errors.append(e) if status is not None: diff --git a/subcmds/checkout.py b/subcmds/checkout.py index 859ddf6cc..e991a4a31 100644 --- a/subcmds/checkout.py +++ b/subcmds/checkout.py @@ -17,8 +17,7 @@ from typing import NamedTuple from command import Command from command import DEFAULT_LOCAL_JOBS -from error import GitError -from error import RepoExitError +import error from progress import Progress from repo_logging import RepoLogger @@ -33,11 +32,11 @@ class CheckoutBranchResult(NamedTuple): error: Exception -class CheckoutCommandError(RepoExitError): +class CheckoutCommandError(error.RepoExitError): """Exception thrown when checkout command fails.""" -class MissingBranchError(RepoExitError): +class MissingBranchError(error.RepoExitError): """Exception thrown when no project has specified branch.""" @@ -64,14 +63,14 @@ The command is equivalent to: @classmethod def _ExecuteOne(cls, nb, project_idx): """Checkout one project.""" - error = None + err = None result = None project = cls.get_parallel_context()["projects"][project_idx] try: result = project.CheckoutBranch(nb) - except GitError as e: - error = e - return CheckoutBranchResult(result, project_idx, error) + except error.GitError as e: + err = e + return CheckoutBranchResult(result, project_idx, err) def Execute(self, opt, args): nb = args[0] diff --git a/subcmds/cherry_pick.py b/subcmds/cherry_pick.py index 4e7b978c8..f6a6cf934 100644 --- a/subcmds/cherry_pick.py +++ b/subcmds/cherry_pick.py @@ -17,7 +17,7 @@ import sys from typing import Tuple from command import Command -from error import GitError +import error from git_command import GitCommand from repo_logging import RepoLogger @@ -57,7 +57,7 @@ change id will be added. try: p.Wait() - except GitError as e: + except error.GitError as e: logger.error(e) logger.warning( "NOTE: When committing (please see above) and editing the " @@ -86,7 +86,7 @@ change id will be added. ) try: p.Wait() - except GitError: + except error.GitError: logger.error("error: Failed to update commit message") raise @@ -107,7 +107,7 @@ change id will be added. if not separator: raise ValueError("missing cat-file header") if header.endswith(" missing") or header.endswith(" ambiguous"): - raise GitError(f"commit {reference} not found") + raise error.GitError(f"commit {reference} not found") parts = header.split(" ", 2) if len(parts) != 3 or parts[1] != "commit": @@ -122,13 +122,13 @@ change id will be added. raise ValueError("truncated cat-file object") commit = output[:-1] - except (GitError, ValueError) as e: + except (error.GitError, ValueError) as e: logger.error( "error: Failed to resolve or read commit %s", reference ) - if isinstance(e, GitError): + if isinstance(e, error.GitError): raise - raise GitError(str(e)) from e + raise error.GitError(str(e)) from e return sha1, commit diff --git a/subcmds/download.py b/subcmds/download.py index edeadefb1..7a1f6e357 100644 --- a/subcmds/download.py +++ b/subcmds/download.py @@ -16,9 +16,7 @@ import re import sys from command import Command -from error import GitError -from error import NoSuchProjectError -from error import RepoExitError +import error from repo_logging import RepoLogger @@ -26,7 +24,7 @@ CHANGE_RE = re.compile(r"^([1-9][0-9]*)(?:[/\.-]([1-9][0-9]*))?$") logger = RepoLogger(__file__) -class DownloadCommandError(RepoExitError): +class DownloadCommandError(error.RepoExitError): """Error raised when download command fails.""" @@ -107,7 +105,7 @@ If no project is specified try to use current directory as a project. # If the cwd is one of the projects, assume they want that. try: project = self.GetProjects(".")[0] - except NoSuchProjectError: + except error.NoSuchProjectError: project = None if project not in projects: logger.error( @@ -121,7 +119,7 @@ If no project is specified try to use current directory as a project. project.RelPath(local=opt.this_manifest_only), project.revisionExpr, ) - raise NoSuchProjectError() + raise error.NoSuchProjectError() else: project = projects[0] print("Defaulting to cwd project", project.name) @@ -143,7 +141,7 @@ If no project is specified try to use current directory as a project. try: self._ExecuteHelper(opt, args) except Exception as e: - if isinstance(e, RepoExitError): + if isinstance(e, error.RepoExitError): raise e raise DownloadCommandError(aggregate_errors=[e]) @@ -202,7 +200,7 @@ If no project is specified try to use current directory as a project. else: project._Checkout(dl.commit) - except GitError: + except error.GitError: logger.error( "[%s] Could not complete the %s of %s", project.name, diff --git a/subcmds/grep.py b/subcmds/grep.py index e0f239fd3..8da236af0 100644 --- a/subcmds/grep.py +++ b/subcmds/grep.py @@ -19,9 +19,7 @@ from typing import NamedTuple from color import Coloring from command import DEFAULT_LOCAL_JOBS from command import PagedCommand -from error import GitError -from error import InvalidArgumentsError -from error import SilentRepoExitError +import error from git_command import GitCommand from repo_logging import RepoLogger @@ -43,10 +41,10 @@ class ExecuteOneResult(NamedTuple): rc: int stdout: str stderr: str - error: GitError + error: error.GitError -class GrepCommandError(SilentRepoExitError): +class GrepCommandError(error.SilentRepoExitError): """Grep command failure. Since Grep command output already outputs errors ensure that aggregate errors exit silently.""" @@ -273,16 +271,16 @@ contain a line that matches both expressions: capture_stderr=True, verify_command=True, ) - except GitError as e: + except error.GitError as e: return ExecuteOneResult(project_idx, -1, None, str(e), e) try: - error = None + err = None rc = p.Wait() - except GitError as e: + except error.GitError as e: rc = 1 - error = e - return ExecuteOneResult(project_idx, rc, p.stdout, p.stderr, error) + err = e + return ExecuteOneResult(project_idx, rc, p.stdout, p.stderr, err) @staticmethod def _ProcessResults( @@ -377,7 +375,7 @@ contain a line that matches both expressions: if "--cached" in cmd_argv: msg = "fatal: cannot combine --cached and --revision" logger.error(msg) - raise InvalidArgumentsError(msg) + raise error.InvalidArgumentsError(msg) have_rev = True cmd_argv.extend(opt.revision) cmd_argv.append("--") diff --git a/subcmds/help.py b/subcmds/help.py index df7806fa5..ba1414a86 100644 --- a/subcmds/help.py +++ b/subcmds/help.py @@ -19,12 +19,12 @@ import textwrap from color import Coloring from command import MirrorSafeCommand from command import PagedCommand -from error import RepoExitError +import error from subcmds import all_commands from wrapper import Wrapper -class InvalidHelpCommand(RepoExitError): +class InvalidHelpCommand(error.RepoExitError): """Invalid command passed into help.""" diff --git a/subcmds/init.py b/subcmds/init.py index 494a1b773..f1377f0cf 100644 --- a/subcmds/init.py +++ b/subcmds/init.py @@ -18,8 +18,7 @@ import sys from color import Coloring from command import InteractiveCommand from command import MirrorSafeCommand -from error import RepoUnhandledExceptionError -from error import UpdateManifestError +import error from git_command import git_require from repo_logging import RepoLogger from wrapper import Wrapper @@ -174,7 +173,7 @@ to update the working directory files. use_local_gitdirs=opt.use_local_gitdirs, ): manifest_name = opt.manifest_name - raise UpdateManifestError( + raise error.UpdateManifestError( f"Unable to sync manifest {manifest_name}" ) @@ -379,7 +378,7 @@ to update the working directory files. err_msg = "fatal: double check your --repo-rev setting." logger.error(err_msg) self.git_event_log.ErrorEvent(err_msg) - raise RepoUnhandledExceptionError(e) + raise error.RepoUnhandledExceptionError(e) branch = rp.GetBranch("default") branch.merge = remote_ref diff --git a/subcmds/rebase.py b/subcmds/rebase.py index db397e891..0099c4a90 100644 --- a/subcmds/rebase.py +++ b/subcmds/rebase.py @@ -16,7 +16,7 @@ import sys from color import Coloring from command import Command -from error import GitError +import error from git_command import GitCommand from project import Project from repo_logging import RepoLogger @@ -39,7 +39,7 @@ def _ResolveOntoManifest(project: Project) -> str: """ try: return project.GetRemote().ToLocal(project.revisionExpr) - except GitError: + except error.GitError: return project.revisionExpr diff --git a/subcmds/selfupdate.py b/subcmds/selfupdate.py index ed3335695..d3f60c592 100644 --- a/subcmds/selfupdate.py +++ b/subcmds/selfupdate.py @@ -16,7 +16,7 @@ import optparse from command import Command from command import MirrorSafeCommand -from error import RepoExitError +import error from repo_logging import RepoLogger from subcmds.sync import _PostRepoFetch from subcmds.sync import _PostRepoUpgrade @@ -25,7 +25,7 @@ from subcmds.sync import _PostRepoUpgrade logger = RepoLogger(__file__) -class SelfupdateError(RepoExitError): +class SelfupdateError(error.RepoExitError): """Exit error for failed selfupdate command.""" diff --git a/subcmds/start.py b/subcmds/start.py index 5817bf68c..98ac6b267 100644 --- a/subcmds/start.py +++ b/subcmds/start.py @@ -17,7 +17,7 @@ from typing import NamedTuple from command import Command from command import DEFAULT_LOCAL_JOBS -from error import RepoExitError +import error from git_command import IsValidBranchName from git_config import IsImmutable from progress import Progress @@ -32,7 +32,7 @@ class ExecuteOneResult(NamedTuple): error: Exception -class StartError(RepoExitError): +class StartError(error.RepoExitError): """Exit error for failed start command.""" @@ -85,7 +85,7 @@ revision specified in the manifest. # a change, then we can't push back to it. Substitute with # dest_branch, if defined; or with manifest default revision instead. branch_merge = "" - error = None + err = None project = cls.get_parallel_context()["projects"][project_idx] if IsImmutable(project.revisionExpr): if project.dest_branch: @@ -99,8 +99,8 @@ revision specified in the manifest. ) except Exception as e: logger.error("error: unable to checkout %s: %s", project.name, e) - error = e - return ExecuteOneResult(project_idx, error) + err = e + return ExecuteOneResult(project_idx, err) def Execute(self, opt, args): nb = args[0] diff --git a/subcmds/sync.py b/subcmds/sync.py index f6181b7cc..e33da7134 100644 --- a/subcmds/sync.py +++ b/subcmds/sync.py @@ -57,14 +57,7 @@ from command import Command from command import DEFAULT_LOCAL_JOBS from command import MirrorSafeCommand from command import WORKER_BATCH_SIZE -from error import GitError -from error import ManifestParseError -from error import RepoChangedException -from error import RepoError -from error import RepoExitError -from error import RepoUnhandledExceptionError -from error import SyncError -from error import UpdateManifestError +import error import event_log from git_command import git_require from git_command import GitCommand @@ -418,19 +411,19 @@ class _InterleavedSyncResult(NamedTuple): results: List[_SyncResult] -class SuperprojectError(SyncError): +class SuperprojectError(error.SyncError): """Superproject sync repo.""" -class SyncFailFastError(SyncError): +class SyncFailFastError(error.SyncError): """Sync exit error when --fail-fast set.""" -class SmartSyncError(SyncError): +class SmartSyncError(error.SyncError): """Smart sync exit error.""" -class ManifestInterruptError(RepoError): +class ManifestInterruptError(error.RepoError): """Aggregate Error to be logged when a user interrupts a manifest update.""" def __init__(self, output, **kwargs): @@ -1116,7 +1109,7 @@ later is required to fix a server side protocol bug. logger.error("Keyboard interrupt while processing %s", project.name) if not cls.is_multiprocessing_active(): raise - except GitError as e: + except error.GitError as e: logger.error("error.GitError: Cannot fetch %s", e) errors.append(e) except Exception as e: @@ -1322,7 +1315,7 @@ later is required to fix a server side protocol bug. if opt.network_only: # Bail out now; the rest touches the working tree. if err_event.is_set(): - e = SyncError( + e = error.SyncError( "error: Exited sync due to fetch errors.", aggregate_errors=errors, ) @@ -1416,7 +1409,7 @@ later is required to fix a server side protocol bug. logger.error("Keyboard interrupt while processing %s", project.name) if not cls.is_multiprocessing_active(): raise - except GitError as e: + except error.GitError as e: logger.error( "error.GitError: Cannot checkout %s: %s", project.name, e ) @@ -1675,7 +1668,7 @@ later is required to fix a server side protocol bug. cls._RunOneGC(bare_git._project, config=config) else: bare_git.pack_refs(config=config) - except GitError: + except error.GitError: err_event.set() except Exception: err_event.set() @@ -2346,7 +2339,7 @@ later is required to fix a server side protocol bug. mp, event_log.TASK_SYNC_LOCAL, start, time.time(), clean ) if not clean: - raise UpdateManifestError(aggregate_errors=errors) + raise error.UpdateManifestError(aggregate_errors=errors) self._ReloadManifest(manifest_name, mp.manifest) def ValidateOptions(self, opt, args): @@ -2454,10 +2447,10 @@ later is required to fix a server side protocol bug. try: self._ExecuteHelper(opt, args, errors) sync_duration_seconds = time.time() - start_time - except (RepoExitError, RepoChangedException): + except (error.RepoExitError, error.RepoChangedException): raise except (KeyboardInterrupt, Exception) as e: - raise RepoUnhandledExceptionError(e, aggregate_errors=errors) + raise error.RepoUnhandledExceptionError(e, aggregate_errors=errors) # Run post-sync hook only after successful sync self._RunPostSyncHook(opt, sync_duration_seconds=sync_duration_seconds) @@ -2490,13 +2483,13 @@ later is required to fix a server side protocol bug. Only valid for the outer manifest; see _GetSuperprojectRevision. """ if not manifest.superproject: - raise SyncError("superproject not defined in manifest") + raise error.SyncError("superproject not defined in manifest") self._ConfigureSuperproject(opt, manifest) sync_result = manifest.superproject.Sync(self.git_event_log) if not sync_result.success: - raise SyncError("failed to sync superproject") + raise error.SyncError("failed to sync superproject") cmd = ["show", f"{opt.superproject_revision}:.supermanifest"] p = GitCommand( @@ -2508,20 +2501,20 @@ later is required to fix a server side protocol bug. capture_stderr=True, ) if p.Wait() != 0: - raise SyncError( + raise error.SyncError( f"failed to read .supermanifest from superproject: {p.stderr}" ) try: _, _, manifest_commit = p.stdout.strip().split() except ValueError: - raise SyncError("could not parse .supermanifest") + raise error.SyncError("could not parse .supermanifest") mp.SetRevision(manifest_commit) try: self._UpdateManifestProject(opt, mp, manifest_name, errors) - except UpdateManifestError as e: - raise SyncError( + except error.UpdateManifestError as e: + raise error.SyncError( "failed to sync manifest project", aggregate_errors=[e] ) @@ -2616,7 +2609,7 @@ later is required to fix a server side protocol bug. manifest, best_effort=implicit_smart_sync, ) - except (SmartSyncError, ManifestParseError) as e: + except (SmartSyncError, error.ManifestParseError) as e: if not implicit_smart_sync: raise # The user did not ask for a smart sync, so failing to get a @@ -2635,7 +2628,7 @@ later is required to fix a server side protocol bug. manifest_name = os.path.basename(smart_sync_manifest_path) try: self._ReloadManifest(manifest_name, manifest) - except ManifestParseError as e: + except error.ManifestParseError as e: reuse_smart_sync_override = False manifest_name = None manifest.ClearOverride() @@ -2805,7 +2798,7 @@ later is required to fix a server side protocol bug. nested = _NestedProjects(projects) if not nested: return - e = SyncError( + e = error.SyncError( "error: repo.reprojectcmd does not support nested projects or " "submodules; found:\n" + "\n".join( @@ -2929,7 +2922,7 @@ later is required to fix a server side protocol bug. logger.error( 'Try re-running with "-j1 --fail-fast" to exit at the first error.' ) - raise SyncError(aggregate_errors=errors) + raise error.SyncError(aggregate_errors=errors) def _SyncPhased( self, @@ -3063,7 +3056,7 @@ later is required to fix a server side protocol bug. ) if not cls.is_multiprocessing_active(): raise - except GitError as e: + except error.GitError as e: fetch_errors.append(e) logger.error("error.GitError: Cannot fetch %s", e) except Exception as e: @@ -3115,7 +3108,7 @@ later is required to fix a server side protocol bug. ) if not cls.is_multiprocessing_active(): raise - except GitError as e: + except error.GitError as e: checkout_errors.append(e) logger.error( "error.GitError: Cannot checkout %s: %s", @@ -3483,7 +3476,7 @@ def _PostRepoFetch(rp, repo_verify=True, verbose=False): wrapper = Wrapper() try: rev = rp.bare_git.describe(rp.GetRevisionId()) - except GitError: + except error.GitError: rev = None _, new_rev = wrapper.check_repo_rev( rp.gitdir, rev, repo_verify=repo_verify @@ -3501,10 +3494,10 @@ def _PostRepoFetch(rp, repo_verify=True, verbose=False): # Refresh index since reset --keep won't do it. rp.work_git.update_index("-q", "--refresh") rp.work_git.reset("--keep", new_rev) - except GitError as e: - raise RepoUnhandledExceptionError(e) + except error.GitError as e: + raise error.RepoUnhandledExceptionError(e) print("info: Restarting repo with latest version") - raise RepoChangedException(["--repo-upgraded"]) + raise error.RepoChangedException(["--repo-upgraded"]) else: logger.warning("warning: Skipped upgrade to unverified version") else: diff --git a/subcmds/upload.py b/subcmds/upload.py index 8b5ae96e2..79652f921 100644 --- a/subcmds/upload.py +++ b/subcmds/upload.py @@ -22,9 +22,7 @@ from typing import List from command import DEFAULT_LOCAL_JOBS from command import InteractiveCommand from editor import Editor -from error import GitError -from error import SilentRepoExitError -from error import UploadError +import error from git_refs import R_HEADS import git_superproject from hooks import RepoHook @@ -37,7 +35,7 @@ _DEFAULT_UNUSUAL_COMMIT_THRESHOLD = 5 logger = RepoLogger(__file__) -class UploadExitError(SilentRepoExitError): +class UploadExitError(error.SilentRepoExitError): """Indicates that there is an upload command error requiring a sys exit.""" @@ -671,7 +669,7 @@ Gerrit Code Review: https://www.gerritcodereview.com/ for branch in todo: try: self._UploadBranch(opt, branch, people) - except (UploadError, GitError) as e: + except (error.UploadError, error.GitError) as e: self.git_event_log.ErrorEvent(f"upload error: {e}") branch.error = e aggregate_errors.append(e) diff --git a/subcmds/wipe.py b/subcmds/wipe.py index 519386499..2b5a9b22e 100644 --- a/subcmds/wipe.py +++ b/subcmds/wipe.py @@ -17,13 +17,12 @@ import sys from typing import List from command import Command -from error import GitError -from error import RepoExitError +import error import platform_utils from project import DeleteWorktreeError -class Error(RepoExitError): +class Error(error.RepoExitError): """Exit error when wipe command fails.""" @@ -101,7 +100,7 @@ Examples: try: if project.HasChanges(): uncommitted_projects.append(project.name) - except GitError: + except error.GitError: uncommitted_projects.append(f"{project.name} (corrupted)") users = objdir_map.get(project.objdir, {project.relpath}) diff --git a/tests/test_project.py b/tests/test_project.py index 22732512d..4277136c7 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -2474,7 +2474,7 @@ class StatelessSyncTests(unittest.TestCase): proj.bare_ref.head = "refs/heads/topic" proj.work_git = mock.MagicMock() proj.work_git.GetHead.return_value = "refs/heads/topic" - proj.work_git.merge_base.side_effect = project.GitError("diverged") + proj.work_git.merge_base.side_effect = error.GitError("diverged") branch = mock.MagicMock() branch.name = "topic" branch.LocalMerge = "refs/remotes/origin/main" diff --git a/tests/test_repo_logging.py b/tests/test_repo_logging.py index c5bba6b8e..035e2035f 100644 --- a/tests/test_repo_logging.py +++ b/tests/test_repo_logging.py @@ -23,7 +23,7 @@ from unittest import mock import pytest from color import SetDefaultColoring -from error import RepoExitError +import error from repo_logging import RepoLogger @@ -32,7 +32,7 @@ def test_log_aggregated_errors_logs_aggregated_errors(mock_error) -> None: """Test if log_aggregated_errors logs a list of aggregated errors.""" logger = RepoLogger(__name__) logger.log_aggregated_errors( - RepoExitError( + error.RepoExitError( aggregate_errors=[ Exception("foo"), Exception("bar"), @@ -61,7 +61,7 @@ def test_log_aggregated_errors_logs_aggregated_errors(mock_error) -> None: def test_log_aggregated_errors_logs_single_error(mock_error) -> None: """Test if log_aggregated_errors logs empty aggregated_errors.""" logger = RepoLogger(__name__) - logger.log_aggregated_errors(RepoExitError()) + logger.log_aggregated_errors(error.RepoExitError()) mock_error.assert_has_calls( [ diff --git a/tests/test_subcmds_cherry_pick.py b/tests/test_subcmds_cherry_pick.py index b52efc86b..e454cb9e0 100644 --- a/tests/test_subcmds_cherry_pick.py +++ b/tests/test_subcmds_cherry_pick.py @@ -18,7 +18,7 @@ from unittest import mock import pytest -from error import GitError +import error from git_command import GitCommand from subcmds import cherry_pick @@ -64,7 +64,7 @@ def test_resolve_reference_rejects_missing_object( mock.create_autospec(GitCommand, return_value=command), ) - with pytest.raises(GitError, match="commit topic not found"): + with pytest.raises(error.GitError, match="commit topic not found"): cherry_pick.CherryPick()._ResolveReference("topic") @@ -81,5 +81,5 @@ def test_resolve_reference_rejects_ambiguous_object( mock.create_autospec(GitCommand, return_value=command), ) - with pytest.raises(GitError, match="commit topic not found"): + with pytest.raises(error.GitError, match="commit topic not found"): cherry_pick.CherryPick()._ResolveReference("topic") diff --git a/tests/test_subcmds_rebase.py b/tests/test_subcmds_rebase.py index a74aecbc7..201ecc516 100644 --- a/tests/test_subcmds_rebase.py +++ b/tests/test_subcmds_rebase.py @@ -19,7 +19,7 @@ import io from types import SimpleNamespace from unittest import mock -from error import GitError +import error from subcmds import rebase @@ -44,7 +44,7 @@ def test_resolve_onto_manifest_fallback() -> None: project.revisionExpr = "main" remote = mock.MagicMock() - remote.ToLocal.side_effect = GitError("Failed to resolve") + remote.ToLocal.side_effect = error.GitError("Failed to resolve") project.GetRemote.return_value = remote res = rebase._ResolveOntoManifest(project) diff --git a/tests/test_subcmds_sync.py b/tests/test_subcmds_sync.py index 4612331df..4c54a9fc8 100644 --- a/tests/test_subcmds_sync.py +++ b/tests/test_subcmds_sync.py @@ -31,9 +31,7 @@ import xmlrpc.server import pytest import command -from error import GitError -from error import ManifestParseError -from error import RepoExitError +import error import manifest_xml from project import SyncNetworkHalfResult from subcmds import sync @@ -1693,13 +1691,13 @@ class SyncCommand(unittest.TestCase): def test_command_exit_error(self): """Ensure unsuccessful commands raise expected errors.""" - self.sync_network_half_error = GitError( + self.sync_network_half_error = error.GitError( "sync_network_half_error error", project=self.project ) - self.sync_local_half_error = GitError( + self.sync_local_half_error = error.GitError( "sync_local_half_error", project=self.project ) - with self.assertRaises(RepoExitError) as e: + with self.assertRaises(error.RepoExitError) as e: self.cmd.Execute(self.opt, []) self.assertIn(self.sync_local_half_error, e.aggregate_errors) self.assertIn(self.sync_network_half_error, e.aggregate_errors) @@ -1751,7 +1749,7 @@ class SyncCommand(unittest.TestCase): p_foo_bar = FakeProject("foo/bar") p_foo.UseReprojectCmd = p_foo_bar.UseReprojectCmd = True self.cmd.GetProjects.return_value = [p_foo, p_foo_bar] - with self.assertRaises(sync.SyncError) as e: + with self.assertRaises(error.SyncError) as e: self._ExecuteUntilSync([]) self.assertIn("foo/bar", str(e.exception)) self.assertNotIn(" - foo\n", str(e.exception)) @@ -1762,7 +1760,7 @@ class SyncCommand(unittest.TestCase): p_sub = FakeProject("foo/sub", parent=p_foo, is_derived=True) p_foo.UseReprojectCmd = p_sub.UseReprojectCmd = True self.cmd.GetProjects.return_value = [p_foo, p_sub] - with self.assertRaises(sync.SyncError) as e: + with self.assertRaises(error.SyncError) as e: self._ExecuteUntilSync([]) self.assertIn("foo/sub", str(e.exception)) @@ -1774,7 +1772,7 @@ class SyncCommand(unittest.TestCase): self.cmd.GetProjects.side_effect = lambda args, **kwargs: ( [p_foo_bar] if args else [p_foo, p_foo_bar] ) - with self.assertRaises(sync.SyncError): + with self.assertRaises(error.SyncError): self._ExecuteUntilSync(["foo/bar"]) self.assertEqual(self.cmd.GetProjects.call_count, 2) _, kwargs = self.cmd.GetProjects.call_args @@ -1905,7 +1903,7 @@ class SyncCommand(unittest.TestCase): with mock.patch.object( self.cmd, "_SmartSyncSetup", - side_effect=ManifestParseError("mismatched tag"), + side_effect=error.ManifestParseError("mismatched tag"), ): with mock.patch.object(self.cmd, "_UpdateRepoProject"): with mock.patch.object( @@ -1926,9 +1924,9 @@ class SyncCommand(unittest.TestCase): with mock.patch.object( self.cmd, "_SmartSyncSetup", - side_effect=ManifestParseError("mismatched tag"), + side_effect=error.ManifestParseError("mismatched tag"), ): - with self.assertRaises(ManifestParseError): + with self.assertRaises(error.ManifestParseError): self.cmd.Execute(self.opt, []) def _ExecuteWithSmartSyncOverride( @@ -2050,7 +2048,7 @@ class SyncCommand(unittest.TestCase): self.opt.smart_sync = None self.opt.local_only = True path, _, _, update_mps = self._ExecuteWithSmartSyncOverride( - reload_error=ManifestParseError("mismatched tag") + reload_error=error.ManifestParseError("mismatched tag") ) self.manifest.ClearOverride.assert_called_once_with() self.assertFalse(os.path.isfile(path)) @@ -2147,7 +2145,7 @@ class SyncUpdateRepoProject(unittest.TestCase): self.manifest.repoProject.LastFetch = time.time() - ( sync._ONE_DAY_S + 1 ) - fetch_error = GitError("Fetch failed") + fetch_error = error.GitError("Fetch failed") self.manifest.repoProject.Sync_NetworkHalf.return_value = ( SyncNetworkHalfResult(False, fetch_error) ) @@ -2440,10 +2438,10 @@ class InterleavedSyncTest(unittest.TestCase): sub = self._make_syncable( FakeProject("foo", name="sub", objdir="b", path_prefix="sub") ) - sub.Sync_LocalHalf.side_effect = GitError("checkout failed") + sub.Sync_LocalHalf.side_effect = error.GitError("checkout failed") self.cmd.git_event_log = mock.MagicMock() - with self.assertRaises(sync.SyncError): + with self.assertRaises(error.SyncError): self._run_interleaved(opt, [outer, sub], [outer, sub]) self.assertEqual( @@ -2565,7 +2563,7 @@ class InterleavedSyncTest(unittest.TestCase): """Test _SyncProjectList with a failed fetch.""" opt = self._get_opts() project = self.projA - fetch_error = GitError("Fetch failed") + fetch_error = error.GitError("Fetch failed") project.Sync_NetworkHalf = mock.Mock( return_value=SyncNetworkHalfResult( error=fetch_error, remote_fetched=False @@ -2607,7 +2605,7 @@ class InterleavedSyncTest(unittest.TestCase): """Test _SyncProjectList with an exception during fetch.""" opt = self._get_opts() project = self.projA - fetch_error = GitError("Fetch failed") + fetch_error = error.GitError("Fetch failed") project.Sync_NetworkHalf = mock.Mock(side_effect=fetch_error) project.Sync_LocalHalf = mock.Mock() self.mock_context["projects"] = [project] @@ -2628,7 +2626,7 @@ class InterleavedSyncTest(unittest.TestCase): project.Sync_NetworkHalf = mock.Mock( return_value=SyncNetworkHalfResult(error=None, remote_fetched=True) ) - checkout_error = GitError("Checkout failed") + checkout_error = error.GitError("Checkout failed") project.Sync_LocalHalf = mock.Mock(side_effect=checkout_error) project.manifest.manifestProject.config = mock.MagicMock() self.mock_context["projects"] = [project] @@ -2886,7 +2884,7 @@ class SyncToSuperprojectRevTests(unittest.TestCase): mock_git.stdout = "invalid_content\n" mock_git_command.return_value = mock_git - with self.assertRaises(sync.SyncError) as e: + with self.assertRaises(error.SyncError) as e: self.cmd._SyncToSuperprojectRev( self.opt, self.manifest, self.mp, "name", self.errors ) @@ -2903,7 +2901,7 @@ class SyncToSuperprojectRevTests(unittest.TestCase): mock_git.stderr = "git error" mock_git_command.return_value = mock_git - with self.assertRaises(sync.SyncError) as e: + with self.assertRaises(error.SyncError) as e: self.cmd._SyncToSuperprojectRev( self.opt, self.manifest, self.mp, "name", self.errors ) @@ -2913,7 +2911,7 @@ class SyncToSuperprojectRevTests(unittest.TestCase): """Test error when superproject is not defined.""" self.manifest.superproject = None - with self.assertRaises(sync.SyncError) as e: + with self.assertRaises(error.SyncError) as e: self.cmd._SyncToSuperprojectRev( self.opt, self.manifest, self.mp, "name", self.errors ) @@ -2925,7 +2923,7 @@ class SyncToSuperprojectRevTests(unittest.TestCase): mock_superproject = self.manifest.superproject mock_superproject.Sync.return_value = mock.Mock(success=False) - with self.assertRaises(sync.SyncError) as e: + with self.assertRaises(error.SyncError) as e: self.cmd._SyncToSuperprojectRev( self.opt, self.manifest, self.mp, "name", self.errors ) @@ -3096,11 +3094,11 @@ class TestSmartSyncSetupRemoteHelper(unittest.TestCase): self.cmd._GetBranch = mock.MagicMock(return_value="main") self.cmd._ReloadManifest = mock.MagicMock( - side_effect=ManifestParseError("mismatched tag") + side_effect=error.ManifestParseError("mismatched tag") ) with mock.patch("builtins.open", mock.mock_open()): - with self.assertRaises(ManifestParseError): + with self.assertRaises(error.ManifestParseError): self.cmd._SmartSyncSetup( self.opt, self.smart_sync_manifest_path, self.manifest ) diff --git a/tests/test_subcmds_upload.py b/tests/test_subcmds_upload.py index 980520baf..187194933 100644 --- a/tests/test_subcmds_upload.py +++ b/tests/test_subcmds_upload.py @@ -19,8 +19,7 @@ from unittest import mock import pytest -from error import GitError -from error import UploadError +import error from subcmds import upload @@ -45,7 +44,9 @@ def cmd() -> upload.Upload: def test_UploadAndReport_UploadError(cmd: upload.Upload) -> None: """Check UploadExitError raised when UploadError encountered.""" opt, _ = cmd.OptionParser.parse_args([]) - with mock.patch.object(cmd, "_UploadBranch", side_effect=UploadError("")): + with mock.patch.object( + cmd, "_UploadBranch", side_effect=error.UploadError("") + ): with pytest.raises(upload.UploadExitError): cmd._UploadAndReport(opt, [mock.MagicMock()], _STUB_PEOPLE) @@ -53,7 +54,9 @@ def test_UploadAndReport_UploadError(cmd: upload.Upload) -> None: def test_UploadAndReport_GitError(cmd: upload.Upload) -> None: """Check UploadExitError raised when GitError encountered.""" opt, _ = cmd.OptionParser.parse_args([]) - with mock.patch.object(cmd, "_UploadBranch", side_effect=GitError("")): + with mock.patch.object( + cmd, "_UploadBranch", side_effect=error.GitError("") + ): with pytest.raises(upload.UploadExitError): cmd._UploadAndReport(opt, [mock.MagicMock()], _STUB_PEOPLE)