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 Mojo Application Manifests """ 7 8import argparse 9import json 10import os 11import shutil 12import sys 13import urlparse 14 15eater_relative = '../../../../../tools/json_comment_eater' 16eater_relative = os.path.join(os.path.abspath(__file__), eater_relative) 17sys.path.insert(0, os.path.normpath(eater_relative)) 18try: 19 import json_comment_eater 20finally: 21 sys.path.pop(0) 22 23def ParseJSONFile(filename): 24 with open(filename) as json_file: 25 try: 26 return json.loads(json_comment_eater.Nom(json_file.read())) 27 except ValueError: 28 print "%s is not a valid JSON document" % filename 29 return None 30 31def MergeDicts(left, right): 32 for k, v in right.iteritems(): 33 if k not in left: 34 left[k] = v 35 else: 36 if isinstance(v, dict): 37 assert isinstance(left[k], dict) 38 MergeDicts(left[k], v) 39 elif isinstance(v, list): 40 assert isinstance(left[k], list) 41 left[k].extend(v) 42 else: 43 raise "Refusing to merge conflicting non-collection values." 44 return left 45 46 47def MergeBaseManifest(parent, base): 48 MergeDicts(parent["capabilities"], base["capabilities"]) 49 50 if "applications" in base: 51 if "applications" not in parent: 52 parent["applications"] = [] 53 parent["applications"].extend(base["applications"]) 54 55 if "process-group" in base: 56 parent["process-group"] = base["process-group"] 57 58 59def main(): 60 parser = argparse.ArgumentParser( 61 description="Collate Mojo application manifests.") 62 parser.add_argument("--parent") 63 parser.add_argument("--output") 64 parser.add_argument("--application-name") 65 parser.add_argument("--base-manifest", default=None) 66 args, children = parser.parse_known_args() 67 68 parent = ParseJSONFile(args.parent) 69 if parent == None: 70 return 1 71 72 if args.base_manifest: 73 base = ParseJSONFile(args.base_manifest) 74 if base == None: 75 return 1 76 MergeBaseManifest(parent, base) 77 78 app_path = parent['name'].split(':')[1] 79 if app_path.startswith('//'): 80 raise ValueError("Application name path component '%s' must not start " \ 81 "with //" % app_path) 82 83 if args.application_name != app_path: 84 raise ValueError("Application name '%s' specified in build file does not " \ 85 "match application name '%s' specified in manifest." % 86 (args.application_name, app_path)) 87 88 applications = [] 89 for child in children: 90 application = ParseJSONFile(child) 91 if application == None: 92 return 1 93 applications.append(application) 94 95 if len(applications) > 0: 96 parent['applications'] = applications 97 98 with open(args.output, 'w') as output_file: 99 json.dump(parent, output_file) 100 101 return 0 102 103if __name__ == "__main__": 104 sys.exit(main()) 105