File: compile_modules.py

package info (click to toggle)
chromium-browser 41.0.2272.118-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie-kfreebsd
  • size: 2,189,132 kB
  • sloc: cpp: 9,691,462; ansic: 3,341,451; python: 712,689; asm: 518,779; xml: 208,926; java: 169,820; sh: 119,353; perl: 68,907; makefile: 28,311; yacc: 13,305; objc: 11,385; tcl: 3,186; cs: 2,225; sql: 2,217; lex: 2,215; lisp: 1,349; pascal: 1,256; awk: 407; ruby: 155; sed: 53; php: 14; exp: 11
file content (127 lines) | stat: -rwxr-xr-x 4,001 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#!/usr/bin/env python
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import argparse
from checker import Checker as Checker
import os
import sys

try:
  import json
except:
  import simplejson as json


class Module(object):
  def __init__(self, name, sources, depends=[], externs=[]):
    self.name = name
    self.sources = sources
    # TODO(dbeam): support depending on other modules/dependency flattening.
    self.depends = depends
    self.externs = externs

  @staticmethod
  def from_dict(d):
    keys = d.keys()

    required = ["name", "sources"]
    assert all(r in keys for r in required), "Module missing name or sources"

    allowed = required + ["depends", "externs"]
    assert all(k in allowed for k in keys), "Module has unknown key"

    depends = d["depends"] if "depends" in d else []
    externs = d["externs"] if "externs" in d else []
    return Module(d["name"], d["sources"], depends=depends, externs=externs)


# TODO(dbeam): should ModuleParser be internal to ModuleCompiler or should we
# pass Modules into ModuleCompiler.compile()? Maybe this is fine?
class ModuleParser(object):
  _cache = {}

  def __init__(self, verbose=False):
    self._verbose = verbose

  def parse(self, file_path):
    if file_path in self._cache:
      print "(INFO) Found module file %s in the cache" % file_path
      return self._cache[file_path]

    file = open(file_path, "r")
    data = json.load(file)
    file.close()

    if self._verbose:
      pretty_json = json.dumps(data, indent=2, separators=(',', ': ')).strip()
      print "(INFO) Layout: " + os.linesep + pretty_json + os.linesep

    self._cache[file_path] = [Module.from_dict(m) for m in data]
    return self._cache[file_path]


class ModuleCompiler(object):
  _checker = None
  _parser = None

  def __init__(self, verbose=False):
    self._verbose = verbose

  def _debug(self, msg, prefix="(INFO) ", suffix=""):
    if self._verbose:
      print prefix + msg.strip() + suffix

  def compile(self, module_file):
    self._debug("MODULE FILE: " + module_file, prefix="")

    # NOTE: It's possible but unlikely that |_checker| or |_parser|'s verbosity
    # isn't the same as |self._verbose| due to this class being called with
    # verbose=False then verbose=True in the same program.
    self._parser = self._parser or ModuleParser(verbose=self._verbose)
    self._checker = self._checker or Checker(verbose=self._verbose)

    current_dir = os.getcwd()
    module_dir = os.path.dirname(module_file)
    rel_path = lambda f: f

    if current_dir and module_dir:
      here_to_module_dir = os.path.relpath(module_dir, current_dir)
      if here_to_module_dir:
        rel_path = lambda f: os.path.join(here_to_module_dir, f)

    modules = self._parser.parse(module_file)

    for m in modules:
      self._debug("MODULE: " + m.name, prefix="", suffix=os.linesep)

      for s in m.sources:
        depends = [rel_path(d) for d in m.depends]
        externs = [rel_path(e) for e in m.externs]
        exit_code, _ = self._checker.check(rel_path(s), depends=depends,
                                           externs=externs)
        if exit_code:
          sys.exit(exit_code)

        if s != m.sources[-1]:
          self._debug(os.linesep, prefix="")

      if m != modules[-1]:
        self._debug(os.linesep, prefix="")


def main(opts):
  module_compiler = ModuleCompiler(verbose=opts.verbose)
  for module_file in opts.module_file:
    module_compiler.compile(module_file)


if __name__ == "__main__":
  parser = argparse.ArgumentParser(
      description="Typecheck JavaScript using Closure compiler")
  parser.add_argument("-v", "--verbose", action="store_true",
                      help="Show more information as this script runs")
  parser.add_argument("module_file", nargs=argparse.ONE_OR_MORE,
                      help="Path to a modules file to check")
  main(parser.parse_args())