Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright (c) 2012 Google Inc. All rights reserved. | 1 # Copyright (c) 2012 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 TestGyp.py: a testing framework for GYP integration tests. | 6 TestGyp.py: a testing framework for GYP integration tests. |
| 7 """ | 7 """ |
| 8 | 8 |
| 9 from __future__ import print_function | |
| 10 | |
| 9 import collections | 11 import collections |
| 10 from contextlib import contextmanager | 12 from contextlib import contextmanager |
| 11 import itertools | 13 import itertools |
| 12 import os | 14 import os |
| 13 import re | 15 import re |
| 14 import shutil | 16 import shutil |
| 15 import subprocess | 17 import subprocess |
| 16 import sys | 18 import sys |
| 17 import tempfile | 19 import tempfile |
| 18 | 20 |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 275 | 277 |
| 276 def report_not_up_to_date(self): | 278 def report_not_up_to_date(self): |
| 277 """ | 279 """ |
| 278 Reports that a build is not up-to-date. | 280 Reports that a build is not up-to-date. |
| 279 | 281 |
| 280 This provides common reporting for formats that have complicated | 282 This provides common reporting for formats that have complicated |
| 281 conditions for checking whether a build is up-to-date. Formats | 283 conditions for checking whether a build is up-to-date. Formats |
| 282 that expect exact output from the command (make) can | 284 that expect exact output from the command (make) can |
| 283 just set stdout= when they call the run_build() method. | 285 just set stdout= when they call the run_build() method. |
| 284 """ | 286 """ |
| 285 print "Build is not up-to-date:" | 287 print("Build is not up-to-date:") |
| 286 print self.banner('STDOUT ') | 288 print(self.banner('STDOUT ')) |
| 287 print self.stdout() | 289 print(self.stdout()) |
| 288 stderr = self.stderr() | 290 stderr = self.stderr() |
| 289 if stderr: | 291 if stderr: |
| 290 print self.banner('STDERR ') | 292 print(self.banner('STDERR ')) |
| 291 print stderr | 293 print(stderr) |
| 292 | 294 |
| 293 def run_gyp(self, gyp_file, *args, **kw): | 295 def run_gyp(self, gyp_file, *args, **kw): |
| 294 """ | 296 """ |
| 295 Runs gyp against the specified gyp_file with the specified args. | 297 Runs gyp against the specified gyp_file with the specified args. |
| 296 """ | 298 """ |
| 297 | 299 |
| 298 # When running gyp, and comparing its output we use a comparitor | 300 # When running gyp, and comparing its output we use a comparitor |
| 299 # that ignores the line numbers that gyp logs in its debug output. | 301 # that ignores the line numbers that gyp logs in its debug output. |
| 300 if kw.pop('ignore_line_numbers', False): | 302 if kw.pop('ignore_line_numbers', False): |
| 301 kw.setdefault('match', match_modulo_line_numbers) | 303 kw.setdefault('match', match_modulo_line_numbers) |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 319 | 321 |
| 320 def run(self, *args, **kw): | 322 def run(self, *args, **kw): |
| 321 """ | 323 """ |
| 322 Executes a program by calling the superclass .run() method. | 324 Executes a program by calling the superclass .run() method. |
| 323 | 325 |
| 324 This exists to provide a common place to filter out keyword | 326 This exists to provide a common place to filter out keyword |
| 325 arguments implemented in this layer, without having to update | 327 arguments implemented in this layer, without having to update |
| 326 the tool-specific subclasses or clutter the tests themselves | 328 the tool-specific subclasses or clutter the tests themselves |
| 327 with platform-specific code. | 329 with platform-specific code. |
| 328 """ | 330 """ |
| 329 if kw.has_key('SYMROOT'): | 331 if 'SYMROOT' in kw: |
| 330 del kw['SYMROOT'] | 332 del kw['SYMROOT'] |
| 331 super(TestGypBase, self).run(*args, **kw) | 333 super(TestGypBase, self).run(*args, **kw) |
| 332 | 334 |
| 333 def set_configuration(self, configuration): | 335 def set_configuration(self, configuration): |
| 334 """ | 336 """ |
| 335 Sets the configuration, to be used for invoking the build | 337 Sets the configuration, to be used for invoking the build |
| 336 tool and testing potential built output. | 338 tool and testing potential built output. |
| 337 """ | 339 """ |
| 338 self.configuration = configuration | 340 self.configuration = configuration |
| 339 | 341 |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 549 """ | 551 """ |
| 550 arguments = kw.get('arguments', [])[:] | 552 arguments = kw.get('arguments', [])[:] |
| 551 if self.configuration: | 553 if self.configuration: |
| 552 arguments.append('BUILDTYPE=' + self.configuration) | 554 arguments.append('BUILDTYPE=' + self.configuration) |
| 553 if target not in (None, self.DEFAULT): | 555 if target not in (None, self.DEFAULT): |
| 554 arguments.append(target) | 556 arguments.append(target) |
| 555 # Sub-directory builds provide per-gyp Makefiles (i.e. | 557 # Sub-directory builds provide per-gyp Makefiles (i.e. |
| 556 # Makefile.gyp_filename), so use that if there is no Makefile. | 558 # Makefile.gyp_filename), so use that if there is no Makefile. |
| 557 chdir = kw.get('chdir', '') | 559 chdir = kw.get('chdir', '') |
| 558 if not os.path.exists(os.path.join(chdir, 'Makefile')): | 560 if not os.path.exists(os.path.join(chdir, 'Makefile')): |
| 559 print "NO Makefile in " + os.path.join(chdir, 'Makefile') | 561 print("NO Makefile in " + os.path.join(chdir, 'Makefile')) |
| 560 arguments.insert(0, '-f') | 562 arguments.insert(0, '-f') |
| 561 arguments.insert(1, os.path.splitext(gyp_file)[0] + '.Makefile') | 563 arguments.insert(1, os.path.splitext(gyp_file)[0] + '.Makefile') |
| 562 kw['arguments'] = arguments | 564 kw['arguments'] = arguments |
| 563 return self.run(program=self.build_tool, **kw) | 565 return self.run(program=self.build_tool, **kw) |
| 564 def up_to_date(self, gyp_file, target=None, **kw): | 566 def up_to_date(self, gyp_file, target=None, **kw): |
| 565 """ | 567 """ |
| 566 Verifies that a build of the specified Make target is up to date. | 568 Verifies that a build of the specified Make target is up to date. |
| 567 """ | 569 """ |
| 568 if target in (None, self.DEFAULT): | 570 if target in (None, self.DEFAULT): |
| 569 message_target = 'all' | 571 message_target = 'all' |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 656 import TestWin | 658 import TestWin |
| 657 registry = TestWin.Registry() | 659 registry = TestWin.Registry() |
| 658 | 660 |
| 659 msvs_to_msbuild = { | 661 msvs_to_msbuild = { |
| 660 '2013': r'12.0', | 662 '2013': r'12.0', |
| 661 '2012': r'4.0', # Really v4.0.30319 which comes with .NET 4.5. | 663 '2012': r'4.0', # Really v4.0.30319 which comes with .NET 4.5. |
| 662 '2010': r'4.0'} | 664 '2010': r'4.0'} |
| 663 | 665 |
| 664 msbuild_basekey = r'HKLM\SOFTWARE\Microsoft\MSBuild\ToolsVersions' | 666 msbuild_basekey = r'HKLM\SOFTWARE\Microsoft\MSBuild\ToolsVersions' |
| 665 if not registry.KeyExists(msbuild_basekey): | 667 if not registry.KeyExists(msbuild_basekey): |
| 666 print 'Error: could not find MSBuild base registry entry' | 668 print('Error: could not find MSBuild base registry entry') |
| 667 return None | 669 return None |
| 668 | 670 |
| 669 msbuild_version = None | 671 msbuild_version = None |
| 670 if msvs_version in msvs_to_msbuild: | 672 if msvs_version in msvs_to_msbuild: |
| 671 msbuild_test_version = msvs_to_msbuild[msvs_version] | 673 msbuild_test_version = msvs_to_msbuild[msvs_version] |
| 672 if registry.KeyExists(msbuild_basekey + '\\' + msbuild_test_version): | 674 if registry.KeyExists(msbuild_basekey + '\\' + msbuild_test_version): |
| 673 msbuild_version = msbuild_test_version | 675 msbuild_version = msbuild_test_version |
| 674 else: | 676 else: |
| 675 print ('Warning: Environment variable GYP_MSVS_VERSION specifies "%s" ' | 677 print ('Warning: Environment variable GYP_MSVS_VERSION specifies "%s" ' |
| 676 'but corresponding MSBuild "%s" was not found.' % | 678 'but corresponding MSBuild "%s" was not found.' % |
| 677 (msvs_version, msbuild_version)) | 679 (msvs_version, msbuild_version)) |
| 678 if not msbuild_version: | 680 if not msbuild_version: |
| 679 for msvs_version in sorted(msvs_to_msbuild, reverse=True): | 681 for msvs_version in sorted(msvs_to_msbuild, reverse=True): |
| 680 msbuild_test_version = msvs_to_msbuild[msvs_version] | 682 msbuild_test_version = msvs_to_msbuild[msvs_version] |
| 681 if registry.KeyExists(msbuild_basekey + '\\' + msbuild_test_version): | 683 if registry.KeyExists(msbuild_basekey + '\\' + msbuild_test_version): |
| 682 msbuild_version = msbuild_test_version | 684 msbuild_version = msbuild_test_version |
| 683 break | 685 break |
| 684 if not msbuild_version: | 686 if not msbuild_version: |
| 685 print 'Error: could not find MSBuild registry entry' | 687 print('Error: could not find MSBuild registry entry') |
| 686 return None | 688 return None |
| 687 | 689 |
| 688 msbuild_path = registry.GetValue(msbuild_basekey + '\\' + msbuild_version, | 690 msbuild_path = registry.GetValue(msbuild_basekey + '\\' + msbuild_version, |
| 689 'MSBuildToolsPath') | 691 'MSBuildToolsPath') |
| 690 if not msbuild_path: | 692 if not msbuild_path: |
| 691 print 'Error: could not get MSBuild registry entry value' | 693 print('Error: could not get MSBuild registry entry value') |
| 692 return None | 694 return None |
| 693 | 695 |
| 694 return os.path.join(msbuild_path, 'MSBuild.exe') | 696 return os.path.join(msbuild_path, 'MSBuild.exe') |
| 695 | 697 |
| 696 | 698 |
| 697 def FindVisualStudioInstallation(): | 699 def FindVisualStudioInstallation(): |
| 698 """Returns appropriate values for .build_tool and .uses_msbuild fields | 700 """Returns appropriate values for .build_tool and .uses_msbuild fields |
| 699 of TestGypBase for Visual Studio. | 701 of TestGypBase for Visual Studio. |
| 700 | 702 |
| 701 We use the value specified by GYP_MSVS_VERSION. If not specified, we | 703 We use the value specified by GYP_MSVS_VERSION. If not specified, we |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 734 # Neither GYP_MSVS_VERSION nor the path help us out. Iterate through | 736 # Neither GYP_MSVS_VERSION nor the path help us out. Iterate through |
| 735 # the choices looking for a match. | 737 # the choices looking for a match. |
| 736 for version in sorted(possible_paths, reverse=True): | 738 for version in sorted(possible_paths, reverse=True): |
| 737 path = possible_paths[version] | 739 path = possible_paths[version] |
| 738 for r in possible_roots: | 740 for r in possible_roots: |
| 739 build_tool = os.path.join(r, path) | 741 build_tool = os.path.join(r, path) |
| 740 if os.path.exists(build_tool): | 742 if os.path.exists(build_tool): |
| 741 uses_msbuild = msvs_version >= '2010' | 743 uses_msbuild = msvs_version >= '2010' |
| 742 msbuild_path = FindMSBuildInstallation(msvs_version) | 744 msbuild_path = FindMSBuildInstallation(msvs_version) |
| 743 return build_tool, uses_msbuild, msbuild_path | 745 return build_tool, uses_msbuild, msbuild_path |
| 744 print 'Error: could not find devenv' | 746 print('Error: could not find devenv') |
| 745 sys.exit(1) | 747 sys.exit(1) |
| 746 | 748 |
| 747 class TestGypOnMSToolchain(TestGypBase): | 749 class TestGypOnMSToolchain(TestGypBase): |
| 748 """ | 750 """ |
| 749 Common subclass for testing generators that target the Microsoft Visual | 751 Common subclass for testing generators that target the Microsoft Visual |
| 750 Studio toolchain (cl, link, dumpbin, etc.) | 752 Studio toolchain (cl, link, dumpbin, etc.) |
| 751 """ | 753 """ |
| 752 @staticmethod | 754 @staticmethod |
| 753 def _ComputeVsvarsPath(devenv_path): | 755 def _ComputeVsvarsPath(devenv_path): |
| 754 devenv_dir = os.path.split(devenv_path)[0] | 756 devenv_dir = os.path.split(devenv_path)[0] |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 879 arguments.extend(['/Project', target]) | 881 arguments.extend(['/Project', target]) |
| 880 if self.configuration: | 882 if self.configuration: |
| 881 arguments.extend(['/ProjectConfig', self.configuration]) | 883 arguments.extend(['/ProjectConfig', self.configuration]) |
| 882 kw['arguments'] = arguments | 884 kw['arguments'] = arguments |
| 883 return self.run(program=self.build_tool, **kw) | 885 return self.run(program=self.build_tool, **kw) |
| 884 def up_to_date(self, gyp_file, target=None, **kw): | 886 def up_to_date(self, gyp_file, target=None, **kw): |
| 885 """ | 887 """ |
| 886 Verifies that a build of the specified Visual Studio target is up to date. | 888 Verifies that a build of the specified Visual Studio target is up to date. |
| 887 | 889 |
| 888 Beware that VS2010 will behave strangely if you build under | 890 Beware that VS2010 will behave strangely if you build under |
| 889 C:\USERS\yourname\AppData\Local. It will cause needless work. The ouptut | 891 C:/USERS/yourname/AppData/Local. It will cause needless work. The ouptut |
|
Nico
2016/07/29 22:22:06
out of interest, is this needed? with \ it's more
AWhetter
2016/11/05 23:59:50
I've worked around it by making the docstring a ra
| |
| 890 will be "1 succeeded and 0 up to date". MSBuild tracing reveals that: | 892 will be "1 succeeded and 0 up to date". MSBuild tracing reveals that: |
| 891 "Project 'C:\Users\...\AppData\Local\...vcxproj' not up to date because | 893 "Project 'C:/Users/.../AppData/Local/...vcxproj' not up to date because |
| 892 'C:\PROGRAM FILES (X86)\MICROSOFT VISUAL STUDIO 10.0\VC\BIN\1033\CLUI.DLL' | 894 'C:/PROGRAM FILES (X86)/MICROSOFT VISUAL STUDIO 10.0/VC/BIN/1033/CLUI.DLL' |
| 893 was modified at 02/21/2011 17:03:30, which is newer than '' which was | 895 was modified at 02/21/2011 17:03:30, which is newer than '' which was |
| 894 modified at 01/01/0001 00:00:00. | 896 modified at 01/01/0001 00:00:00. |
| 895 | 897 |
| 896 The workaround is to specify a workdir when instantiating the test, e.g. | 898 The workaround is to specify a workdir when instantiating the test, e.g. |
| 897 test = TestGyp.TestGyp(workdir='workarea') | 899 test = TestGyp.TestGyp(workdir='workarea') |
| 898 """ | 900 """ |
| 899 result = self.build(gyp_file, target, **kw) | 901 result = self.build(gyp_file, target, **kw) |
| 900 if not result: | 902 if not result: |
| 901 stdout = self.stdout() | 903 stdout = self.stdout() |
| 902 | 904 |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1180 ] | 1182 ] |
| 1181 | 1183 |
| 1182 def TestGyp(*args, **kw): | 1184 def TestGyp(*args, **kw): |
| 1183 """ | 1185 """ |
| 1184 Returns an appropriate TestGyp* instance for a specified GYP format. | 1186 Returns an appropriate TestGyp* instance for a specified GYP format. |
| 1185 """ | 1187 """ |
| 1186 format = kw.pop('format', os.environ.get('TESTGYP_FORMAT')) | 1188 format = kw.pop('format', os.environ.get('TESTGYP_FORMAT')) |
| 1187 for format_class in format_class_list: | 1189 for format_class in format_class_list: |
| 1188 if format == format_class.format: | 1190 if format == format_class.format: |
| 1189 return format_class(*args, **kw) | 1191 return format_class(*args, **kw) |
| 1190 raise Exception, "unknown format %r" % format | 1192 raise Exception("unknown format %r" % format) |
| OLD | NEW |