Add project annotation handling to repo
Allow the optional addition of "annotation" nodes nested under
projects. Each annotation node must have "name" and "value"
attributes. These name/value pairs will be exported into the
environment during any forall command, prefixed with "REPO__"
In addition, an optional "keep" attribute with case insensitive "true"
or "false" values can be included to determine whether the annotation
will be exported with 'repo manifest'
Change-Id: Icd7540afaae02c958f769ce3d25661aa721a9de8
Signed-off-by: James W. Mills <jameswmills@gmail.com>
diff --git a/docs/manifest-format.txt b/docs/manifest-format.txt
index a7bb156..e5f5ee1 100644
--- a/docs/manifest-format.txt
+++ b/docs/manifest-format.txt
@@ -43,12 +43,17 @@
<!ELEMENT manifest-server (EMPTY)>
<!ATTLIST url CDATA #REQUIRED>
- <!ELEMENT project (EMPTY)>
+ <!ELEMENT project (annotation?)>
<!ATTLIST project name CDATA #REQUIRED>
<!ATTLIST project path CDATA #IMPLIED>
<!ATTLIST project remote IDREF #IMPLIED>
<!ATTLIST project revision CDATA #IMPLIED>
<!ATTLIST project groups CDATA #IMPLIED>
+
+ <!ELEMENT annotation (EMPTY)>
+ <!ATTLIST annotation name CDATA #REQUIRED>
+ <!ATTLIST annotation value CDATA #REQUIRED>
+ <!ATTLIST annotation keep CDATA "true">
<!ELEMENT remove-project (EMPTY)>
<!ATTLIST remove-project name CDATA #REQUIRED>
@@ -163,6 +168,17 @@
whitespace or comma separated. All projects are part of the group
"default" unless "-default" is specified in the list of groups.
+Element annotation
+------------------
+
+Zero or more annotation elements may be specified as children of a
+project element. Each element describes a name-value pair that will be
+exported into each project's environment during a 'forall' command,
+prefixed with REPO__. In addition, there is an optional attribute
+"keep" which accepts the case insensitive values "true" (default) or
+"false". This attribute determines whether or not the annotation will
+be kept when exported with the manifest subcommand.
+
Element remove-project
----------------------
diff --git a/manifest_xml.py b/manifest_xml.py
index a250382..9b804da 100644
--- a/manifest_xml.py
+++ b/manifest_xml.py
@@ -203,6 +203,13 @@
if p.groups:
e.setAttribute('groups', ','.join(p.groups))
+ for a in p.annotations:
+ if a.keep == "true":
+ ae = doc.createElement('annotation')
+ ae.setAttribute('name', a.name)
+ ae.setAttribute('value', a.value)
+ e.appendChild(ae)
+
if self._repo_hooks_project:
root.appendChild(doc.createTextNode(''))
e = doc.createElement('repo-hooks')
@@ -545,6 +552,8 @@
for n in node.childNodes:
if n.nodeName == 'copyfile':
self._ParseCopyFile(project, n)
+ if n.nodeName == 'annotation':
+ self._ParseAnnotation(project, n)
return project
@@ -556,6 +565,17 @@
# dest is relative to the top of the tree
project.AddCopyFile(src, dest, os.path.join(self.topdir, dest))
+ def _ParseAnnotation(self, project, node):
+ name = self._reqatt(node, 'name')
+ value = self._reqatt(node, 'value')
+ try:
+ keep = self._reqatt(node, 'keep').lower()
+ except ManifestParseError:
+ keep = "true"
+ if keep != "true" and keep != "false":
+ raise ManifestParseError, "optional \"keep\" attribute must be \"true\" or \"false\""
+ project.AddAnnotation(name, value, keep)
+
def _get_remote(self, node):
name = node.getAttribute('remote')
if not name:
diff --git a/project.py b/project.py
index 49fef2f..e297926 100644
--- a/project.py
+++ b/project.py
@@ -213,6 +213,11 @@
Coloring.__init__(self, config, 'diff')
self.project = self.printer('header', attr = 'bold')
+class _Annotation:
+ def __init__(self, name, value, keep):
+ self.name = name
+ self.value = value
+ self.keep = keep
class _CopyFile:
def __init__(self, src, dest, abssrc, absdest):
@@ -529,6 +534,7 @@
self.snapshots = {}
self.copyfiles = []
+ self.annotations = []
self.config = GitConfig.ForRepository(
gitdir = self.gitdir,
defaults = self.manifest.globalConfig)
@@ -1175,6 +1181,9 @@
abssrc = os.path.join(self.worktree, src)
self.copyfiles.append(_CopyFile(src, dest, abssrc, absdest))
+ def AddAnnotation(self, name, value, keep):
+ self.annotations.append(_Annotation(name, value, keep))
+
def DownloadPatchSet(self, change_id, patch_id):
"""Download a single patch set of a single change to FETCH_HEAD.
"""
diff --git a/subcmds/forall.py b/subcmds/forall.py
index d3e70ae..9436f4e 100644
--- a/subcmds/forall.py
+++ b/subcmds/forall.py
@@ -82,6 +82,11 @@
REPO_RREV is the name of the revision from the manifest, exactly
as written in the manifest.
+REPO__* are any extra environment variables, specified by the
+"annotation" element under any project element. This can be useful
+for differentiating trees based on user-specific criteria, or simply
+annotating tree details.
+
shell positional arguments ($1, $2, .., $#) are set to any arguments
following <command>.
@@ -162,6 +167,8 @@
setenv('REPO_REMOTE', project.remote.name)
setenv('REPO_LREV', project.GetRevisionId())
setenv('REPO_RREV', project.revisionExpr)
+ for a in project.annotations:
+ setenv("REPO__%s" % (a.name), a.value)
if mirror:
setenv('GIT_DIR', project.gitdir)