mirror of
https://gerrit.googlesource.com/git-repo
synced 2026-07-16 13:47:03 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 978adb7ea5 | |||
| 0398c6718e | |||
| 3bb4871c44 |
@@ -84,9 +84,14 @@ def _Color(fg=None, bg=None, attr=None):
|
||||
|
||||
DEFAULT = None
|
||||
|
||||
|
||||
class _CheckConsoleSentinel:
|
||||
"""Sentinel for checking console coloring."""
|
||||
|
||||
|
||||
# Placholder value that indicates we need to check if the user is in an
|
||||
# interactive terminal session to determine if we turn on color or not.
|
||||
_CHECK_CONSOLE = object()
|
||||
_CHECK_CONSOLE = _CheckConsoleSentinel()
|
||||
|
||||
# https://git-scm.com/docs/git-config#Documentation/git-config.txt-colorui
|
||||
_CONFIG_TO_COLOR_SETTING = {
|
||||
|
||||
+16
-4
@@ -17,6 +17,7 @@ import multiprocessing
|
||||
import optparse
|
||||
import os
|
||||
import re
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from error import InvalidProjectGroupsError
|
||||
from error import NoSuchProjectError
|
||||
@@ -25,6 +26,10 @@ from event_log import EventLog
|
||||
import progress
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from project import Project
|
||||
|
||||
|
||||
# Are we generating man-pages?
|
||||
GENERATE_MANPAGES = os.environ.get("_REPO_GENERATE_MANPAGES_") == " indeed! "
|
||||
|
||||
@@ -375,7 +380,7 @@ class Command:
|
||||
manifest=None,
|
||||
groups="",
|
||||
missing_ok=False,
|
||||
submodules_ok=False,
|
||||
submodules_ok=None,
|
||||
all_manifests=False,
|
||||
):
|
||||
"""A list of projects that match the arguments.
|
||||
@@ -385,7 +390,9 @@ class Command:
|
||||
manifest: an XmlManifest, the manifest to use, or None for default.
|
||||
groups: a string, the manifest groups in use.
|
||||
missing_ok: a boolean, whether to allow missing projects.
|
||||
submodules_ok: a boolean, whether to allow submodules.
|
||||
submodules_ok: whether to allow submodules. True allows them for
|
||||
all projects, False disallows them for all projects, and None
|
||||
defers to each project's sync-s setting.
|
||||
all_manifests: a boolean, if True then all manifests and
|
||||
submanifests are used. If False, then only the local
|
||||
(sub)manifest is used.
|
||||
@@ -403,6 +410,11 @@ class Command:
|
||||
all_projects_list = manifest.projects
|
||||
result = []
|
||||
|
||||
def should_include_submodules(project: "Project") -> bool:
|
||||
if submodules_ok is None:
|
||||
return project.sync_s
|
||||
return submodules_ok
|
||||
|
||||
if not groups:
|
||||
groups = manifest.GetManifestGroupsStr()
|
||||
groups = [x for x in re.split(r"[,\s]+", groups) if x]
|
||||
@@ -410,7 +422,7 @@ class Command:
|
||||
if not args:
|
||||
derived_projects = {}
|
||||
for project in all_projects_list:
|
||||
if submodules_ok or project.sync_s:
|
||||
if should_include_submodules(project):
|
||||
derived_projects.update(
|
||||
(p.RelPath(local=False), p)
|
||||
for p in project.GetDerivedSubprojects()
|
||||
@@ -452,7 +464,7 @@ class Command:
|
||||
if (
|
||||
project
|
||||
and not project.Derived
|
||||
and (submodules_ok or project.sync_s)
|
||||
and should_include_submodules(project)
|
||||
):
|
||||
search_again = False
|
||||
for subproject in project.GetDerivedSubprojects():
|
||||
|
||||
@@ -323,6 +323,7 @@ _repo() {
|
||||
'(-u --manifest-server-username)'{-u,--manifest-server-username=}'[Username for manifest server]:username:' \
|
||||
'(-p --manifest-server-password)'{-p,--manifest-server-password=}'[Password for manifest server]:password:' \
|
||||
'--fetch-submodules[Fetch submodules]' \
|
||||
'--no-fetch-submodules[Do not fetch submodules]' \
|
||||
'--use-superproject[Use superproject]' \
|
||||
'--no-use-superproject[Do not use superproject]' \
|
||||
'--tags[Sync tags]' \
|
||||
|
||||
@@ -83,6 +83,9 @@ password to authenticate with the manifest server
|
||||
\fB\-\-fetch\-submodules\fR
|
||||
fetch submodules from server
|
||||
.TP
|
||||
\fB\-\-no\-fetch\-submodules\fR
|
||||
don't fetch submodules from server
|
||||
.TP
|
||||
\fB\-\-use\-superproject\fR
|
||||
use the manifest superproject to sync projects; implies \fB\-c\fR
|
||||
.TP
|
||||
|
||||
+7
-3
@@ -1,5 +1,5 @@
|
||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||
.TH REPO "1" "June 2026" "repo sync" "Repo Manual"
|
||||
.TH REPO "1" "July 2026" "repo sync" "Repo Manual"
|
||||
.SH NAME
|
||||
repo \- repo sync - manual page for repo sync
|
||||
.SH SYNOPSIS
|
||||
@@ -83,6 +83,9 @@ password to authenticate with the manifest server
|
||||
\fB\-\-fetch\-submodules\fR
|
||||
fetch submodules from server
|
||||
.TP
|
||||
\fB\-\-no\-fetch\-submodules\fR
|
||||
don't fetch submodules from server
|
||||
.TP
|
||||
\fB\-\-use\-superproject\fR
|
||||
use the manifest superproject to sync projects; implies \fB\-c\fR
|
||||
.TP
|
||||
@@ -212,8 +215,9 @@ bootstrap a new Git repository from a resumeable bundle file on a content
|
||||
delivery network. This may be necessary if there are problems with the local
|
||||
Python HTTP client or proxy configuration, but the Git binary works.
|
||||
.PP
|
||||
The \fB\-\-fetch\-submodules\fR option enables fetching Git submodules of a project from
|
||||
server.
|
||||
The \fB\-\-fetch\-submodules\fR option enables fetching Git submodules of all projects
|
||||
from the server. The \fB\-\-no\-fetch\-submodules\fR option disables fetching Git
|
||||
submodules, even when a project has sync\-s="true" in the manifest.
|
||||
.PP
|
||||
The \fB\-c\fR/\-\-current\-branch option can be used to only fetch objects that are on the
|
||||
branch specified by a project's revision.
|
||||
|
||||
+14
-1
@@ -16,7 +16,9 @@ import sys
|
||||
|
||||
from color import Coloring
|
||||
from command import Command
|
||||
from error import GitError
|
||||
from git_command import GitCommand
|
||||
from project import Project
|
||||
from repo_logging import RepoLogger
|
||||
|
||||
|
||||
@@ -30,6 +32,17 @@ class RebaseColoring(Coloring):
|
||||
self.fail = self.printer("fail", fg="red")
|
||||
|
||||
|
||||
def _ResolveOntoManifest(project: Project) -> str:
|
||||
"""Resolve project's revisionExpr to a local tracking branch.
|
||||
|
||||
Falls back to the raw revisionExpr if ToLocal fails or raises GitError.
|
||||
"""
|
||||
try:
|
||||
return project.GetRemote().ToLocal(project.revisionExpr)
|
||||
except GitError:
|
||||
return project.revisionExpr
|
||||
|
||||
|
||||
class Rebase(Command):
|
||||
COMMON = True
|
||||
helpSummary = "Rebase local branches on upstream branch"
|
||||
@@ -162,7 +175,7 @@ branch but need to incorporate new upstream changes "underneath" them.
|
||||
args = common_args[:]
|
||||
if opt.onto_manifest:
|
||||
args.append("--onto")
|
||||
args.append(project.revisionExpr)
|
||||
args.append(_ResolveOntoManifest(project))
|
||||
|
||||
args.append(upbranch.LocalMerge)
|
||||
|
||||
|
||||
+8
-1
@@ -379,7 +379,8 @@ may be necessary if there are problems with the local Python
|
||||
HTTP client or proxy configuration, but the Git binary works.
|
||||
|
||||
The --fetch-submodules option enables fetching Git submodules
|
||||
of a project from server.
|
||||
of all projects from the server. The --no-fetch-submodules option disables
|
||||
fetching Git submodules, even when a project has sync-s="true" in the manifest.
|
||||
|
||||
The -c/--current-branch option can be used to only fetch objects that
|
||||
are on the branch specified by a project's revision.
|
||||
@@ -573,6 +574,12 @@ later is required to fix a server side protocol bug.
|
||||
action="store_true",
|
||||
help="fetch submodules from server",
|
||||
)
|
||||
p.add_option(
|
||||
"--no-fetch-submodules",
|
||||
dest="fetch_submodules",
|
||||
action="store_false",
|
||||
help="don't fetch submodules from server",
|
||||
)
|
||||
p.add_option(
|
||||
"--use-superproject",
|
||||
action="store_true",
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
"""Unittests for the command.py module."""
|
||||
|
||||
import pytest
|
||||
|
||||
from command import Command
|
||||
|
||||
|
||||
@@ -86,3 +88,32 @@ def test_get_projects_keeps_derived_subprojects_for_repeated_repo():
|
||||
projects = cmd.GetProjects([])
|
||||
|
||||
assert set(projects) == {project_a, project_b, submodule_a, submodule_b}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"submodules_ok, sync_s, includes_submodule",
|
||||
[
|
||||
(None, False, False),
|
||||
(None, True, True),
|
||||
(True, False, True),
|
||||
(True, True, True),
|
||||
(False, False, False),
|
||||
(False, True, False),
|
||||
],
|
||||
)
|
||||
def test_get_projects_submodule_override(
|
||||
submodules_ok, sync_s, includes_submodule
|
||||
):
|
||||
"""The CLI override takes precedence over a project's sync-s setting."""
|
||||
submodule = FakeProject("submodule", "project/submodule")
|
||||
project = FakeProject(
|
||||
"project",
|
||||
"project",
|
||||
derived_subprojects=[submodule],
|
||||
sync_s=sync_s,
|
||||
)
|
||||
cmd = Command(manifest=FakeManifest([project]))
|
||||
|
||||
projects = cmd.GetProjects([], submodules_ok=submodules_ok)
|
||||
|
||||
assert (submodule in projects) is includes_submodule
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
# Copyright (C) 2026 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Unittests for the subcmds/rebase.py module."""
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from error import GitError
|
||||
from subcmds import rebase
|
||||
|
||||
|
||||
def test_resolve_onto_manifest_success() -> None:
|
||||
"""Test _ResolveOntoManifest when ToLocal succeeds."""
|
||||
project = mock.MagicMock()
|
||||
project.revisionExpr = "main"
|
||||
|
||||
remote = mock.MagicMock()
|
||||
remote.ToLocal.return_value = "refs/remotes/goog/main"
|
||||
project.GetRemote.return_value = remote
|
||||
|
||||
res = rebase._ResolveOntoManifest(project)
|
||||
assert res == "refs/remotes/goog/main"
|
||||
project.GetRemote.assert_called_once()
|
||||
remote.ToLocal.assert_called_once_with("main")
|
||||
|
||||
|
||||
def test_resolve_onto_manifest_fallback() -> None:
|
||||
"""Test _ResolveOntoManifest when ToLocal raises GitError."""
|
||||
project = mock.MagicMock()
|
||||
project.revisionExpr = "main"
|
||||
|
||||
remote = mock.MagicMock()
|
||||
remote.ToLocal.side_effect = GitError("Failed to resolve")
|
||||
project.GetRemote.return_value = remote
|
||||
|
||||
res = rebase._ResolveOntoManifest(project)
|
||||
assert res == "main"
|
||||
project.GetRemote.assert_called_once()
|
||||
remote.ToLocal.assert_called_once_with("main")
|
||||
@@ -30,6 +30,23 @@ from project import SyncNetworkHalfResult
|
||||
from subcmds import sync
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"cli_args, expected",
|
||||
[
|
||||
([], None),
|
||||
(["--fetch-submodules"], True),
|
||||
(["--no-fetch-submodules"], False),
|
||||
],
|
||||
)
|
||||
def test_fetch_submodules_option(cli_args, expected):
|
||||
"""The fetch-submodules flags preserve an unset manifest-driven state."""
|
||||
cmd = sync.Sync()
|
||||
|
||||
opts, _ = cmd.OptionParser.parse_args(cli_args)
|
||||
|
||||
assert opts.fetch_submodules is expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"use_superproject, cli_args, result",
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user