summaryrefslogtreecommitdiffstats
path: root/project.py
diff options
context:
space:
mode:
authorGavin Mak <gavinmak@google.com>2025-08-13 22:48:36 -0700
committerGavin Mak <gavinmak@google.com>2025-08-13 23:17:56 -0700
commita64149a7a77814132629bbb4c07d922c2222df25 (patch)
treebe39644559d35dab72d9f7d19e9115c0ccf3e1fd /project.py
parent3e6acf2778b533aedb2a1f6f6e3a3159e0b8c86d (diff)
downloadgit-repo-a64149a7a77814132629bbb4c07d922c2222df25.tar.gz
sync: Record and propagate errors from deferred actions
Failures in deferred sync actions were not recorded because `_Later.Run` discarded the `GitError` exception. Record the specific error using `syncbuf.fail()` and propagate it for proper error aggregation and reporting. Bug: 438178765 Change-Id: Iad59e389f9677bd6b8d873ee1ea2aa6ce44c86fa Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/498141 Tested-by: Gavin Mak <gavinmak@google.com> Reviewed-by: Scott Lee <ddoman@google.com>
Diffstat (limited to 'project.py')
-rw-r--r--project.py29
1 files changed, 19 insertions, 10 deletions
diff --git a/project.py b/project.py
index 9bfd4827..73263d93 100644
--- a/project.py
+++ b/project.py
@@ -1539,18 +1539,14 @@ class Project:
1539 force_checkout=False, 1539 force_checkout=False,
1540 force_rebase=False, 1540 force_rebase=False,
1541 submodules=False, 1541 submodules=False,
1542 errors=None,
1543 verbose=False, 1542 verbose=False,
1544 ): 1543 ):
1545 """Perform only the local IO portion of the sync process. 1544 """Perform only the local IO portion of the sync process.
1546 1545
1547 Network access is not required. 1546 Network access is not required.
1548 """ 1547 """
1549 if errors is None:
1550 errors = []
1551 1548
1552 def fail(error: Exception): 1549 def fail(error: Exception):
1553 errors.append(error)
1554 syncbuf.fail(self, error) 1550 syncbuf.fail(self, error)
1555 1551
1556 if not os.path.exists(self.gitdir): 1552 if not os.path.exists(self.gitdir):
@@ -4031,7 +4027,8 @@ class _Later:
4031 if not self.quiet: 4027 if not self.quiet:
4032 out.nl() 4028 out.nl()
4033 return True 4029 return True
4034 except GitError: 4030 except GitError as e:
4031 syncbuf.fail(self.project, e)
4035 out.nl() 4032 out.nl()
4036 return False 4033 return False
4037 4034
@@ -4047,7 +4044,12 @@ class _SyncColoring(Coloring):
4047class SyncBuffer: 4044class SyncBuffer:
4048 def __init__(self, config, detach_head=False): 4045 def __init__(self, config, detach_head=False):
4049 self._messages = [] 4046 self._messages = []
4050 self._failures = [] 4047
4048 # Failures that have not yet been printed. Cleared after printing.
4049 self._pending_failures = []
4050 # A persistent record of all failures during the buffer's lifetime.
4051 self._all_failures = []
4052
4051 self._later_queue1 = [] 4053 self._later_queue1 = []
4052 self._later_queue2 = [] 4054 self._later_queue2 = []
4053 4055
@@ -4062,7 +4064,9 @@ class SyncBuffer:
4062 self._messages.append(_InfoMessage(project, fmt % args)) 4064 self._messages.append(_InfoMessage(project, fmt % args))
4063 4065
4064 def fail(self, project, err=None): 4066 def fail(self, project, err=None):
4065 self._failures.append(_Failure(project, err)) 4067 failure = _Failure(project, err)
4068 self._pending_failures.append(failure)
4069 self._all_failures.append(failure)
4066 self._MarkUnclean() 4070 self._MarkUnclean()
4067 4071
4068 def later1(self, project, what, quiet): 4072 def later1(self, project, what, quiet):
@@ -4082,6 +4086,11 @@ class SyncBuffer:
4082 self.recent_clean = True 4086 self.recent_clean = True
4083 return recent_clean 4087 return recent_clean
4084 4088
4089 @property
4090 def errors(self):
4091 """Returns a list of all exceptions accumulated in the buffer."""
4092 return [f.why for f in self._all_failures if f.why]
4093
4085 def _MarkUnclean(self): 4094 def _MarkUnclean(self):
4086 self.clean = False 4095 self.clean = False
4087 self.recent_clean = False 4096 self.recent_clean = False
@@ -4100,18 +4109,18 @@ class SyncBuffer:
4100 return True 4109 return True
4101 4110
4102 def _PrintMessages(self): 4111 def _PrintMessages(self):
4103 if self._messages or self._failures: 4112 if self._messages or self._pending_failures:
4104 if os.isatty(2): 4113 if os.isatty(2):
4105 self.out.write(progress.CSI_ERASE_LINE) 4114 self.out.write(progress.CSI_ERASE_LINE)
4106 self.out.write("\r") 4115 self.out.write("\r")
4107 4116
4108 for m in self._messages: 4117 for m in self._messages:
4109 m.Print(self) 4118 m.Print(self)
4110 for m in self._failures: 4119 for m in self._pending_failures:
4111 m.Print(self) 4120 m.Print(self)
4112 4121
4113 self._messages = [] 4122 self._messages = []
4114 self._failures = [] 4123 self._pending_failures = []
4115 4124
4116 4125
4117class MetaProject(Project): 4126class MetaProject(Project):