| OLD | NEW |
| 1 # Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved. | 1 # Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved. |
| 2 # | 2 # |
| 3 # Redistribution and use in source and binary forms, with or without | 3 # Redistribution and use in source and binary forms, with or without |
| 4 # modification, are permitted provided that the following conditions | 4 # modification, are permitted provided that the following conditions |
| 5 # are met: | 5 # are met: |
| 6 # | 6 # |
| 7 # 1. Redistributions of source code must retain the above | 7 # 1. Redistributions of source code must retain the above |
| 8 # copyright notice, this list of conditions and the following | 8 # copyright notice, this list of conditions and the following |
| 9 # disclaimer. | 9 # disclaimer. |
| 10 # 2. Redistributions in binary form must reproduce the above | 10 # 2. Redistributions in binary form must reproduce the above |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 66 """ | 66 """ |
| 67 | 67 |
| 68 import logging | 68 import logging |
| 69 import mimetypes | 69 import mimetypes |
| 70 import optparse | 70 import optparse |
| 71 import os | 71 import os |
| 72 import sys | 72 import sys |
| 73 | 73 |
| 74 from webkitpy.common.host import Host | 74 from webkitpy.common.host import Host |
| 75 from webkitpy.common.webkit_finder import WebKitFinder | 75 from webkitpy.common.webkit_finder import WebKitFinder |
| 76 from webkitpy.common.system.executive import ScriptError |
| 76 from webkitpy.layout_tests.models.test_expectations import TestExpectationParser | 77 from webkitpy.layout_tests.models.test_expectations import TestExpectationParser |
| 77 from webkitpy.w3c.test_parser import TestParser | 78 from webkitpy.w3c.test_parser import TestParser |
| 78 from webkitpy.w3c.test_converter import convert_for_webkit | 79 from webkitpy.w3c.test_converter import convert_for_webkit |
| 79 | 80 |
| 80 | 81 |
| 81 # Maximum length of import path starting from top of source repository. | 82 # Maximum length of import path starting from top of source repository. |
| 82 # This limit is here because the Windows builders cannot create paths that are | 83 # This limit is here because the Windows builders cannot create paths that are |
| 83 # longer than the Windows max path length (260). See http://crbug.com/609871. | 84 # longer than the Windows max path length (260). See http://crbug.com/609871. |
| 84 MAX_PATH_LENGTH = 125 | 85 MAX_PATH_LENGTH = 125 |
| 85 | 86 |
| 86 | 87 |
| 87 _log = logging.getLogger(__name__) | 88 _log = logging.getLogger(__name__) |
| 88 | 89 |
| 89 | 90 |
| 90 def main(_argv, _stdout, _stderr): | 91 def main(_argv, _stdout, _stderr): |
| 91 options, args = parse_args() | 92 options, args = parse_args() |
| 92 host = Host() | 93 host = Host() |
| 93 source_repo_path = host.filesystem.normpath(os.path.abspath(args[0])) | 94 dir_to_import = host.filesystem.normpath(os.path.abspath(args[0])) |
| 95 if len(args) == 1: |
| 96 top_of_repo = dir_to_import |
| 97 else: |
| 98 top_of_repo = host.filesystem.normpath(os.path.abspath(args[1])) |
| 94 | 99 |
| 95 if not host.filesystem.exists(source_repo_path): | 100 if not host.filesystem.exists(dir_to_import): |
| 96 sys.exit('Repository directory %s not found!' % source_repo_path) | 101 sys.exit('Directory %s not found!' % dir_to_import) |
| 102 if not host.filesystem.exists(top_of_repo): |
| 103 sys.exit('Repository directory %s not found!' % top_of_repo) |
| 104 if top_of_repo not in dir_to_import: |
| 105 sys.exit('Repository directory %s must be a parent of %s' % (top_of_repo
, dir_to_import)) |
| 97 | 106 |
| 98 configure_logging() | 107 configure_logging() |
| 99 test_importer = TestImporter(host, source_repo_path, options) | 108 test_importer = TestImporter(host, dir_to_import, top_of_repo, options) |
| 100 test_importer.do_import() | 109 test_importer.do_import() |
| 101 | 110 |
| 102 | 111 |
| 103 def configure_logging(): | 112 def configure_logging(): |
| 104 class LogHandler(logging.StreamHandler): | 113 class LogHandler(logging.StreamHandler): |
| 105 | 114 |
| 106 def format(self, record): | 115 def format(self, record): |
| 107 if record.levelno > logging.INFO: | 116 if record.levelno > logging.INFO: |
| 108 return "%s: %s" % (record.levelname, record.getMessage()) | 117 return "%s: %s" % (record.levelname, record.getMessage()) |
| 109 return record.getMessage() | 118 return record.getMessage() |
| 110 | 119 |
| 111 logger = logging.getLogger() | 120 logger = logging.getLogger() |
| 112 logger.setLevel(logging.INFO) | 121 logger.setLevel(logging.INFO) |
| 113 handler = LogHandler() | 122 handler = LogHandler() |
| 114 handler.setLevel(logging.INFO) | 123 handler.setLevel(logging.INFO) |
| 115 logger.addHandler(handler) | 124 logger.addHandler(handler) |
| 116 return handler | 125 return handler |
| 117 | 126 |
| 118 | 127 |
| 119 def parse_args(): | 128 def parse_args(): |
| 120 parser = optparse.OptionParser(usage='usage: %prog [options] source_repo_pat
h') | 129 parser = optparse.OptionParser(usage='usage: %prog [options] [dir_to_import]
[top_of_repo]') |
| 121 parser.add_option('-n', '--no-overwrite', dest='overwrite', action='store_fa
lse', default=True, | 130 parser.add_option('-n', '--no-overwrite', dest='overwrite', action='store_fa
lse', default=True, |
| 122 help='Flag to prevent duplicate test files from overwritin
g existing tests. By default, they will be overwritten.') | 131 help='Flag to prevent duplicate test files from overwritin
g existing tests. By default, they will be overwritten.') |
| 123 parser.add_option('-a', '--all', action='store_true', default=False, | 132 parser.add_option('-a', '--all', action='store_true', default=False, |
| 124 help='Import all tests including reftests, JS tests, and m
anual/pixel tests. By default, only reftests and JS tests are imported.') | 133 help='Import all tests including reftests, JS tests, and m
anual/pixel tests. By default, only reftests and JS tests are imported.') |
| 125 parser.add_option('-d', '--dest-dir', dest='destination', default='w3c', | 134 parser.add_option('-d', '--dest-dir', dest='destination', default='w3c', |
| 126 help='Import into a specified directory relative to the La
youtTests root. By default, files are imported under LayoutTests/w3c.') | 135 help='Import into a specified directory relative to the La
youtTests root. By default, files are imported under LayoutTests/w3c.') |
| 127 parser.add_option('--ignore-expectations', action='store_true', default=Fals
e, | 136 parser.add_option('--ignore-expectations', action='store_true', default=Fals
e, |
| 128 help='Ignore the W3CImportExpectations file and import eve
rything.') | 137 help='Ignore the W3CImportExpectations file and import eve
rything.') |
| 129 parser.add_option('--dry-run', action='store_true', default=False, | 138 parser.add_option('--dry-run', action='store_true', default=False, |
| 130 help='Dryrun only (don\'t actually write any results).') | 139 help='Dryrun only (don\'t actually write any results).') |
| 131 | 140 |
| 132 options, args = parser.parse_args() | 141 options, args = parser.parse_args() |
| 133 if len(args) != 1: | 142 if len(args) > 2: |
| 134 parser.error('Incorrect number of arguments; source repo path is require
d.') | 143 parser.error('Incorrect number of arguments') |
| 144 elif len(args) == 0: |
| 145 # If no top-of-repo path was given, then assume that the user means to |
| 146 # use the current working directory as the top-of-repo path. |
| 147 # TODO(qyearsley): Remove this behavior, since it's a little confusing. |
| 148 args = (os.getcwd(),) |
| 135 return options, args | 149 return options, args |
| 136 | 150 |
| 137 | 151 |
| 138 class TestImporter(object): | 152 class TestImporter(object): |
| 139 | 153 |
| 140 def __init__(self, host, source_repo_path, options): | 154 def __init__(self, host, dir_to_import, top_of_repo, options): |
| 141 self.host = host | 155 self.host = host |
| 142 self.source_repo_path = source_repo_path | 156 self.dir_to_import = dir_to_import |
| 157 self.top_of_repo = top_of_repo |
| 143 self.options = options | 158 self.options = options |
| 144 | 159 |
| 145 self.filesystem = self.host.filesystem | 160 self.filesystem = self.host.filesystem |
| 146 self.webkit_finder = WebKitFinder(self.filesystem) | 161 self.webkit_finder = WebKitFinder(self.filesystem) |
| 147 self._webkit_root = self.webkit_finder.webkit_base() | 162 self._webkit_root = self.webkit_finder.webkit_base() |
| 148 self.layout_tests_dir = self.webkit_finder.path_from_webkit_base('Layout
Tests') | 163 self.layout_tests_dir = self.webkit_finder.path_from_webkit_base('Layout
Tests') |
| 149 self.destination_directory = self.filesystem.normpath(self.filesystem.jo
in(self.layout_tests_dir, options.destination, | 164 self.destination_directory = self.filesystem.normpath(self.filesystem.jo
in(self.layout_tests_dir, options.destination, |
| 150
self.filesystem.basename(self.source_repo_path))) | 165
self.filesystem.basename(self.top_of_repo))) |
| 151 self.import_in_place = (self.source_repo_path == self.destination_direct
ory) | 166 self.import_in_place = (self.dir_to_import == self.destination_directory
) |
| 152 self.dir_above_repo = self.filesystem.dirname(self.source_repo_path) | 167 self.dir_above_repo = self.filesystem.dirname(self.top_of_repo) |
| 153 | 168 |
| 154 self.import_list = [] | 169 self.import_list = [] |
| 155 | 170 |
| 156 def do_import(self): | 171 def do_import(self): |
| 157 _log.info("Importing %s into %s", self.source_repo_path, self.destinatio
n_directory) | 172 _log.info("Importing %s into %s", self.dir_to_import, self.destination_d
irectory) |
| 158 self.find_importable_tests() | 173 self.find_importable_tests(self.dir_to_import) |
| 159 self.import_tests() | 174 self.import_tests() |
| 160 | 175 |
| 161 def find_importable_tests(self): | 176 def find_importable_tests(self, directory): |
| 162 """Walks through the source directory to find what tests should be impor
ted. | 177 """Walks through the source directory to find what tests should be impor
ted. |
| 163 | 178 |
| 164 This function sets self.import_list, which contains information about ho
w many | 179 This function sets self.import_list, which contains information about ho
w many |
| 165 tests are being imported, and their source and destination paths. | 180 tests are being imported, and their source and destination paths. |
| 166 """ | 181 """ |
| 167 paths_to_skip = self.find_paths_to_skip() | 182 paths_to_skip = self.find_paths_to_skip() |
| 168 | 183 |
| 169 for root, dirs, files in self.filesystem.walk(self.source_repo_path): | 184 for root, dirs, files in self.filesystem.walk(directory): |
| 170 cur_dir = root.replace(self.dir_above_repo + '/', '') + '/' | 185 cur_dir = root.replace(self.dir_above_repo + '/', '') + '/' |
| 171 _log.info(' scanning ' + cur_dir + '...') | 186 _log.info(' scanning ' + cur_dir + '...') |
| 172 total_tests = 0 | 187 total_tests = 0 |
| 173 reftests = 0 | 188 reftests = 0 |
| 174 jstests = 0 | 189 jstests = 0 |
| 175 | 190 |
| 176 # Files in 'tools' are not for browser testing (e.g., a script for g
enerating test files). | 191 # Files in 'tools' are not for browser testing (e.g., a script for g
enerating test files). |
| 177 # http://testthewebforward.org/docs/test-format-guidelines.html#tool
s | 192 # http://testthewebforward.org/docs/test-format-guidelines.html#tool
s |
| 178 DIRS_TO_SKIP = ('.git', 'test-plan', 'tools') | 193 DIRS_TO_SKIP = ('.git', 'test-plan', 'tools') |
| 179 | 194 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 195 if not self.options.dry_run and self.import_in_place: | 210 if not self.options.dry_run and self.import_in_place: |
| 196 _log.info(" pruning %s" % path_base) | 211 _log.info(" pruning %s" % path_base) |
| 197 self.filesystem.rmtree(path_full) | 212 self.filesystem.rmtree(path_full) |
| 198 else: | 213 else: |
| 199 _log.info(" skipping %s" % path_base) | 214 _log.info(" skipping %s" % path_base) |
| 200 | 215 |
| 201 copy_list = [] | 216 copy_list = [] |
| 202 | 217 |
| 203 for filename in files: | 218 for filename in files: |
| 204 path_full = self.filesystem.join(root, filename) | 219 path_full = self.filesystem.join(root, filename) |
| 205 path_base = path_full.replace(self.source_repo_path + '/', '') | 220 path_base = path_full.replace(directory + '/', '') |
| 206 path_base = self.destination_directory.replace(self.layout_tests
_dir + '/', '') + '/' + path_base | 221 path_base = self.destination_directory.replace(self.layout_tests
_dir + '/', '') + '/' + path_base |
| 207 if path_base in paths_to_skip: | 222 if path_base in paths_to_skip: |
| 208 if not self.options.dry_run and self.import_in_place: | 223 if not self.options.dry_run and self.import_in_place: |
| 209 _log.info(" pruning %s" % path_base) | 224 _log.info(" pruning %s" % path_base) |
| 210 self.filesystem.remove(path_full) | 225 self.filesystem.remove(path_full) |
| 211 continue | 226 continue |
| 212 else: | 227 else: |
| 213 continue | 228 continue |
| 214 # FIXME: This block should really be a separate function, but th
e early-continues make that difficult. | 229 # FIXME: This block should really be a separate function, but th
e early-continues make that difficult. |
| 215 | 230 |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 311 total_imported_reftests += dir_to_copy['reftests'] | 326 total_imported_reftests += dir_to_copy['reftests'] |
| 312 total_imported_jstests += dir_to_copy['jstests'] | 327 total_imported_jstests += dir_to_copy['jstests'] |
| 313 | 328 |
| 314 prefixed_properties = [] | 329 prefixed_properties = [] |
| 315 | 330 |
| 316 if not dir_to_copy['copy_list']: | 331 if not dir_to_copy['copy_list']: |
| 317 continue | 332 continue |
| 318 | 333 |
| 319 orig_path = dir_to_copy['dirname'] | 334 orig_path = dir_to_copy['dirname'] |
| 320 | 335 |
| 321 subpath = self.filesystem.relpath(orig_path, self.source_repo_path) | 336 subpath = self.filesystem.relpath(orig_path, self.top_of_repo) |
| 322 new_path = self.filesystem.join(self.destination_directory, subpath) | 337 new_path = self.filesystem.join(self.destination_directory, subpath) |
| 323 | 338 |
| 324 if not self.filesystem.exists(new_path): | 339 if not self.filesystem.exists(new_path): |
| 325 self.filesystem.maybe_make_directory(new_path) | 340 self.filesystem.maybe_make_directory(new_path) |
| 326 | 341 |
| 327 copied_files = [] | 342 copied_files = [] |
| 328 | 343 |
| 329 for file_to_copy in dir_to_copy['copy_list']: | 344 for file_to_copy in dir_to_copy['copy_list']: |
| 330 # FIXME: Split this block into a separate function. | 345 # FIXME: Split this block into a separate function. |
| 331 orig_filepath = self.filesystem.normpath(file_to_copy['src']) | 346 orig_filepath = self.filesystem.normpath(file_to_copy['src']) |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 398 _log.info('Properties needing prefixes (by count):') | 413 _log.info('Properties needing prefixes (by count):') |
| 399 for prefixed_property in sorted(total_prefixed_properties, key=lambd
a p: total_prefixed_properties[p]): | 414 for prefixed_property in sorted(total_prefixed_properties, key=lambd
a p: total_prefixed_properties[p]): |
| 400 _log.info(' %s: %s', prefixed_property, total_prefixed_properti
es[prefixed_property]) | 415 _log.info(' %s: %s', prefixed_property, total_prefixed_properti
es[prefixed_property]) |
| 401 | 416 |
| 402 def path_too_long(self, source_path): | 417 def path_too_long(self, source_path): |
| 403 """Checks whether a source path is too long to import. | 418 """Checks whether a source path is too long to import. |
| 404 | 419 |
| 405 Args: | 420 Args: |
| 406 Absolute path of file to be imported. | 421 Absolute path of file to be imported. |
| 407 """ | 422 """ |
| 408 path_from_repo_base = os.path.relpath(source_path, self.source_repo_path
) | 423 path_from_repo_base = os.path.relpath(source_path, self.top_of_repo) |
| 409 return len(path_from_repo_base) > MAX_PATH_LENGTH | 424 return len(path_from_repo_base) > MAX_PATH_LENGTH |
| OLD | NEW |