1645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#!/usr/bin/env python
2645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez# Copyright 2016 The Chromium Authors. All rights reserved.
3645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez# Use of this source code is governed by a BSD-style license that can be
4645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez# found in the LICENSE file.
5645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
6645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez""" A collator for Mojo Application Manifests """
7645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
8645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezimport argparse
9645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezimport json
10645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezimport os
11645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezimport shutil
12645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezimport sys
13645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezimport urlparse
14645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
15645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezeater_relative = '../../../../../tools/json_comment_eater'
16645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezeater_relative = os.path.join(os.path.abspath(__file__), eater_relative)
17645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezsys.path.insert(0, os.path.normpath(eater_relative))
18645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveztry:
19645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  import json_comment_eater
20645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezfinally:
21645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  sys.path.pop(0)
22645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
23645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezdef ParseJSONFile(filename):
24645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  with open(filename) as json_file:
25645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    try:
26645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      return json.loads(json_comment_eater.Nom(json_file.read()))
27645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    except ValueError:
28645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      print "%s is not a valid JSON document" % filename
29645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      return None
30645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
31645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezdef MergeDicts(left, right):
32645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  for k, v in right.iteritems():
33645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if k not in left:
34645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      left[k] = v
35645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    else:
36645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      if isinstance(v, dict):
37645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        assert isinstance(left[k], dict)
38645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        MergeDicts(left[k], v)
39645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      elif isinstance(v, list):
40645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        assert isinstance(left[k], list)
41645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        left[k].extend(v)
42645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      else:
43645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        raise "Refusing to merge conflicting non-collection values."
44645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return left
45645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
46645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
47645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezdef MergeBaseManifest(parent, base):
48645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  MergeDicts(parent["capabilities"], base["capabilities"])
49645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
50645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if "applications" in base:
51645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if "applications" not in parent:
52645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      parent["applications"] = []
53645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    parent["applications"].extend(base["applications"])
54645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
55645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if "process-group" in base:
56645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    parent["process-group"] = base["process-group"]
57645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
58645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
59645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezdef main():
60645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  parser = argparse.ArgumentParser(
61645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      description="Collate Mojo application manifests.")
62645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  parser.add_argument("--parent")
63645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  parser.add_argument("--output")
64645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  parser.add_argument("--application-name")
65645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  parser.add_argument("--base-manifest", default=None)
66645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  args, children = parser.parse_known_args()
67645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
68645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  parent = ParseJSONFile(args.parent)
69645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if parent == None:
70645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return 1
71645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
72645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if args.base_manifest:
73645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    base = ParseJSONFile(args.base_manifest)
74645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if base == None:
75645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      return 1
76645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    MergeBaseManifest(parent, base)
77645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
78645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  app_path = parent['name'].split(':')[1]
79645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if app_path.startswith('//'):
80645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    raise ValueError("Application name path component '%s' must not start " \
81645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                     "with //" % app_path)
82645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
83645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if args.application_name != app_path:
84645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    raise ValueError("Application name '%s' specified in build file does not " \
85645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                     "match application name '%s' specified in manifest." %
86645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                     (args.application_name, app_path))
87645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
88645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  applications = []
89645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  for child in children:
90645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    application = ParseJSONFile(child)
91645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if application == None:
92645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      return 1
93645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    applications.append(application)
94645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
95645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if len(applications) > 0:
96645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    parent['applications'] = applications
97645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
98645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  with open(args.output, 'w') as output_file:
99645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    json.dump(parent, output_file)
100645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
101645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return 0
102645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
103645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezif __name__ == "__main__":
104645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  sys.exit(main())
105