diff --git a/subcmds/abandon.py b/subcmds/abandon.py index 996c3d2c..f6c0c66c 100644 --- a/subcmds/abandon.py +++ b/subcmds/abandon.py @@ -15,7 +15,6 @@ import collections import functools import itertools -import sys from command import Command from command import DEFAULT_LOCAL_JOBS @@ -23,6 +22,10 @@ from error import RepoError from error import RepoExitError from git_command import git from progress import Progress +from repo_logging import RepoLogger + + +logger = RepoLogger(__file__) class AbandonError(RepoExitError): @@ -126,18 +129,12 @@ It is equivalent to "git branch -D ". if err: for br in err.keys(): err_msg = "error: cannot abandon %s" % br - print(err_msg, file=sys.stderr) + logger.error(err_msg) for proj in err[br]: - print( - " " * len(err_msg) + " | %s" % _RelPath(proj), - file=sys.stderr, - ) + logger.error(" " * len(err_msg) + " | %s", _RelPath(proj)) raise AbandonError(aggregate_errors=aggregate_errors) elif not success: - print( - "error: no project has local branch(es) : %s" % nb, - file=sys.stderr, - ) + logger.error("error: no project has local branch(es) : %s", nb) raise AbandonError(aggregate_errors=aggregate_errors) else: # Everything below here is displaying status. diff --git a/subcmds/checkout.py b/subcmds/checkout.py index 67f1838c..ea48263e 100644 --- a/subcmds/checkout.py +++ b/subcmds/checkout.py @@ -13,7 +13,6 @@ # limitations under the License. import functools -import sys from typing import NamedTuple from command import Command @@ -22,6 +21,10 @@ from error import GitError from error import RepoExitError from progress import Progress from project import Project +from repo_logging import RepoLogger + + +logger = RepoLogger(__file__) class CheckoutBranchResult(NamedTuple): @@ -99,12 +102,9 @@ The command is equivalent to: if err_projects: for p in err_projects: - print( - "error: %s/: cannot checkout %s" % (p.relpath, nb), - file=sys.stderr, - ) + logger.error("error: %s/: cannot checkout %s", p.relpath, nb) raise CheckoutCommandError(aggregate_errors=err) elif not success: msg = f"error: no project has branch {nb}" - print(msg, file=sys.stderr) + logger.error(msg) raise MissingBranchError(msg) diff --git a/subcmds/cherry_pick.py b/subcmds/cherry_pick.py index 980720eb..f9ae3e32 100644 --- a/subcmds/cherry_pick.py +++ b/subcmds/cherry_pick.py @@ -18,9 +18,11 @@ import sys from command import Command from error import GitError from git_command import GitCommand +from repo_logging import RepoLogger CHANGE_ID_RE = re.compile(r"^\s*Change-Id: I([0-9a-f]{40})\s*$") +logger = RepoLogger(__file__) class CherryPick(Command): @@ -52,7 +54,7 @@ change id will be added. try: p.Wait() except GitError: - print(p.stderr, file=sys.stderr) + logger.error(p.stderr) raise sha1 = p.stdout.strip() @@ -67,9 +69,7 @@ change id will be added. try: p.Wait() except GitError: - print( - "error: Failed to retrieve old commit message", file=sys.stderr - ) + logger.error("error: Failed to retrieve old commit message") raise old_msg = self._StripHeader(p.stdout) @@ -85,14 +85,13 @@ change id will be added. try: p.Wait() except GitError as e: - print(str(e)) - print( + logger.error(e) + logger.warn( "NOTE: When committing (please see above) and editing the " "commit message, please remove the old Change-Id-line and " - "add:" + "add:\n%s", + self._GetReference(sha1), ) - print(self._GetReference(sha1), file=sys.stderr) - print(file=sys.stderr) raise if p.stdout: @@ -115,10 +114,7 @@ change id will be added. try: p.Wait() except GitError: - print( - "error: Failed to update commit message", - file=sys.stderr, - ) + logger.error("error: Failed to update commit message") raise def _IsChangeId(self, line): diff --git a/subcmds/download.py b/subcmds/download.py index e33698e1..4396c9e7 100644 --- a/subcmds/download.py +++ b/subcmds/download.py @@ -19,9 +19,11 @@ from command import Command from error import GitError from error import NoSuchProjectError from error import RepoExitError +from repo_logging import RepoLogger CHANGE_RE = re.compile(r"^([1-9][0-9]*)(?:[/\.-]([1-9][0-9]*))?$") +logger = RepoLogger(__file__) class DownloadCommandError(RepoExitError): @@ -109,21 +111,16 @@ If no project is specified try to use current directory as a project. except NoSuchProjectError: project = None if project not in projects: - print( + logger.error( "error: %s matches too many projects; please " - "re-run inside the project checkout." % (a,), - file=sys.stderr, + "re-run inside the project checkout.", + a, ) for project in projects: - print( - " %s/ @ %s" - % ( - project.RelPath( - local=opt.this_manifest_only - ), - project.revisionExpr, - ), - file=sys.stderr, + logger.error( + " %s/ @ %s", + project.RelPath(local=opt.this_manifest_only), + project.revisionExpr, ) raise NoSuchProjectError() else: @@ -156,18 +153,21 @@ If no project is specified try to use current directory as a project. dl = project.DownloadPatchSet(change_id, ps_id) if not opt.revert and not dl.commits: - print( - "[%s] change %d/%d has already been merged" - % (project.name, change_id, ps_id), - file=sys.stderr, + logger.error( + "[%s] change %d/%d has already been merged", + project.name, + change_id, + ps_id, ) continue if len(dl.commits) > 1: - print( - "[%s] %d/%d depends on %d unmerged changes:" - % (project.name, change_id, ps_id, len(dl.commits)), - file=sys.stderr, + logger.error( + "[%s] %d/%d depends on %d unmerged changes:", + project.name, + change_id, + ps_id, + len(dl.commits), ) for c in dl.commits: print(" %s" % (c), file=sys.stderr) @@ -204,9 +204,10 @@ If no project is specified try to use current directory as a project. project._Checkout(dl.commit) except GitError: - print( - "[%s] Could not complete the %s of %s" - % (project.name, mode, dl.commit), - file=sys.stderr, + logger.error( + "[%s] Could not complete the %s of %s", + project.name, + mode, + dl.commit, ) raise diff --git a/subcmds/forall.py b/subcmds/forall.py index 9a02c49f..287f2e04 100644 --- a/subcmds/forall.py +++ b/subcmds/forall.py @@ -28,8 +28,10 @@ from command import DEFAULT_LOCAL_JOBS from command import MirrorSafeCommand from command import WORKER_BATCH_SIZE from error import ManifestInvalidRevisionError +from repo_logging import RepoLogger +logger = RepoLogger(__file__) _CAN_COLOR = [ "branch", "diff", @@ -293,10 +295,10 @@ without iterating through the remaining projects. rc = rc or errno.EINTR except Exception as e: # Catch any other exceptions raised - print( - "forall: unhandled error, terminating the pool: %s: %s" - % (type(e).__name__, e), - file=sys.stderr, + logger.error( + "forall: unhandled error, terminating the pool: %s: %s", + type(e).__name__, + e, ) rc = rc or getattr(e, "errno", 1) if rc != 0: diff --git a/subcmds/grep.py b/subcmds/grep.py index 19c06d4d..b677b6bd 100644 --- a/subcmds/grep.py +++ b/subcmds/grep.py @@ -24,6 +24,10 @@ from error import InvalidArgumentsError from error import SilentRepoExitError from git_command import GitCommand from project import Project +from repo_logging import RepoLogger + + +logger = RepoLogger(__file__) class GrepColoring(Coloring): @@ -371,7 +375,7 @@ contain a line that matches both expressions: if opt.revision: if "--cached" in cmd_argv: msg = "fatal: cannot combine --cached and --revision" - print(msg, file=sys.stderr) + logger.error(msg) raise InvalidArgumentsError(msg) have_rev = True cmd_argv.extend(opt.revision) @@ -396,5 +400,5 @@ contain a line that matches both expressions: sys.exit(0) elif have_rev and bad_rev: for r in opt.revision: - print("error: can't search revision %s" % r, file=sys.stderr) + logger.error("error: can't search revision %s", r) raise GrepCommandError(aggregate_errors=errors) diff --git a/subcmds/init.py b/subcmds/init.py index 529b212b..9ac42d8e 100644 --- a/subcmds/init.py +++ b/subcmds/init.py @@ -23,9 +23,12 @@ from error import UpdateManifestError from git_command import git_require from git_command import MIN_GIT_VERSION_HARD from git_command import MIN_GIT_VERSION_SOFT +from repo_logging import RepoLogger from wrapper import Wrapper +logger = RepoLogger(__file__) + _REPO_ALLOW_SHALLOW = os.environ.get("REPO_ALLOW_SHALLOW") @@ -330,11 +333,11 @@ to update the working directory files. def Execute(self, opt, args): git_require(MIN_GIT_VERSION_HARD, fail=True) if not git_require(MIN_GIT_VERSION_SOFT): - print( - "repo: warning: git-%s+ will soon be required; please upgrade " - "your version of git to maintain support." - % (".".join(str(x) for x in MIN_GIT_VERSION_SOFT),), - file=sys.stderr, + logger.warning( + "repo: warning: git-%s+ will soon be required; " + "please upgrade your version of git to maintain " + "support.", + ".".join(str(x) for x in MIN_GIT_VERSION_SOFT), ) rp = self.manifest.repoProject @@ -357,10 +360,7 @@ to update the working directory files. ) except wrapper.CloneFailure as e: err_msg = "fatal: double check your --repo-rev setting." - print( - err_msg, - file=sys.stderr, - ) + logger.error(err_msg) self.git_event_log.ErrorEvent(err_msg) raise RepoUnhandledExceptionError(e) diff --git a/subcmds/manifest.py b/subcmds/manifest.py index f72df348..101240d1 100644 --- a/subcmds/manifest.py +++ b/subcmds/manifest.py @@ -17,6 +17,10 @@ import os import sys from command import PagedCommand +from repo_logging import RepoLogger + + +logger = RepoLogger(__file__) class Manifest(PagedCommand): @@ -132,7 +136,7 @@ to indicate the remote ref to push changes to via 'repo upload'. manifest.SetUseLocalManifests(not opt.ignore_local_manifests) if opt.json: - print("warning: --json is experimental!", file=sys.stderr) + logger.warn("warning: --json is experimental!") doc = manifest.ToDict( peg_rev=opt.peg_rev, peg_rev_upstream=opt.peg_rev_upstream, @@ -159,13 +163,13 @@ to indicate the remote ref to push changes to via 'repo upload'. if output_file != "-": fd.close() if manifest.path_prefix: - print( - f"Saved {manifest.path_prefix} submanifest to " - f"{output_file}", - file=sys.stderr, + logger.warn( + "Saved %s submanifest to %s", + manifest.path_prefix, + output_file, ) else: - print(f"Saved manifest to {output_file}", file=sys.stderr) + logger.warn("Saved manifest to %s", output_file) def ValidateOptions(self, opt, args): if args: diff --git a/subcmds/rebase.py b/subcmds/rebase.py index c0e83adf..439557c2 100644 --- a/subcmds/rebase.py +++ b/subcmds/rebase.py @@ -17,6 +17,10 @@ import sys from color import Coloring from command import Command from git_command import GitCommand +from repo_logging import RepoLogger + + +logger = RepoLogger(__file__) class RebaseColoring(Coloring): @@ -104,17 +108,15 @@ branch but need to incorporate new upstream changes "underneath" them. one_project = len(all_projects) == 1 if opt.interactive and not one_project: - print( - "error: interactive rebase not supported with multiple " - "projects", - file=sys.stderr, + logger.error( + "error: interactive rebase not supported with multiple projects" ) + if len(args) == 1: - print( - "note: project %s is mapped to more than one path" - % (args[0],), - file=sys.stderr, + logger.warn( + "note: project %s is mapped to more than one path", args[0] ) + return 1 # Setup the common git rebase args that we use for all projects. @@ -145,10 +147,9 @@ branch but need to incorporate new upstream changes "underneath" them. cb = project.CurrentBranch if not cb: if one_project: - print( - "error: project %s has a detached HEAD" - % _RelPath(project), - file=sys.stderr, + logger.error( + "error: project %s has a detached HEAD", + _RelPath(project), ) return 1 # Ignore branches with detached HEADs. @@ -157,10 +158,9 @@ branch but need to incorporate new upstream changes "underneath" them. upbranch = project.GetBranch(cb) if not upbranch.LocalMerge: if one_project: - print( - "error: project %s does not track any remote branches" - % _RelPath(project), - file=sys.stderr, + logger.error( + "error: project %s does not track any remote branches", + _RelPath(project), ) return 1 # Ignore branches without remotes. diff --git a/subcmds/selfupdate.py b/subcmds/selfupdate.py index 51d963ee..72683097 100644 --- a/subcmds/selfupdate.py +++ b/subcmds/selfupdate.py @@ -13,15 +13,18 @@ # limitations under the License. import optparse -import sys from command import Command from command import MirrorSafeCommand from error import RepoExitError +from repo_logging import RepoLogger from subcmds.sync import _PostRepoFetch from subcmds.sync import _PostRepoUpgrade +logger = RepoLogger(__file__) + + class SelfupdateError(RepoExitError): """Exit error for failed selfupdate command.""" @@ -66,7 +69,7 @@ need to be performed by an end-user. else: result = rp.Sync_NetworkHalf() if result.error: - print("error: can't update repo", file=sys.stderr) + logger.error("error: can't update repo") raise SelfupdateError(aggregate_errors=[result.error]) rp.bare_git.gc("--auto") diff --git a/subcmds/stage.py b/subcmds/stage.py index 4d54eb19..92a00ea0 100644 --- a/subcmds/stage.py +++ b/subcmds/stage.py @@ -17,6 +17,10 @@ import sys from color import Coloring from command import InteractiveCommand from git_command import GitCommand +from repo_logging import RepoLogger + + +logger = RepoLogger(__file__) class _ProjectList(Coloring): @@ -62,7 +66,7 @@ The '%prog' command stages files to prepare the next commit. if p.IsDirty() ] if not all_projects: - print("no projects have uncommitted modifications", file=sys.stderr) + logger.error("no projects have uncommitted modifications") return out = _ProjectList(self.manifest.manifestProject.config) diff --git a/subcmds/upload.py b/subcmds/upload.py index ec89ad43..618a10e1 100644 --- a/subcmds/upload.py +++ b/subcmds/upload.py @@ -29,10 +29,12 @@ from git_command import GitCommand from git_refs import R_HEADS from hooks import RepoHook from project import ReviewableBranch +from repo_logging import RepoLogger from subcmds.sync import LocalSyncState _DEFAULT_UNUSUAL_COMMIT_THRESHOLD = 5 +logger = RepoLogger(__file__) class UploadExitError(SilentRepoExitError): @@ -70,16 +72,16 @@ def _VerifyPendingCommits(branches: List[ReviewableBranch]) -> bool: # If any branch has many commits, prompt the user. if many_commits: if len(branches) > 1: - print( + logger.warn( "ATTENTION: One or more branches has an unusually high number " "of commits." ) else: - print( + logger.warn( "ATTENTION: You are uploading an unusually high number of " "commits." ) - print( + logger.warn( "YOU PROBABLY DO NOT MEAN TO DO THIS. (Did you rebase across " "branches?)" ) @@ -93,7 +95,7 @@ def _VerifyPendingCommits(branches: List[ReviewableBranch]) -> bool: def _die(fmt, *args): msg = fmt % args - print("error: %s" % msg, file=sys.stderr) + logger.error("error: %s", msg) raise UploadExitError(msg) @@ -748,16 +750,13 @@ Gerrit Code Review: https://www.gerritcodereview.com/ for result in results: project, avail = result if avail is None: - print( + logger.error( 'repo: error: %s: Unable to upload branch "%s". ' "You might be able to fix the branch by running:\n" - " git branch --set-upstream-to m/%s" - % ( - project.RelPath(local=opt.this_manifest_only), - project.CurrentBranch, - project.manifest.branch, - ), - file=sys.stderr, + " git branch --set-upstream-to m/%s", + project.RelPath(local=opt.this_manifest_only), + project.CurrentBranch, + project.manifest.branch, ) elif avail: pending.append(result) @@ -772,14 +771,11 @@ Gerrit Code Review: https://www.gerritcodereview.com/ if not pending: if opt.branch is None: - print( - "repo: error: no branches ready for upload", file=sys.stderr - ) + logger.error("repo: error: no branches ready for upload") else: - print( - 'repo: error: no branches named "%s" ready for upload' - % (opt.branch,), - file=sys.stderr, + logger.error( + 'repo: error: no branches named "%s" ready for upload', + opt.branch, ) return 1 @@ -809,10 +805,9 @@ Gerrit Code Review: https://www.gerritcodereview.com/ project_list=pending_proj_names, worktree_list=pending_worktrees ): if LocalSyncState(manifest).IsPartiallySynced(): - print( + logger.error( "Partially synced tree detected. Syncing all projects " - "may resolve issues you're seeing.", - file=sys.stderr, + "may resolve issues you're seeing." ) ret = 1 if ret: