• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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