Modified: trunk/Tools/Scripts/webkitpy/common/system/filesystem.py (89205 => 89206)
--- trunk/Tools/Scripts/webkitpy/common/system/filesystem.py 2011-06-18 20:34:57 UTC (rev 89205)
+++ trunk/Tools/Scripts/webkitpy/common/system/filesystem.py 2011-06-18 20:36:47 UTC (rev 89206)
@@ -263,6 +263,10 @@
with codecs.open(path, 'r', 'utf8') as f:
return f.read()
+ def split(self, path):
+ """Return (dirname, basename + '.' + ext)"""
+ return os.path.split(path)
+
def splitext(self, path):
"""Return (dirname + os.sep + basename, '.' + ext)"""
return os.path.splitext(path)
Modified: trunk/Tools/Scripts/webkitpy/common/system/filesystem_mock.py (89205 => 89206)
--- trunk/Tools/Scripts/webkitpy/common/system/filesystem_mock.py 2011-06-18 20:34:57 UTC (rev 89205)
+++ trunk/Tools/Scripts/webkitpy/common/system/filesystem_mock.py 2011-06-18 20:36:47 UTC (rev 89206)
@@ -277,6 +277,12 @@
if d.startswith(path):
self.dirs[d] = None
+ def split(self, path):
+ idx = path.rfind(self.sep)
+ if idx == -1:
+ return ('', path)
+ return (path[:idx], path[(idx + 1):])
+
def splitext(self, path):
idx = path.rfind('.')
if idx == -1:
Modified: trunk/Tools/Scripts/webkitpy/layout_tests/layout_package/manager.py (89205 => 89206)
--- trunk/Tools/Scripts/webkitpy/layout_tests/layout_package/manager.py 2011-06-18 20:34:57 UTC (rev 89205)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/layout_package/manager.py 2011-06-18 20:36:47 UTC (rev 89206)
@@ -43,6 +43,7 @@
import math
import Queue
import random
+import re
import sys
import time
@@ -374,7 +375,7 @@
if self._options.randomize_order:
random.shuffle(self._test_files_list)
else:
- self._test_files_list.sort()
+ self._test_files_list.sort(key=lambda path: path_key(self._fs, path))
# If the user specifies they just want to run a subset of the tests,
# just grab a subset of the non-skipped tests.
@@ -1370,6 +1371,34 @@
return tests
+def path_key(filesystem, path):
+ """Turns a path into a list with two sublists, the natural key of the
+ dirname, and the natural key of the basename.
+
+ This can be used when sorting paths so that files in a directory.
+ directory are kept together rather than being mixed in with files in
+ subdirectories."""
+ dirname, basename = filesystem.split(path)
+ return (natural_sort_key(dirname + filesystem.sep), natural_sort_key(basename))
+
+
+def natural_sort_key(string_to_split):
+ """ Turn a string into a list of string and number chunks.
+ "z23a" -> ["z", 23, "a"]
+
+ Can be used to implement "natural sort" order. See:
+ http://www.codinghorror.com/blog/2007/12/sorting-for-humans-natural-sort-order.html
+ http://nedbatchelder.com/blog/200712.html#e20071211T054956
+ """
+ def tryint(val):
+ try:
+ return int(val)
+ except:
+ return val
+
+ return [tryint(chunk) for chunk in re.split('(\d+)', string_to_split)]
+
+
class _WorkerState(object):
"""A class for the manager to use to track the current state of the workers."""
def __init__(self, number, worker_connection):
Modified: trunk/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_unittest.py (89205 => 89206)
--- trunk/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_unittest.py 2011-06-18 20:34:57 UTC (rev 89205)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_unittest.py 2011-06-18 20:36:47 UTC (rev 89206)
@@ -80,5 +80,48 @@
self.assertEqual(expected_tests_to_http_lock, set(multi_thread_results[0][1]))
+class NaturalCompareTest(unittest.TestCase):
+ def assert_cmp(self, x, y, result):
+ self.assertEquals(cmp(manager.natural_sort_key(x), manager.natural_sort_key(y)), result)
+
+ def test_natural_compare(self):
+ self.assert_cmp('a', 'a', 0)
+ self.assert_cmp('ab', 'a', 1)
+ self.assert_cmp('a', 'ab', -1)
+ self.assert_cmp('', '', 0)
+ self.assert_cmp('', 'ab', -1)
+ self.assert_cmp('1', '2', -1)
+ self.assert_cmp('2', '1', 1)
+ self.assert_cmp('1', '10', -1)
+ self.assert_cmp('2', '10', -1)
+ self.assert_cmp('foo_1.html', 'foo_2.html', -1)
+ self.assert_cmp('foo_1.1.html', 'foo_2.html', -1)
+ self.assert_cmp('foo_1.html', 'foo_10.html', -1)
+ self.assert_cmp('foo_2.html', 'foo_10.html', -1)
+ self.assert_cmp('foo_23.html', 'foo_10.html', 1)
+ self.assert_cmp('foo_23.html', 'foo_100.html', -1)
+
+
+class PathCompareTest(unittest.TestCase):
+ def setUp(self):
+ self.filesystem = filesystem_mock.MockFileSystem()
+
+ def path_key(self, k):
+ return manager.path_key(self.filesystem, k)
+
+ def assert_cmp(self, x, y, result):
+ self.assertEquals(cmp(self.path_key(x), self.path_key(y)), result)
+
+ def test_path_compare(self):
+ self.assert_cmp('/a', '/a', 0)
+ self.assert_cmp('/a', '/b', -1)
+ self.assert_cmp('/a2', '/a10', -1)
+ self.assert_cmp('/a2/foo', '/a10/foo', -1)
+ self.assert_cmp('/a/foo11', '/a/foo2', 1)
+ self.assert_cmp('/ab', '/a/a/b', -1)
+ self.assert_cmp('/a/a/b', '/ab', 1)
+ self.assert_cmp('/foo-bar/baz', '/foo/baz', -1)
+
+
if __name__ == '__main__':
unittest.main()