OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """ A collator for Service Manifests """ | 6 """ A collator for Service Manifests """ |
7 | 7 |
8 import argparse | 8 import argparse |
9 import json | 9 import json |
10 import os | 10 import os |
11 import shutil | 11 import shutil |
12 import sys | 12 import sys |
13 import urlparse | 13 import urlparse |
14 | 14 |
15 | 15 |
16 # Keys which are completely overridden by manifest overlays | 16 # Keys which are completely overridden by manifest overlays |
17 _MANIFEST_OVERLAY_OVERRIDE_KEYS = [ | 17 _MANIFEST_OVERLAY_OVERRIDE_KEYS = [ |
18 "display_name", | 18 "display_name", |
19 ] | 19 ] |
20 | 20 |
21 eater_relative = '../../../../../../tools/json_comment_eater' | 21 eater_relative = "../../../../../../tools/json_comment_eater" |
22 eater_relative = os.path.join(os.path.abspath(__file__), eater_relative) | 22 eater_relative = os.path.join(os.path.abspath(__file__), eater_relative) |
23 sys.path.insert(0, os.path.normpath(eater_relative)) | 23 sys.path.insert(0, os.path.normpath(eater_relative)) |
24 try: | 24 try: |
25 import json_comment_eater | 25 import json_comment_eater |
26 finally: | 26 finally: |
27 sys.path.pop(0) | 27 sys.path.pop(0) |
28 | 28 |
29 | 29 |
30 def ParseJSONFile(filename): | 30 def ParseJSONFile(filename): |
31 with open(filename) as json_file: | 31 with open(filename) as json_file: |
(...skipping 27 matching lines...) Expand all Loading... |
59 if "services" in overlay: | 59 if "services" in overlay: |
60 if "services" not in manifest: | 60 if "services" not in manifest: |
61 manifest["services"] = [] | 61 manifest["services"] = [] |
62 manifest["services"].extend(overlay["services"]) | 62 manifest["services"].extend(overlay["services"]) |
63 | 63 |
64 for key in _MANIFEST_OVERLAY_OVERRIDE_KEYS: | 64 for key in _MANIFEST_OVERLAY_OVERRIDE_KEYS: |
65 if key in overlay: | 65 if key in overlay: |
66 manifest[key] = overlay[key] | 66 manifest[key] = overlay[key] |
67 | 67 |
68 | 68 |
| 69 def SanityCheckManifestServices(manifest): |
| 70 """Ensures any given service name appears only once within a manifest.""" |
| 71 known_services = set() |
| 72 def has_no_dupes(root): |
| 73 if "name" in root: |
| 74 name = root["name"] |
| 75 if name in known_services: |
| 76 raise ValueError( |
| 77 "Duplicate manifest entry found for service: %s" % name) |
| 78 known_services.add(name) |
| 79 if "services" not in root: |
| 80 return True |
| 81 return all(has_no_dupes(service) for service in root["services"]) |
| 82 return has_no_dupes(manifest) |
| 83 |
| 84 |
69 def main(): | 85 def main(): |
70 parser = argparse.ArgumentParser( | 86 parser = argparse.ArgumentParser( |
71 description="Collate Service Manifests.") | 87 description="Collate Service Manifests.") |
72 parser.add_argument("--parent") | 88 parser.add_argument("--parent") |
73 parser.add_argument("--output") | 89 parser.add_argument("--output") |
74 parser.add_argument("--name") | 90 parser.add_argument("--name") |
75 parser.add_argument("--pretty", action="store_true") | 91 parser.add_argument("--pretty", action="store_true") |
76 parser.add_argument("--overlays", nargs="+", dest="overlays", default=[]) | 92 parser.add_argument("--overlays", nargs="+", dest="overlays", default=[]) |
77 parser.add_argument("--packaged-services", nargs="+", | 93 parser.add_argument("--packaged-services", nargs="+", |
78 dest="packaged_services", default=[]) | 94 dest="packaged_services", default=[]) |
79 args, _ = parser.parse_known_args() | 95 args, _ = parser.parse_known_args() |
80 | 96 |
81 parent = ParseJSONFile(args.parent) | 97 parent = ParseJSONFile(args.parent) |
82 | 98 |
83 service_path = parent['name'] | 99 service_name = parent["name"] if "name" in parent else "" |
84 if args.name and args.name != service_path: | 100 if args.name and args.name != service_name: |
85 raise ValueError("Service name '%s' specified in build file does not " \ | 101 raise ValueError("Service name '%s' specified in build file does not " \ |
86 "match name '%s' specified in manifest." % | 102 "match name '%s' specified in manifest." % |
87 (args.name, service_path)) | 103 (args.name, service_name)) |
88 | 104 |
89 packaged_services = [] | 105 packaged_services = [] |
90 for child_manifest in args.packaged_services: | 106 for child_manifest in args.packaged_services: |
91 packaged_services.append(ParseJSONFile(child_manifest)) | 107 packaged_services.append(ParseJSONFile(child_manifest)) |
92 | 108 |
93 if len(packaged_services) > 0: | 109 if len(packaged_services) > 0: |
94 if 'services' not in parent: | 110 if "services" not in parent: |
95 parent['services'] = packaged_services | 111 parent["services"] = packaged_services |
96 else: | 112 else: |
97 parent['services'].extend(packaged_services) | 113 parent["services"].extend(packaged_services) |
98 | 114 |
99 for overlay_path in args.overlays: | 115 for overlay_path in args.overlays: |
100 MergeManifestOverlay(parent, ParseJSONFile(overlay_path)) | 116 MergeManifestOverlay(parent, ParseJSONFile(overlay_path)) |
101 | 117 |
102 with open(args.output, 'w') as output_file: | 118 with open(args.output, "w") as output_file: |
103 json.dump(parent, output_file, indent=2 if args.pretty else -1) | 119 json.dump(parent, output_file, indent=2 if args.pretty else -1) |
104 | 120 |
| 121 # NOTE: We do the sanity check and possible failure *after* outputting the |
| 122 # aggregate manifest so it's easier to inspect erroneous output. |
| 123 SanityCheckManifestServices(parent) |
| 124 |
105 return 0 | 125 return 0 |
106 | 126 |
107 if __name__ == "__main__": | 127 if __name__ == "__main__": |
108 sys.exit(main()) | 128 sys.exit(main()) |
OLD | NEW |