diff options
| -rw-r--r-- | manifest_xml.py | 55 | ||||
| -rw-r--r-- | subcmds/manifest.py | 30 |
2 files changed, 78 insertions, 7 deletions
diff --git a/manifest_xml.py b/manifest_xml.py index bf730caa..e1ef330f 100644 --- a/manifest_xml.py +++ b/manifest_xml.py | |||
| @@ -283,9 +283,8 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md | |||
| 283 | def _ParseGroups(self, groups): | 283 | def _ParseGroups(self, groups): |
| 284 | return [x for x in re.split(r'[,\s]+', groups) if x] | 284 | return [x for x in re.split(r'[,\s]+', groups) if x] |
| 285 | 285 | ||
| 286 | def Save(self, fd, peg_rev=False, peg_rev_upstream=True, peg_rev_dest_branch=True, groups=None): | 286 | def ToXml(self, peg_rev=False, peg_rev_upstream=True, peg_rev_dest_branch=True, groups=None): |
| 287 | """Write the current manifest out to the given file descriptor. | 287 | """Return the current manifest XML.""" |
| 288 | """ | ||
| 289 | mp = self.manifestProject | 288 | mp = self.manifestProject |
| 290 | 289 | ||
| 291 | if groups is None: | 290 | if groups is None: |
| @@ -459,6 +458,56 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md | |||
| 459 | ' '.join(self._repo_hooks_project.enabled_repo_hooks)) | 458 | ' '.join(self._repo_hooks_project.enabled_repo_hooks)) |
| 460 | root.appendChild(e) | 459 | root.appendChild(e) |
| 461 | 460 | ||
| 461 | return doc | ||
| 462 | |||
| 463 | def ToDict(self, **kwargs): | ||
| 464 | """Return the current manifest as a dictionary.""" | ||
| 465 | # Elements that may only appear once. | ||
| 466 | SINGLE_ELEMENTS = { | ||
| 467 | 'notice', | ||
| 468 | 'default', | ||
| 469 | 'manifest-server', | ||
| 470 | 'repo-hooks', | ||
| 471 | } | ||
| 472 | # Elements that may be repeated. | ||
| 473 | MULTI_ELEMENTS = { | ||
| 474 | 'remote', | ||
| 475 | 'remove-project', | ||
| 476 | 'project', | ||
| 477 | 'extend-project', | ||
| 478 | 'include', | ||
| 479 | # These are children of 'project' nodes. | ||
| 480 | 'annotation', | ||
| 481 | 'project', | ||
| 482 | 'copyfile', | ||
| 483 | 'linkfile', | ||
| 484 | } | ||
| 485 | |||
| 486 | doc = self.ToXml(**kwargs) | ||
| 487 | ret = {} | ||
| 488 | |||
| 489 | def append_children(ret, node): | ||
| 490 | for child in node.childNodes: | ||
| 491 | if child.nodeType == xml.dom.Node.ELEMENT_NODE: | ||
| 492 | attrs = child.attributes | ||
| 493 | element = dict((attrs.item(i).localName, attrs.item(i).value) | ||
| 494 | for i in range(attrs.length)) | ||
| 495 | if child.nodeName in SINGLE_ELEMENTS: | ||
| 496 | ret[child.nodeName] = element | ||
| 497 | elif child.nodeName in MULTI_ELEMENTS: | ||
| 498 | ret.setdefault(child.nodeName, []).append(element) | ||
| 499 | else: | ||
| 500 | raise ManifestParseError('Unhandled element "%s"' % (child.nodeName,)) | ||
| 501 | |||
| 502 | append_children(element, child) | ||
| 503 | |||
| 504 | append_children(ret, doc.firstChild) | ||
| 505 | |||
| 506 | return ret | ||
| 507 | |||
| 508 | def Save(self, fd, **kwargs): | ||
| 509 | """Write the current manifest out to the given file descriptor.""" | ||
| 510 | doc = self.ToXml(**kwargs) | ||
| 462 | doc.writexml(fd, '', ' ', '\n', 'UTF-8') | 511 | doc.writexml(fd, '', ' ', '\n', 'UTF-8') |
| 463 | 512 | ||
| 464 | def _output_manifest_project_extras(self, p, e): | 513 | def _output_manifest_project_extras(self, p, e): |
diff --git a/subcmds/manifest.py b/subcmds/manifest.py index f0a0d069..0052d7aa 100644 --- a/subcmds/manifest.py +++ b/subcmds/manifest.py | |||
| @@ -15,6 +15,8 @@ | |||
| 15 | # limitations under the License. | 15 | # limitations under the License. |
| 16 | 16 | ||
| 17 | from __future__ import print_function | 17 | from __future__ import print_function |
| 18 | |||
| 19 | import json | ||
| 18 | import os | 20 | import os |
| 19 | import sys | 21 | import sys |
| 20 | 22 | ||
| @@ -68,6 +70,10 @@ to indicate the remote ref to push changes to via 'repo upload'. | |||
| 68 | help='If in -r mode, do not write the dest-branch field. ' | 70 | help='If in -r mode, do not write the dest-branch field. ' |
| 69 | 'Only of use if the branch names for a sha1 manifest are ' | 71 | 'Only of use if the branch names for a sha1 manifest are ' |
| 70 | 'sensitive.') | 72 | 'sensitive.') |
| 73 | p.add_option('--json', default=False, action='store_true', | ||
| 74 | help='Output manifest in JSON format (experimental).') | ||
| 75 | p.add_option('--pretty', default=False, action='store_true', | ||
| 76 | help='Format output for humans to read.') | ||
| 71 | p.add_option('-o', '--output-file', | 77 | p.add_option('-o', '--output-file', |
| 72 | dest='output_file', | 78 | dest='output_file', |
| 73 | default='-', | 79 | default='-', |
| @@ -83,10 +89,26 @@ to indicate the remote ref to push changes to via 'repo upload'. | |||
| 83 | fd = sys.stdout | 89 | fd = sys.stdout |
| 84 | else: | 90 | else: |
| 85 | fd = open(opt.output_file, 'w') | 91 | fd = open(opt.output_file, 'w') |
| 86 | self.manifest.Save(fd, | 92 | if opt.json: |
| 87 | peg_rev=opt.peg_rev, | 93 | print('warning: --json is experimental!', file=sys.stderr) |
| 88 | peg_rev_upstream=opt.peg_rev_upstream, | 94 | doc = self.manifest.ToDict(peg_rev=opt.peg_rev, |
| 89 | peg_rev_dest_branch=opt.peg_rev_dest_branch) | 95 | peg_rev_upstream=opt.peg_rev_upstream, |
| 96 | peg_rev_dest_branch=opt.peg_rev_dest_branch) | ||
| 97 | |||
| 98 | json_settings = { | ||
| 99 | # JSON style guide says Uunicode characters are fully allowed. | ||
| 100 | 'ensure_ascii': False, | ||
| 101 | # We use 2 space indent to match JSON style guide. | ||
| 102 | 'indent': 2 if opt.pretty else None, | ||
| 103 | 'separators': (',', ': ') if opt.pretty else (',', ':'), | ||
| 104 | 'sort_keys': True, | ||
| 105 | } | ||
| 106 | fd.write(json.dumps(doc, **json_settings)) | ||
| 107 | else: | ||
| 108 | self.manifest.Save(fd, | ||
| 109 | peg_rev=opt.peg_rev, | ||
| 110 | peg_rev_upstream=opt.peg_rev_upstream, | ||
| 111 | peg_rev_dest_branch=opt.peg_rev_dest_branch) | ||
| 90 | fd.close() | 112 | fd.close() |
| 91 | if opt.output_file != '-': | 113 | if opt.output_file != '-': |
| 92 | print('Saved manifest to %s' % opt.output_file, file=sys.stderr) | 114 | print('Saved manifest to %s' % opt.output_file, file=sys.stderr) |
