Commit df22662a authored by maruel@chromium.org's avatar maruel@chromium.org

get_native_path_case() now preserves the trailing os.sep.path and work with non-existing path.

This simplifies a few code paths.
Add unit test to make sure the behavior is consistent accross platforms.

Fixes test regressions.

R=cmp@chromium.org
NOTRY=true
BUG=
TEST=


Review URL: https://chromiumcodereview.appspot.com/10753006

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@146137 0039d316-1c4b-4281-b951-d872f2087c98
parent 99229b21
...@@ -606,7 +606,8 @@ class Isolate_trace_read_merge(IsolateModeBase): ...@@ -606,7 +606,8 @@ class Isolate_trace_read_merge(IsolateModeBase):
LEVEL = isolate.STATS_ONLY LEVEL = isolate.STATS_ONLY
def _check_merge(self, filename): def _check_merge(self, filename):
filepath = os.path.join(ROOT_DIR, 'data', 'isolate', filename) filepath = isolate.trace_inputs.get_native_path_case(
os.path.join(ROOT_DIR, 'data', 'isolate', filename))
expected = 'Updating %s\n' % filepath expected = 'Updating %s\n' % filepath
with open(filepath, 'rb') as f: with open(filepath, 'rb') as f:
old_content = f.read() old_content = f.read()
...@@ -883,8 +884,8 @@ class IsolateNoOutdir(IsolateBase): ...@@ -883,8 +884,8 @@ class IsolateNoOutdir(IsolateBase):
self.assertEquals(self._wrap_in_condition(expected), output) self.assertEquals(self._wrap_in_condition(expected), output)
output = self._execute('merge', [], True) output = self._execute('merge', [], True)
expected = 'Updating %s\n' % os.path.join( expected = 'Updating %s\n' % isolate.trace_inputs.get_native_path_case(
self.root, 'data', 'isolate', 'touch_root.isolate') os.path.join(self.root, 'data', 'isolate', 'touch_root.isolate'))
self.assertEquals(expected, output) self.assertEquals(expected, output)
# In theory the file is going to be updated but in practice its content # In theory the file is going to be updated but in practice its content
# won't change. # won't change.
......
...@@ -104,7 +104,10 @@ class RunTestFromArchive(unittest.TestCase): ...@@ -104,7 +104,10 @@ class RunTestFromArchive(unittest.TestCase):
'--cache', self.cache, '--cache', self.cache,
'--remote', self.table, '--remote', self.table,
] ]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc = subprocess.Popen(
cmd,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True)
out, err = proc.communicate() out, err = proc.communicate()
self.assertEquals(1070, len(out)) self.assertEquals(1070, len(out))
self.assertEquals('', err) self.assertEquals('', err)
...@@ -132,7 +135,10 @@ class RunTestFromArchive(unittest.TestCase): ...@@ -132,7 +135,10 @@ class RunTestFromArchive(unittest.TestCase):
'--cache', self.cache, '--cache', self.cache,
'--remote', self.table, '--remote', self.table,
] ]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc = subprocess.Popen(
cmd,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True)
out, err = proc.communicate() out, err = proc.communicate()
self.assertEquals(1070, len(out)) self.assertEquals(1070, len(out))
self.assertEquals('', err) self.assertEquals('', err)
...@@ -146,7 +152,10 @@ class RunTestFromArchive(unittest.TestCase): ...@@ -146,7 +152,10 @@ class RunTestFromArchive(unittest.TestCase):
'--cache', self.cache, '--cache', self.cache,
'--remote', self.table, '--remote', self.table,
] ]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc = subprocess.Popen(
cmd,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True)
out, err = proc.communicate() out, err = proc.communicate()
self.assertEquals('', out) self.assertEquals('', out)
self.assertEquals('No file to map\n', err) self.assertEquals('No file to map\n', err)
......
...@@ -194,29 +194,32 @@ if sys.platform == 'win32': ...@@ -194,29 +194,32 @@ if sys.platform == 'win32':
return os.path.isabs(path) or len(path) == 2 and path[1] == ':' return os.path.isabs(path) or len(path) == 2 and path[1] == ':'
def get_native_path_case(path): def get_native_path_case(p):
"""Returns the native path case for an existing file. """Returns the native path case for an existing file.
On Windows, removes any leading '\\?\'. On Windows, removes any leading '\\?\'.
""" """
if not isabs(path): if not isabs(p):
raise ValueError( raise ValueError(
'Can\'t get native path case for a non-absolute path: %s' % path, 'Can\'t get native path case for a non-absolute path: %s' % p,
path) p)
# Windows used to have an option to turn on case sensitivity on non Win32 # Windows used to have an option to turn on case sensitivity on non Win32
# subsystem but that's out of scope here and isn't supported anymore. # subsystem but that's out of scope here and isn't supported anymore.
# Go figure why GetShortPathName() is needed. # Go figure why GetShortPathName() is needed.
try: try:
path = GetLongPathName(GetShortPathName(path)) out = GetLongPathName(GetShortPathName(p))
except OSError: except OSError, e:
# This is wrong to silently eat the exception but there's nothing that can if e.args[0] in (2, 3):
# be done about it. # The path does not exist. Try to recurse and reconstruct the path.
logging.info('No access to %s' % path) base = os.path.dirname(p)
if path.startswith('\\\\?\\'): rest = os.path.basename(p)
path = path[4:] return os.path.join(get_native_path_case(base), rest)
raise
if out.startswith('\\\\?\\'):
out = out[4:]
# Always upper case the first letter since GetLongPathName() will return the # Always upper case the first letter since GetLongPathName() will return the
# drive letter in the case it was given. # drive letter in the case it was given.
return path[0].upper() + path[1:] return out[0].upper() + out[1:]
def CommandLineToArgvW(command_line): def CommandLineToArgvW(command_line):
...@@ -254,8 +257,16 @@ elif sys.platform == 'darwin': ...@@ -254,8 +257,16 @@ elif sys.platform == 'darwin':
logging.debug('native_case(%s)' % p) logging.debug('native_case(%s)' % p)
try: try:
rel_ref, _ = Carbon.File.FSPathMakeRef(p) rel_ref, _ = Carbon.File.FSPathMakeRef(p)
return rel_ref.FSRefMakePath() out = rel_ref.FSRefMakePath()
if p.endswith(os.path.sep) and not out.endswith(os.path.sep):
return out + os.path.sep
return out
except MacOS.Error, e: except MacOS.Error, e:
if e.args[0] == -43:
# The path does not exist. Try to recurse and reconstruct the path.
base = os.path.dirname(p)
rest = os.path.basename(p)
return os.path.join(_native_case(base), rest)
raise OSError( raise OSError(
e.args[0], 'Failed to get native path for %s' % p, p, e.args[1]) e.args[0], 'Failed to get native path for %s' % p, p, e.args[1])
...@@ -294,7 +305,7 @@ elif sys.platform == 'darwin': ...@@ -294,7 +305,7 @@ elif sys.platform == 'darwin':
# There was a symlink, process it. # There was a symlink, process it.
base, symlink, rest = _split_at_symlink_native(None, path) base, symlink, rest = _split_at_symlink_native(None, path)
assert symlink, (path, base, symlink, rest) assert symlink, (path, base, symlink, rest, resolved)
prev = base prev = base
base = safe_join(_native_case(base), symlink) base = safe_join(_native_case(base), symlink)
assert len(base) > len(prev) assert len(base) > len(prev)
...@@ -334,7 +345,10 @@ else: # OSes other than Windows and OSX. ...@@ -334,7 +345,10 @@ else: # OSes other than Windows and OSX.
# Linux traces tends to not be normalized so use this occasion to normalize # Linux traces tends to not be normalized so use this occasion to normalize
# it. This function implementation already normalizes the path on the other # it. This function implementation already normalizes the path on the other
# OS so this needs to be done here to be coherent between OSes. # OS so this needs to be done here to be coherent between OSes.
return os.path.normpath(path) out = os.path.normpath(path)
if path.endswith(os.path.sep) and not out.endswith(os.path.sep):
return out + os.path.sep
return out
if sys.platform != 'win32': # All non-Windows OSes. if sys.platform != 'win32': # All non-Windows OSes.
...@@ -569,8 +583,7 @@ class Results(object): ...@@ -569,8 +583,7 @@ class Results(object):
assert tainted or bool(root) != bool(isabs(path)), (root, path) assert tainted or bool(root) != bool(isabs(path)), (root, path)
assert tainted or ( assert tainted or (
not os.path.exists(self.full_path) or not os.path.exists(self.full_path) or
(self.full_path.rstrip(os.path.sep) == (self.full_path == get_native_path_case(self.full_path))), (
get_native_path_case(self.full_path))), (
tainted, self.full_path, get_native_path_case(self.full_path)) tainted, self.full_path, get_native_path_case(self.full_path))
@property @property
......
...@@ -64,12 +64,47 @@ class TraceInputs(unittest.TestCase): ...@@ -64,12 +64,47 @@ class TraceInputs(unittest.TestCase):
self.assertEquals(os.path.join('/usr', '$FOO/bar'), actual.full_path) self.assertEquals(os.path.join('/usr', '$FOO/bar'), actual.full_path)
self.assertEquals(True, actual.tainted) self.assertEquals(True, actual.tainted)
if sys.platform == 'win32': def test_native_case_end_with_os_path_sep(self):
def test_native_case_windows(self): # Make sure the trailing os.path.sep is kept.
windows_path = os.environ['SystemRoot'] path = trace_inputs.get_native_path_case(ROOT_DIR) + os.path.sep
self.assertEquals(trace_inputs.get_native_path_case(path), path)
def test_native_case_non_existing(self):
# Make sure it doesn't throw on non-existing files.
non_existing = 'trace_input_test_this_file_should_not_exist'
path = os.path.expanduser('~/' + non_existing)
self.assertFalse(os.path.exists(path))
path = trace_inputs.get_native_path_case(ROOT_DIR) + os.path.sep
self.assertEquals(trace_inputs.get_native_path_case(path), path)
if sys.platform in ('darwin', 'win32'):
def test_native_case_not_sensitive(self):
# The home directory is almost guaranteed to have mixed upper/lower case
# letters on both Windows and OSX.
# This test also ensures that the output is independent on the input
# string case.
path = os.path.expanduser('~')
self.assertTrue(os.path.isdir(path))
# This test assumes the variable is in the native path case on disk, this
# should be the case. Verify this assumption:
self.assertEquals(path, trace_inputs.get_native_path_case(path))
self.assertEquals( self.assertEquals(
trace_inputs.get_native_path_case(windows_path.lower()), trace_inputs.get_native_path_case(path.lower()),
trace_inputs.get_native_path_case(windows_path.upper())) trace_inputs.get_native_path_case(path.upper()))
def test_native_case_not_sensitive_non_existent(self):
# This test also ensures that the output is independent on the input
# string case.
non_existing = os.path.join(
'trace_input_test_this_dir_should_not_exist', 'really not', '')
path = os.path.expanduser(os.path.join('~', non_existing))
self.assertFalse(os.path.exists(path))
lower = trace_inputs.get_native_path_case(path.lower())
upper = trace_inputs.get_native_path_case(path.upper())
# Make sure non-existing element is not modified:
self.assertTrue(lower.endswith(non_existing.lower()))
self.assertTrue(upper.endswith(non_existing.upper()))
self.assertEquals(lower[:-len(non_existing)], upper[:-len(non_existing)])
if sys.platform != 'win32': if sys.platform != 'win32':
def test_symlink(self): def test_symlink(self):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment