OLD | NEW |
1 # Copyright (C) 2013 Google Inc. All rights reserved. | 1 # Copyright (C) 2013 Google Inc. 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 are | 4 # modification, are permitted provided that the following conditions are |
5 # met: | 5 # met: |
6 # | 6 # |
7 # * Redistributions of source code must retain the above copyright | 7 # * Redistributions of source code must retain the above copyright |
8 # notice, this list of conditions and the following disclaimer. | 8 # notice, this list of conditions and the following disclaimer. |
9 # * Redistributions in binary form must reproduce the above | 9 # * Redistributions in binary form must reproduce the above |
10 # copyright notice, this list of conditions and the following disclaimer | 10 # copyright notice, this list of conditions and the following disclaimer |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 from webkitpy.layout_tests.port.base import Port | 56 from webkitpy.layout_tests.port.base import Port |
57 from webkitpy.layout_tests.models.test_expectations import TestExpectations | 57 from webkitpy.layout_tests.models.test_expectations import TestExpectations |
58 | 58 |
59 | 59 |
60 logging.basicConfig() | 60 logging.basicConfig() |
61 _log = logging.getLogger(__name__) | 61 _log = logging.getLogger(__name__) |
62 _log.setLevel(logging.INFO) | 62 _log.setLevel(logging.INFO) |
63 | 63 |
64 PLATFORM_DIRECTORY = 'platform' | 64 PLATFORM_DIRECTORY = 'platform' |
65 | 65 |
| 66 |
66 class LayoutTestsMover(object): | 67 class LayoutTestsMover(object): |
67 | 68 |
68 def __init__(self, port=None): | 69 def __init__(self, port=None): |
69 self._port = port | 70 self._port = port |
70 if not self._port: | 71 if not self._port: |
71 host = Host() | 72 host = Host() |
72 # Given that we use include_overrides=False and model_all_expectatio
ns=True when | 73 # Given that we use include_overrides=False and model_all_expectatio
ns=True when |
73 # constructing the TestExpectations object, it doesn't matter which
Port object we use. | 74 # constructing the TestExpectations object, it doesn't matter which
Port object we use. |
74 self._port = host.port_factory.get() | 75 self._port = host.port_factory.get() |
75 self._port.host.initialize_scm() | 76 self._port.host.initialize_scm() |
(...skipping 27 matching lines...) Expand all Loading... |
103 raise Exception('Destination path %s is not in LayoutTests directory
' % self._destination) | 104 raise Exception('Destination path %s is not in LayoutTests directory
' % self._destination) |
104 | 105 |
105 # If destination is an existing directory, we move the children of origi
n into destination. | 106 # If destination is an existing directory, we move the children of origi
n into destination. |
106 # However, if any of the children of origin would clash with existing ch
ildren of | 107 # However, if any of the children of origin would clash with existing ch
ildren of |
107 # destination, we fail. | 108 # destination, we fail. |
108 # FIXME: Consider adding support for recursively moving into an existing
directory. | 109 # FIXME: Consider adding support for recursively moving into an existing
directory. |
109 if self._filesystem.isdir(self._absolute_destination): | 110 if self._filesystem.isdir(self._absolute_destination): |
110 for file_path in self._filesystem.listdir(self._absolute_origin): | 111 for file_path in self._filesystem.listdir(self._absolute_origin): |
111 if self._filesystem.exists(self._filesystem.join(self._absolute_
destination, file_path)): | 112 if self._filesystem.exists(self._filesystem.join(self._absolute_
destination, file_path)): |
112 raise Exception('Origin path %s clashes with existing destin
ation path %s' % | 113 raise Exception('Origin path %s clashes with existing destin
ation path %s' % |
113 (self._filesystem.join(self._origin, file_path), sel
f._filesystem.join(self._destination, file_path))) | 114 (self._filesystem.join(self._origin, file_pa
th), self._filesystem.join(self._destination, file_path))) |
114 | 115 |
115 def _get_expectations_for_test(self, model, test_path): | 116 def _get_expectations_for_test(self, model, test_path): |
116 """Given a TestExpectationsModel object, finds all expectations that mat
ch the specified | 117 """Given a TestExpectationsModel object, finds all expectations that mat
ch the specified |
117 test, specified as a relative path. Handles the fact that expectations m
ay be keyed by | 118 test, specified as a relative path. Handles the fact that expectations m
ay be keyed by |
118 directory. | 119 directory. |
119 """ | 120 """ |
120 expectations = set() | 121 expectations = set() |
121 if model.has_test(test_path): | 122 if model.has_test(test_path): |
122 expectations.add(model.get_expectation_line(test_path)) | 123 expectations.add(model.get_expectation_line(test_path)) |
123 test_path = self._filesystem.dirname(test_path) | 124 test_path = self._filesystem.dirname(test_path) |
124 while not test_path == '': | 125 while not test_path == '': |
125 # The model requires a trailing slash for directories. | 126 # The model requires a trailing slash for directories. |
126 test_path_for_model = test_path + '/' | 127 test_path_for_model = test_path + '/' |
127 if model.has_test(test_path_for_model): | 128 if model.has_test(test_path_for_model): |
128 expectations.add(model.get_expectation_line(test_path_for_model)
) | 129 expectations.add(model.get_expectation_line(test_path_for_model)
) |
129 test_path = self._filesystem.dirname(test_path) | 130 test_path = self._filesystem.dirname(test_path) |
130 return expectations | 131 return expectations |
131 | 132 |
132 def _get_expectations(self, model, path): | 133 def _get_expectations(self, model, path): |
133 """Given a TestExpectationsModel object, finds all expectations for all
tests under the | 134 """Given a TestExpectationsModel object, finds all expectations for all
tests under the |
134 specified relative path. | 135 specified relative path. |
135 """ | 136 """ |
136 expectations = set() | 137 expectations = set() |
137 for test in self._filesystem.files_under(self._filesystem.join(self._lay
out_tests_root, path), dirs_to_skip=['script-tests', 'resources'], | 138 for test in self._filesystem.files_under(self._filesystem.join(self._lay
out_tests_root, path), dirs_to_skip=['script-tests', 'resources'], |
138 file_filter=Port.is_test_file): | 139 file_filter=Port.is_test_file): |
139 expectations = expectations.union(self._get_expectations_for_test(mo
del, self._filesystem.relpath(test, self._layout_tests_root))) | 140 expectations = expectations.union( |
| 141 self._get_expectations_for_test( |
| 142 model, |
| 143 self._filesystem.relpath( |
| 144 test, |
| 145 self._layout_tests_root))) |
140 return expectations | 146 return expectations |
141 | 147 |
142 @staticmethod | 148 @staticmethod |
143 def _clone_expectation_line_for_path(expectation_line, path): | 149 def _clone_expectation_line_for_path(expectation_line, path): |
144 """Clones a TestExpectationLine object and updates the clone to apply to
the specified | 150 """Clones a TestExpectationLine object and updates the clone to apply to
the specified |
145 relative path. | 151 relative path. |
146 """ | 152 """ |
147 clone = copy.copy(expectation_line) | 153 clone = copy.copy(expectation_line) |
148 clone.original_string = re.compile(expectation_line.name).sub(path, expe
ctation_line.original_string) | 154 clone.original_string = re.compile(expectation_line.name).sub(path, expe
ctation_line.original_string) |
149 clone.name = path | 155 clone.name = path |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
204 # Both the root path and the target of the reference my be subject to th
e move, so there are | 210 # Both the root path and the target of the reference my be subject to th
e move, so there are |
205 # four cases to consider. In the case where both or neither are subject
to the move, the | 211 # four cases to consider. In the case where both or neither are subject
to the move, the |
206 # reference doesn't need updating. | 212 # reference doesn't need updating. |
207 # | 213 # |
208 # This is true even if the reference includes superfluous dot segments w
hich mention a moved | 214 # This is true even if the reference includes superfluous dot segments w
hich mention a moved |
209 # directory, as dot segments are collapsed during URL normalization. For
example, if | 215 # directory, as dot segments are collapsed during URL normalization. For
example, if |
210 # foo.html contains a reference 'bar/../script.js', this remains valid (
though ugly) even if | 216 # foo.html contains a reference 'bar/../script.js', this remains valid (
though ugly) even if |
211 # bar/ is moved to baz/, because the reference is always normalized to '
script.js'. | 217 # bar/ is moved to baz/, because the reference is always normalized to '
script.js'. |
212 absolute_reference = self._filesystem.normpath(self._filesystem.join(roo
t, reference)) | 218 absolute_reference = self._filesystem.normpath(self._filesystem.join(roo
t, reference)) |
213 if self._is_child_path(self._absolute_origin, root) == self._is_child_pa
th(self._absolute_origin, absolute_reference): | 219 if self._is_child_path(self._absolute_origin, root) == self._is_child_pa
th(self._absolute_origin, absolute_reference): |
214 return None; | 220 return None |
215 | 221 |
216 new_root = self._move_path(root, self._absolute_origin, self._absolute_d
estination) | 222 new_root = self._move_path(root, self._absolute_origin, self._absolute_d
estination) |
217 new_absolute_reference = self._move_path(absolute_reference, self._absol
ute_origin, self._absolute_destination) | 223 new_absolute_reference = self._move_path(absolute_reference, self._absol
ute_origin, self._absolute_destination) |
218 return self._filesystem.relpath(new_absolute_reference, new_root) | 224 return self._filesystem.relpath(new_absolute_reference, new_root) |
219 | 225 |
220 def _get_all_updated_references(self, references): | 226 def _get_all_updated_references(self, references): |
221 """Determines the updated references due to the move. Returns a dictiona
ry that maps from an | 227 """Determines the updated references due to the move. Returns a dictiona
ry that maps from an |
222 absolute file path to a dictionary that maps from a reference string to
the corresponding | 228 absolute file path to a dictionary that maps from a reference string to
the corresponding |
223 updated reference. | 229 updated reference. |
224 """ | 230 """ |
(...skipping 21 matching lines...) Expand all Loading... |
246 for target in updates.keys(): | 252 for target in updates.keys(): |
247 regex = re.compile(r'((?:src=|href=|importScripts\(|url\()["\']?)%s(
["\']?)' % target) | 253 regex = re.compile(r'((?:src=|href=|importScripts\(|url\()["\']?)%s(
["\']?)' % target) |
248 contents = regex.sub(r'\1%s\2' % updates[target], contents) | 254 contents = regex.sub(r'\1%s\2' % updates[target], contents) |
249 self._filesystem.write_binary_file(path, contents) | 255 self._filesystem.write_binary_file(path, contents) |
250 self._scm.add(path) | 256 self._scm.add(path) |
251 | 257 |
252 def _update_test_source_files(self): | 258 def _update_test_source_files(self): |
253 def is_test_source_file(filesystem, dirname, basename): | 259 def is_test_source_file(filesystem, dirname, basename): |
254 pass_regex = re.compile(r'\.(css|js)$') | 260 pass_regex = re.compile(r'\.(css|js)$') |
255 fail_regex = re.compile(r'-expected\.') | 261 fail_regex = re.compile(r'-expected\.') |
256 return (Port.is_test_file(filesystem, dirname, basename) or pass_reg
ex.search(basename)) and not fail_regex.search(basename) | 262 return (Port.is_test_file(filesystem, dirname, basename) |
| 263 or pass_regex.search(basename)) and not fail_regex.search(ba
sename) |
257 | 264 |
258 test_source_files = self._filesystem.files_under(self._layout_tests_root
, file_filter=is_test_source_file) | 265 test_source_files = self._filesystem.files_under(self._layout_tests_root
, file_filter=is_test_source_file) |
259 _log.info('Considering %s test source files for references' % len(test_s
ource_files)) | 266 _log.info('Considering %s test source files for references' % len(test_s
ource_files)) |
260 references = self._find_references(test_source_files) | 267 references = self._find_references(test_source_files) |
261 _log.info('Considering references in %s files' % len(references)) | 268 _log.info('Considering references in %s files' % len(references)) |
262 updates = self._get_all_updated_references(references) | 269 updates = self._get_all_updated_references(references) |
263 _log.info('Updating references in %s files' % len(updates)) | 270 _log.info('Updating references in %s files' % len(updates)) |
264 count = 0 | 271 count = 0 |
265 for file_path in updates.keys(): | 272 for file_path in updates.keys(): |
266 self._update_file(file_path, updates[file_path]) | 273 self._update_file(file_path, updates[file_path]) |
(...skipping 17 matching lines...) Expand all Loading... |
284 self._scm.move(self._scm_path(origin, directory), self._scm_path(des
tination, directory)) | 291 self._scm.move(self._scm_path(origin, directory), self._scm_path(des
tination, directory)) |
285 self._filesystem.rmtree(absolute_origin) | 292 self._filesystem.rmtree(absolute_origin) |
286 | 293 |
287 def _move_files(self): | 294 def _move_files(self): |
288 """Moves the all files that correspond to the move, including platform-s
pecific expected | 295 """Moves the all files that correspond to the move, including platform-s
pecific expected |
289 results. | 296 results. |
290 """ | 297 """ |
291 self._move_directory(self._origin, self._destination) | 298 self._move_directory(self._origin, self._destination) |
292 for directory in self._filesystem.listdir(self._filesystem.join(self._la
yout_tests_root, PLATFORM_DIRECTORY)): | 299 for directory in self._filesystem.listdir(self._filesystem.join(self._la
yout_tests_root, PLATFORM_DIRECTORY)): |
293 self._move_directory(self._filesystem.join(PLATFORM_DIRECTORY, direc
tory, self._origin), | 300 self._move_directory(self._filesystem.join(PLATFORM_DIRECTORY, direc
tory, self._origin), |
294 self._filesystem.join(PLATFORM_DIRECTORY, directory,
self._destination)) | 301 self._filesystem.join(PLATFORM_DIRECTORY, direc
tory, self._destination)) |
295 | 302 |
296 def _commit_changes(self): | 303 def _commit_changes(self): |
297 if not self._scm.supports_local_commits(): | 304 if not self._scm.supports_local_commits(): |
298 return | 305 return |
299 title = 'Move LayoutTests directory %s to %s' % (self._origin, self._des
tination) | 306 title = 'Move LayoutTests directory %s to %s' % (self._origin, self._des
tination) |
300 _log.info('Committing change \'%s\'' % title) | 307 _log.info('Committing change \'%s\'' % title) |
301 self._scm.commit_locally_with_message('%s\n\nThis commit was automatical
ly generated by move-layout-tests.' % title, | 308 self._scm.commit_locally_with_message('%s\n\nThis commit was automatical
ly generated by move-layout-tests.' % title, |
302 commit_all_working_directory_chang
es=False) | 309 commit_all_working_directory_chang
es=False) |
303 | 310 |
304 def move(self, origin, destination): | 311 def move(self, origin, destination): |
305 self._origin = origin | 312 self._origin = origin |
306 self._destination = destination | 313 self._destination = destination |
307 self._absolute_origin = self._filesystem.join(self._layout_tests_root, s
elf._origin) | 314 self._absolute_origin = self._filesystem.join(self._layout_tests_root, s
elf._origin) |
308 self._absolute_destination = self._filesystem.join(self._layout_tests_ro
ot, self._destination) | 315 self._absolute_destination = self._filesystem.join(self._layout_tests_ro
ot, self._destination) |
309 self._validate_input() | 316 self._validate_input() |
310 self._update_expectations() | 317 self._update_expectations() |
311 self._update_test_source_files() | 318 self._update_test_source_files() |
312 self._move_files() | 319 self._move_files() |
313 # FIXME: Handle virtual test suites. | 320 # FIXME: Handle virtual test suites. |
314 self._commit_changes() | 321 self._commit_changes() |
315 | 322 |
| 323 |
316 def main(argv): | 324 def main(argv): |
317 parser = optparse.OptionParser(description=__doc__) | 325 parser = optparse.OptionParser(description=__doc__) |
318 parser.add_option('--origin', | 326 parser.add_option('--origin', |
319 help=('The directory of tests to move, as a relative path
from the LayoutTests directory.')) | 327 help=('The directory of tests to move, as a relative path
from the LayoutTests directory.')) |
320 parser.add_option('--destination', | 328 parser.add_option('--destination', |
321 help=('The new path for the directory of tests, as a relat
ive path from the LayoutTests directory.')) | 329 help=('The new path for the directory of tests, as a relat
ive path from the LayoutTests directory.')) |
322 options, _ = parser.parse_args() | 330 options, _ = parser.parse_args() |
323 LayoutTestsMover().move(options.origin, options.destination) | 331 LayoutTestsMover().move(options.origin, options.destination) |
OLD | NEW |