blob: d424419a417e96f552efb1d218dd2264e0c52a5a [file] [log] [blame]
Aaron Masseye4d92222020-07-13 17:41:29 +00001#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# Copyright 2020 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
Aaron Massey40b5d422020-08-11 17:29:21 +00007"""This is a utility script for parsing the repo manifest used by gerrit.el"""
Aaron Masseye4d92222020-07-13 17:41:29 +00008
9import xml.parsers.expat as xml
10import sys
11import argparse
12import pathlib
Aaron Massey40b5d422020-08-11 17:29:21 +000013import subprocess
Aaron Masseye4d92222020-07-13 17:41:29 +000014
Aaron Massey40b5d422020-08-11 17:29:21 +000015def parse_manifest_projects_to_lisp_alist(repo_root_path):
16 """Parse repo manifest to Lisp alist.
Aaron Masseye4d92222020-07-13 17:41:29 +000017
18 Any project without a dest-branch attribute is skipped.
19
20 Args:
Aaron Massey40b5d422020-08-11 17:29:21 +000021 repo_root_path: The path to a repo root.
Aaron Masseye4d92222020-07-13 17:41:29 +000022
23 Returns:
24 Lisp readable alist with elements of the form ((name . dest-branch) . path)
25
26 Raises:
Aaron Massey40b5d422020-08-11 17:29:21 +000027 CalledProcessError: The repo tool threw an error getting the manifest.
Aaron Masseye4d92222020-07-13 17:41:29 +000028 ExpatError: An error occured when attempting to parse.
29 """
30
31 assoc_list_entries = []
32
33 def _project_elem_handler(name, attrs):
34 """XML element handler collecting project elements to form a Lisp alist.
35
36 Args:
37 name: The name of the handled xml element.
38 attrs: A dictionary of the handled xml element's attributes.
39 """
40 if name == 'project':
Aaron Masseye4d92222020-07-13 17:41:29 +000041 project_name = attrs['name']
Aaron Massey0a509122020-08-10 21:46:43 +000042 project_path = attrs.get('path', project_name)
43 dest_branch = attrs.get('dest-branch')
Aaron Masseye4d92222020-07-13 17:41:29 +000044 if not dest_branch:
45 # We skip anything without a dest-branch
46 return
47 # We don't want the refs/heads/ prefix of dest-branch
48 dest_branch = dest_branch.replace('refs/heads/', '')
49
50 key = '("{}" . "{}")'.format(project_name, dest_branch)
51 value = '"{}"'.format(project_path)
52
53 assoc_list_entries.append('({} . {})'.format(key, value))
54
55 p = xml.ParserCreate()
56 p.StartElementHandler = _project_elem_handler
Aaron Massey40b5d422020-08-11 17:29:21 +000057
58 repo_cmd = ['repo', '--no-pager', 'manifest']
59 repo_cmd_result = subprocess.run(repo_cmd,
60 cwd=repo_root_path.expanduser().resolve(),
61 capture_output=True,
62 check=True)
63 p.Parse(repo_cmd_result.stdout)
64 return '({})'.format(''.join(assoc_list_entries))
Aaron Masseye4d92222020-07-13 17:41:29 +000065
66
67def main(argv):
68 """main."""
69 arg_parser = argparse.ArgumentParser()
Aaron Massey40b5d422020-08-11 17:29:21 +000070 arg_parser.add_argument('repo_root_path',
Aaron Masseye4d92222020-07-13 17:41:29 +000071 type=pathlib.Path,
Aaron Massey40b5d422020-08-11 17:29:21 +000072 help='System path to repo root.')
Aaron Masseye4d92222020-07-13 17:41:29 +000073 args = arg_parser.parse_args(argv)
74
75 try:
Aaron Massey40b5d422020-08-11 17:29:21 +000076 print(parse_manifest_projects_to_lisp_alist(args.repo_root_path))
Aaron Masseye4d92222020-07-13 17:41:29 +000077 return 0
78
79 except xml.ExpatError as err:
80 print('XML Parsing Error:', err)
81 return 1
82
83
84if __name__ == '__main__':
85 sys.exit(main(sys.argv[1:]))