OLD | NEW |
---|---|
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 | 2 |
3 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 3 # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 from compiler.ast import Const | 7 from compiler.ast import Const |
8 from compiler.ast import Dict | 8 from compiler.ast import Dict |
9 from compiler.ast import Discard | 9 from compiler.ast import Discard |
10 from compiler.ast import List | 10 from compiler.ast import List |
11 from compiler.ast import Module | 11 from compiler.ast import Module |
12 from compiler.ast import Node | 12 from compiler.ast import Node |
13 from compiler.ast import Stmt | 13 from compiler.ast import Stmt |
14 import compiler | 14 import compiler |
15 import copy | 15 import copy |
16 import gyp.common | 16 import gyp.common |
17 import optparse | 17 import optparse |
18 import os.path | 18 import os.path |
19 import re | 19 import re |
20 import shlex | 20 import shlex |
21 import subprocess | 21 import subprocess |
22 import shlex | |
22 import sys | 23 import sys |
23 | 24 |
24 | 25 |
25 # A list of types that are treated as linkable. | 26 # A list of types that are treated as linkable. |
26 linkable_types = ['executable', 'shared_library', 'loadable_module'] | 27 linkable_types = ['executable', 'shared_library', 'loadable_module'] |
27 | 28 |
28 # A list of sections that contain links to other targets. | 29 # A list of sections that contain links to other targets. |
29 dependency_sections = ['dependencies', 'export_dependent_settings'] | 30 dependency_sections = ['dependencies', 'export_dependent_settings'] |
30 | 31 |
31 # base_path_sections is a list of sections defined by GYP that contain | 32 # base_path_sections is a list of sections defined by GYP that contain |
(...skipping 432 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
464 """Returns True if |string| is in its canonical integer form. | 465 """Returns True if |string| is in its canonical integer form. |
465 | 466 |
466 The canonical form is such that str(int(string)) == string. | 467 The canonical form is such that str(int(string)) == string. |
467 """ | 468 """ |
468 if not isinstance(string, str) or not canonical_int_re.match(string): | 469 if not isinstance(string, str) or not canonical_int_re.match(string): |
469 return False | 470 return False |
470 | 471 |
471 return True | 472 return True |
472 | 473 |
473 | 474 |
474 early_variable_re = re.compile('(?P<replace>(?P<type><((!?@?)|\|)?)' | 475 # This matches things like "<(asdf)", "<!(cmd)", "<!@(cmd)", "<|(list)", |
475 '\((?P<is_array>\s*\[?)' | 476 # "<!interpreter(arguments)", "<([list])", and even "<([)" and "<(<())". |
476 '(?P<content>.*?)(\]?)\))') | 477 # In the last case, the inner "<()" is captured in match['content']. |
477 late_variable_re = re.compile('(?P<replace>(?P<type>>((!?@?)|\|)?)' | 478 early_variable_re = re.compile( |
478 '\((?P<is_array>\s*\[?)' | 479 '(?P<replace>(?P<type><(?:(?:!?@?)|\|)?)' |
479 '(?P<content>.*?)(\]?)\))') | 480 '(?P<command_string>[-a-zA-Z0-9_.]+)?' |
481 '\((?P<is_array>\s*\[?)' | |
482 '(?P<content>.*?)(\]?)\))') | |
483 | |
484 # This matches the same as early_variable_re, but with '>' instead of '<'. | |
485 late_variable_re = re.compile( | |
486 '(?P<replace>(?P<type>>(?:(?:!?@?)|\|)?)' | |
487 '(?P<command_string>[-a-zA-Z0-9_.]+)?' | |
488 '\((?P<is_array>\s*\[?)' | |
489 '(?P<content>.*?)(\]?)\))') | |
480 | 490 |
481 # Global cache of results from running commands so they don't have to be run | 491 # Global cache of results from running commands so they don't have to be run |
482 # more then once. | 492 # more then once. |
483 cached_command_results = {} | 493 cached_command_results = {} |
484 | 494 |
485 | 495 |
486 def FixupPlatformCommand(cmd): | 496 def FixupPlatformCommand(cmd): |
487 if sys.platform == 'win32': | 497 if sys.platform == 'win32': |
488 if type(cmd) == list: | 498 if type(cmd) == list: |
489 cmd = [re.sub('^cat ', 'type ', cmd[0])] + cmd[1:] | 499 cmd = [re.sub('^cat ', 'type ', cmd[0])] + cmd[1:] |
(...skipping 28 matching lines...) Expand all Loading... | |
518 # of what's intended for replacement. | 528 # of what's intended for replacement. |
519 matches.reverse() | 529 matches.reverse() |
520 for match_group in matches: | 530 for match_group in matches: |
521 match = match_group.groupdict() | 531 match = match_group.groupdict() |
522 gyp.DebugOutput(gyp.DEBUG_VARIABLES, | 532 gyp.DebugOutput(gyp.DEBUG_VARIABLES, |
523 "Matches: %s" % repr(match)) | 533 "Matches: %s" % repr(match)) |
524 # match['replace'] is the substring to look for, match['type'] | 534 # match['replace'] is the substring to look for, match['type'] |
525 # is the character code for the replacement type (< > <! >! <| >| <@ | 535 # is the character code for the replacement type (< > <! >! <| >| <@ |
526 # >@ <!@ >!@), match['is_array'] contains a '[' for command | 536 # >@ <!@ >!@), match['is_array'] contains a '[' for command |
527 # arrays, and match['content'] is the name of the variable (< >) | 537 # arrays, and match['content'] is the name of the variable (< >) |
528 # or command to run (<! >!). | 538 # or command to run (<! >!). match['command_string'] is an optional |
539 # command string. Currently, only 'python' is supported. | |
Mark Mentovai
2011/05/24 21:54:57
Except you’ve called it pymod_do_main in the code
Nico
2011/05/24 22:02:19
Done.
| |
529 | 540 |
530 # run_command is true if a ! variant is used. | 541 # run_command is true if a ! variant is used. |
531 run_command = '!' in match['type'] | 542 run_command = '!' in match['type'] |
543 command_string = match['command_string'] | |
532 | 544 |
533 # file_list is true if a | variant is used. | 545 # file_list is true if a | variant is used. |
534 file_list = '|' in match['type'] | 546 file_list = '|' in match['type'] |
535 | 547 |
536 # Capture these now so we can adjust them later. | 548 # Capture these now so we can adjust them later. |
537 replace_start = match_group.start('replace') | 549 replace_start = match_group.start('replace') |
538 replace_end = match_group.end('replace') | 550 replace_end = match_group.end('replace') |
539 | 551 |
540 # Find the ending paren, and re-evaluate the contained string. | 552 # Find the ending paren, and re-evaluate the contained string. |
541 (c_start, c_end) = FindEnclosingBracketGroup(input_str[replace_start:]) | 553 (c_start, c_end) = FindEnclosingBracketGroup(input_str[replace_start:]) |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
627 # is invoked it produces different output by design. When the need | 639 # is invoked it produces different output by design. When the need |
628 # arises, the syntax should be extended to support no caching off a | 640 # arises, the syntax should be extended to support no caching off a |
629 # command's output so it is run every time. | 641 # command's output so it is run every time. |
630 cache_key = str(contents) | 642 cache_key = str(contents) |
631 cached_value = cached_command_results.get(cache_key, None) | 643 cached_value = cached_command_results.get(cache_key, None) |
632 if cached_value is None: | 644 if cached_value is None: |
633 gyp.DebugOutput(gyp.DEBUG_VARIABLES, | 645 gyp.DebugOutput(gyp.DEBUG_VARIABLES, |
634 "Executing command '%s' in directory '%s'" % | 646 "Executing command '%s' in directory '%s'" % |
635 (contents,build_file_dir)) | 647 (contents,build_file_dir)) |
636 | 648 |
637 # Fix up command with platform specific workarounds. | 649 replacement = '' |
638 contents = FixupPlatformCommand(contents) | |
639 p = subprocess.Popen(contents, shell=use_shell, | |
640 stdout=subprocess.PIPE, | |
641 stderr=subprocess.PIPE, | |
642 stdin=subprocess.PIPE, | |
643 cwd=build_file_dir) | |
644 | 650 |
645 (p_stdout, p_stderr) = p.communicate('') | 651 if command_string == 'pymod_do_main': |
652 # <!pymod_do_main(modulename param eters) loads |modulename| as a | |
653 # python module and then calls that module's DoMain() function, | |
654 # passing "param eters" as a single string argument. For modules | |
Mark Mentovai
2011/05/24 22:04:16
Sorry, I read this comment saying |passing "param
Nico
2011/05/24 22:09:52
Done.
| |
655 # that don't load quickly, this can be faster than | |
656 # <!(python modulename param eters). Do this in |build_file_dir|. | |
657 oldwd = os.getcwd() # Python doesn't like os.open('.'): no fchdir. | |
658 os.chdir(build_file_dir) | |
646 | 659 |
647 if p.wait() != 0 or p_stderr: | 660 parsed_contents = shlex.split(contents) |
648 sys.stderr.write(p_stderr) | 661 py_module = __import__(parsed_contents[0]) |
649 # Simulate check_call behavior, since check_call only exists | 662 replacement = str(py_module.DoMain(parsed_contents[1:])).rstrip() |
Mark Mentovai
2011/05/24 21:54:57
This is hokey. Any reason you don’t just pass pars
Nico
2011/05/24 22:02:19
I think that's what I'm doing.
| |
650 # in python 2.5 and later. | 663 |
651 raise Exception("Call to '%s' returned exit status %d." % | 664 os.chdir(oldwd) |
652 (contents, p.returncode)) | 665 assert replacement != None |
653 replacement = p_stdout.rstrip() | 666 else: |
Mark Mentovai
2011/05/24 21:54:57
assert on unknown command_strings?
Nico
2011/05/24 22:02:19
Done.
| |
667 # Fix up command with platform specific workarounds. | |
668 contents = FixupPlatformCommand(contents) | |
669 p = subprocess.Popen(contents, shell=use_shell, | |
670 stdout=subprocess.PIPE, | |
671 stderr=subprocess.PIPE, | |
672 stdin=subprocess.PIPE, | |
673 cwd=build_file_dir) | |
674 | |
675 (p_stdout, p_stderr) = p.communicate('') | |
676 | |
677 if p.wait() != 0 or p_stderr: | |
678 sys.stderr.write(p_stderr) | |
679 # Simulate check_call behavior, since check_call only exists | |
680 # in python 2.5 and later. | |
681 raise Exception("Call to '%s' returned exit status %d." % | |
682 (contents, p.returncode)) | |
683 replacement = p_stdout.rstrip() | |
654 | 684 |
655 cached_command_results[cache_key] = replacement | 685 cached_command_results[cache_key] = replacement |
656 else: | 686 else: |
657 gyp.DebugOutput(gyp.DEBUG_VARIABLES, | 687 gyp.DebugOutput(gyp.DEBUG_VARIABLES, |
658 "Had cache value for command '%s' in directory '%s'" % | 688 "Had cache value for command '%s' in directory '%s'" % |
659 (contents,build_file_dir)) | 689 (contents,build_file_dir)) |
660 replacement = cached_value | 690 replacement = cached_value |
661 | 691 |
662 else: | 692 else: |
663 if not contents in variables: | 693 if not contents in variables: |
(...skipping 1577 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2241 ValidateRunAsInTarget(target, target_dict, build_file) | 2271 ValidateRunAsInTarget(target, target_dict, build_file) |
2242 ValidateActionsInTarget(target, target_dict, build_file) | 2272 ValidateActionsInTarget(target, target_dict, build_file) |
2243 | 2273 |
2244 # Generators might not expect ints. Turn them into strs. | 2274 # Generators might not expect ints. Turn them into strs. |
2245 TurnIntIntoStrInDict(data) | 2275 TurnIntIntoStrInDict(data) |
2246 | 2276 |
2247 # TODO(mark): Return |data| for now because the generator needs a list of | 2277 # TODO(mark): Return |data| for now because the generator needs a list of |
2248 # build files that came in. In the future, maybe it should just accept | 2278 # build files that came in. In the future, maybe it should just accept |
2249 # a list, and not the whole data dict. | 2279 # a list, and not the whole data dict. |
2250 return [flat_list, targets, data] | 2280 return [flat_list, targets, data] |
OLD | NEW |