OLD | NEW |
| (Empty) |
1 #!/usr/bin/env python | |
2 # Copyright 2016 The Chromium Authors. All rights reserved. | |
3 # Use of this source code is governed by a BSD-style license that can be | |
4 # found in the LICENSE file. | |
5 | |
6 """ A collator for Service Manifests """ | |
7 | |
8 import argparse | |
9 import json | |
10 import os | |
11 import shutil | |
12 import sys | |
13 import urlparse | |
14 | |
15 | |
16 # Keys which are completely overridden by manifest overlays | |
17 _MANIFEST_OVERLAY_OVERRIDE_KEYS = [ | |
18 "display_name", | |
19 "process-group", | |
20 ] | |
21 | |
22 eater_relative = '../../../../../../tools/json_comment_eater' | |
23 eater_relative = os.path.join(os.path.abspath(__file__), eater_relative) | |
24 sys.path.insert(0, os.path.normpath(eater_relative)) | |
25 try: | |
26 import json_comment_eater | |
27 finally: | |
28 sys.path.pop(0) | |
29 | |
30 | |
31 def ParseJSONFile(filename): | |
32 with open(filename) as json_file: | |
33 try: | |
34 return json.loads(json_comment_eater.Nom(json_file.read())) | |
35 except ValueError as e: | |
36 print "%s is not a valid JSON document" % filename | |
37 raise e | |
38 | |
39 | |
40 def MergeDicts(left, right): | |
41 for k, v in right.iteritems(): | |
42 if k not in left: | |
43 left[k] = v | |
44 else: | |
45 if isinstance(v, dict): | |
46 assert isinstance(left[k], dict) | |
47 MergeDicts(left[k], v) | |
48 elif isinstance(v, list): | |
49 assert isinstance(left[k], list) | |
50 left[k].extend(v) | |
51 else: | |
52 raise "Refusing to merge conflicting non-collection values." | |
53 return left | |
54 | |
55 | |
56 def MergeManifestOverlay(manifest, overlay): | |
57 MergeDicts(manifest["capabilities"], overlay["capabilities"]) | |
58 | |
59 if "services" in overlay: | |
60 if "services" not in manifest: | |
61 manifest["services"] = [] | |
62 manifest["services"].extend(overlay["services"]) | |
63 | |
64 for key in _MANIFEST_OVERLAY_OVERRIDE_KEYS: | |
65 if key in overlay: | |
66 manifest[key] = overlay[key] | |
67 | |
68 | |
69 def main(): | |
70 parser = argparse.ArgumentParser( | |
71 description="Collate Service Manifests.") | |
72 parser.add_argument("--parent") | |
73 parser.add_argument("--output") | |
74 parser.add_argument("--name") | |
75 parser.add_argument("--overlays", nargs="+", dest="overlays", default=[]) | |
76 args, children = parser.parse_known_args() | |
77 | |
78 parent = ParseJSONFile(args.parent) | |
79 | |
80 service_path = parent['name'].split(':')[1] | |
81 if service_path.startswith('//'): | |
82 raise ValueError("Service name path component '%s' must not start " \ | |
83 "with //" % service_path) | |
84 | |
85 if args.name != service_path: | |
86 raise ValueError("Service name '%s' specified in build file does not " \ | |
87 "match name '%s' specified in manifest." % | |
88 (args.name, service_path)) | |
89 | |
90 services = [] | |
91 for child in children: | |
92 services.append(ParseJSONFile(child)) | |
93 | |
94 if len(services) > 0: | |
95 parent['services'] = services | |
96 | |
97 for overlay_path in args.overlays: | |
98 MergeManifestOverlay(parent, ParseJSONFile(overlay_path)) | |
99 | |
100 with open(args.output, 'w') as output_file: | |
101 json.dump(parent, output_file) | |
102 | |
103 return 0 | |
104 | |
105 if __name__ == "__main__": | |
106 sys.exit(main()) | |
OLD | NEW |