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

Side by Side Diff: pylib/gyp/generator/analyzer.py

Issue 481433003: Makes the analyzer output the set of targets needing a build (Closed) Base URL: http://gyp.googlecode.com/svn/trunk/
Patch Set: review feedback Created 6 years, 4 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | test/analyzer/gyptest-analyzer.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2014 Google Inc. All rights reserved. 1 # Copyright (c) 2014 Google Inc. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """ 5 """
6 This script is intended for use as a GYP_GENERATOR. It takes as input (by way of 6 This script is intended for use as a GYP_GENERATOR. It takes as input (by way of
7 the generator flag config_path) the path of a json file that dictates the files 7 the generator flag config_path) the path of a json file that dictates the files
8 and targets to search for. The following keys are supported: 8 and targets to search for. The following keys are supported:
9 files: list of paths (relative) of the files to search for. 9 files: list of paths (relative) of the files to search for.
10 targets: list of targets to search for. The target names are unqualified. 10 targets: list of targets to search for. The target names are unqualified.
11 11
12 The following is output: 12 The following is output:
13 error: only supplied if there is an error. 13 error: only supplied if there is an error.
14 warning: only supplied if there is a warning. 14 warning: only supplied if there is a warning.
15 targets: the set of targets passed in via targets that either directly or 15 targets: the set of targets passed in via targets that either directly or
16 indirectly depend upon the set of paths supplied in files. 16 indirectly depend upon the set of paths supplied in files.
17 status: indicates if any of the supplied files matched at least one target. 17 build_targets: minimal set of targets that directly depend on the changed
18 files and need to be built. The expectation is this set of targets is passed
19 into a build step.
20 status: outputs one of three values: none of the supplied files were found,
21 one of the include files changed so that it should be assumed everything
22 changed (in this case targets and build_targets are not output) or at
23 least one file was found.
18 24
19 If the generator flag analyzer_output_path is specified, output is written 25 If the generator flag analyzer_output_path is specified, output is written
20 there. Otherwise output is written to stdout. 26 there. Otherwise output is written to stdout.
21 """ 27 """
22 28
23 import gyp.common 29 import gyp.common
24 import gyp.ninja_syntax as ninja_syntax 30 import gyp.ninja_syntax as ninja_syntax
25 import json 31 import json
26 import os 32 import os
27 import posixpath 33 import posixpath
28 import sys 34 import sys
29 35
30 debug = False 36 debug = False
31 37
32 found_dependency_string = 'Found dependency' 38 found_dependency_string = 'Found dependency'
33 no_dependency_string = 'No dependencies' 39 no_dependency_string = 'No dependencies'
40 # Status when it should be assumed that everything has changed.
41 all_changed_string = 'Found dependency (all)'
34 42
35 # MatchStatus is used indicate if and how a target depends upon the supplied 43 # MatchStatus is used indicate if and how a target depends upon the supplied
36 # sources. 44 # sources.
37 # The target's sources contain one of the supplied paths. 45 # The target's sources contain one of the supplied paths.
38 MATCH_STATUS_MATCHES = 1 46 MATCH_STATUS_MATCHES = 1
39 # The target has a dependency on another target that contains one of the 47 # The target has a dependency on another target that contains one of the
40 # supplied paths. 48 # supplied paths.
41 MATCH_STATUS_MATCHES_BY_DEPENDENCY = 2 49 MATCH_STATUS_MATCHES_BY_DEPENDENCY = 2
42 # The target's sources weren't in the supplied paths and none of the target's 50 # The target's sources weren't in the supplied paths and none of the target's
43 # dependencies depend upon a target that matched. 51 # dependencies depend upon a target that matched.
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 if len(base_path): 144 if len(base_path):
137 base_path += '/' 145 base_path += '/'
138 146
139 if debug: 147 if debug:
140 print 'ExtractSources', target, base_path 148 print 'ExtractSources', target, base_path
141 149
142 results = [] 150 results = []
143 if 'sources' in target_dict: 151 if 'sources' in target_dict:
144 _AddSources(target_dict['sources'], base_path, base_path_components, 152 _AddSources(target_dict['sources'], base_path, base_path_components,
145 results) 153 results)
146 # Include the inputs from any actions. Any changes to these effect the 154 # Include the inputs from any actions. Any changes to these affect the
147 # resulting output. 155 # resulting output.
148 if 'actions' in target_dict: 156 if 'actions' in target_dict:
149 for action in target_dict['actions']: 157 for action in target_dict['actions']:
150 _ExtractSourcesFromAction(action, base_path, base_path_components, 158 _ExtractSourcesFromAction(action, base_path, base_path_components,
151 results) 159 results)
152 if 'rules' in target_dict: 160 if 'rules' in target_dict:
153 for rule in target_dict['rules']: 161 for rule in target_dict['rules']:
154 _ExtractSourcesFromAction(rule, base_path, base_path_components, results) 162 _ExtractSourcesFromAction(rule, base_path, base_path_components, results)
155 163
156 return results 164 return results
157 165
158 166
159 class Target(object): 167 class Target(object):
160 """Holds information about a particular target: 168 """Holds information about a particular target:
161 deps: set of the names of direct dependent targets. 169 deps: set of Targets this Target depends upon. This is not recursive, only the
162 match_staus: one of the MatchStatus values""" 170 direct dependent Targets.
163 def __init__(self): 171 match_status: one of the MatchStatus values.
172 back_deps: set of Targets that have a dependency on this Target.
173 visited: used during iteration to indicate whether we've visited this target.
174 This is used for two iterations, once in building the set of Targets and
175 again in _GetBuildTargets().
176 name: fully qualified name of the target.
177 requires_build: True if the target type is such that it needs to be built.
178 See _DoesTargetTypeRequireBuild for details.
179 added_to_compile_targets: used when determining if the target was added to the
180 set of targets that needs to be built.
181 in_roots: true if this target is a descendant of one of the root nodes."""
182 def __init__(self, name):
164 self.deps = set() 183 self.deps = set()
165 self.match_status = MATCH_STATUS_TBD 184 self.match_status = MATCH_STATUS_TBD
185 self.back_deps = set()
186 self.name = name
187 # TODO(sky): I don't like hanging this off Target. This state is specific
188 # to certain functions and should be isolated there.
189 self.visited = False
190 self.requires_build = False
191 self.added_to_compile_targets = False
192 self.in_roots = False
166 193
167 194
168 class Config(object): 195 class Config(object):
169 """Details what we're looking for 196 """Details what we're looking for
170 files: set of files to search for 197 files: set of files to search for
171 targets: see file description for details""" 198 targets: see file description for details."""
172 def __init__(self): 199 def __init__(self):
173 self.files = [] 200 self.files = []
174 self.targets = [] 201 self.targets = set()
175 202
176 def Init(self, params): 203 def Init(self, params):
177 """Initializes Config. This is a separate method as it raises an exception 204 """Initializes Config. This is a separate method as it raises an exception
178 if there is a parse error.""" 205 if there is a parse error."""
179 generator_flags = params.get('generator_flags', {}) 206 generator_flags = params.get('generator_flags', {})
180 config_path = generator_flags.get('config_path', None) 207 config_path = generator_flags.get('config_path', None)
181 if not config_path: 208 if not config_path:
182 return 209 return
183 try: 210 try:
184 f = open(config_path, 'r') 211 f = open(config_path, 'r')
185 config = json.load(f) 212 config = json.load(f)
186 f.close() 213 f.close()
187 except IOError: 214 except IOError:
188 raise Exception('Unable to open file ' + config_path) 215 raise Exception('Unable to open file ' + config_path)
189 except ValueError as e: 216 except ValueError as e:
190 raise Exception('Unable to parse config file ' + config_path + str(e)) 217 raise Exception('Unable to parse config file ' + config_path + str(e))
191 if not isinstance(config, dict): 218 if not isinstance(config, dict):
192 raise Exception('config_path must be a JSON file containing a dictionary') 219 raise Exception('config_path must be a JSON file containing a dictionary')
193 self.files = config.get('files', []) 220 self.files = config.get('files', [])
194 # Coalesce duplicates 221 self.targets = set(config.get('targets', []))
195 self.targets = list(set(config.get('targets', [])))
196 222
197 223
198 def _WasBuildFileModified(build_file, data, files): 224 def _WasBuildFileModified(build_file, data, files):
199 """Returns true if the build file |build_file| is either in |files| or 225 """Returns true if the build file |build_file| is either in |files| or
200 one of the files included by |build_file| is in |files|.""" 226 one of the files included by |build_file| is in |files|."""
201 if _ToGypPath(build_file) in files: 227 if _ToGypPath(build_file) in files:
202 if debug: 228 if debug:
203 print 'gyp file modified', build_file 229 print 'gyp file modified', build_file
204 return True 230 return True
205 231
206 # First element of included_files is the file itself. 232 # First element of included_files is the file itself.
207 if len(data[build_file]['included_files']) <= 1: 233 if len(data[build_file]['included_files']) <= 1:
208 return False 234 return False
209 235
210 for include_file in data[build_file]['included_files'][1:]: 236 for include_file in data[build_file]['included_files'][1:]:
211 # |included_files| are relative to the directory of the |build_file|. 237 # |included_files| are relative to the directory of the |build_file|.
212 rel_include_file = \ 238 rel_include_file = \
213 _ToGypPath(gyp.common.UnrelativePath(include_file, build_file)) 239 _ToGypPath(gyp.common.UnrelativePath(include_file, build_file))
214 if rel_include_file in files: 240 if rel_include_file in files:
215 if debug: 241 if debug:
216 print 'included gyp file modified, gyp_file=', build_file, \ 242 print 'included gyp file modified, gyp_file=', build_file, \
217 'included file=', rel_include_file 243 'included file=', rel_include_file
218 return True 244 return True
219 return False 245 return False
220 246
221 247
222 def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files): 248 def _GetOrCreateTargetByName(targets, target_name):
223 """Generates a dictionary with the key the name of a target and the value a 249 """Creates or returns the Target at targets[target_name]. If there is no
224 Target. |toplevel_dir| is the root of the source tree. If the sources of 250 Target for |target_name| one is created. Returns a tuple of whether a new
225 a target match that of |files|, then |target.matched| is set to True. 251 Target was created and the Target."""
226 This returns a tuple of the dictionary and whether at least one target's 252 if target_name in targets:
227 sources listed one of the paths in |files|.""" 253 return False, targets[target_name]
254 target = Target(target_name)
255 targets[target_name] = target
256 return True, target
257
258
259 def _DoesTargetTypeRequireBuild(target_dict):
260 """Returns true if the target type is such that it needs to be built."""
261 # If a 'none' target has rules or actions we assume it requires a build.
262 return target_dict['type'] != 'none' or \
263 target_dict.get('actions') or target_dict.get('rules')
264
265
266 def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files,
267 build_files):
268 """Returns a tuple of the following:
269 . A dictionary mapping from fully qualified name to Target.
270 . A list of the targets that have a source file in |files|.
271 . Set of root Targets reachable from the the files |build_files|.
272 This sets the |match_status| of the targets that contain any of the source
273 files in |files| to MATCH_STATUS_MATCHES.
274 |toplevel_dir| is the root of the source tree."""
275 # Maps from target name to Target.
228 targets = {} 276 targets = {}
229 277
278 # Targets that matched.
279 matching_targets = []
280
230 # Queue of targets to visit. 281 # Queue of targets to visit.
231 targets_to_visit = target_list[:] 282 targets_to_visit = target_list[:]
232 283
233 matched = False
234
235 # Maps from build file to a boolean indicating whether the build file is in 284 # Maps from build file to a boolean indicating whether the build file is in
236 # |files|. 285 # |files|.
237 build_file_in_files = {} 286 build_file_in_files = {}
238 287
288 # Root targets across all files.
289 roots = set()
290
291 # Set of Targets in |build_files|.
292 build_file_targets = set()
293
239 while len(targets_to_visit) > 0: 294 while len(targets_to_visit) > 0:
240 target_name = targets_to_visit.pop() 295 target_name = targets_to_visit.pop()
241 if target_name in targets: 296 created_target, target = _GetOrCreateTargetByName(targets, target_name)
297 if created_target:
298 roots.add(target)
299 elif target.visited:
242 continue 300 continue
243 301
244 target = Target() 302 target.visited = True
245 targets[target_name] = target 303 target.requires_build = _DoesTargetTypeRequireBuild(
304 target_dicts[target_name])
246 305
247 build_file = gyp.common.ParseQualifiedTarget(target_name)[0] 306 build_file = gyp.common.ParseQualifiedTarget(target_name)[0]
248 if not build_file in build_file_in_files: 307 if not build_file in build_file_in_files:
249 build_file_in_files[build_file] = \ 308 build_file_in_files[build_file] = \
250 _WasBuildFileModified(build_file, data, files) 309 _WasBuildFileModified(build_file, data, files)
251 310
311 if build_file in build_files:
312 build_file_targets.add(target)
313
252 # If a build file (or any of its included files) is modified we assume all 314 # If a build file (or any of its included files) is modified we assume all
253 # targets in the file are modified. 315 # targets in the file are modified.
254 if build_file_in_files[build_file]: 316 if build_file_in_files[build_file]:
317 print 'matching target from modified build file', target_name
255 target.match_status = MATCH_STATUS_MATCHES 318 target.match_status = MATCH_STATUS_MATCHES
256 matched = True 319 matching_targets.append(target)
257 else: 320 else:
258 sources = _ExtractSources(target_name, target_dicts[target_name], 321 sources = _ExtractSources(target_name, target_dicts[target_name],
259 toplevel_dir) 322 toplevel_dir)
260 for source in sources: 323 for source in sources:
261 if source in files: 324 if source in files:
325 print 'target', target_name, 'matches', source
262 target.match_status = MATCH_STATUS_MATCHES 326 target.match_status = MATCH_STATUS_MATCHES
263 matched = True 327 matching_targets.append(target)
264 break 328 break
265 329
330 # Add dependencies to visit as well as updating back pointers for deps.
266 for dep in target_dicts[target_name].get('dependencies', []): 331 for dep in target_dicts[target_name].get('dependencies', []):
267 targets[target_name].deps.add(dep)
268 targets_to_visit.append(dep) 332 targets_to_visit.append(dep)
269 333
270 return targets, matched 334 created_dep_target, dep_target = _GetOrCreateTargetByName(targets, dep)
335 if not created_dep_target:
336 roots.discard(dep_target)
337
338 target.deps.add(dep_target)
339 dep_target.back_deps.add(target)
340
341 return targets, matching_targets, roots & build_file_targets
271 342
272 343
273 def _GetUnqualifiedToQualifiedMapping(all_targets, to_find): 344 def _GetUnqualifiedToTargetMapping(all_targets, to_find):
274 """Returns a mapping (dictionary) from unqualified name to qualified name for 345 """Returns a mapping (dictionary) from unqualified name to Target for all the
275 all the targets in |to_find|.""" 346 Targets in |to_find|."""
276 result = {} 347 result = {}
277 if not to_find: 348 if not to_find:
278 return result 349 return result
279 to_find = set(to_find) 350 to_find = set(to_find)
280 for target_name in all_targets.keys(): 351 for target_name in all_targets.keys():
281 extracted = gyp.common.ParseQualifiedTarget(target_name) 352 extracted = gyp.common.ParseQualifiedTarget(target_name)
282 if len(extracted) > 1 and extracted[1] in to_find: 353 if len(extracted) > 1 and extracted[1] in to_find:
283 to_find.remove(extracted[1]) 354 to_find.remove(extracted[1])
284 result[extracted[1]] = target_name 355 result[extracted[1]] = all_targets[target_name]
285 if not to_find: 356 if not to_find:
286 return result 357 return result
287 return result 358 return result
288 359
289 360
290 def _DoesTargetDependOn(target, all_targets): 361 def _DoesTargetDependOn(target):
291 """Returns true if |target| or any of its dependencies matches the supplied 362 """Returns true if |target| or any of its dependencies matches the supplied
292 set of paths. This updates |matches| of the Targets as it recurses. 363 set of paths. This updates |matches| of the Targets as it recurses.
293 target: the Target to look for. 364 target: the Target to look for."""
294 all_targets: mapping from target name to Target.
295 matching_targets: set of targets looking for."""
296 if target.match_status == MATCH_STATUS_DOESNT_MATCH: 365 if target.match_status == MATCH_STATUS_DOESNT_MATCH:
297 return False 366 return False
298 if target.match_status == MATCH_STATUS_MATCHES or \ 367 if target.match_status == MATCH_STATUS_MATCHES or \
299 target.match_status == MATCH_STATUS_MATCHES_BY_DEPENDENCY: 368 target.match_status == MATCH_STATUS_MATCHES_BY_DEPENDENCY:
300 return True 369 return True
301 for dep_name in target.deps: 370 for dep in target.deps:
302 dep_target = all_targets[dep_name] 371 if _DoesTargetDependOn(dep):
303 if _DoesTargetDependOn(dep_target, all_targets): 372 target.match_status = MATCH_STATUS_MATCHES_BY_DEPENDENCY
304 dep_target.match_status = MATCH_STATUS_MATCHES_BY_DEPENDENCY
305 return True 373 return True
306 dep_target.match_status = MATCH_STATUS_DOESNT_MATCH 374 target.match_status = MATCH_STATUS_DOESNT_MATCH
307 return False 375 return False
308 376
309 377
310 def _GetTargetsDependingOn(all_targets, possible_targets): 378 def _GetTargetsDependingOn(possible_targets):
311 """Returns the list of targets in |possible_targets| that depend (either 379 """Returns the list of Targets in |possible_targets| that depend (either
312 directly on indirectly) on the matched files. 380 directly on indirectly) on the matched targets.
313 all_targets: mapping from target name to Target.
314 possible_targets: targets to search from.""" 381 possible_targets: targets to search from."""
315 found = [] 382 found = []
316 for target in possible_targets: 383 for target in possible_targets:
317 if _DoesTargetDependOn(all_targets[target], all_targets): 384 if _DoesTargetDependOn(target):
318 # possible_targets was initially unqualified, keep it unqualified. 385 found.append(target)
319 found.append(gyp.common.ParseQualifiedTarget(target)[1])
320 return found 386 return found
321 387
322 388
389 def _AddBuildTargets(target, roots, add_if_no_ancestor, result):
390 """Recurses through all targets that depend on |target|, adding all targets
391 that need to be built (and are in |roots|) to |result|.
392 roots: set of root targets.
393 add_if_no_ancestor: If true and there are no ancestors of |target| then add
394 |target| to |result|. |target| must still be in |roots|.
395 result: targets that need to be built are added here."""
396 if target.visited:
397 return
398
399 target.visited = True
400 target.in_roots = not target.back_deps and target in roots
401
402 for back_dep_target in target.back_deps:
403 _AddBuildTargets(back_dep_target, roots, False, result)
404 target.added_to_compile_targets |= back_dep_target.added_to_compile_targets
405 target.in_roots |= back_dep_target.in_roots
406
407 if not target.added_to_compile_targets and target.in_roots and \
408 (add_if_no_ancestor or target.requires_build):
409 result.add(target)
410 target.added_to_compile_targets = True
411
412
413 def _GetBuildTargets(matching_targets, roots):
414 """Returns the set of Targets that require a build.
415 matching_targets: targets that changed and need to be built.
416 roots: set of root targets in the build files to search from."""
417 result = set()
418 for target in matching_targets:
419 _AddBuildTargets(target, roots, True, result)
420 return result
421
422
323 def _WriteOutput(params, **values): 423 def _WriteOutput(params, **values):
324 """Writes the output, either to stdout or a file is specified.""" 424 """Writes the output, either to stdout or a file is specified."""
425 if 'error' in values:
426 print 'Error:', values['error']
427 if 'status' in values:
428 print values['status']
429 if 'targets' in values:
430 values['targets'].sort()
431 print 'Supplied targets that depend on changed files:'
432 for target in values['targets']:
433 print '\t', target
434 if 'build_targets' in values:
435 values['build_targets'].sort()
436 print 'Targets that require a build:'
437 for target in values['build_targets']:
438 print '\t', target
439
325 output_path = params.get('generator_flags', {}).get( 440 output_path = params.get('generator_flags', {}).get(
326 'analyzer_output_path', None) 441 'analyzer_output_path', None)
327 if not output_path: 442 if not output_path:
328 print json.dumps(values) 443 print json.dumps(values)
329 return 444 return
330 try: 445 try:
331 f = open(output_path, 'w') 446 f = open(output_path, 'w')
332 f.write(json.dumps(values) + '\n') 447 f.write(json.dumps(values) + '\n')
333 f.close() 448 f.close()
334 except IOError as e: 449 except IOError as e:
335 print 'Error writing to output file', output_path, str(e) 450 print 'Error writing to output file', output_path, str(e)
336 451
337 452
453 def _WasGypIncludeFileModified(params, files):
454 """Returns true if one of the files in |files| is in the set of included
455 files."""
456 if params['options'].includes:
457 for include in params['options'].includes:
458 if _ToGypPath(include) in files:
459 print 'Include file modified, assuming all changed', include
460 return True
461 return False
462
463
464 def _NamesNotIn(names, mapping):
465 """Returns a list of the values in |names| that are not in |mapping|."""
466 return [name for name in names if name not in mapping]
467
468
469 def _LookupTargets(names, mapping):
470 """Returns a list of the mapping[name] for each value in |names| that is in
471 |mapping|."""
472 return [mapping[name] for name in names if name in mapping]
473
474
338 def CalculateVariables(default_variables, params): 475 def CalculateVariables(default_variables, params):
339 """Calculate additional variables for use in the build (called by gyp).""" 476 """Calculate additional variables for use in the build (called by gyp)."""
340 flavor = gyp.common.GetFlavor(params) 477 flavor = gyp.common.GetFlavor(params)
341 if flavor == 'mac': 478 if flavor == 'mac':
342 default_variables.setdefault('OS', 'mac') 479 default_variables.setdefault('OS', 'mac')
343 elif flavor == 'win': 480 elif flavor == 'win':
344 default_variables.setdefault('OS', 'win') 481 default_variables.setdefault('OS', 'win')
345 # Copy additional generator configuration data from VS, which is shared 482 # Copy additional generator configuration data from VS, which is shared
346 # by the Windows Ninja generator. 483 # by the Windows Ninja generator.
347 import gyp.generator.msvs as msvs_generator 484 import gyp.generator.msvs as msvs_generator
(...skipping 16 matching lines...) Expand all
364 try: 501 try:
365 config.Init(params) 502 config.Init(params)
366 if not config.files: 503 if not config.files:
367 raise Exception('Must specify files to analyze via config_path generator ' 504 raise Exception('Must specify files to analyze via config_path generator '
368 'flag') 505 'flag')
369 506
370 toplevel_dir = _ToGypPath(os.path.abspath(params['options'].toplevel_dir)) 507 toplevel_dir = _ToGypPath(os.path.abspath(params['options'].toplevel_dir))
371 if debug: 508 if debug:
372 print 'toplevel_dir', toplevel_dir 509 print 'toplevel_dir', toplevel_dir
373 510
374 matched = False 511 if _WasGypIncludeFileModified(params, config.files):
375 matched_include = False 512 result_dict = { 'status': all_changed_string,
513 'targets': list(config.targets) }
514 _WriteOutput(params, **result_dict)
515 return
376 516
377 # If one of the modified files is an include file then everything is 517 all_targets, matching_targets, roots = _GenerateTargets(
378 # affected. 518 data, target_list, target_dicts, toplevel_dir, frozenset(config.files),
379 if params['options'].includes: 519 params['build_files'])
380 for include in params['options'].includes:
381 if _ToGypPath(include) in config.files:
382 if debug:
383 print 'include path modified', include
384 matched_include = True
385 matched = True
386 break
387
388 if not matched:
389 all_targets, matched = _GenerateTargets(data, target_list, target_dicts,
390 toplevel_dir,
391 frozenset(config.files))
392 520
393 warning = None 521 warning = None
394 if matched_include: 522 unqualified_mapping = _GetUnqualifiedToTargetMapping(all_targets,
395 output_targets = config.targets 523 config.targets)
396 elif matched: 524 if len(unqualified_mapping) != len(config.targets):
397 unqualified_mapping = _GetUnqualifiedToQualifiedMapping( 525 not_found = _NamesNotIn(config.targets, unqualified_mapping)
398 all_targets, config.targets) 526 warning = 'Unable to find all targets: ' + str(not_found)
399 if len(unqualified_mapping) != len(config.targets): 527
400 not_found = [] 528 if matching_targets:
401 for target in config.targets: 529 search_targets = _LookupTargets(config.targets, unqualified_mapping)
402 if not target in unqualified_mapping: 530 matched_search_targets = _GetTargetsDependingOn(search_targets)
403 not_found.append(target) 531 # Reset the visited status for _GetBuildTargets.
404 warning = 'Unable to find all targets: ' + str(not_found) 532 for target in all_targets.itervalues():
405 qualified_targets = [] 533 target.visited = False
406 for target in config.targets: 534 build_targets = _GetBuildTargets(matching_targets, roots)
407 if target in unqualified_mapping: 535 matched_search_targets = [gyp.common.ParseQualifiedTarget(target.name)[1]
408 qualified_targets.append(unqualified_mapping[target]) 536 for target in matched_search_targets]
409 output_targets = _GetTargetsDependingOn(all_targets, qualified_targets) 537 build_targets = [gyp.common.ParseQualifiedTarget(target.name)[1]
538 for target in build_targets]
410 else: 539 else:
411 output_targets = [] 540 matched_search_targets = []
541 build_targets = []
412 542
413 result_dict = { 'targets': output_targets, 543 result_dict = { 'targets': matched_search_targets,
414 'status': found_dependency_string if matched else 544 'status': found_dependency_string if matching_targets else
415 no_dependency_string } 545 no_dependency_string,
546 'build_targets': build_targets}
416 if warning: 547 if warning:
417 result_dict['warning'] = warning 548 result_dict['warning'] = warning
418 _WriteOutput(params, **result_dict) 549 _WriteOutput(params, **result_dict)
419 550
420 except Exception as e: 551 except Exception as e:
421 _WriteOutput(params, error=str(e)) 552 _WriteOutput(params, error=str(e))
OLDNEW
« no previous file with comments | « no previous file | test/analyzer/gyptest-analyzer.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698