Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / third_party / tvcm / tvcm / parse_deps.py
1 # Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4 """The core of this script is the calc_load_sequence function. This function
5 loads the provided javascript files and figures out their dependencies by
6 reading the tvcm.require statements in each file. This allows us to, for
7 example, have a trio of modules, foo, bar and baz, where foo.js contains:
8
9     tvcm.require('bar');
10
11 and bar.js contains:
12
13     tvcm.require('baz');
14
15 If these three modules are in the current directory, then:
16
17     calc_load_sequence(['foo'], '.')
18
19 Will return the correct sequence in which to load these modules based on these
20 dependencies, which is: [Module('baz'), Module('bar'), Module('foo')].
21
22 """
23
24 import os
25
26 from tvcm import module
27 from tvcm import resource_loader
28
29
30 def calc_load_sequence(filenames, project):
31   """Given a list of starting javascript files, figure out all the Module
32   objects that need to be loaded to satisfy their dependencies.
33
34   The javascript files should specify their dependencies in a format that is
35   textually equivalent to tvcm/__init__.js' require syntax, namely:
36
37       tvcm.require(module1);
38       tvcm.require(module2);
39       tvcm.requireStylesheet(stylesheet);
40
41   Args:
42     filenames: A list of starting file paths for trace viewer modules.
43
44   Returns:
45     A list of Module objects in the order that they should be loaded.
46   """
47   if os.path.join('tvcm', '__init__.js') not in filenames:
48     filenames = list(filenames)
49     filenames.insert(0, os.path.join('tvcm', '__init__.js'))
50   return calc_load_sequence_internal(filenames, project)
51
52
53 def calc_load_sequence_internal(filenames, project):
54   """Helper function for calc_load_sequence.
55
56   Args:
57     filenames: A list of starting file paths for trace viewer modules.
58     project : A tvcm.Project
59
60   Returns:
61     A list of Module objects in the list that they should be loaded.
62   """
63   loader = resource_loader.ResourceLoader(project)
64   initial_module_name_indices = {}
65   for filename in filenames:
66     m = loader.load_module(module_filename=filename)
67     if m.name not in initial_module_name_indices:
68       initial_module_name_indices[m.name] = len(initial_module_name_indices)
69
70   # Find the root modules: ones that have no dependencies. While doing that,
71   # sort the dependent module list so that the computed load order is stable.
72   module_ref_counts = {}
73   for m in loader.loaded_modules.values():
74     m.dependent_modules.sort(lambda x, y: cmp(x.name, y.name))
75     module_ref_counts[m.name] = 0
76
77   # Count the number of references to each module.
78   def inc_ref_count(name):
79     module_ref_counts[name] = module_ref_counts[name] + 1
80   for m in loader.loaded_modules.values():
81     for dependent_module in m.dependent_modules:
82       inc_ref_count(dependent_module.name)
83
84   # Root modules are modules with nothing depending on them.
85   root_modules = [loader.loaded_modules[name]
86                   for name, ref_count in module_ref_counts.items()
87                   if ref_count == 0]
88
89   # Sort root_modules by the order they were originally requested,
90   # then sort everything else by name.
91   def compare_root_module(x, y):
92     n = len(initial_module_name_indices)
93     iX = initial_module_name_indices.get(x.name, n)
94     iY = initial_module_name_indices.get(y.name, n)
95     if cmp(iX, iY) != 0:
96       return cmp(iX, iY)
97     return cmp(x.name, y.name)
98   root_modules.sort(compare_root_module)
99
100   already_loaded_set = set()
101   load_sequence = []
102   for m in root_modules:
103     m.compute_load_sequence_recursive(load_sequence, already_loaded_set)
104   return load_sequence