summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/manifest-format.md8
-rw-r--r--man/repo-manifest.110
-rw-r--r--manifest_xml.py90
-rw-r--r--project.py6
-rw-r--r--tests/test_manifest_xml.py8
5 files changed, 62 insertions, 60 deletions
diff --git a/docs/manifest-format.md b/docs/manifest-format.md
index 42e1ab18..b45b9180 100644
--- a/docs/manifest-format.md
+++ b/docs/manifest-format.md
@@ -287,7 +287,7 @@ should be placed. If not supplied, `revision` is used.
287 287
288`path` may not be an absolute path or use "." or ".." path components. 288`path` may not be an absolute path or use "." or ".." path components.
289 289
290Attribute `groups`: List of additional groups to which all projects 290Attribute `groups`: Set of additional groups to which all projects
291in the included submanifest belong. This appends and recurses, meaning 291in the included submanifest belong. This appends and recurses, meaning
292all projects in submanifests carry all parent submanifest groups. 292all projects in submanifests carry all parent submanifest groups.
293Same syntax as the corresponding element of `project`. 293Same syntax as the corresponding element of `project`.
@@ -355,7 +355,7 @@ When using `repo upload`, changes will be submitted for code
355review on this branch. If unspecified both here and in the 355review on this branch. If unspecified both here and in the
356default element, `revision` is used instead. 356default element, `revision` is used instead.
357 357
358Attribute `groups`: List of groups to which this project belongs, 358Attribute `groups`: Set of groups to which this project belongs,
359whitespace or comma separated. All projects belong to the group 359whitespace or comma separated. All projects belong to the group
360"all", and each project automatically belongs to a group of 360"all", and each project automatically belongs to a group of
361its name:`name` and path:`path`. E.g. for 361its name:`name` and path:`path`. E.g. for
@@ -403,7 +403,7 @@ of the repo client where the Git working directory for this project
403should be placed. This is used to move a project in the checkout by 403should be placed. This is used to move a project in the checkout by
404overriding the existing `path` setting. 404overriding the existing `path` setting.
405 405
406Attribute `groups`: List of additional groups to which this project 406Attribute `groups`: Set of additional groups to which this project
407belongs. Same syntax as the corresponding element of `project`. 407belongs. Same syntax as the corresponding element of `project`.
408 408
409Attribute `revision`: If specified, overrides the revision of the original 409Attribute `revision`: If specified, overrides the revision of the original
@@ -572,7 +572,7 @@ the manifest repository's root.
572"name" may not be an absolute path or use "." or ".." path components. 572"name" may not be an absolute path or use "." or ".." path components.
573These restrictions are not enforced for [Local Manifests]. 573These restrictions are not enforced for [Local Manifests].
574 574
575Attribute `groups`: List of additional groups to which all projects 575Attribute `groups`: Set of additional groups to which all projects
576in the included manifest belong. This appends and recurses, meaning 576in the included manifest belong. This appends and recurses, meaning
577all projects in included manifests carry all parent include groups. 577all projects in included manifests carry all parent include groups.
578This also applies to all extend-project elements in the included manifests. 578This also applies to all extend-project elements in the included manifests.
diff --git a/man/repo-manifest.1 b/man/repo-manifest.1
index 1a97ff7d..38c728e6 100644
--- a/man/repo-manifest.1
+++ b/man/repo-manifest.1
@@ -365,7 +365,7 @@ supplied, `revision` is used.
365.PP 365.PP
366`path` may not be an absolute path or use "." or ".." path components. 366`path` may not be an absolute path or use "." or ".." path components.
367.PP 367.PP
368Attribute `groups`: List of additional groups to which all projects in the 368Attribute `groups`: Set of additional groups to which all projects in the
369included submanifest belong. This appends and recurses, meaning all projects in 369included submanifest belong. This appends and recurses, meaning all projects in
370submanifests carry all parent submanifest groups. Same syntax as the 370submanifests carry all parent submanifest groups. Same syntax as the
371corresponding element of `project`. 371corresponding element of `project`.
@@ -427,7 +427,7 @@ Attribute `dest\-branch`: Name of a Git branch (e.g. `main`). When using `repo
427upload`, changes will be submitted for code review on this branch. If 427upload`, changes will be submitted for code review on this branch. If
428unspecified both here and in the default element, `revision` is used instead. 428unspecified both here and in the default element, `revision` is used instead.
429.PP 429.PP
430Attribute `groups`: List of groups to which this project belongs, whitespace or 430Attribute `groups`: Set of groups to which this project belongs, whitespace or
431comma separated. All projects belong to the group "all", and each project 431comma separated. All projects belong to the group "all", and each project
432automatically belongs to a group of its name:`name` and path:`path`. E.g. for 432automatically belongs to a group of its name:`name` and path:`path`. E.g. for
433`<project name="monkeys" path="barrel\-of"/>`, that project definition is 433`<project name="monkeys" path="barrel\-of"/>`, that project definition is
@@ -471,8 +471,8 @@ repo client where the Git working directory for this project should be placed.
471This is used to move a project in the checkout by overriding the existing `path` 471This is used to move a project in the checkout by overriding the existing `path`
472setting. 472setting.
473.PP 473.PP
474Attribute `groups`: List of additional groups to which this project belongs. 474Attribute `groups`: Set of additional groups to which this project belongs. Same
475Same syntax as the corresponding element of `project`. 475syntax as the corresponding element of `project`.
476.PP 476.PP
477Attribute `revision`: If specified, overrides the revision of the original 477Attribute `revision`: If specified, overrides the revision of the original
478project. Same syntax as the corresponding element of `project`. 478project. Same syntax as the corresponding element of `project`.
@@ -634,7 +634,7 @@ repository's root.
634"name" may not be an absolute path or use "." or ".." path components. These 634"name" may not be an absolute path or use "." or ".." path components. These
635restrictions are not enforced for [Local Manifests]. 635restrictions are not enforced for [Local Manifests].
636.PP 636.PP
637Attribute `groups`: List of additional groups to which all projects in the 637Attribute `groups`: Set of additional groups to which all projects in the
638included manifest belong. This appends and recurses, meaning all projects in 638included manifest belong. This appends and recurses, meaning all projects in
639included manifests carry all parent include groups. This also applies to all 639included manifests carry all parent include groups. This also applies to all
640extend\-project elements in the included manifests. Same syntax as the 640extend\-project elements in the included manifests. Same syntax as the
diff --git a/manifest_xml.py b/manifest_xml.py
index 33a55282..2d476748 100644
--- a/manifest_xml.py
+++ b/manifest_xml.py
@@ -255,7 +255,7 @@ class _XmlSubmanifest:
255 project: a string, the name of the manifest project. 255 project: a string, the name of the manifest project.
256 revision: a string, the commitish. 256 revision: a string, the commitish.
257 manifestName: a string, the submanifest file name. 257 manifestName: a string, the submanifest file name.
258 groups: a list of strings, the groups to add to all projects in the 258 groups: a set of strings, the groups to add to all projects in the
259 submanifest. 259 submanifest.
260 default_groups: a list of strings, the default groups to sync. 260 default_groups: a list of strings, the default groups to sync.
261 path: a string, the relative path for the submanifest checkout. 261 path: a string, the relative path for the submanifest checkout.
@@ -281,7 +281,7 @@ class _XmlSubmanifest:
281 self.project = project 281 self.project = project
282 self.revision = revision 282 self.revision = revision
283 self.manifestName = manifestName 283 self.manifestName = manifestName
284 self.groups = groups 284 self.groups = groups or set()
285 self.default_groups = default_groups 285 self.default_groups = default_groups
286 self.path = path 286 self.path = path
287 self.parent = parent 287 self.parent = parent
@@ -304,7 +304,7 @@ class _XmlSubmanifest:
304 self.repo_client = RepoClient( 304 self.repo_client = RepoClient(
305 parent.repodir, 305 parent.repodir,
306 linkFile, 306 linkFile,
307 parent_groups=",".join(groups) or "", 307 parent_groups=groups,
308 submanifest_path=os.path.join(parent.path_prefix, self.relpath), 308 submanifest_path=os.path.join(parent.path_prefix, self.relpath),
309 outer_client=outer_client, 309 outer_client=outer_client,
310 default_groups=default_groups, 310 default_groups=default_groups,
@@ -345,7 +345,7 @@ class _XmlSubmanifest:
345 manifestName = self.manifestName or "default.xml" 345 manifestName = self.manifestName or "default.xml"
346 revision = self.revision or self.name 346 revision = self.revision or self.name
347 path = self.path or revision.split("/")[-1] 347 path = self.path or revision.split("/")[-1]
348 groups = self.groups or [] 348 groups = self.groups
349 349
350 return SubmanifestSpec( 350 return SubmanifestSpec(
351 self.name, manifestUrl, manifestName, revision, path, groups 351 self.name, manifestUrl, manifestName, revision, path, groups
@@ -359,9 +359,7 @@ class _XmlSubmanifest:
359 359
360 def GetGroupsStr(self): 360 def GetGroupsStr(self):
361 """Returns the `groups` given for this submanifest.""" 361 """Returns the `groups` given for this submanifest."""
362 if self.groups: 362 return ",".join(sorted(self.groups))
363 return ",".join(self.groups)
364 return ""
365 363
366 def GetDefaultGroupsStr(self): 364 def GetDefaultGroupsStr(self):
367 """Returns the `default-groups` given for this submanifest.""" 365 """Returns the `default-groups` given for this submanifest."""
@@ -381,7 +379,7 @@ class SubmanifestSpec:
381 self.manifestName = manifestName 379 self.manifestName = manifestName
382 self.revision = revision 380 self.revision = revision
383 self.path = path 381 self.path = path
384 self.groups = groups or [] 382 self.groups = groups
385 383
386 384
387class XmlManifest: 385class XmlManifest:
@@ -393,7 +391,7 @@ class XmlManifest:
393 manifest_file, 391 manifest_file,
394 local_manifests=None, 392 local_manifests=None,
395 outer_client=None, 393 outer_client=None,
396 parent_groups="", 394 parent_groups=None,
397 submanifest_path="", 395 submanifest_path="",
398 default_groups=None, 396 default_groups=None,
399 ): 397 ):
@@ -409,7 +407,8 @@ class XmlManifest:
409 manifests. This will usually be 407 manifests. This will usually be
410 |repodir|/|LOCAL_MANIFESTS_DIR_NAME|. 408 |repodir|/|LOCAL_MANIFESTS_DIR_NAME|.
411 outer_client: RepoClient of the outer manifest. 409 outer_client: RepoClient of the outer manifest.
412 parent_groups: a string, the groups to apply to this projects. 410 parent_groups: a set of strings, the groups to apply to this
411 manifest.
413 submanifest_path: The submanifest root relative to the repo root. 412 submanifest_path: The submanifest root relative to the repo root.
414 default_groups: a string, the default manifest groups to use. 413 default_groups: a string, the default manifest groups to use.
415 """ 414 """
@@ -432,7 +431,7 @@ class XmlManifest:
432 self.manifestFileOverrides = {} 431 self.manifestFileOverrides = {}
433 self.local_manifests = local_manifests 432 self.local_manifests = local_manifests
434 self._load_local_manifests = True 433 self._load_local_manifests = True
435 self.parent_groups = parent_groups 434 self.parent_groups = parent_groups or set()
436 self.default_groups = default_groups 435 self.default_groups = default_groups
437 436
438 if submanifest_path and not outer_client: 437 if submanifest_path and not outer_client:
@@ -567,6 +566,14 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
567 """ 566 """
568 return [x for x in re.split(r"[,\s]+", field) if x] 567 return [x for x in re.split(r"[,\s]+", field) if x]
569 568
569 def _ParseSet(self, field):
570 """Parse fields that contain flattened sets.
571
572 These are whitespace & comma separated. Empty elements will be
573 discarded.
574 """
575 return set(self._ParseList(field))
576
570 def ToXml( 577 def ToXml(
571 self, 578 self,
572 peg_rev=False, 579 peg_rev=False,
@@ -725,10 +732,9 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
725 le.setAttribute("dest", lf.dest) 732 le.setAttribute("dest", lf.dest)
726 e.appendChild(le) 733 e.appendChild(le)
727 734
728 default_groups = ["all", "name:%s" % p.name, "path:%s" % p.relpath] 735 egroups = p.groups - {"all", f"name:{p.name}", f"path:{p.relpath}"}
729 egroups = [g for g in p.groups if g not in default_groups]
730 if egroups: 736 if egroups:
731 e.setAttribute("groups", ",".join(egroups)) 737 e.setAttribute("groups", ",".join(sorted(egroups)))
732 738
733 for a in p.annotations: 739 for a in p.annotations:
734 if a.keep == "true": 740 if a.keep == "true":
@@ -1171,12 +1177,12 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
1171 b = b[len(R_HEADS) :] 1177 b = b[len(R_HEADS) :]
1172 self.branch = b 1178 self.branch = b
1173 1179
1174 parent_groups = self.parent_groups 1180 parent_groups = self.parent_groups.copy()
1175 if self.path_prefix: 1181 if self.path_prefix:
1176 parent_groups = ( 1182 parent_groups |= {
1177 f"{SUBMANIFEST_GROUP_PREFIX}:path:" 1183 f"{SUBMANIFEST_GROUP_PREFIX}:path:"
1178 f"{self.path_prefix},{parent_groups}" 1184 f"{self.path_prefix}"
1179 ) 1185 }
1180 1186
1181 # The manifestFile was specified by the user which is why we 1187 # The manifestFile was specified by the user which is why we
1182 # allow include paths to point anywhere. 1188 # allow include paths to point anywhere.
@@ -1202,16 +1208,16 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
1202 # Since local manifests are entirely managed by 1208 # Since local manifests are entirely managed by
1203 # the user, allow them to point anywhere the 1209 # the user, allow them to point anywhere the
1204 # user wants. 1210 # user wants.
1205 local_group = ( 1211 local_group = {
1206 f"{LOCAL_MANIFEST_GROUP_PREFIX}:" 1212 f"{LOCAL_MANIFEST_GROUP_PREFIX}:"
1207 f"{local_file[:-4]}" 1213 f"{local_file[:-4]}"
1208 ) 1214 }
1209 nodes.append( 1215 nodes.append(
1210 self._ParseManifestXml( 1216 self._ParseManifestXml(
1211 local, 1217 local,
1212 self.subdir, 1218 self.subdir,
1213 parent_groups=( 1219 parent_groups=(
1214 f"{local_group},{parent_groups}" 1220 local_group | parent_groups
1215 ), 1221 ),
1216 restrict_includes=False, 1222 restrict_includes=False,
1217 ) 1223 )
@@ -1262,7 +1268,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
1262 self, 1268 self,
1263 path, 1269 path,
1264 include_root, 1270 include_root,
1265 parent_groups="", 1271 parent_groups=None,
1266 restrict_includes=True, 1272 restrict_includes=True,
1267 parent_node=None, 1273 parent_node=None,
1268 ): 1274 ):
@@ -1271,11 +1277,11 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
1271 Args: 1277 Args:
1272 path: The XML file to read & parse. 1278 path: The XML file to read & parse.
1273 include_root: The path to interpret include "name"s relative to. 1279 include_root: The path to interpret include "name"s relative to.
1274 parent_groups: The groups to apply to this projects. 1280 parent_groups: The set of groups to apply to this manifest.
1275 restrict_includes: Whether to constrain the "name" attribute of 1281 restrict_includes: Whether to constrain the "name" attribute of
1276 includes. 1282 includes.
1277 parent_node: The parent include node, to apply attribute to this 1283 parent_node: The parent include node, to apply attributes to this
1278 projects. 1284 manifest.
1279 1285
1280 Returns: 1286 Returns:
1281 List of XML nodes. 1287 List of XML nodes.
@@ -1307,12 +1313,10 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
1307 raise ManifestInvalidPathError( 1313 raise ManifestInvalidPathError(
1308 f'<include> invalid "name": {name}: {msg}' 1314 f'<include> invalid "name": {name}: {msg}'
1309 ) 1315 )
1310 include_groups = "" 1316 include_groups = (parent_groups or set()).copy()
1311 if parent_groups:
1312 include_groups = parent_groups
1313 if node.hasAttribute("groups"): 1317 if node.hasAttribute("groups"):
1314 include_groups = ( 1318 include_groups |= self._ParseSet(
1315 node.getAttribute("groups") + "," + include_groups 1319 node.getAttribute("groups")
1316 ) 1320 )
1317 fp = os.path.join(include_root, name) 1321 fp = os.path.join(include_root, name)
1318 if not os.path.isfile(fp): 1322 if not os.path.isfile(fp):
@@ -1339,12 +1343,12 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
1339 "project", 1343 "project",
1340 "extend-project", 1344 "extend-project",
1341 ): 1345 ):
1342 nodeGroups = parent_groups 1346 nodeGroups = parent_groups.copy()
1343 if node.hasAttribute("groups"): 1347 if node.hasAttribute("groups"):
1344 nodeGroups = ( 1348 nodeGroups |= self._ParseSet(
1345 node.getAttribute("groups") + "," + nodeGroups 1349 node.getAttribute("groups")
1346 ) 1350 )
1347 node.setAttribute("groups", nodeGroups) 1351 node.setAttribute("groups", ",".join(sorted(nodeGroups)))
1348 if ( 1352 if (
1349 parent_node 1353 parent_node
1350 and node.nodeName == "project" 1354 and node.nodeName == "project"
@@ -1461,7 +1465,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
1461 dest_path = node.getAttribute("dest-path") 1465 dest_path = node.getAttribute("dest-path")
1462 groups = node.getAttribute("groups") 1466 groups = node.getAttribute("groups")
1463 if groups: 1467 if groups:
1464 groups = self._ParseList(groups) 1468 groups = self._ParseSet(groups or "")
1465 revision = node.getAttribute("revision") 1469 revision = node.getAttribute("revision")
1466 remote_name = node.getAttribute("remote") 1470 remote_name = node.getAttribute("remote")
1467 if not remote_name: 1471 if not remote_name:
@@ -1482,7 +1486,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
1482 if path and p.relpath != path: 1486 if path and p.relpath != path:
1483 continue 1487 continue
1484 if groups: 1488 if groups:
1485 p.groups.extend(groups) 1489 p.groups |= groups
1486 if revision: 1490 if revision:
1487 if base_revision: 1491 if base_revision:
1488 if p.revisionExpr != base_revision: 1492 if p.revisionExpr != base_revision:
@@ -1813,7 +1817,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
1813 groups = "" 1817 groups = ""
1814 if node.hasAttribute("groups"): 1818 if node.hasAttribute("groups"):
1815 groups = node.getAttribute("groups") 1819 groups = node.getAttribute("groups")
1816 groups = self._ParseList(groups) 1820 groups = self._ParseSet(groups)
1817 default_groups = self._ParseList(node.getAttribute("default-groups")) 1821 default_groups = self._ParseList(node.getAttribute("default-groups"))
1818 path = node.getAttribute("path") 1822 path = node.getAttribute("path")
1819 if path == "": 1823 if path == "":
@@ -1922,11 +1926,6 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
1922 1926
1923 upstream = node.getAttribute("upstream") or self._default.upstreamExpr 1927 upstream = node.getAttribute("upstream") or self._default.upstreamExpr
1924 1928
1925 groups = ""
1926 if node.hasAttribute("groups"):
1927 groups = node.getAttribute("groups")
1928 groups = self._ParseList(groups)
1929
1930 if parent is None: 1929 if parent is None:
1931 ( 1930 (
1932 relpath, 1931 relpath,
@@ -1941,8 +1940,11 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
1941 parent, name, path 1940 parent, name, path
1942 ) 1941 )
1943 1942
1944 default_groups = ["all", "name:%s" % name, "path:%s" % relpath] 1943 groups = ""
1945 groups.extend(set(default_groups).difference(groups)) 1944 if node.hasAttribute("groups"):
1945 groups = node.getAttribute("groups")
1946 groups = self._ParseSet(groups)
1947 groups |= {"all", f"name:{name}", f"path:{relpath}"}
1946 1948
1947 if self.IsMirror and node.hasAttribute("force-path"): 1949 if self.IsMirror and node.hasAttribute("force-path"):
1948 if XmlBool(node, "force-path", False): 1950 if XmlBool(node, "force-path", False):
diff --git a/project.py b/project.py
index 41606442..b65cb1ae 100644
--- a/project.py
+++ b/project.py
@@ -554,7 +554,7 @@ class Project:
554 revisionExpr, 554 revisionExpr,
555 revisionId, 555 revisionId,
556 rebase=True, 556 rebase=True,
557 groups=None, 557 groups=set(),
558 sync_c=False, 558 sync_c=False,
559 sync_s=False, 559 sync_s=False,
560 sync_tags=True, 560 sync_tags=True,
@@ -839,9 +839,9 @@ class Project:
839 """ 839 """
840 default_groups = self.manifest.default_groups or ["default"] 840 default_groups = self.manifest.default_groups or ["default"]
841 expanded_manifest_groups = manifest_groups or default_groups 841 expanded_manifest_groups = manifest_groups or default_groups
842 expanded_project_groups = ["all"] + (self.groups or []) 842 expanded_project_groups = {"all"} | self.groups
843 if "notdefault" not in expanded_project_groups: 843 if "notdefault" not in expanded_project_groups:
844 expanded_project_groups += ["default"] 844 expanded_project_groups |= {"default"}
845 845
846 matched = False 846 matched = False
847 for group in expanded_manifest_groups: 847 for group in expanded_manifest_groups:
diff --git a/tests/test_manifest_xml.py b/tests/test_manifest_xml.py
index f5991515..960d0cd8 100644
--- a/tests/test_manifest_xml.py
+++ b/tests/test_manifest_xml.py
@@ -605,12 +605,12 @@ class ProjectElementTests(ManifestParseTestCase):
605 manifest.projects[0].name: manifest.projects[0].groups, 605 manifest.projects[0].name: manifest.projects[0].groups,
606 manifest.projects[1].name: manifest.projects[1].groups, 606 manifest.projects[1].name: manifest.projects[1].groups,
607 } 607 }
608 self.assertCountEqual( 608 self.assertEqual(
609 result["test-name"], ["name:test-name", "all", "path:test-path"] 609 result["test-name"], {"name:test-name", "all", "path:test-path"}
610 ) 610 )
611 self.assertCountEqual( 611 self.assertEqual(
612 result["extras"], 612 result["extras"],
613 ["g1", "g2", "g1", "name:extras", "all", "path:path"], 613 {"g1", "g2", "name:extras", "all", "path:path"},
614 ) 614 )
615 groupstr = "default,platform-" + platform.system().lower() 615 groupstr = "default,platform-" + platform.system().lower()
616 self.assertEqual(groupstr, manifest.GetGroupsStr()) 616 self.assertEqual(groupstr, manifest.GetGroupsStr())