mirror of
https://gerrit.googlesource.com/git-repo
synced 2026-01-12 09:30:28 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
25858c8b16 | ||
|
|
52bab0ba27 | ||
|
|
2e6d0881d9 | ||
|
|
74edacd8e5 | ||
|
|
5d95ba8d85 | ||
|
|
82d500eb7a | ||
|
|
21269c3eed |
@@ -133,3 +133,43 @@ def main(project_list, worktree_list=None, **kwargs):
|
||||
kwargs: Leave this here for forward-compatibility.
|
||||
"""
|
||||
```
|
||||
|
||||
### post-sync
|
||||
|
||||
This hook runs when `repo sync` completes without errors.
|
||||
|
||||
Note: This includes cases where no actual checkout may occur. The hook will still run.
|
||||
For example:
|
||||
- `repo sync -n` performs network fetches only and skips the checkout phase.
|
||||
- `repo sync <project>` only updates the specified project(s).
|
||||
- Partial failures may still result in a successful exit.
|
||||
|
||||
This hook is useful for post-processing tasks such as setting up git hooks,
|
||||
bootstrapping configuration files, or running project initialization logic.
|
||||
|
||||
The hook is defined using the existing `<repo-hooks>` manifest block and is
|
||||
optional. If the hook script fails or is missing, `repo sync` will still
|
||||
complete successfully, and the error will be printed as a warning.
|
||||
|
||||
Example:
|
||||
|
||||
```xml
|
||||
<project name="myorg/dev-tools" path="tools" revision="main" />
|
||||
<repo-hooks in-project="myorg/dev-tools" enabled-list="post-sync">
|
||||
<hook name="post-sync" />
|
||||
</repo-hooks>
|
||||
```
|
||||
|
||||
The `post-sync.py` file should be defined like:
|
||||
|
||||
```py
|
||||
def main(repo_topdir=None, **kwargs):
|
||||
"""Main function invoked directly by repo.
|
||||
|
||||
We must use the name "main" as that is what repo requires.
|
||||
|
||||
Args:
|
||||
repo_topdir: The absolute path to the top-level directory of the repo workspace.
|
||||
kwargs: Leave this here for forward-compatibility.
|
||||
"""
|
||||
```
|
||||
|
||||
1
hooks.py
1
hooks.py
@@ -25,6 +25,7 @@ from git_refs import HEAD
|
||||
# The API we've documented to hook authors. Keep in sync with repo-hooks.md.
|
||||
_API_ARGS = {
|
||||
"pre-upload": {"project_list", "worktree_list"},
|
||||
"post-sync": {"repo_topdir"},
|
||||
}
|
||||
|
||||
|
||||
|
||||
10
progress.py
10
progress.py
@@ -101,6 +101,7 @@ class Progress:
|
||||
self._units = units
|
||||
self._elide = elide and _TTY
|
||||
self._quiet = quiet
|
||||
self._ended = False
|
||||
|
||||
# Only show the active jobs section if we run more than one in parallel.
|
||||
self._show_jobs = False
|
||||
@@ -118,6 +119,11 @@ class Progress:
|
||||
if not quiet and show_elapsed:
|
||||
self._update_thread.start()
|
||||
|
||||
def update_total(self, new_total):
|
||||
"""Updates the total if the new total is larger."""
|
||||
if new_total > self._total:
|
||||
self._total = new_total
|
||||
|
||||
def _update_loop(self):
|
||||
while True:
|
||||
self.update(inc=0)
|
||||
@@ -211,6 +217,10 @@ class Progress:
|
||||
self.update(inc=0)
|
||||
|
||||
def end(self):
|
||||
if self._ended:
|
||||
return
|
||||
self._ended = True
|
||||
|
||||
self._update_event.set()
|
||||
if not _TTY or IsTraceToStderr() or self._quiet:
|
||||
return
|
||||
|
||||
27
project.py
27
project.py
@@ -2061,10 +2061,7 @@ class Project:
|
||||
if head == revid:
|
||||
# Same revision; just update HEAD to point to the new
|
||||
# target branch, but otherwise take no other action.
|
||||
_lwrite(
|
||||
self.work_git.GetDotgitPath(subpath=HEAD),
|
||||
f"ref: {R_HEADS}{name}\n",
|
||||
)
|
||||
self.work_git.SetHead(R_HEADS + name)
|
||||
return True
|
||||
|
||||
GitCommand(
|
||||
@@ -2100,9 +2097,7 @@ class Project:
|
||||
|
||||
revid = self.GetRevisionId(all_refs)
|
||||
if head == revid:
|
||||
_lwrite(
|
||||
self.work_git.GetDotgitPath(subpath=HEAD), "%s\n" % revid
|
||||
)
|
||||
self.work_git.DetachHead(revid)
|
||||
else:
|
||||
self._Checkout(revid, quiet=True)
|
||||
GitCommand(
|
||||
@@ -3492,9 +3487,7 @@ class Project:
|
||||
self._createDotGit(dotgit)
|
||||
|
||||
if init_dotgit:
|
||||
_lwrite(
|
||||
os.path.join(self.gitdir, HEAD), f"{self.GetRevisionId()}\n"
|
||||
)
|
||||
self.work_git.UpdateRef(HEAD, self.GetRevisionId(), detach=True)
|
||||
|
||||
# Finish checking out the worktree.
|
||||
cmd = ["read-tree", "--reset", "-u", "-v", HEAD]
|
||||
@@ -3841,19 +3834,11 @@ class Project:
|
||||
|
||||
def GetHead(self):
|
||||
"""Return the ref that HEAD points to."""
|
||||
path = self.GetDotgitPath(subpath=HEAD)
|
||||
try:
|
||||
with open(path) as fd:
|
||||
line = fd.readline()
|
||||
except OSError as e:
|
||||
return self.rev_parse("--symbolic-full-name", HEAD)
|
||||
except GitError as e:
|
||||
path = self.GetDotgitPath(subpath=HEAD)
|
||||
raise NoManifestException(path, str(e))
|
||||
try:
|
||||
line = line.decode()
|
||||
except AttributeError:
|
||||
pass
|
||||
if line.startswith("ref: "):
|
||||
return line[5:-1]
|
||||
return line[:-1]
|
||||
|
||||
def SetHead(self, ref, message=None):
|
||||
cmdv = []
|
||||
|
||||
@@ -127,6 +127,7 @@ to update the working directory files.
|
||||
return {
|
||||
"REPO_MANIFEST_URL": "manifest_url",
|
||||
"REPO_MIRROR_LOCATION": "reference",
|
||||
"REPO_GIT_LFS": "git_lfs",
|
||||
}
|
||||
|
||||
def _SyncManifest(self, opt):
|
||||
|
||||
@@ -68,6 +68,7 @@ from git_config import GetUrlCookieFile
|
||||
from git_refs import HEAD
|
||||
from git_refs import R_HEADS
|
||||
import git_superproject
|
||||
from hooks import RepoHook
|
||||
import platform_utils
|
||||
from progress import elapsed_str
|
||||
from progress import jobs_str
|
||||
@@ -411,16 +412,18 @@ later is required to fix a server side protocol bug.
|
||||
type=int,
|
||||
metavar="JOBS",
|
||||
help="number of network jobs to run in parallel (defaults to "
|
||||
"--jobs or 1). Ignored when --interleaved is set",
|
||||
"--jobs or 1). Ignored unless --no-interleaved is set",
|
||||
)
|
||||
p.add_option(
|
||||
"--jobs-checkout",
|
||||
default=None,
|
||||
type=int,
|
||||
metavar="JOBS",
|
||||
help="number of local checkout jobs to run in parallel (defaults "
|
||||
f"to --jobs or {DEFAULT_LOCAL_JOBS}). Ignored when --interleaved "
|
||||
"is set",
|
||||
help=(
|
||||
"number of local checkout jobs to run in parallel (defaults "
|
||||
f"to --jobs or {DEFAULT_LOCAL_JOBS}). Ignored unless "
|
||||
"--no-interleaved is set"
|
||||
),
|
||||
)
|
||||
|
||||
p.add_option(
|
||||
@@ -479,7 +482,14 @@ later is required to fix a server side protocol bug.
|
||||
p.add_option(
|
||||
"--interleaved",
|
||||
action="store_true",
|
||||
help="fetch and checkout projects in parallel (experimental)",
|
||||
default=True,
|
||||
help="fetch and checkout projects in parallel (default)",
|
||||
)
|
||||
p.add_option(
|
||||
"--no-interleaved",
|
||||
dest="interleaved",
|
||||
action="store_false",
|
||||
help="fetch and checkout projects in phases",
|
||||
)
|
||||
p.add_option(
|
||||
"-n",
|
||||
@@ -623,6 +633,7 @@ later is required to fix a server side protocol bug.
|
||||
action="store_true",
|
||||
help=optparse.SUPPRESS_HELP,
|
||||
)
|
||||
RepoHook.AddOptionGroup(p, "post-sync")
|
||||
|
||||
def _GetBranch(self, manifest_project):
|
||||
"""Returns the branch name for getting the approved smartsync manifest.
|
||||
@@ -1847,6 +1858,21 @@ later is required to fix a server side protocol bug.
|
||||
except (KeyboardInterrupt, Exception) as e:
|
||||
raise RepoUnhandledExceptionError(e, aggregate_errors=errors)
|
||||
|
||||
# Run post-sync hook only after successful sync
|
||||
self._RunPostSyncHook(opt)
|
||||
|
||||
def _RunPostSyncHook(self, opt):
|
||||
"""Run post-sync hook if configured in manifest <repo-hooks>."""
|
||||
hook = RepoHook.FromSubcmd(
|
||||
hook_type="post-sync",
|
||||
manifest=self.manifest,
|
||||
opt=opt,
|
||||
abort_if_user_denies=False,
|
||||
)
|
||||
success = hook.Run(repo_topdir=self.client.topdir)
|
||||
if not success:
|
||||
print("Warning: post-sync hook reported failure.")
|
||||
|
||||
def _ExecuteHelper(self, opt, args, errors):
|
||||
manifest = self.outer_manifest
|
||||
if not opt.outer_manifest:
|
||||
@@ -2488,11 +2514,22 @@ later is required to fix a server side protocol bug.
|
||||
|
||||
pending_relpaths = {p.relpath for p in projects_to_sync}
|
||||
if previously_pending_relpaths == pending_relpaths:
|
||||
stalled_projects_str = "\n".join(
|
||||
f" - {path}"
|
||||
for path in sorted(list(pending_relpaths))
|
||||
)
|
||||
logger.error(
|
||||
"Stall detected in interleaved sync, not all "
|
||||
"projects could be synced."
|
||||
"The following projects failed and could not "
|
||||
"be synced:\n%s",
|
||||
stalled_projects_str,
|
||||
)
|
||||
err_event.set()
|
||||
|
||||
# Include these in the final error report.
|
||||
self._interleaved_err_checkout = True
|
||||
self._interleaved_err_checkout_results.extend(
|
||||
list(pending_relpaths)
|
||||
)
|
||||
break
|
||||
previously_pending_relpaths = pending_relpaths
|
||||
|
||||
@@ -2553,6 +2590,7 @@ later is required to fix a server side protocol bug.
|
||||
manifest=manifest,
|
||||
all_manifests=not opt.this_manifest_only,
|
||||
)
|
||||
pm.update_total(len(project_list))
|
||||
finally:
|
||||
sync_event.set()
|
||||
sync_progress_thread.join()
|
||||
|
||||
Reference in New Issue
Block a user