Add multi-manifest support with <submanifest> element
To be addressed in another change:
- a partial `repo sync` (with a list of projects/paths to sync)
requires `--this-tree-only`.
Change-Id: I6c7400bf001540e9d7694fa70934f8f204cb5f57
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/322657
Tested-by: LaMont Jones <lamontjones@google.com>
Reviewed-by: Mike Frysinger <vapier@google.com>
diff --git a/subcmds/abandon.py b/subcmds/abandon.py
index 85d85f5..c3d2d5b 100644
--- a/subcmds/abandon.py
+++ b/subcmds/abandon.py
@@ -69,7 +69,8 @@
nb = args[0]
err = defaultdict(list)
success = defaultdict(list)
- all_projects = self.GetProjects(args[1:])
+ all_projects = self.GetProjects(args[1:], all_manifests=not opt.this_manifest_only)
+ _RelPath = lambda p: p.RelPath(local=opt.this_manifest_only)
def _ProcessResults(_pool, pm, states):
for (results, project) in states:
@@ -94,7 +95,7 @@
err_msg = "error: cannot abandon %s" % br
print(err_msg, file=sys.stderr)
for proj in err[br]:
- print(' ' * len(err_msg) + " | %s" % proj.relpath, file=sys.stderr)
+ print(' ' * len(err_msg) + " | %s" % _RelPath(proj), file=sys.stderr)
sys.exit(1)
elif not success:
print('error: no project has local branch(es) : %s' % nb,
@@ -110,5 +111,5 @@
result = "all project"
else:
result = "%s" % (
- ('\n' + ' ' * width + '| ').join(p.relpath for p in success[br]))
+ ('\n' + ' ' * width + '| ').join(_RelPath(p) for p in success[br]))
print("%s%s| %s\n" % (br, ' ' * (width - len(br)), result))
diff --git a/subcmds/branches.py b/subcmds/branches.py
index 7b5decc..b89cc2f 100644
--- a/subcmds/branches.py
+++ b/subcmds/branches.py
@@ -98,7 +98,7 @@
PARALLEL_JOBS = DEFAULT_LOCAL_JOBS
def Execute(self, opt, args):
- projects = self.GetProjects(args)
+ projects = self.GetProjects(args, all_manifests=not opt.this_manifest_only)
out = BranchColoring(self.manifest.manifestProject.config)
all_branches = {}
project_cnt = len(projects)
@@ -147,6 +147,7 @@
hdr('%c%c %-*s' % (current, published, width, name))
out.write(' |')
+ _RelPath = lambda p: p.RelPath(local=opt.this_manifest_only)
if in_cnt < project_cnt:
fmt = out.write
paths = []
@@ -154,19 +155,20 @@
if i.IsSplitCurrent or (in_cnt <= project_cnt - in_cnt):
in_type = 'in'
for b in i.projects:
+ relpath = b.project.relpath
if not i.IsSplitCurrent or b.current:
- paths.append(b.project.relpath)
+ paths.append(_RelPath(b.project))
else:
- non_cur_paths.append(b.project.relpath)
+ non_cur_paths.append(_RelPath(b.project))
else:
fmt = out.notinproject
in_type = 'not in'
have = set()
for b in i.projects:
- have.add(b.project.relpath)
+ have.add(_RelPath(b.project))
for p in projects:
- if p.relpath not in have:
- paths.append(p.relpath)
+ if _RelPath(p) not in have:
+ paths.append(_RelPath(p))
s = ' %s %s' % (in_type, ', '.join(paths))
if not i.IsSplitCurrent and (width + 7 + len(s) < 80):
diff --git a/subcmds/checkout.py b/subcmds/checkout.py
index 9b42948..768b602 100644
--- a/subcmds/checkout.py
+++ b/subcmds/checkout.py
@@ -47,7 +47,7 @@
nb = args[0]
err = []
success = []
- all_projects = self.GetProjects(args[1:])
+ all_projects = self.GetProjects(args[1:], all_manifests=not opt.this_manifest_only)
def _ProcessResults(_pool, pm, results):
for status, project in results:
diff --git a/subcmds/diff.py b/subcmds/diff.py
index 00a7ec2..a1f4ba8 100644
--- a/subcmds/diff.py
+++ b/subcmds/diff.py
@@ -50,7 +50,7 @@
return (ret, buf.getvalue())
def Execute(self, opt, args):
- all_projects = self.GetProjects(args)
+ all_projects = self.GetProjects(args, all_manifests=not opt.this_manifest_only)
def _ProcessResults(_pool, _output, results):
ret = 0
diff --git a/subcmds/diffmanifests.py b/subcmds/diffmanifests.py
index f6cc30a..0e5f410 100644
--- a/subcmds/diffmanifests.py
+++ b/subcmds/diffmanifests.py
@@ -179,6 +179,9 @@
def ValidateOptions(self, opt, args):
if not args or len(args) > 2:
self.OptionParser.error('missing manifests to diff')
+ if opt.this_manifest_only is False:
+ raise self.OptionParser.error(
+ '`diffmanifest` only supports the current tree')
def Execute(self, opt, args):
self.out = _Coloring(self.client.globalConfig)
diff --git a/subcmds/download.py b/subcmds/download.py
index 523f25e..1582484 100644
--- a/subcmds/download.py
+++ b/subcmds/download.py
@@ -48,7 +48,7 @@
dest='ffonly', action='store_true',
help="force fast-forward merge")
- def _ParseChangeIds(self, args):
+ def _ParseChangeIds(self, opt, args):
if not args:
self.Usage()
@@ -77,7 +77,7 @@
ps_id = max(int(match.group(1)), ps_id)
to_get.append((project, chg_id, ps_id))
else:
- projects = self.GetProjects([a])
+ projects = self.GetProjects([a], all_manifests=not opt.this_manifest_only)
if len(projects) > 1:
# If the cwd is one of the projects, assume they want that.
try:
@@ -88,8 +88,8 @@
print('error: %s matches too many projects; please re-run inside '
'the project checkout.' % (a,), file=sys.stderr)
for project in projects:
- print(' %s/ @ %s' % (project.relpath, project.revisionExpr),
- file=sys.stderr)
+ print(' %s/ @ %s' % (project.RelPath(local=opt.this_manifest_only),
+ project.revisionExpr), file=sys.stderr)
sys.exit(1)
else:
project = projects[0]
@@ -105,7 +105,7 @@
self.OptionParser.error('-x and --ff are mutually exclusive options')
def Execute(self, opt, args):
- for project, change_id, ps_id in self._ParseChangeIds(args):
+ for project, change_id, ps_id in self._ParseChangeIds(opt, args):
dl = project.DownloadPatchSet(change_id, ps_id)
if not dl:
print('[%s] change %d/%d not found'
diff --git a/subcmds/forall.py b/subcmds/forall.py
index 7c1dea9..cc578b5 100644
--- a/subcmds/forall.py
+++ b/subcmds/forall.py
@@ -168,6 +168,7 @@
def Execute(self, opt, args):
cmd = [opt.command[0]]
+ all_trees = not opt.this_manifest_only
shell = True
if re.compile(r'^[a-z0-9A-Z_/\.-]+$').match(cmd[0]):
@@ -213,11 +214,11 @@
self.manifest.Override(smart_sync_manifest_path)
if opt.regex:
- projects = self.FindProjects(args)
+ projects = self.FindProjects(args, all_manifests=all_trees)
elif opt.inverse_regex:
- projects = self.FindProjects(args, inverse=True)
+ projects = self.FindProjects(args, inverse=True, all_manifests=all_trees)
else:
- projects = self.GetProjects(args, groups=opt.groups)
+ projects = self.GetProjects(args, groups=opt.groups, all_manifests=all_trees)
os.environ['REPO_COUNT'] = str(len(projects))
@@ -290,6 +291,7 @@
setenv('REPO_PROJECT', project.name)
setenv('REPO_PATH', project.relpath)
+ setenv('REPO_OUTERPATH', project.RelPath(local=opt.this_manifest_only))
setenv('REPO_REMOTE', project.remote.name)
try:
# If we aren't in a fully synced state and we don't have the ref the manifest
@@ -320,7 +322,7 @@
output = ''
if ((opt.project_header and opt.verbose)
or not opt.project_header):
- output = 'skipping %s/' % project.relpath
+ output = 'skipping %s/' % project.RelPath(local=opt.this_manifest_only)
return (1, output)
if opt.verbose:
@@ -344,7 +346,7 @@
if mirror:
project_header_path = project.name
else:
- project_header_path = project.relpath
+ project_header_path = project.RelPath(local=opt.this_manifest_only)
out.project('project %s/' % project_header_path)
out.nl()
buf.write(output)
diff --git a/subcmds/gitc_init.py b/subcmds/gitc_init.py
index e705b61..1d81baf 100644
--- a/subcmds/gitc_init.py
+++ b/subcmds/gitc_init.py
@@ -24,6 +24,7 @@
class GitcInit(init.Init, GitcAvailableCommand):
COMMON = True
+ MULTI_MANIFEST_SUPPORT = False
helpSummary = "Initialize a GITC Client."
helpUsage = """
%prog [options] [client name]
diff --git a/subcmds/grep.py b/subcmds/grep.py
index 8ac4ba1..93c9ae5 100644
--- a/subcmds/grep.py
+++ b/subcmds/grep.py
@@ -172,15 +172,16 @@
return (project, p.Wait(), p.stdout, p.stderr)
@staticmethod
- def _ProcessResults(full_name, have_rev, _pool, out, results):
+ def _ProcessResults(full_name, have_rev, opt, _pool, out, results):
git_failed = False
bad_rev = False
have_match = False
+ _RelPath = lambda p: p.RelPath(local=opt.this_manifest_only)
for project, rc, stdout, stderr in results:
if rc < 0:
git_failed = True
- out.project('--- project %s ---' % project.relpath)
+ out.project('--- project %s ---' % _RelPath(project))
out.nl()
out.fail('%s', stderr)
out.nl()
@@ -192,7 +193,7 @@
if have_rev and 'fatal: ambiguous argument' in stderr:
bad_rev = True
else:
- out.project('--- project %s ---' % project.relpath)
+ out.project('--- project %s ---' % _RelPath(project))
out.nl()
out.fail('%s', stderr.strip())
out.nl()
@@ -208,13 +209,13 @@
rev, line = line.split(':', 1)
out.write("%s", rev)
out.write(':')
- out.project(project.relpath)
+ out.project(_RelPath(project))
out.write('/')
out.write("%s", line)
out.nl()
elif full_name:
for line in r:
- out.project(project.relpath)
+ out.project(_RelPath(project))
out.write('/')
out.write("%s", line)
out.nl()
@@ -239,7 +240,7 @@
cmd_argv.append(args[0])
args = args[1:]
- projects = self.GetProjects(args)
+ projects = self.GetProjects(args, all_manifests=not opt.this_manifest_only)
full_name = False
if len(projects) > 1:
@@ -259,7 +260,7 @@
opt.jobs,
functools.partial(self._ExecuteOne, cmd_argv),
projects,
- callback=functools.partial(self._ProcessResults, full_name, have_rev),
+ callback=functools.partial(self._ProcessResults, full_name, have_rev, opt),
output=out,
ordered=True)
diff --git a/subcmds/info.py b/subcmds/info.py
index 6c1246e..4bedf9d 100644
--- a/subcmds/info.py
+++ b/subcmds/info.py
@@ -61,6 +61,8 @@
self.opt = opt
+ if not opt.this_manifest_only:
+ self.manifest = self.manifest.outer_client
manifestConfig = self.manifest.manifestProject.config
mergeBranch = manifestConfig.GetBranch("default").merge
manifestGroups = (manifestConfig.GetString('manifest.groups')
@@ -80,17 +82,17 @@
self.printSeparator()
if not opt.overview:
- self.printDiffInfo(args)
+ self._printDiffInfo(opt, args)
else:
- self.printCommitOverview(args)
+ self._printCommitOverview(opt, args)
def printSeparator(self):
self.text("----------------------------")
self.out.nl()
- def printDiffInfo(self, args):
+ def _printDiffInfo(self, opt, args):
# We let exceptions bubble up to main as they'll be well structured.
- projs = self.GetProjects(args)
+ projs = self.GetProjects(args, all_manifests=not opt.this_manifest_only)
for p in projs:
self.heading("Project: ")
@@ -179,9 +181,9 @@
self.text(" ".join(split[1:]))
self.out.nl()
- def printCommitOverview(self, args):
+ def _printCommitOverview(self, opt, args):
all_branches = []
- for project in self.GetProjects(args):
+ for project in self.GetProjects(args, all_manifests=not opt.this_manifest_only):
br = [project.GetUploadableBranch(x)
for x in project.GetBranches()]
br = [x for x in br if x]
@@ -200,7 +202,7 @@
if project != branch.project:
project = branch.project
self.out.nl()
- self.headtext(project.relpath)
+ self.headtext(project.RelPath(local=opt.this_manifest_only))
self.out.nl()
commits = branch.commits
diff --git a/subcmds/init.py b/subcmds/init.py
index 32c85f7..b9775a3 100644
--- a/subcmds/init.py
+++ b/subcmds/init.py
@@ -32,6 +32,7 @@
class Init(InteractiveCommand, MirrorSafeCommand):
COMMON = True
+ MULTI_MANIFEST_SUPPORT = False
helpSummary = "Initialize a repo client checkout in the current directory"
helpUsage = """
%prog [options] [manifest url]
@@ -90,6 +91,17 @@
def _Options(self, p, gitc_init=False):
Wrapper().InitParser(p, gitc_init=gitc_init)
+ m = p.add_option_group('Multi-manifest')
+ m.add_option('--outer-manifest', action='store_true',
+ help='operate starting at the outermost manifest')
+ m.add_option('--no-outer-manifest', dest='outer_manifest',
+ action='store_false', default=None,
+ help='do not operate on outer manifests')
+ m.add_option('--this-manifest-only', action='store_true', default=None,
+ help='only operate on this (sub)manifest')
+ m.add_option('--no-this-manifest-only', '--all-manifests',
+ dest='this_manifest_only', action='store_false',
+ help='operate on this manifest and its submanifests')
def _RegisteredEnvironmentOptions(self):
return {'REPO_MANIFEST_URL': 'manifest_url',
diff --git a/subcmds/list.py b/subcmds/list.py
index 6adf85b..ad8036e 100644
--- a/subcmds/list.py
+++ b/subcmds/list.py
@@ -77,16 +77,17 @@
args: Positional args. Can be a list of projects to list, or empty.
"""
if not opt.regex:
- projects = self.GetProjects(args, groups=opt.groups, missing_ok=opt.all)
+ projects = self.GetProjects(args, groups=opt.groups, missing_ok=opt.all,
+ all_manifests=not opt.this_manifest_only)
else:
- projects = self.FindProjects(args)
+ projects = self.FindProjects(args, all_manifests=not opt.this_manifest_only)
def _getpath(x):
if opt.fullpath:
return x.worktree
if opt.relative_to:
return os.path.relpath(x.worktree, opt.relative_to)
- return x.relpath
+ return x.RelPath(local=opt.this_manifest_only)
lines = []
for project in projects:
diff --git a/subcmds/manifest.py b/subcmds/manifest.py
index 0fbdeac..08905cb 100644
--- a/subcmds/manifest.py
+++ b/subcmds/manifest.py
@@ -15,6 +15,7 @@
import json
import os
import sys
+import optparse
from command import PagedCommand
@@ -75,7 +76,7 @@
p.add_option('-o', '--output-file',
dest='output_file',
default='-',
- help='file to save the manifest to',
+ help='file to save the manifest to. (Filename prefix for multi-tree.)',
metavar='-|NAME.xml')
def _Output(self, opt):
@@ -83,36 +84,45 @@
if opt.manifest_name:
self.manifest.Override(opt.manifest_name, False)
- if opt.output_file == '-':
- fd = sys.stdout
- else:
- fd = open(opt.output_file, 'w')
+ for manifest in self.ManifestList(opt):
+ output_file = opt.output_file
+ if output_file == '-':
+ fd = sys.stdout
+ else:
+ if manifest.path_prefix:
+ output_file = f'{opt.output_file}:{manifest.path_prefix.replace("/", "%2f")}'
+ fd = open(output_file, 'w')
- self.manifest.SetUseLocalManifests(not opt.ignore_local_manifests)
+ manifest.SetUseLocalManifests(not opt.ignore_local_manifests)
- if opt.json:
- print('warning: --json is experimental!', file=sys.stderr)
- doc = self.manifest.ToDict(peg_rev=opt.peg_rev,
- peg_rev_upstream=opt.peg_rev_upstream,
- peg_rev_dest_branch=opt.peg_rev_dest_branch)
+ if opt.json:
+ print('warning: --json is experimental!', file=sys.stderr)
+ doc = manifest.ToDict(peg_rev=opt.peg_rev,
+ peg_rev_upstream=opt.peg_rev_upstream,
+ peg_rev_dest_branch=opt.peg_rev_dest_branch)
- json_settings = {
- # JSON style guide says Uunicode characters are fully allowed.
- 'ensure_ascii': False,
- # We use 2 space indent to match JSON style guide.
- 'indent': 2 if opt.pretty else None,
- 'separators': (',', ': ') if opt.pretty else (',', ':'),
- 'sort_keys': True,
- }
- fd.write(json.dumps(doc, **json_settings))
- else:
- self.manifest.Save(fd,
- peg_rev=opt.peg_rev,
- peg_rev_upstream=opt.peg_rev_upstream,
- peg_rev_dest_branch=opt.peg_rev_dest_branch)
- fd.close()
- if opt.output_file != '-':
- print('Saved manifest to %s' % opt.output_file, file=sys.stderr)
+ json_settings = {
+ # JSON style guide says Uunicode characters are fully allowed.
+ 'ensure_ascii': False,
+ # We use 2 space indent to match JSON style guide.
+ 'indent': 2 if opt.pretty else None,
+ 'separators': (',', ': ') if opt.pretty else (',', ':'),
+ 'sort_keys': True,
+ }
+ fd.write(json.dumps(doc, **json_settings))
+ else:
+ manifest.Save(fd,
+ peg_rev=opt.peg_rev,
+ peg_rev_upstream=opt.peg_rev_upstream,
+ peg_rev_dest_branch=opt.peg_rev_dest_branch)
+ if output_file != '-':
+ fd.close()
+ if manifest.path_prefix:
+ print(f'Saved {manifest.path_prefix} submanifest to {output_file}',
+ file=sys.stderr)
+ else:
+ print(f'Saved manifest to {output_file}', file=sys.stderr)
+
def ValidateOptions(self, opt, args):
if args:
diff --git a/subcmds/overview.py b/subcmds/overview.py
index 63f5a79..11dba95 100644
--- a/subcmds/overview.py
+++ b/subcmds/overview.py
@@ -47,7 +47,7 @@
def Execute(self, opt, args):
all_branches = []
- for project in self.GetProjects(args):
+ for project in self.GetProjects(args, all_manifests=not opt.this_manifest_only):
br = [project.GetUploadableBranch(x)
for x in project.GetBranches()]
br = [x for x in br if x]
@@ -76,7 +76,7 @@
if project != branch.project:
project = branch.project
out.nl()
- out.project('project %s/' % project.relpath)
+ out.project('project %s/' % project.RelPath(local=opt.this_manifest_only))
out.nl()
commits = branch.commits
diff --git a/subcmds/prune.py b/subcmds/prune.py
index 584ee7e..251acca 100644
--- a/subcmds/prune.py
+++ b/subcmds/prune.py
@@ -31,7 +31,7 @@
return project.PruneHeads()
def Execute(self, opt, args):
- projects = self.GetProjects(args)
+ projects = self.GetProjects(args, all_manifests=not opt.this_manifest_only)
# NB: Should be able to refactor this module to display summary as results
# come back from children.
@@ -63,7 +63,7 @@
if project != branch.project:
project = branch.project
out.nl()
- out.project('project %s/' % project.relpath)
+ out.project('project %s/' % project.RelPath(local=opt.this_manifest_only))
out.nl()
print('%s %-33s ' % (
diff --git a/subcmds/rebase.py b/subcmds/rebase.py
index 7c53eb7..3d1a63e 100644
--- a/subcmds/rebase.py
+++ b/subcmds/rebase.py
@@ -69,7 +69,7 @@
'consistent if you previously synced to a manifest)')
def Execute(self, opt, args):
- all_projects = self.GetProjects(args)
+ all_projects = self.GetProjects(args, all_manifests=not opt.this_manifest_only)
one_project = len(all_projects) == 1
if opt.interactive and not one_project:
@@ -98,6 +98,7 @@
config = self.manifest.manifestProject.config
out = RebaseColoring(config)
out.redirect(sys.stdout)
+ _RelPath = lambda p: p.RelPath(local=opt.this_manifest_only)
ret = 0
for project in all_projects:
@@ -107,7 +108,7 @@
cb = project.CurrentBranch
if not cb:
if one_project:
- print("error: project %s has a detached HEAD" % project.relpath,
+ print("error: project %s has a detached HEAD" % _RelPath(project),
file=sys.stderr)
return 1
# ignore branches with detatched HEADs
@@ -117,7 +118,7 @@
if not upbranch.LocalMerge:
if one_project:
print("error: project %s does not track any remote branches"
- % project.relpath, file=sys.stderr)
+ % _RelPath(project), file=sys.stderr)
return 1
# ignore branches without remotes
continue
@@ -130,7 +131,7 @@
args.append(upbranch.LocalMerge)
out.project('project %s: rebasing %s -> %s',
- project.relpath, cb, upbranch.LocalMerge)
+ _RelPath(project), cb, upbranch.LocalMerge)
out.nl()
out.flush()
diff --git a/subcmds/stage.py b/subcmds/stage.py
index 0389a4f..5f17cb6 100644
--- a/subcmds/stage.py
+++ b/subcmds/stage.py
@@ -50,7 +50,9 @@
self.Usage()
def _Interactive(self, opt, args):
- all_projects = [p for p in self.GetProjects(args) if p.IsDirty()]
+ all_projects = [
+ p for p in self.GetProjects(args, all_manifests=not opt.this_manifest_only)
+ if p.IsDirty()]
if not all_projects:
print('no projects have uncommitted modifications', file=sys.stderr)
return
@@ -62,7 +64,8 @@
for i in range(len(all_projects)):
project = all_projects[i]
- out.write('%3d: %s', i + 1, project.relpath + '/')
+ out.write('%3d: %s', i + 1,
+ project.RelPath(local=opt.this_manifest_only) + '/')
out.nl()
out.nl()
@@ -99,7 +102,9 @@
_AddI(all_projects[a_index - 1])
continue
- projects = [p for p in all_projects if a in [p.name, p.relpath]]
+ projects = [
+ p for p in all_projects
+ if a in [p.name, p.RelPath(local=opt.this_manifest_only)]]
if len(projects) == 1:
_AddI(projects[0])
continue
diff --git a/subcmds/start.py b/subcmds/start.py
index 2addaf2..809df96 100644
--- a/subcmds/start.py
+++ b/subcmds/start.py
@@ -84,7 +84,8 @@
projects = ['.'] # start it in the local project by default
all_projects = self.GetProjects(projects,
- missing_ok=bool(self.gitc_manifest))
+ missing_ok=bool(self.gitc_manifest),
+ all_manifests=not opt.this_manifest_only)
# This must happen after we find all_projects, since GetProjects may need
# the local directory, which will disappear once we save the GITC manifest.
@@ -137,6 +138,6 @@
if err:
for p in err:
- print("error: %s/: cannot start %s" % (p.relpath, nb),
+ print("error: %s/: cannot start %s" % (p.RelPath(local=opt.this_manifest_only), nb),
file=sys.stderr)
sys.exit(1)
diff --git a/subcmds/status.py b/subcmds/status.py
index 5b66954..0aa4200 100644
--- a/subcmds/status.py
+++ b/subcmds/status.py
@@ -117,7 +117,7 @@
outstring.append(''.join([status_header, item, '/']))
def Execute(self, opt, args):
- all_projects = self.GetProjects(args)
+ all_projects = self.GetProjects(args, all_manifests=not opt.this_manifest_only)
def _ProcessResults(_pool, _output, results):
ret = 0
@@ -141,9 +141,10 @@
if opt.orphans:
proj_dirs = set()
proj_dirs_parents = set()
- for project in self.GetProjects(None, missing_ok=True):
- proj_dirs.add(project.relpath)
- (head, _tail) = os.path.split(project.relpath)
+ for project in self.GetProjects(None, missing_ok=True, all_manifests=not opt.this_manifest_only):
+ relpath = project.RelPath(local=opt.this_manifest_only)
+ proj_dirs.add(relpath)
+ (head, _tail) = os.path.split(relpath)
while head != "":
proj_dirs_parents.add(head)
(head, _tail) = os.path.split(head)
diff --git a/subcmds/sync.py b/subcmds/sync.py
index 707c5bb..f5584dc 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -66,6 +66,7 @@
class Sync(Command, MirrorSafeCommand):
jobs = 1
COMMON = True
+ MULTI_MANIFEST_SUPPORT = False
helpSummary = "Update working tree to the latest revision"
helpUsage = """
%prog [<project>...]
@@ -704,7 +705,7 @@
if project.relpath:
new_project_paths.append(project.relpath)
file_name = 'project.list'
- file_path = os.path.join(self.repodir, file_name)
+ file_path = os.path.join(self.manifest.subdir, file_name)
old_project_paths = []
if os.path.exists(file_path):
@@ -760,7 +761,7 @@
}
copylinkfile_name = 'copy-link-files.json'
- copylinkfile_path = os.path.join(self.manifest.repodir, copylinkfile_name)
+ copylinkfile_path = os.path.join(self.manifest.subdir, copylinkfile_name)
old_copylinkfile_paths = {}
if os.path.exists(copylinkfile_path):
@@ -932,6 +933,9 @@
if opt.prune is None:
opt.prune = True
+ if self.manifest.is_multimanifest and not opt.this_manifest_only and args:
+ self.OptionParser.error('partial syncs must use --this-manifest-only')
+
def Execute(self, opt, args):
if opt.jobs:
self.jobs = opt.jobs
diff --git a/subcmds/upload.py b/subcmds/upload.py
index c48deab..ef3d8e9 100644
--- a/subcmds/upload.py
+++ b/subcmds/upload.py
@@ -226,7 +226,8 @@
destination = opt.dest_branch or project.dest_branch or project.revisionExpr
print('Upload project %s/ to remote branch %s%s:' %
- (project.relpath, destination, ' (private)' if opt.private else ''))
+ (project.RelPath(local=opt.this_manifest_only), destination,
+ ' (private)' if opt.private else ''))
print(' branch %s (%2d commit%s, %s):' % (
name,
len(commit_list),
@@ -262,7 +263,7 @@
script.append('# Uncomment the branches to upload:')
for project, avail in pending:
script.append('#')
- script.append('# project %s/:' % project.relpath)
+ script.append('# project %s/:' % project.RelPath(local=opt.this_manifest_only))
b = {}
for branch in avail:
@@ -285,7 +286,7 @@
script.append('# %s' % commit)
b[name] = branch
- projects[project.relpath] = project
+ projects[project.RelPath(local=opt.this_manifest_only)] = project
branches[project.name] = b
script.append('')
@@ -313,7 +314,7 @@
_die('project for branch %s not in script', name)
branch = branches[project.name].get(name)
if not branch:
- _die('branch %s not in %s', name, project.relpath)
+ _die('branch %s not in %s', name, project.RelPath(local=opt.this_manifest_only))
todo.append(branch)
if not todo:
_die("nothing uncommented for upload")
@@ -481,7 +482,7 @@
else:
fmt = '\n (%s)'
print(('[FAILED] %-15s %-15s' + fmt) % (
- branch.project.relpath + '/',
+ branch.project.RelPath(local=opt.this_manifest_only) + '/',
branch.name,
str(branch.error)),
file=sys.stderr)
@@ -490,7 +491,7 @@
for branch in todo:
if branch.uploaded:
print('[OK ] %-15s %s' % (
- branch.project.relpath + '/',
+ branch.project.RelPath(local=opt.this_manifest_only) + '/',
branch.name),
file=sys.stderr)
@@ -524,7 +525,7 @@
return (project, avail)
def Execute(self, opt, args):
- projects = self.GetProjects(args)
+ projects = self.GetProjects(args, all_manifests=not opt.this_manifest_only)
def _ProcessResults(_pool, _out, results):
pending = []
@@ -534,7 +535,8 @@
print('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, project.CurrentBranch, self.manifest.branch),
+ (project.RelPath(local=opt.this_manifest_only), project.CurrentBranch,
+ project.manifest.branch),
file=sys.stderr)
elif avail:
pending.append(result)
@@ -554,15 +556,23 @@
(opt.branch,), file=sys.stderr)
return 1
- pending_proj_names = [project.name for (project, available) in pending]
- pending_worktrees = [project.worktree for (project, available) in pending]
- hook = RepoHook.FromSubcmd(
- hook_type='pre-upload', manifest=self.manifest,
- opt=opt, abort_if_user_denies=True)
- if not hook.Run(
- project_list=pending_proj_names,
- worktree_list=pending_worktrees):
- return 1
+ manifests = {project.manifest.topdir: project.manifest
+ for (project, available) in pending}
+ ret = 0
+ for manifest in manifests.values():
+ pending_proj_names = [project.name for (project, available) in pending
+ if project.manifest.topdir == manifest.topdir]
+ pending_worktrees = [project.worktree for (project, available) in pending
+ if project.manifest.topdir == manifest.topdir]
+ hook = RepoHook.FromSubcmd(
+ hook_type='pre-upload', manifest=manifest,
+ opt=opt, abort_if_user_denies=True)
+ if not hook.Run(
+ project_list=pending_proj_names,
+ worktree_list=pending_worktrees):
+ ret = 1
+ if ret:
+ return ret
reviewers = _SplitEmails(opt.reviewers) if opt.reviewers else []
cc = _SplitEmails(opt.cc) if opt.cc else []