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

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

Issue 1431343002: Changes semantics of analyzer (Closed) Base URL: https://chromium.googlesource.com/external/gyp@master
Patch Set: comments Created 5 years, 1 month 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 | « 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 test_targets: unqualified target names to search for. Any target in this list
11 that depends upon a file in |files| is output regardless of the type of target
12 or chain of dependencies.
13 compile_targets: Additional unqualified targets to search for. Targets in this
Dirk Pranke 2015/11/11 03:51:16 "Additional" is perhaps a bit confusing in this co
sky 2015/11/11 18:38:10 I thought we agreed on compile_targets as the name
14 list that depend upon a file in |files| are not necessarily output. For
15 example, if the target is out type none then the target is not output (but one
16 of the descendants of the target will be).
11 17
12 The following is output: 18 The following is output:
13 error: only supplied if there is an error. 19 error: only supplied if there is an error.
14 build_targets: minimal set of targets that directly depend on the changed 20 compile_targets: minimal set of targets that directly or indirectly depend on
15 files and need to be built. The expectation is this set of targets is passed 21 the files in |files| and is one of the supplied targets or a target that one
16 into a build step. The returned values are either values in the supplied 22 of the supplied targets depends on.
Dirk Pranke 2015/11/11 03:51:16 maybe note that the second clause only applies if
sky 2015/11/11 18:38:10 Done.
17 targets, or have a dependency on one of the supplied targets. 23 The expectation is this set of targets is passed into a build step.
24 test_targets: set of targets from the supplied |test_targets| that either
25 directly or indictly depend upon a file in |files|. This list if useful
Dirk Pranke 2015/11/11 03:51:16 typo: s/indictly/indirectly .
sky 2015/11/11 18:38:10 Done.
26 if additional processing needs to be done for certain targets after the
27 build, such as running tests.
18 status: outputs one of three values: none of the supplied files were found, 28 status: outputs one of three values: none of the supplied files were found,
19 one of the include files changed so that it should be assumed everything 29 one of the include files changed so that it should be assumed everything
20 changed (in this case targets and build_targets are not output) or at 30 changed (in this case test_targets and compile_targets are not output) or at
21 least one file was found. 31 least one file was found.
22 invalid_targets: list of supplied targets thare were not found. 32 invalid_targets: list of supplied targets thare were not found.
Dirk Pranke 2015/11/11 03:51:16 typo: s/thare/that/
sky 2015/11/11 18:38:10 Done.
23 33
24 Example: 34 Example:
25 Consider a graph like the following: 35 Consider a graph like the following:
26 A D 36 A D
27 / \ 37 / \
28 B C 38 B C
29 A depends upon both B and C, A is of type none and B and C are executables. 39 A depends upon both B and C, A is of type none and B and C are executables.
30 D is an executable, has no dependencies and nothing depends on it. 40 D is an executable, has no dependencies and nothing depends on it.
31 If |targets| = ["A"] and files = ["b.cc", "d.cc"] (B depends upon b.cc and D 41 If |compile_targets| = ["A"], |test_targets| = ["B", "C"] and
32 depends upon d.cc), then the following is output: 42 files = ["b.cc", "d.cc"] (B depends upon b.cc and D depends upon d.cc), then
33 |build_targets| = ["B"] B must built as it depends upon the changed file b.cc 43 the following is output:
44 |compile_targets| = ["B"] B must built as it depends upon the changed file b.cc
34 and the supplied target A depends upon it. A is not output as a build_target 45 and the supplied target A depends upon it. A is not output as a build_target
35 as it is of type none with no rules and actions. 46 as it is of type none with no rules and actions.
47 |test_targets| = ["B"] B directly depends upon the change file b.cc.
36 48
37 Even though the file d.cc, which D depends upon, has changed D is not output 49 Even though the file d.cc, which D depends upon, has changed D is not output
38 as none of the supplied targets (A) depend upon D. 50 as it was not supplied by way of |compile_targets| or |test_targets|.
39 51
40 If the generator flag analyzer_output_path is specified, output is written 52 If the generator flag analyzer_output_path is specified, output is written
41 there. Otherwise output is written to stdout. 53 there. Otherwise output is written to stdout.
42 """ 54 """
43 55
44 import gyp.common 56 import gyp.common
45 import gyp.ninja_syntax as ninja_syntax 57 import gyp.ninja_syntax as ninja_syntax
46 import json 58 import json
47 import os 59 import os
48 import posixpath 60 import posixpath
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
218 self.is_or_has_linked_ancestor = False 230 self.is_or_has_linked_ancestor = False
219 231
220 232
221 class Config(object): 233 class Config(object):
222 """Details what we're looking for 234 """Details what we're looking for
223 files: set of files to search for 235 files: set of files to search for
224 targets: see file description for details.""" 236 targets: see file description for details."""
225 def __init__(self): 237 def __init__(self):
226 self.files = [] 238 self.files = []
227 self.targets = set() 239 self.targets = set()
240 self.compile_targets = set()
241 self.test_targets = set()
242 # Needed until recipes is updated.
Dirk Pranke 2015/11/11 03:51:16 Nit: "are updated" :).
sky 2015/11/11 18:38:10 Done.
243 self.deprecated_mode = False
228 244
229 def Init(self, params): 245 def Init(self, params):
230 """Initializes Config. This is a separate method as it raises an exception 246 """Initializes Config. This is a separate method as it raises an exception
231 if there is a parse error.""" 247 if there is a parse error."""
232 generator_flags = params.get('generator_flags', {}) 248 generator_flags = params.get('generator_flags', {})
233 config_path = generator_flags.get('config_path', None) 249 config_path = generator_flags.get('config_path', None)
234 if not config_path: 250 if not config_path:
235 return 251 return
236 try: 252 try:
237 f = open(config_path, 'r') 253 f = open(config_path, 'r')
238 config = json.load(f) 254 config = json.load(f)
239 f.close() 255 f.close()
240 except IOError: 256 except IOError:
241 raise Exception('Unable to open file ' + config_path) 257 raise Exception('Unable to open file ' + config_path)
242 except ValueError as e: 258 except ValueError as e:
243 raise Exception('Unable to parse config file ' + config_path + str(e)) 259 raise Exception('Unable to parse config file ' + config_path + str(e))
244 if not isinstance(config, dict): 260 if not isinstance(config, dict):
245 raise Exception('config_path must be a JSON file containing a dictionary') 261 raise Exception('config_path must be a JSON file containing a dictionary')
246 self.files = config.get('files', []) 262 self.files = config.get('files', [])
247 self.targets = set(config.get('targets', [])) 263 if config.get('targets'):
264 self.targets = set(config.get('targets'))
265 self.deprecated_mode = True
266 else:
267 self.compile_targets = set(config.get('compile_targets', []))
268 self.test_targets = set(config.get('test_targets', []))
248 269
249 270
250 def _WasBuildFileModified(build_file, data, files, toplevel_dir): 271 def _WasBuildFileModified(build_file, data, files, toplevel_dir):
251 """Returns true if the build file |build_file| is either in |files| or 272 """Returns true if the build file |build_file| is either in |files| or
252 one of the files included by |build_file| is in |files|. |toplevel_dir| is 273 one of the files included by |build_file| is in |files|. |toplevel_dir| is
253 the root of the source tree.""" 274 the root of the source tree."""
254 if _ToLocalPath(toplevel_dir, _ToGypPath(build_file)) in files: 275 if _ToLocalPath(toplevel_dir, _ToGypPath(build_file)) in files:
255 if debug: 276 if debug:
256 print 'gyp file modified', build_file 277 print 'gyp file modified', build_file
257 return True 278 return True
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
289 return bool(target_dict['type'] != 'none' or 310 return bool(target_dict['type'] != 'none' or
290 target_dict.get('actions') or target_dict.get('rules')) 311 target_dict.get('actions') or target_dict.get('rules'))
291 312
292 313
293 def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files, 314 def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files,
294 build_files): 315 build_files):
295 """Returns a tuple of the following: 316 """Returns a tuple of the following:
296 . A dictionary mapping from fully qualified name to Target. 317 . A dictionary mapping from fully qualified name to Target.
297 . A list of the targets that have a source file in |files|. 318 . A list of the targets that have a source file in |files|.
298 . Set of root Targets reachable from the the files |build_files|. This 319 . Set of root Targets reachable from the the files |build_files|. This
299 is the set of targets built by the 'all' target. 320 is the set of targets built by the 'all' target.
Dirk Pranke 2015/11/11 03:51:16 As we discussed, in a sense 'root Targets' is misl
sky 2015/11/11 18:38:10 Agreed.
300 This sets the |match_status| of the targets that contain any of the source 321 This sets the |match_status| of the targets that contain any of the source
301 files in |files| to MATCH_STATUS_MATCHES. 322 files in |files| to MATCH_STATUS_MATCHES.
302 |toplevel_dir| is the root of the source tree.""" 323 |toplevel_dir| is the root of the source tree."""
303 # Maps from target name to Target. 324 # Maps from target name to Target.
304 targets = {} 325 targets = {}
305 326
306 # Targets that matched. 327 # Targets that matched.
307 matching_targets = [] 328 matching_targets = []
308 329
309 # Queue of targets to visit. 330 # Queue of targets to visit.
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 if not created_dep_target: 389 if not created_dep_target:
369 roots.discard(dep_target) 390 roots.discard(dep_target)
370 391
371 target.deps.add(dep_target) 392 target.deps.add(dep_target)
372 dep_target.back_deps.add(target) 393 dep_target.back_deps.add(target)
373 394
374 return targets, matching_targets, roots & build_file_targets 395 return targets, matching_targets, roots & build_file_targets
375 396
376 397
377 def _GetUnqualifiedToTargetMapping(all_targets, to_find): 398 def _GetUnqualifiedToTargetMapping(all_targets, to_find):
378 """Returns a mapping (dictionary) from unqualified name to Target for all the 399 """Returns a tuple of the following:
379 Targets in |to_find|.""" 400 . mapping (dictionary) from unqualified name to Target for all the
401 Targets in |to_find|.
402 . any target names not found. If this is empty all targets were found."""
380 result = {} 403 result = {}
381 if not to_find: 404 if not to_find:
382 return result 405 return {}, []
383 to_find = set(to_find) 406 to_find = set(to_find)
384 for target_name in all_targets.keys(): 407 for target_name in all_targets.keys():
385 extracted = gyp.common.ParseQualifiedTarget(target_name) 408 extracted = gyp.common.ParseQualifiedTarget(target_name)
386 if len(extracted) > 1 and extracted[1] in to_find: 409 if len(extracted) > 1 and extracted[1] in to_find:
387 to_find.remove(extracted[1]) 410 to_find.remove(extracted[1])
388 result[extracted[1]] = all_targets[target_name] 411 result[extracted[1]] = all_targets[target_name]
389 if not to_find: 412 if not to_find:
390 return result 413 return result, []
391 return result 414 return result, [x for x in to_find]
392 415
393 416
394 def _AddBuildTargets(target, roots, result): 417 def _AddBuildTargetsDeprecated(target, roots, result):
395 """Recurses through all targets that depend on |target|, adding all targets 418 """Recurses through all targets that depend on |target|, adding all targets
396 that need to be built (and are in |roots|) to |result|. 419 that need to be built (and are in |roots|) to |result|.
397 roots: set of root targets. 420 roots: set of root targets.
398 result: targets that need to be built are added here.""" 421 result: targets that need to be built are added here."""
399 if target.visited: 422 if target.visited:
400 return 423 return
401 424
402 target.visited = True 425 target.visited = True
403 target.in_roots = target in roots 426 target.in_roots = target in roots
404 427
405 for back_dep_target in target.back_deps: 428 for back_dep_target in target.back_deps:
406 _AddBuildTargets(back_dep_target, roots, result) 429 _AddBuildTargetsDeprecated(back_dep_target, roots, result)
407 target.added_to_compile_targets |= back_dep_target.added_to_compile_targets 430 target.added_to_compile_targets |= back_dep_target.added_to_compile_targets
408 target.in_roots |= back_dep_target.in_roots 431 target.in_roots |= back_dep_target.in_roots
409 target.is_or_has_linked_ancestor |= ( 432 target.is_or_has_linked_ancestor |= (
410 back_dep_target.is_or_has_linked_ancestor) 433 back_dep_target.is_or_has_linked_ancestor)
411 434
412 # Always add 'executable' targets. Even though they may be built by other 435 # Always add 'executable' targets. Even though they may be built by other
413 # targets that depend upon them it makes detection of what is going to be 436 # targets that depend upon them it makes detection of what is going to be
414 # built easier. 437 # built easier.
415 # And always add static_libraries that have no dependencies on them from 438 # And always add static_libraries that have no dependencies on them from
416 # linkables. This is necessary as the other dependencies on them may be 439 # linkables. This is necessary as the other dependencies on them may be
417 # static libraries themselves, which are not compile time dependencies. 440 # static libraries themselves, which are not compile time dependencies.
418 if target.in_roots and \ 441 if target.in_roots and \
419 (target.is_executable or 442 (target.is_executable or
420 (not target.added_to_compile_targets and target.requires_build) or 443 (not target.added_to_compile_targets and target.requires_build) or
421 (target.is_static_library and not target.is_or_has_linked_ancestor)): 444 (target.is_static_library and not target.is_or_has_linked_ancestor)):
422 print '\t\tadding to build targets', target.name, 'executable', \ 445 print '\t\tadding to build targets', target.name, 'executable', \
423 target.is_executable, 'added_to_compile_targets', \ 446 target.is_executable, 'added_to_compile_targets', \
424 target.added_to_compile_targets, 'requires_build', \ 447 target.added_to_compile_targets, 'requires_build', \
425 target.requires_build, 'is_static_library', \ 448 target.requires_build, 'is_static_library', \
426 target.is_static_library, 'is_or_has_linked_ancestor', \ 449 target.is_static_library, 'is_or_has_linked_ancestor', \
427 target.is_or_has_linked_ancestor 450 target.is_or_has_linked_ancestor
428 result.add(target) 451 result.add(target)
429 target.added_to_compile_targets = True 452 target.added_to_compile_targets = True
430 453
431 454
432 def _GetBuildTargets(matching_targets, roots): 455 def _GetBuildTargetsDeprecated(matching_targets, roots):
433 """Returns the set of Targets that require a build. 456 """Returns the set of Targets that require a build.
434 matching_targets: targets that changed and need to be built. 457 matching_targets: targets that changed and need to be built.
435 roots: set of root targets in the build files to search from.""" 458 roots: set of root targets in the build files to search from."""
436 result = set() 459 result = set()
437 for target in matching_targets: 460 for target in matching_targets:
438 print '\tfinding build targets for match', target.name 461 print '\tfinding build targets for match', target.name
439 _AddBuildTargets(target, roots, result) 462 _AddBuildTargetsDeprecated(target, roots, result)
440 return result 463 return result
441 464
442 465
466 def _DoesTargetDependOn(target):
sky 2015/11/10 18:41:31 This function and the next are exactly the same as
467 """Returns true if |target| or any of its dependencies matches the supplied
468 set of paths. This updates |matches| of the Targets as it recurses.
Dirk Pranke 2015/11/11 03:51:16 "the supplied set of paths" is unclear (to me) her
sky 2015/11/11 18:38:10 I updated the docs and changed names. As to the d
469 target: the Target to look for."""
470 if target.match_status == MATCH_STATUS_DOESNT_MATCH:
471 return False
472 if target.match_status == MATCH_STATUS_MATCHES or \
473 target.match_status == MATCH_STATUS_MATCHES_BY_DEPENDENCY:
474 return True
475 for dep in target.deps:
476 if _DoesTargetDependOn(dep):
477 target.match_status = MATCH_STATUS_MATCHES_BY_DEPENDENCY
478 print '\t', target.name, 'matches by dep', dep.name
479 return True
480 target.match_status = MATCH_STATUS_DOESNT_MATCH
481 return False
482
483
484 def _GetTargetsDependingOn(possible_targets):
Dirk Pranke 2015/11/11 03:51:16 See comments above for _DoesTargetDependOn() (as r
485 """Returns the list of Targets in |possible_targets| that depend (either
486 directly on indirectly) on the matched targets.
487 possible_targets: targets to search from."""
488 found = []
489 print 'Targets that matched by dependency:'
490 for target in possible_targets:
491 if _DoesTargetDependOn(target):
492 found.append(target)
493 return found
494
495
496 def _AddCompileTargets(target, roots, add_if_no_ancestor, result):
sky 2015/11/10 18:41:31 And this is _AddBuildTargets from before https://c
497 """Recurses through all targets that depend on |target|, adding all targets
498 that need to be built (and are in |roots|) to |result|.
499 roots: set of root targets.
500 add_if_no_ancestor: If true and there are no ancestors of |target| then add
501 |target| to |result|. |target| must still be in |roots|.
502 result: targets that need to be built are added here."""
503 if target.visited:
504 return
505
506 target.visited = True
507 target.in_roots = target in roots
508
509 for back_dep_target in target.back_deps:
510 _AddCompileTargets(back_dep_target, roots, False, result)
511 target.added_to_compile_targets |= back_dep_target.added_to_compile_targets
512 target.in_roots |= back_dep_target.in_roots
513 target.is_or_has_linked_ancestor |= (
514 back_dep_target.is_or_has_linked_ancestor)
515
516 # Always add 'executable' targets. Even though they may be built by other
517 # targets that depend upon them it makes detection of what is going to be
518 # built easier.
519 # And always add static_libraries that have no dependencies on them from
520 # linkables. This is necessary as the other dependencies on them may be
521 # static libraries themselves, which are not compile time dependencies.
522 if target.in_roots and \
523 (target.is_executable or
524 (not target.added_to_compile_targets and
525 (add_if_no_ancestor or target.requires_build)) or
526 (target.is_static_library and add_if_no_ancestor and
527 not target.is_or_has_linked_ancestor)):
528 print '\t\tadding to compile targets', target.name, 'executable', \
529 target.is_executable, 'added_to_compile_targets', \
530 target.added_to_compile_targets, 'add_if_no_ancestor', \
531 add_if_no_ancestor, 'requires_build', target.requires_build, \
532 'is_static_library', target.is_static_library, \
533 'is_or_has_linked_ancestor', target.is_or_has_linked_ancestor
534 result.add(target)
535 target.added_to_compile_targets = True
536
537
538 def _GetCompileTargets(matching_targets, roots):
539 """Returns the set of Targets that require a build.
540 matching_targets: targets that changed and need to be built.
541 roots: set of root targets in the build files to search from."""
Dirk Pranke 2015/11/11 03:51:16 calling this 'roots' is also a bit confusing, beca
sky 2015/11/11 18:38:10 Done.
542 result = set()
543 for target in matching_targets:
544 print 'finding compile targets for match', target.name
545 _AddCompileTargets(target, roots, True, result)
546 return result
547
548
443 def _WriteOutput(params, **values): 549 def _WriteOutput(params, **values):
Dirk Pranke 2015/11/11 03:51:16 Nit: it looks like you only ever call this like _W
sky 2015/11/11 18:38:10 There is one place that doesn't. See the last line
444 """Writes the output, either to stdout or a file is specified.""" 550 """Writes the output, either to stdout or a file is specified."""
445 if 'error' in values: 551 if 'error' in values:
446 print 'Error:', values['error'] 552 print 'Error:', values['error']
447 if 'status' in values: 553 if 'status' in values:
448 print values['status'] 554 print values['status']
449 if 'targets' in values: 555 if 'targets' in values:
450 values['targets'].sort() 556 values['targets'].sort()
451 print 'Supplied targets that depend on changed files:' 557 print 'Supplied targets that depend on changed files:'
452 for target in values['targets']: 558 for target in values['targets']:
453 print '\t', target 559 print '\t', target
454 if 'invalid_targets' in values: 560 if 'invalid_targets' in values:
455 values['invalid_targets'].sort() 561 values['invalid_targets'].sort()
456 print 'The following targets were not found:' 562 print 'The following targets were not found:'
457 for target in values['invalid_targets']: 563 for target in values['invalid_targets']:
458 print '\t', target 564 print '\t', target
459 if 'build_targets' in values: 565 if 'build_targets' in values:
460 values['build_targets'].sort() 566 values['build_targets'].sort()
461 print 'Targets that require a build:' 567 print 'Targets that require a build:'
462 for target in values['build_targets']: 568 for target in values['build_targets']:
463 print '\t', target 569 print '\t', target
570 if 'compile_targets' in values:
571 values['compile_targets'].sort()
572 print 'Targets that need to be built:'
573 for target in values['compile_targets']:
574 print '\t', target
575 if 'test_targets' in values:
576 values['test_targets'].sort()
577 print 'Test targets:'
578 for target in values['test_targets']:
579 print '\t', target
464 580
465 output_path = params.get('generator_flags', {}).get( 581 output_path = params.get('generator_flags', {}).get(
466 'analyzer_output_path', None) 582 'analyzer_output_path', None)
467 if not output_path: 583 if not output_path:
468 print json.dumps(values) 584 print json.dumps(values)
469 return 585 return
470 try: 586 try:
471 f = open(output_path, 'w') 587 f = open(output_path, 'w')
472 f.write(json.dumps(values) + '\n') 588 f.write(json.dumps(values) + '\n')
473 f.close() 589 f.close()
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
513 'generator_additional_path_sections', []) 629 'generator_additional_path_sections', [])
514 630
515 gyp.msvs_emulation.CalculateCommonVariables(default_variables, params) 631 gyp.msvs_emulation.CalculateCommonVariables(default_variables, params)
516 else: 632 else:
517 operating_system = flavor 633 operating_system = flavor
518 if flavor == 'android': 634 if flavor == 'android':
519 operating_system = 'linux' # Keep this legacy behavior for now. 635 operating_system = 'linux' # Keep this legacy behavior for now.
520 default_variables.setdefault('OS', operating_system) 636 default_variables.setdefault('OS', operating_system)
521 637
522 638
639 def _GenerateOutputDeprecated(target_list, target_dicts, data, params, config):
640 """Old deprecated behavior, will be nuked shortly."""
641 toplevel_dir = _ToGypPath(os.path.abspath(params['options'].toplevel_dir))
642
643 if _WasGypIncludeFileModified(params, config.files):
644 result_dict = { 'status': all_changed_string,
645 'targets': list(config.targets) }
Dirk Pranke 2015/11/11 03:51:16 this is probably a nit, since this is the way the
sky 2015/11/11 18:38:10 I believe the recipe code ignores the targets if a
646 _WriteOutput(params, **result_dict)
647 return
648
649 all_targets, matching_targets, root_targets = _GenerateTargets(
650 data, target_list, target_dicts, toplevel_dir, frozenset(config.files),
651 params['build_files'])
652
653 unqualified_mapping, invalid_targets = _GetUnqualifiedToTargetMapping(
654 all_targets, config.targets)
655
656 if matching_targets:
657 search_targets = _LookupTargets(config.targets, unqualified_mapping)
658 print 'supplied targets'
659 for target in config.targets:
660 print '\t', target
661 print 'expanded supplied targets'
662 for target in search_targets:
663 print '\t', target.name
664 # Reset the visited status for _GetBuildTargets.
665 for target in all_targets.itervalues():
666 target.visited = False
667 build_targets = _GetBuildTargetsDeprecated(matching_targets, search_targets)
668 build_targets = [gyp.common.ParseQualifiedTarget(target.name)[1]
669 for target in build_targets]
670 else:
671 build_targets = []
672
673 result_dict = { 'targets': build_targets,
674 'status': found_dependency_string if matching_targets else
675 no_dependency_string,
676 'build_targets': build_targets}
677 if invalid_targets:
678 result_dict['invalid_targets'] = invalid_targets
679 _WriteOutput(params, **result_dict)
680
681
523 def GenerateOutput(target_list, target_dicts, data, params): 682 def GenerateOutput(target_list, target_dicts, data, params):
524 """Called by gyp as the final stage. Outputs results.""" 683 """Called by gyp as the final stage. Outputs results."""
525 config = Config() 684 config = Config()
526 try: 685 try:
527 config.Init(params) 686 config.Init(params)
687
528 if not config.files: 688 if not config.files:
529 raise Exception('Must specify files to analyze via config_path generator ' 689 raise Exception('Must specify files to analyze via config_path generator '
530 'flag') 690 'flag')
531 691
692 if config.deprecated_mode:
693 _GenerateOutputDeprecated(target_list, target_dicts, data, params,
694 config)
695 return
696
532 toplevel_dir = _ToGypPath(os.path.abspath(params['options'].toplevel_dir)) 697 toplevel_dir = _ToGypPath(os.path.abspath(params['options'].toplevel_dir))
533 if debug: 698 if debug:
534 print 'toplevel_dir', toplevel_dir 699 print 'toplevel_dir', toplevel_dir
535 700
536 if _WasGypIncludeFileModified(params, config.files): 701 if _WasGypIncludeFileModified(params, config.files):
537 result_dict = { 'status': all_changed_string, 702 result_dict = { 'status': all_changed_string,
538 'targets': list(config.targets) } 703 'test_targets': list(config.test_targets),
704 'compile_targets': list(config.compile_targets) }
539 _WriteOutput(params, **result_dict) 705 _WriteOutput(params, **result_dict)
540 return 706 return
541 707
Dirk Pranke 2015/11/11 03:51:16 General comments on the rest of this function: It
sky 2015/11/11 18:38:10 I moved all of this off into a class. Hopefully it
542 all_targets, matching_targets, _ = _GenerateTargets( 708 all_targets, changed_targets, root_targets = _GenerateTargets(
Dirk Pranke 2015/11/11 03:51:16 'changed_targets' is the list of targets *directly
543 data, target_list, target_dicts, toplevel_dir, frozenset(config.files), 709 data, target_list, target_dicts, toplevel_dir, frozenset(config.files),
544 params['build_files']) 710 params['build_files'])
545 711
546 unqualified_mapping = _GetUnqualifiedToTargetMapping(all_targets, 712 supplied_target_names = config.compile_targets | config.test_targets
Dirk Pranke 2015/11/11 03:51:16 We discussed this earlier (as to how this was safe
547 config.targets) 713 # 'all' is added back below.
548 invalid_targets = None 714 supplied_targets_contains_all = 'all' in supplied_target_names
549 if len(unqualified_mapping) != len(config.targets): 715 supplied_target_names.discard('all')
550 invalid_targets = _NamesNotIn(config.targets, unqualified_mapping) 716 unqualified_mapping, invalid_targets = _GetUnqualifiedToTargetMapping(
717 all_targets, supplied_target_names)
551 718
552 if matching_targets: 719 if changed_targets:
553 search_targets = _LookupTargets(config.targets, unqualified_mapping) 720 # Find the test targets first. 'all' is special cased to mean all the
554 print 'supplied targets' 721 # root targets. To deal with all the supplied |test_targets| are expanded
555 for target in config.targets: 722 # to include the root targets during lookup. If any of the root targets
556 print '\t', target 723 # match, we remove it and replace it with 'all'.
Dirk Pranke 2015/11/11 03:51:16 Same concerns about 'all' and 'root targets' here
557 print 'expanded supplied targets' 724 test_target_names = set(config.test_targets)
558 for target in search_targets: 725 test_target_names_contains_all = 'all' in test_target_names
726 test_target_names.discard('all')
727 test_targets = _LookupTargets(test_target_names, unqualified_mapping)
728 original_test_targets = set(test_targets)
729 if test_target_names_contains_all:
730 test_targets = [x for x in (set(test_targets) | set(root_targets))]
Dirk Pranke 2015/11/11 03:51:16 Rewrite as test_targets = list(set(test_targets)
731 print 'supplied test_targets'
732 for target_name in config.test_targets:
733 print '\t', target_name
734 print 'found test_targets'
735 for target in test_targets:
559 print '\t', target.name 736 print '\t', target.name
737 print 'searching for matching test targets'
738 test_targets = _GetTargetsDependingOn(test_targets)
Dirk Pranke 2015/11/11 03:51:16 maybe instead something like: affected_test_targe
739 test_targets_contains_all = (test_target_names_contains_all and
740 set(test_targets) & set(root_targets))
Dirk Pranke 2015/11/11 03:51:16 and then rewriting this as something like: affe
741 if test_targets_contains_all:
742 # Remove any of the targets for all that were not explicitly supplied,
743 # 'all' is subsequentely added to the matching names below.
744 test_targets = [x for x in (set(test_targets) &
745 set(original_test_targets))]
Dirk Pranke 2015/11/11 03:51:16 affected_test_targets = list(set(affected_test_tar
746
747 print 'matched test_targets'
748 for target in test_targets:
749 print '\t', target.name
750 test_target_names = [gyp.common.ParseQualifiedTarget(target.name)[1]
751 for target in test_targets]
752 if test_targets_contains_all:
753 test_target_names.append('all')
754 print '\tall'
755
756 # Compile targets are found by searching up from changed targets.
560 # Reset the visited status for _GetBuildTargets. 757 # Reset the visited status for _GetBuildTargets.
561 for target in all_targets.itervalues(): 758 for target in all_targets.itervalues():
562 target.visited = False 759 target.visited = False
563 print 'Finding build targets' 760
564 build_targets = _GetBuildTargets(matching_targets, search_targets) 761 supplied_targets = _LookupTargets(supplied_target_names,
Dirk Pranke 2015/11/11 03:51:16 see comments above re: supplied_target_names being
565 build_targets = [gyp.common.ParseQualifiedTarget(target.name)[1] 762 unqualified_mapping)
566 for target in build_targets] 763 if supplied_targets_contains_all:
764 supplied_targets = [x for x in (set(supplied_targets) |
765 set(root_targets))]
766 print 'Supplied test_targets & compile_targets'
767 for target in supplied_targets:
768 print '\t', target.name
769 print 'Finding compile targets'
770 compile_targets = _GetCompileTargets(changed_targets, supplied_targets)
771 compile_target_names = [gyp.common.ParseQualifiedTarget(target.name)[1]
772 for target in compile_targets]
567 else: 773 else:
568 build_targets = [] 774 compile_target_names = []
775 test_target_names = []
569 776
570 # TODO(sky): nuke 'targets'. 777 found_at_least_one_target = compile_target_names or test_target_names
571 result_dict = { 'targets': build_targets, 778 result_dict = { 'test_targets': test_target_names,
572 'status': found_dependency_string if matching_targets else 779 'status': found_dependency_string if
573 no_dependency_string, 780 found_at_least_one_target else no_dependency_string,
574 'build_targets': build_targets} 781 'compile_targets': compile_target_names}
575 if invalid_targets: 782 if invalid_targets:
576 result_dict['invalid_targets'] = invalid_targets 783 result_dict['invalid_targets'] = invalid_targets
Dirk Pranke 2015/11/11 03:51:16 Looks like you *don't* return an error if there ar
577 _WriteOutput(params, **result_dict) 784 _WriteOutput(params, **result_dict)
578 785
579 except Exception as e: 786 except Exception as e:
580 _WriteOutput(params, error=str(e)) 787 _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