Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(502)

Side by Side Diff: tools/perf/core/find_dependencies.py

Issue 2933163002: Revert of Remove find_dependencies script (Closed)
Patch Set: Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/perf/core/bootstrap.py ('k') | tools/perf/core/find_dependencies_unittest.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright 2014 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
5 import fnmatch
6 import imp
7 import logging
8 import optparse
9 import os
10 import sys
11 import zipfile
12
13 from telemetry import benchmark
14 from telemetry.core import discover
15 from telemetry.internal.util import command_line
16 from telemetry.internal.util import path
17 from telemetry.internal.util import path_set
18
19 try:
20 from modulegraph import modulegraph # pylint: disable=import-error
21 except ImportError as err:
22 modulegraph = None
23 import_error = err
24
25 from core import bootstrap
26 from core import path_util
27
28 DEPS_FILE = 'bootstrap_deps'
29
30
31 def FindBootstrapDependencies(base_dir):
32 deps_file = os.path.join(base_dir, DEPS_FILE)
33 if not os.path.exists(deps_file):
34 return []
35 deps_paths = bootstrap.ListAllDepsPaths(deps_file)
36 return set(os.path.realpath(os.path.join(
37 path_util.GetChromiumSrcDir(), '..', deps_path))
38 for deps_path in deps_paths)
39
40
41 def FindPythonDependencies(module_path):
42 logging.info('Finding Python dependencies of %s', module_path)
43 if modulegraph is None:
44 raise import_error
45
46 sys_path = sys.path
47 sys.path = list(sys_path)
48 try:
49 # Load the module to inherit its sys.path modifications.
50 sys.path.insert(0, os.path.abspath(os.path.dirname(module_path)))
51 imp.load_source(
52 os.path.splitext(os.path.basename(module_path))[0], module_path)
53
54 # Analyze the module for its imports.
55 graph = modulegraph.ModuleGraph()
56 graph.run_script(module_path)
57
58 # Filter for only imports in Chromium.
59 for node in graph.nodes():
60 if not node.filename:
61 continue
62 module_path = os.path.realpath(node.filename)
63
64 _, incoming_edges = graph.get_edges(node)
65 message = 'Discovered %s (Imported by: %s)' % (
66 node.filename, ', '.join(
67 d.filename for d in incoming_edges
68 if d is not None and d.filename is not None))
69 logging.info(message)
70
71 # This check is done after the logging/printing above to make sure that
72 # we also print out the dependency edges that include python packages
73 # that are not in chromium.
74 if not path.IsSubpath(module_path, path_util.GetChromiumSrcDir()):
75 continue
76
77 yield module_path
78 if node.packagepath is not None:
79 for p in node.packagepath:
80 yield p
81
82 finally:
83 sys.path = sys_path
84
85
86 def FindPageSetDependencies(base_dir):
87 logging.info('Finding page sets in %s', base_dir)
88
89 # Add base_dir to path so our imports relative to base_dir will work.
90 sys.path.append(base_dir)
91 tests = discover.DiscoverClasses(base_dir, base_dir, benchmark.Benchmark,
92 index_by_class_name=True)
93
94 for test_class in tests.itervalues():
95 test_obj = test_class()
96
97 # Ensure the test's default options are set if needed.
98 parser = optparse.OptionParser()
99 test_obj.AddCommandLineArgs(parser, None)
100 options = optparse.Values()
101 for k, v in parser.get_default_values().__dict__.iteritems():
102 options.ensure_value(k, v)
103
104 # Page set paths are relative to their runner script, not relative to us.
105 path.GetBaseDir = lambda: base_dir
106 # TODO: Loading the page set will automatically download its Cloud Storage
107 # deps. This is really expensive, and we don't want to do this by default.
108 story_set = test_obj.CreateStorySet(options)
109
110 # Add all of its serving_dirs as dependencies.
111 for serving_dir in story_set.serving_dirs:
112 yield serving_dir
113
114
115 def FindExcludedFiles(files, options):
116 # Define some filters for files.
117 def IsHidden(path_string):
118 for pathname_component in path_string.split(os.sep):
119 if pathname_component.startswith('.'):
120 return True
121 return False
122
123 def IsPyc(path_string):
124 return os.path.splitext(path_string)[1] == '.pyc'
125
126 def IsInCloudStorage(path_string):
127 return os.path.exists(path_string + '.sha1')
128
129 def MatchesExcludeOptions(path_string):
130 for pattern in options.exclude:
131 if (fnmatch.fnmatch(path_string, pattern) or
132 fnmatch.fnmatch(os.path.basename(path_string), pattern)):
133 return True
134 return False
135
136 # Collect filters we're going to use to exclude files.
137 exclude_conditions = [
138 IsHidden,
139 IsPyc,
140 IsInCloudStorage,
141 MatchesExcludeOptions,
142 ]
143
144 # Check all the files against the filters.
145 for file_path in files:
146 if any(condition(file_path) for condition in exclude_conditions):
147 yield file_path
148
149
150 def FindDependencies(target_paths, options):
151 # Verify arguments.
152 for target_path in target_paths:
153 if not os.path.exists(target_path):
154 raise ValueError('Path does not exist: %s' % target_path)
155
156 dependencies = path_set.PathSet()
157
158 # Including Telemetry's major entry points will (hopefully) include Telemetry
159 # and all its dependencies. If the user doesn't pass any arguments, we just
160 # have Telemetry.
161 dependencies |= FindPythonDependencies(os.path.realpath(
162 os.path.join(path_util.GetTelemetryDir(),
163 'telemetry', 'benchmark_runner.py')))
164 dependencies |= FindPythonDependencies(os.path.realpath(
165 os.path.join(path_util.GetTelemetryDir(),
166 'telemetry', 'testing', 'run_tests.py')))
167
168 # Add dependencies.
169 for target_path in target_paths:
170 base_dir = os.path.dirname(os.path.realpath(target_path))
171
172 dependencies.add(base_dir)
173 dependencies |= FindBootstrapDependencies(base_dir)
174 dependencies |= FindPythonDependencies(target_path)
175 if options.include_page_set_data:
176 dependencies |= FindPageSetDependencies(base_dir)
177
178 # Remove excluded files.
179 dependencies -= FindExcludedFiles(set(dependencies), options)
180
181 return dependencies
182
183
184 def ZipDependencies(target_paths, dependencies, options):
185 base_dir = os.path.dirname(os.path.realpath(path_util.GetChromiumSrcDir()))
186
187 with zipfile.ZipFile(options.zip, 'w', zipfile.ZIP_DEFLATED) as zip_file:
188 # Add dependencies to archive.
189 for dependency_path in dependencies:
190 path_in_archive = os.path.join(
191 'telemetry', os.path.relpath(dependency_path, base_dir))
192 zip_file.write(dependency_path, path_in_archive)
193
194 # Add symlinks to executable paths, for ease of use.
195 for target_path in target_paths:
196 link_info = zipfile.ZipInfo(
197 os.path.join('telemetry', os.path.basename(target_path)))
198 link_info.create_system = 3 # Unix attributes.
199 # 010 is regular file, 0111 is the permission bits rwxrwxrwx.
200 link_info.external_attr = 0100777 << 16 # Octal.
201
202 relative_path = os.path.relpath(target_path, base_dir)
203 link_script = (
204 '#!/usr/bin/env python\n\n'
205 'import os\n'
206 'import sys\n\n\n'
207 'script = os.path.join(os.path.dirname(__file__), \'%s\')\n'
208 'os.execv(sys.executable, [sys.executable, script] + sys.argv[1:])'
209 % relative_path)
210
211 zip_file.writestr(link_info, link_script)
212
213
214 class FindDependenciesCommand(command_line.OptparseCommand):
215 """Prints all dependencies"""
216
217 @classmethod
218 def AddCommandLineArgs(cls, parser, _):
219 parser.add_option(
220 '-v', '--verbose', action='count', dest='verbosity',
221 help='Increase verbosity level (repeat as needed).')
222
223 parser.add_option(
224 '-p', '--include-page-set-data', action='store_true', default=False,
225 help='Scan tests for page set data and include them.')
226
227 parser.add_option(
228 '-e', '--exclude', action='append', default=[],
229 help='Exclude paths matching EXCLUDE. Can be used multiple times.')
230
231 parser.add_option(
232 '-z', '--zip',
233 help='Store files in a zip archive at ZIP.')
234
235 @classmethod
236 def ProcessCommandLineArgs(cls, parser, args, _):
237 if args.verbosity >= 2:
238 logging.getLogger().setLevel(logging.DEBUG)
239 elif args.verbosity:
240 logging.getLogger().setLevel(logging.INFO)
241 else:
242 logging.getLogger().setLevel(logging.WARNING)
243
244 def Run(self, args):
245 target_paths = args.positional_args
246 dependencies = FindDependencies(target_paths, args)
247 if args.zip:
248 ZipDependencies(target_paths, dependencies, args)
249 print 'Zip archive written to %s.' % args.zip
250 else:
251 print '\n'.join(sorted(dependencies))
252 return 0
OLDNEW
« no previous file with comments | « tools/perf/core/bootstrap.py ('k') | tools/perf/core/find_dependencies_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698