mirror of
https://gerrit.googlesource.com/git-repo
synced 2025-06-30 20:17:08 +00:00
Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
c657844efe | |||
1d3b4fbeec | |||
be71c2f80f | |||
696e0c48a9 | |||
b2263ba124 | |||
945c006f40 | |||
71122f941f | |||
07a4529278 | |||
17833322d9 |
@ -8,7 +8,7 @@ that you can put anywhere in your path.
|
|||||||
|
|
||||||
* Homepage: <https://gerrit.googlesource.com/git-repo/>
|
* Homepage: <https://gerrit.googlesource.com/git-repo/>
|
||||||
* Mailing list: [repo-discuss on Google Groups][repo-discuss]
|
* Mailing list: [repo-discuss on Google Groups][repo-discuss]
|
||||||
* Bug reports: <https://bugs.chromium.org/p/gerrit/issues/list?q=component:Applications%3Erepo>
|
* Bug reports: <https://issues.gerritcodereview.com/issues?q=is:open%20componentid:1370071>
|
||||||
* Source: <https://gerrit.googlesource.com/git-repo/>
|
* Source: <https://gerrit.googlesource.com/git-repo/>
|
||||||
* Overview: <https://source.android.com/source/developing.html>
|
* Overview: <https://source.android.com/source/developing.html>
|
||||||
* Docs: <https://source.android.com/source/using-repo.html>
|
* Docs: <https://source.android.com/source/using-repo.html>
|
||||||
@ -50,6 +50,6 @@ $ chmod a+rx ~/.bin/repo
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
[new-bug]: https://bugs.chromium.org/p/gerrit/issues/entry?template=Repo+tool+issue
|
[new-bug]: https://issues.gerritcodereview.com/issues/new?component=1370071
|
||||||
[issue tracker]: https://bugs.chromium.org/p/gerrit/issues/list?q=component:Applications%3Erepo
|
[issue tracker]: https://issues.gerritcodereview.com/issues?q=is:open%20componentid:1370071
|
||||||
[repo-discuss]: https://groups.google.com/forum/#!forum/repo-discuss
|
[repo-discuss]: https://groups.google.com/forum/#!forum/repo-discuss
|
||||||
|
@ -109,7 +109,8 @@ following DTD:
|
|||||||
<!ATTLIST extend-project upstream CDATA #IMPLIED>
|
<!ATTLIST extend-project upstream CDATA #IMPLIED>
|
||||||
|
|
||||||
<!ELEMENT remove-project EMPTY>
|
<!ELEMENT remove-project EMPTY>
|
||||||
<!ATTLIST remove-project name CDATA #REQUIRED>
|
<!ATTLIST remove-project name CDATA #IMPLIED>
|
||||||
|
<!ATTLIST remove-project path CDATA #IMPLIED>
|
||||||
<!ATTLIST remove-project optional CDATA #IMPLIED>
|
<!ATTLIST remove-project optional CDATA #IMPLIED>
|
||||||
|
|
||||||
<!ELEMENT repo-hooks EMPTY>
|
<!ELEMENT repo-hooks EMPTY>
|
||||||
@ -473,7 +474,7 @@ of the repo client.
|
|||||||
|
|
||||||
### Element remove-project
|
### Element remove-project
|
||||||
|
|
||||||
Deletes the named project from the internal manifest table, possibly
|
Deletes a project from the internal manifest table, possibly
|
||||||
allowing a subsequent project element in the same manifest file to
|
allowing a subsequent project element in the same manifest file to
|
||||||
replace the project with a different source.
|
replace the project with a different source.
|
||||||
|
|
||||||
@ -481,6 +482,17 @@ This element is mostly useful in a local manifest file, where
|
|||||||
the user can remove a project, and possibly replace it with their
|
the user can remove a project, and possibly replace it with their
|
||||||
own definition.
|
own definition.
|
||||||
|
|
||||||
|
The project `name` or project `path` can be used to specify the remove target
|
||||||
|
meaning one of them is required. If only name is specified, all
|
||||||
|
projects with that name are removed.
|
||||||
|
|
||||||
|
If both name and path are specified, only projects with the same name and
|
||||||
|
path are removed, meaning projects with the same name but in other
|
||||||
|
locations are kept.
|
||||||
|
|
||||||
|
If only path is specified, a matching project is removed regardless of its
|
||||||
|
name. Logic otherwise behaves like both are specified.
|
||||||
|
|
||||||
Attribute `optional`: Set to true to ignore remove-project elements with no
|
Attribute `optional`: Set to true to ignore remove-project elements with no
|
||||||
matching `project` element.
|
matching `project` element.
|
||||||
|
|
||||||
|
33
main.py
33
main.py
@ -25,6 +25,7 @@ import netrc
|
|||||||
import optparse
|
import optparse
|
||||||
import os
|
import os
|
||||||
import shlex
|
import shlex
|
||||||
|
import signal
|
||||||
import sys
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
import time
|
import time
|
||||||
@ -95,6 +96,7 @@ else:
|
|||||||
file=sys.stderr,
|
file=sys.stderr,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
KEYBOARD_INTERRUPT_EXIT = 128 + signal.SIGINT
|
||||||
|
|
||||||
global_options = optparse.OptionParser(
|
global_options = optparse.OptionParser(
|
||||||
usage="repo [-p|--paginate|--no-pager] COMMAND [ARGS]",
|
usage="repo [-p|--paginate|--no-pager] COMMAND [ARGS]",
|
||||||
@ -374,7 +376,11 @@ class _Repo(object):
|
|||||||
git_trace2_event_log.StartEvent()
|
git_trace2_event_log.StartEvent()
|
||||||
git_trace2_event_log.CommandEvent(name="repo", subcommands=[name])
|
git_trace2_event_log.CommandEvent(name="repo", subcommands=[name])
|
||||||
|
|
||||||
try:
|
def execute_command_helper():
|
||||||
|
"""
|
||||||
|
Execute the subcommand.
|
||||||
|
"""
|
||||||
|
nonlocal result
|
||||||
cmd.CommonValidateOptions(copts, cargs)
|
cmd.CommonValidateOptions(copts, cargs)
|
||||||
cmd.ValidateOptions(copts, cargs)
|
cmd.ValidateOptions(copts, cargs)
|
||||||
|
|
||||||
@ -409,6 +415,23 @@ class _Repo(object):
|
|||||||
if hasattr(copts, "manifest_branch"):
|
if hasattr(copts, "manifest_branch"):
|
||||||
child_argv.extend(["--manifest-branch", spec.revision])
|
child_argv.extend(["--manifest-branch", spec.revision])
|
||||||
result = self._Run(name, gopts, child_argv) or result
|
result = self._Run(name, gopts, child_argv) or result
|
||||||
|
|
||||||
|
def execute_command():
|
||||||
|
"""
|
||||||
|
Execute the command and log uncaught exceptions.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
execute_command_helper()
|
||||||
|
except (KeyboardInterrupt, SystemExit, Exception) as e:
|
||||||
|
ok = isinstance(e, SystemExit) and not e.code
|
||||||
|
if not ok:
|
||||||
|
exception_name = type(e).__name__
|
||||||
|
git_trace2_event_log.ErrorEvent(
|
||||||
|
f"RepoExitError:{exception_name}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
try:
|
||||||
|
execute_command()
|
||||||
except (
|
except (
|
||||||
DownloadError,
|
DownloadError,
|
||||||
ManifestInvalidRevisionError,
|
ManifestInvalidRevisionError,
|
||||||
@ -448,6 +471,12 @@ class _Repo(object):
|
|||||||
if e.code:
|
if e.code:
|
||||||
result = e.code
|
result = e.code
|
||||||
raise
|
raise
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
result = KEYBOARD_INTERRUPT_EXIT
|
||||||
|
raise
|
||||||
|
except Exception:
|
||||||
|
result = 1
|
||||||
|
raise
|
||||||
finally:
|
finally:
|
||||||
finish = time.time()
|
finish = time.time()
|
||||||
elapsed = finish - start
|
elapsed = finish - start
|
||||||
@ -813,7 +842,7 @@ def _Main(argv):
|
|||||||
result = repo._Run(name, gopts, argv) or 0
|
result = repo._Run(name, gopts, argv) or 0
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print("aborted by user", file=sys.stderr)
|
print("aborted by user", file=sys.stderr)
|
||||||
result = 1
|
result = KEYBOARD_INTERRUPT_EXIT
|
||||||
except ManifestParseError as mpe:
|
except ManifestParseError as mpe:
|
||||||
print("fatal: %s" % mpe, file=sys.stderr)
|
print("fatal: %s" % mpe, file=sys.stderr)
|
||||||
result = 1
|
result = 1
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
.TH REPO "1" "November 2022" "repo" "Repo Manual"
|
.TH REPO "1" "June 2023" "repo" "Repo Manual"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
repo \- repository management tool built on top of git
|
repo \- repository management tool built on top of git
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@ -137,4 +137,4 @@ version
|
|||||||
Display the version of repo
|
Display the version of repo
|
||||||
.PP
|
.PP
|
||||||
See 'repo help <command>' for more information on a specific command.
|
See 'repo help <command>' for more information on a specific command.
|
||||||
Bug reports: https://bugs.chromium.org/p/gerrit/issues/entry?template=Repo+tool+issue
|
Bug reports: https://issues.gerritcodereview.com/issues/new?component=1370071
|
||||||
|
@ -981,6 +981,12 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
|
|||||||
return self.manifestProject.clone_filter
|
return self.manifestProject.clone_filter
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def CloneFilterForDepth(self):
|
||||||
|
if self.manifestProject.clone_filter_for_depth:
|
||||||
|
return self.manifestProject.clone_filter_for_depth
|
||||||
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def PartialCloneExclude(self):
|
def PartialCloneExclude(self):
|
||||||
exclude = self.manifest.manifestProject.partial_clone_exclude or ""
|
exclude = self.manifest.manifestProject.partial_clone_exclude or ""
|
||||||
@ -1529,22 +1535,45 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
|
|||||||
self._contactinfo = ContactInfo(bugurl)
|
self._contactinfo = ContactInfo(bugurl)
|
||||||
|
|
||||||
if node.nodeName == "remove-project":
|
if node.nodeName == "remove-project":
|
||||||
name = self._reqatt(node, "name")
|
name = node.getAttribute("name")
|
||||||
|
path = node.getAttribute("path")
|
||||||
|
|
||||||
if name in self._projects:
|
# Name or path needed.
|
||||||
for p in self._projects[name]:
|
if not name and not path:
|
||||||
|
raise ManifestParseError(
|
||||||
|
"remove-project must have name and/or path"
|
||||||
|
)
|
||||||
|
|
||||||
|
removed_project = ""
|
||||||
|
|
||||||
|
# Find and remove projects based on name and/or path.
|
||||||
|
for projname, projects in list(self._projects.items()):
|
||||||
|
for p in projects:
|
||||||
|
if name == projname and not path:
|
||||||
del self._paths[p.relpath]
|
del self._paths[p.relpath]
|
||||||
|
if not removed_project:
|
||||||
del self._projects[name]
|
del self._projects[name]
|
||||||
|
removed_project = name
|
||||||
|
elif path == p.relpath and (
|
||||||
|
name == projname or not name
|
||||||
|
):
|
||||||
|
self._projects[projname].remove(p)
|
||||||
|
del self._paths[p.relpath]
|
||||||
|
removed_project = p.name
|
||||||
|
|
||||||
# If the manifest removes the hooks project, treat it as if
|
# If the manifest removes the hooks project, treat it as if
|
||||||
# it deleted
|
# it deleted the repo-hooks element too.
|
||||||
# the repo-hooks element too.
|
if (
|
||||||
if repo_hooks_project == name:
|
removed_project
|
||||||
|
and removed_project not in self._projects
|
||||||
|
and repo_hooks_project == removed_project
|
||||||
|
):
|
||||||
repo_hooks_project = None
|
repo_hooks_project = None
|
||||||
elif not XmlBool(node, "optional", False):
|
|
||||||
|
if not removed_project and not XmlBool(node, "optional", False):
|
||||||
raise ManifestParseError(
|
raise ManifestParseError(
|
||||||
"remove-project element specifies non-existent "
|
"remove-project element specifies non-existent "
|
||||||
"project: %s" % name
|
"project: %s" % node.toxml()
|
||||||
)
|
)
|
||||||
|
|
||||||
# Store repo hooks project information.
|
# Store repo hooks project information.
|
||||||
|
5
pager.py
5
pager.py
@ -118,7 +118,10 @@ def _BecomePager(pager):
|
|||||||
# available versions of 'less', a better 'more'.
|
# available versions of 'less', a better 'more'.
|
||||||
_a, _b, _c = select.select([0], [], [0])
|
_a, _b, _c = select.select([0], [], [0])
|
||||||
|
|
||||||
os.environ["LESS"] = "FRSX"
|
# This matches the behavior of git, which sets $LESS to `FRX` if it is not
|
||||||
|
# set. See:
|
||||||
|
# https://git-scm.com/docs/git-config#Documentation/git-config.txt-corepager
|
||||||
|
os.environ.setdefault("LESS", "FRX")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.execvp(pager, [pager])
|
os.execvp(pager, [pager])
|
||||||
|
11
progress.py
11
progress.py
@ -23,7 +23,7 @@ except ImportError:
|
|||||||
|
|
||||||
from repo_trace import IsTraceToStderr
|
from repo_trace import IsTraceToStderr
|
||||||
|
|
||||||
_NOT_TTY = not os.isatty(2)
|
_TTY = sys.stderr.isatty()
|
||||||
|
|
||||||
# This will erase all content in the current line (wherever the cursor is).
|
# This will erase all content in the current line (wherever the cursor is).
|
||||||
# It does not move the cursor, so this is usually followed by \r to move to
|
# It does not move the cursor, so this is usually followed by \r to move to
|
||||||
@ -97,7 +97,8 @@ class Progress(object):
|
|||||||
self._start = time.time()
|
self._start = time.time()
|
||||||
self._show = not delay
|
self._show = not delay
|
||||||
self._units = units
|
self._units = units
|
||||||
self._elide = elide
|
self._elide = elide and _TTY
|
||||||
|
|
||||||
# Only show the active jobs section if we run more than one in parallel.
|
# Only show the active jobs section if we run more than one in parallel.
|
||||||
self._show_jobs = False
|
self._show_jobs = False
|
||||||
self._active = 0
|
self._active = 0
|
||||||
@ -129,7 +130,7 @@ class Progress(object):
|
|||||||
def _write(self, s):
|
def _write(self, s):
|
||||||
s = "\r" + s
|
s = "\r" + s
|
||||||
if self._elide:
|
if self._elide:
|
||||||
col = os.get_terminal_size().columns
|
col = os.get_terminal_size(sys.stderr.fileno()).columns
|
||||||
if len(s) > col:
|
if len(s) > col:
|
||||||
s = s[: col - 1] + ".."
|
s = s[: col - 1] + ".."
|
||||||
sys.stderr.write(s)
|
sys.stderr.write(s)
|
||||||
@ -157,7 +158,7 @@ class Progress(object):
|
|||||||
msg = self._last_msg
|
msg = self._last_msg
|
||||||
self._last_msg = msg
|
self._last_msg = msg
|
||||||
|
|
||||||
if _NOT_TTY or IsTraceToStderr():
|
if not _TTY or IsTraceToStderr():
|
||||||
return
|
return
|
||||||
|
|
||||||
elapsed_sec = time.time() - self._start
|
elapsed_sec = time.time() - self._start
|
||||||
@ -199,7 +200,7 @@ class Progress(object):
|
|||||||
|
|
||||||
def end(self):
|
def end(self):
|
||||||
self._update_event.set()
|
self._update_event.set()
|
||||||
if _NOT_TTY or IsTraceToStderr() or not self._show:
|
if not _TTY or IsTraceToStderr() or not self._show:
|
||||||
return
|
return
|
||||||
|
|
||||||
duration = duration_str(time.time() - self._start)
|
duration = duration_str(time.time() - self._start)
|
||||||
|
30
project.py
30
project.py
@ -1186,6 +1186,7 @@ class Project(object):
|
|||||||
ssh_proxy=None,
|
ssh_proxy=None,
|
||||||
clone_filter=None,
|
clone_filter=None,
|
||||||
partial_clone_exclude=set(),
|
partial_clone_exclude=set(),
|
||||||
|
clone_filter_for_depth=None,
|
||||||
):
|
):
|
||||||
"""Perform only the network IO portion of the sync process.
|
"""Perform only the network IO portion of the sync process.
|
||||||
Local working directory/branch state is not affected.
|
Local working directory/branch state is not affected.
|
||||||
@ -1295,6 +1296,10 @@ class Project(object):
|
|||||||
else:
|
else:
|
||||||
depth = self.manifest.manifestProject.depth
|
depth = self.manifest.manifestProject.depth
|
||||||
|
|
||||||
|
if depth and clone_filter_for_depth:
|
||||||
|
depth = None
|
||||||
|
clone_filter = clone_filter_for_depth
|
||||||
|
|
||||||
# See if we can skip the network fetch entirely.
|
# See if we can skip the network fetch entirely.
|
||||||
remote_fetched = False
|
remote_fetched = False
|
||||||
if not (
|
if not (
|
||||||
@ -3884,6 +3889,11 @@ class ManifestProject(MetaProject):
|
|||||||
"""Partial clone exclude string"""
|
"""Partial clone exclude string"""
|
||||||
return self.config.GetString("repo.partialcloneexclude")
|
return self.config.GetString("repo.partialcloneexclude")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def clone_filter_for_depth(self):
|
||||||
|
"""Replace shallow clone with partial clone."""
|
||||||
|
return self.config.GetString("repo.clonefilterfordepth")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def manifest_platform(self):
|
def manifest_platform(self):
|
||||||
"""The --platform argument from `repo init`."""
|
"""The --platform argument from `repo init`."""
|
||||||
@ -3961,6 +3971,7 @@ class ManifestProject(MetaProject):
|
|||||||
manifest_name=spec.manifestName,
|
manifest_name=spec.manifestName,
|
||||||
this_manifest_only=True,
|
this_manifest_only=True,
|
||||||
outer_manifest=False,
|
outer_manifest=False,
|
||||||
|
clone_filter_for_depth=mp.clone_filter_for_depth,
|
||||||
)
|
)
|
||||||
|
|
||||||
def Sync(
|
def Sync(
|
||||||
@ -3991,6 +4002,7 @@ class ManifestProject(MetaProject):
|
|||||||
tags="",
|
tags="",
|
||||||
this_manifest_only=False,
|
this_manifest_only=False,
|
||||||
outer_manifest=True,
|
outer_manifest=True,
|
||||||
|
clone_filter_for_depth=None,
|
||||||
):
|
):
|
||||||
"""Sync the manifest and all submanifests.
|
"""Sync the manifest and all submanifests.
|
||||||
|
|
||||||
@ -4035,6 +4047,8 @@ class ManifestProject(MetaProject):
|
|||||||
current sub manifest.
|
current sub manifest.
|
||||||
outer_manifest: a boolean, whether to start at the outermost
|
outer_manifest: a boolean, whether to start at the outermost
|
||||||
manifest.
|
manifest.
|
||||||
|
clone_filter_for_depth: a string, when specified replaces shallow
|
||||||
|
clones with partial.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
a boolean, whether the sync was successful.
|
a boolean, whether the sync was successful.
|
||||||
@ -4297,6 +4311,9 @@ class ManifestProject(MetaProject):
|
|||||||
file=sys.stderr,
|
file=sys.stderr,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if clone_filter_for_depth is not None:
|
||||||
|
self.ConfigureCloneFilterForDepth(clone_filter_for_depth)
|
||||||
|
|
||||||
if use_superproject is not None:
|
if use_superproject is not None:
|
||||||
self.config.SetBoolean("repo.superproject", use_superproject)
|
self.config.SetBoolean("repo.superproject", use_superproject)
|
||||||
|
|
||||||
@ -4311,6 +4328,7 @@ class ManifestProject(MetaProject):
|
|||||||
submodules=submodules,
|
submodules=submodules,
|
||||||
clone_filter=clone_filter,
|
clone_filter=clone_filter,
|
||||||
partial_clone_exclude=self.manifest.PartialCloneExclude,
|
partial_clone_exclude=self.manifest.PartialCloneExclude,
|
||||||
|
clone_filter_for_depth=self.manifest.CloneFilterForDepth,
|
||||||
).success
|
).success
|
||||||
if not success:
|
if not success:
|
||||||
r = self.GetRemote()
|
r = self.GetRemote()
|
||||||
@ -4415,6 +4433,18 @@ class ManifestProject(MetaProject):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def ConfigureCloneFilterForDepth(self, clone_filter_for_depth):
|
||||||
|
"""Configure clone filter to replace shallow clones.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
clone_filter_for_depth: a string or None, e.g. 'blob:none' will
|
||||||
|
disable shallow clones and replace with partial clone. None will
|
||||||
|
enable shallow clones.
|
||||||
|
"""
|
||||||
|
self.config.SetString(
|
||||||
|
"repo.clonefilterfordepth", clone_filter_for_depth
|
||||||
|
)
|
||||||
|
|
||||||
def _ConfigureDepth(self, depth):
|
def _ConfigureDepth(self, depth):
|
||||||
"""Configure the depth we'll sync down.
|
"""Configure the depth we'll sync down.
|
||||||
|
|
||||||
|
4
repo
4
repo
@ -146,10 +146,10 @@ REPO_REV = os.environ.get('REPO_REV')
|
|||||||
if not REPO_REV:
|
if not REPO_REV:
|
||||||
REPO_REV = 'stable'
|
REPO_REV = 'stable'
|
||||||
# URL to file bug reports for repo tool issues.
|
# URL to file bug reports for repo tool issues.
|
||||||
BUG_URL = 'https://bugs.chromium.org/p/gerrit/issues/entry?template=Repo+tool+issue'
|
BUG_URL = 'https://issues.gerritcodereview.com/issues/new?component=1370071'
|
||||||
|
|
||||||
# increment this whenever we make important changes to this script
|
# increment this whenever we make important changes to this script
|
||||||
VERSION = (2, 32)
|
VERSION = (2, 35)
|
||||||
|
|
||||||
# increment this if the MAINTAINER_KEYS block is modified
|
# increment this if the MAINTAINER_KEYS block is modified
|
||||||
KEYRING_VERSION = (2, 3)
|
KEYRING_VERSION = (2, 3)
|
||||||
|
2
setup.py
2
setup.py
@ -40,7 +40,7 @@ setuptools.setup(
|
|||||||
long_description_content_type="text/plain",
|
long_description_content_type="text/plain",
|
||||||
url="https://gerrit.googlesource.com/git-repo/",
|
url="https://gerrit.googlesource.com/git-repo/",
|
||||||
project_urls={
|
project_urls={
|
||||||
"Bug Tracker": "https://bugs.chromium.org/p/gerrit/issues/list?q=component:Applications%3Erepo", # noqa: E501
|
"Bug Tracker": "https://issues.gerritcodereview.com/issues?q=is:open%20componentid:1370071", # noqa: E501
|
||||||
},
|
},
|
||||||
# https://pypi.org/classifiers/
|
# https://pypi.org/classifiers/
|
||||||
classifiers=[
|
classifiers=[
|
||||||
|
@ -20,6 +20,8 @@ from command import InteractiveCommand, MirrorSafeCommand
|
|||||||
from git_command import git_require, MIN_GIT_VERSION_SOFT, MIN_GIT_VERSION_HARD
|
from git_command import git_require, MIN_GIT_VERSION_SOFT, MIN_GIT_VERSION_HARD
|
||||||
from wrapper import Wrapper
|
from wrapper import Wrapper
|
||||||
|
|
||||||
|
_REPO_ALLOW_SHALLOW = os.environ.get("REPO_ALLOW_SHALLOW")
|
||||||
|
|
||||||
|
|
||||||
class Init(InteractiveCommand, MirrorSafeCommand):
|
class Init(InteractiveCommand, MirrorSafeCommand):
|
||||||
COMMON = True
|
COMMON = True
|
||||||
@ -125,6 +127,9 @@ to update the working directory files.
|
|||||||
# manifest project is special and is created when instantiating the
|
# manifest project is special and is created when instantiating the
|
||||||
# manifest which happens before we parse options.
|
# manifest which happens before we parse options.
|
||||||
self.manifest.manifestProject.clone_depth = opt.manifest_depth
|
self.manifest.manifestProject.clone_depth = opt.manifest_depth
|
||||||
|
clone_filter_for_depth = (
|
||||||
|
"blob:none" if (_REPO_ALLOW_SHALLOW == "0") else None
|
||||||
|
)
|
||||||
if not self.manifest.manifestProject.Sync(
|
if not self.manifest.manifestProject.Sync(
|
||||||
manifest_url=opt.manifest_url,
|
manifest_url=opt.manifest_url,
|
||||||
manifest_branch=opt.manifest_branch,
|
manifest_branch=opt.manifest_branch,
|
||||||
@ -140,6 +145,7 @@ to update the working directory files.
|
|||||||
partial_clone=opt.partial_clone,
|
partial_clone=opt.partial_clone,
|
||||||
clone_filter=opt.clone_filter,
|
clone_filter=opt.clone_filter,
|
||||||
partial_clone_exclude=opt.partial_clone_exclude,
|
partial_clone_exclude=opt.partial_clone_exclude,
|
||||||
|
clone_filter_for_depth=clone_filter_for_depth,
|
||||||
clone_bundle=opt.clone_bundle,
|
clone_bundle=opt.clone_bundle,
|
||||||
git_lfs=opt.git_lfs,
|
git_lfs=opt.git_lfs,
|
||||||
use_superproject=opt.use_superproject,
|
use_superproject=opt.use_superproject,
|
||||||
|
@ -79,6 +79,8 @@ _ONE_DAY_S = 24 * 60 * 60
|
|||||||
_REPO_AUTO_GC = "REPO_AUTO_GC"
|
_REPO_AUTO_GC = "REPO_AUTO_GC"
|
||||||
_AUTO_GC = os.environ.get(_REPO_AUTO_GC) == "1"
|
_AUTO_GC = os.environ.get(_REPO_AUTO_GC) == "1"
|
||||||
|
|
||||||
|
_REPO_ALLOW_SHALLOW = os.environ.get("REPO_ALLOW_SHALLOW")
|
||||||
|
|
||||||
|
|
||||||
class _FetchOneResult(NamedTuple):
|
class _FetchOneResult(NamedTuple):
|
||||||
"""_FetchOne return value.
|
"""_FetchOne return value.
|
||||||
@ -638,6 +640,7 @@ later is required to fix a server side protocol bug.
|
|||||||
ssh_proxy=self.ssh_proxy,
|
ssh_proxy=self.ssh_proxy,
|
||||||
clone_filter=project.manifest.CloneFilter,
|
clone_filter=project.manifest.CloneFilter,
|
||||||
partial_clone_exclude=project.manifest.PartialCloneExclude,
|
partial_clone_exclude=project.manifest.PartialCloneExclude,
|
||||||
|
clone_filter_for_depth=project.manifest.CloneFilterForDepth,
|
||||||
)
|
)
|
||||||
success = sync_result.success
|
success = sync_result.success
|
||||||
remote_fetched = sync_result.remote_fetched
|
remote_fetched = sync_result.remote_fetched
|
||||||
@ -674,18 +677,22 @@ later is required to fix a server side protocol bug.
|
|||||||
cls.ssh_proxy = ssh_proxy
|
cls.ssh_proxy = ssh_proxy
|
||||||
|
|
||||||
def _GetSyncProgressMessage(self):
|
def _GetSyncProgressMessage(self):
|
||||||
if len(self._sync_dict) == 0:
|
|
||||||
return None
|
|
||||||
|
|
||||||
earliest_time = float("inf")
|
earliest_time = float("inf")
|
||||||
earliest_proj = None
|
earliest_proj = None
|
||||||
for project, t in self._sync_dict.items():
|
items = self._sync_dict.items()
|
||||||
|
for project, t in items:
|
||||||
if t < earliest_time:
|
if t < earliest_time:
|
||||||
earliest_time = t
|
earliest_time = t
|
||||||
earliest_proj = project
|
earliest_proj = project
|
||||||
|
|
||||||
|
if not earliest_proj:
|
||||||
|
# This function is called when sync is still running but in some
|
||||||
|
# cases (by chance), _sync_dict can contain no entries. Return some
|
||||||
|
# text to indicate that sync is still working.
|
||||||
|
return "..working.."
|
||||||
|
|
||||||
elapsed = time.time() - earliest_time
|
elapsed = time.time() - earliest_time
|
||||||
jobs = jobs_str(len(self._sync_dict))
|
jobs = jobs_str(len(items))
|
||||||
return f"{jobs} | {elapsed_str(elapsed)} {earliest_proj}"
|
return f"{jobs} | {elapsed_str(elapsed)} {earliest_proj}"
|
||||||
|
|
||||||
def _Fetch(self, projects, opt, err_event, ssh_proxy):
|
def _Fetch(self, projects, opt, err_event, ssh_proxy):
|
||||||
@ -1440,6 +1447,7 @@ later is required to fix a server side protocol bug.
|
|||||||
submodules=mp.manifest.HasSubmodules,
|
submodules=mp.manifest.HasSubmodules,
|
||||||
clone_filter=mp.manifest.CloneFilter,
|
clone_filter=mp.manifest.CloneFilter,
|
||||||
partial_clone_exclude=mp.manifest.PartialCloneExclude,
|
partial_clone_exclude=mp.manifest.PartialCloneExclude,
|
||||||
|
clone_filter_for_depth=mp.manifest.CloneFilterForDepth,
|
||||||
)
|
)
|
||||||
finish = time.time()
|
finish = time.time()
|
||||||
self.event_log.AddSync(
|
self.event_log.AddSync(
|
||||||
@ -1589,6 +1597,15 @@ later is required to fix a server side protocol bug.
|
|||||||
_PostRepoUpgrade(manifest, quiet=opt.quiet)
|
_PostRepoUpgrade(manifest, quiet=opt.quiet)
|
||||||
|
|
||||||
mp = manifest.manifestProject
|
mp = manifest.manifestProject
|
||||||
|
|
||||||
|
if _REPO_ALLOW_SHALLOW is not None:
|
||||||
|
if _REPO_ALLOW_SHALLOW == "1":
|
||||||
|
mp.ConfigureCloneFilterForDepth(None)
|
||||||
|
elif (
|
||||||
|
_REPO_ALLOW_SHALLOW == "0" and mp.clone_filter_for_depth is None
|
||||||
|
):
|
||||||
|
mp.ConfigureCloneFilterForDepth("blob:none")
|
||||||
|
|
||||||
if opt.mp_update:
|
if opt.mp_update:
|
||||||
self._UpdateAllManifestProjects(opt, mp, manifest_name)
|
self._UpdateAllManifestProjects(opt, mp, manifest_name)
|
||||||
else:
|
else:
|
||||||
@ -1659,6 +1676,13 @@ later is required to fix a server side protocol bug.
|
|||||||
err_update_projects = False
|
err_update_projects = False
|
||||||
err_update_linkfiles = False
|
err_update_linkfiles = False
|
||||||
|
|
||||||
|
# Log the repo projects by existing and new.
|
||||||
|
existing = [x for x in all_projects if x.Exists]
|
||||||
|
mp.config.SetString("repo.existingprojectcount", str(len(existing)))
|
||||||
|
mp.config.SetString(
|
||||||
|
"repo.newprojectcount", str(len(all_projects) - len(existing))
|
||||||
|
)
|
||||||
|
|
||||||
self._fetch_times = _FetchTimes(manifest)
|
self._fetch_times = _FetchTimes(manifest)
|
||||||
if not opt.local_only:
|
if not opt.local_only:
|
||||||
with multiprocessing.Manager() as manager:
|
with multiprocessing.Manager() as manager:
|
||||||
|
@ -996,6 +996,44 @@ class RemoveProjectElementTests(ManifestParseTestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(manifest.projects, [])
|
self.assertEqual(manifest.projects, [])
|
||||||
|
|
||||||
|
def test_remove_using_path_attrib(self):
|
||||||
|
manifest = self.getXmlManifest(
|
||||||
|
"""
|
||||||
|
<manifest>
|
||||||
|
<remote name="default-remote" fetch="http://localhost" />
|
||||||
|
<default remote="default-remote" revision="refs/heads/main" />
|
||||||
|
<project name="project1" path="tests/path1" />
|
||||||
|
<project name="project1" path="tests/path2" />
|
||||||
|
<project name="project2" />
|
||||||
|
<project name="project3" />
|
||||||
|
<project name="project4" path="tests/path3" />
|
||||||
|
<project name="project4" path="tests/path4" />
|
||||||
|
<project name="project5" />
|
||||||
|
<project name="project6" path="tests/path6" />
|
||||||
|
|
||||||
|
<remove-project name="project1" path="tests/path2" />
|
||||||
|
<remove-project name="project3" />
|
||||||
|
<remove-project name="project4" />
|
||||||
|
<remove-project path="project5" />
|
||||||
|
<remove-project path="tests/path6" />
|
||||||
|
</manifest>
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
found_proj1_path1 = False
|
||||||
|
found_proj2 = False
|
||||||
|
for proj in manifest.projects:
|
||||||
|
if proj.name == "project1":
|
||||||
|
found_proj1_path1 = True
|
||||||
|
self.assertEqual(proj.relpath, "tests/path1")
|
||||||
|
if proj.name == "project2":
|
||||||
|
found_proj2 = True
|
||||||
|
self.assertNotEqual(proj.name, "project3")
|
||||||
|
self.assertNotEqual(proj.name, "project4")
|
||||||
|
self.assertNotEqual(proj.name, "project5")
|
||||||
|
self.assertNotEqual(proj.name, "project6")
|
||||||
|
self.assertTrue(found_proj1_path1)
|
||||||
|
self.assertTrue(found_proj2)
|
||||||
|
|
||||||
|
|
||||||
class ExtendProjectElementTests(ManifestParseTestCase):
|
class ExtendProjectElementTests(ManifestParseTestCase):
|
||||||
"""Tests for <extend-project>."""
|
"""Tests for <extend-project>."""
|
||||||
|
Reference in New Issue
Block a user