Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(62)

Unified Diff: tools/isolate/trace_inputs.py

Issue 10091011: Added function to get native path case on Windows and OSX. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase against 10080013 Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/isolate/isolate_test.py ('k') | tools/isolate/trace_inputs_smoke_test.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/isolate/trace_inputs.py
diff --git a/tools/isolate/trace_inputs.py b/tools/isolate/trace_inputs.py
index aebe5c1f5724b8015df2730dacc0d3bee8059767..6cb6dc81651be3fc79f118717e7134cf44fcf233 100755
--- a/tools/isolate/trace_inputs.py
+++ b/tools/isolate/trace_inputs.py
@@ -21,6 +21,15 @@ import re
import subprocess
import sys
+## OS-specific imports
+
+if sys.platform == 'win32':
+ from ctypes.wintypes import create_unicode_buffer
+ from ctypes.wintypes import windll, FormatError # pylint: disable=E0611
+ from ctypes.wintypes import GetLastError # pylint: disable=E0611
+elif sys.platform == 'darwin':
+ import Carbon.File # pylint: disable=F0401
+
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
ROOT_DIR = os.path.dirname(os.path.dirname(BASE_DIR))
@@ -29,12 +38,9 @@ KEY_TRACKED = 'isolate_dependency_tracked'
KEY_UNTRACKED = 'isolate_dependency_untracked'
-if sys.platform == 'win32':
- from ctypes.wintypes import create_unicode_buffer
- from ctypes.wintypes import windll, FormatError # pylint: disable=E0611
- from ctypes.wintypes import GetLastError # pylint: disable=E0611
-
+## OS-specific functions
+if sys.platform == 'win32':
def QueryDosDevice(drive_letter):
"""Returns the Windows 'native' path for a DOS drive letter."""
assert re.match(r'^[a-zA-Z]:$', drive_letter), drive_letter
@@ -56,6 +62,10 @@ if sys.platform == 'win32':
def GetShortPathName(long_path):
"""Returns the Windows short path equivalent for a 'long' path."""
long_path = unicode(long_path)
+ # Adds '\\\\?\\' when given an absolute path so the MAX_PATH (260) limit is
+ # not enforced.
+ if os.path.isabs(long_path) and not long_path.startswith('\\\\?\\'):
+ long_path = '\\\\?\\' + long_path
chars = windll.kernel32.GetShortPathNameW(long_path, None, 0)
if chars:
p = create_unicode_buffer(chars)
@@ -71,6 +81,28 @@ if sys.platform == 'win32':
str(long_path), FormatError(err), err))
+ def GetLongPathName(short_path):
+ """Returns the Windows long path equivalent for a 'short' path."""
+ short_path = unicode(short_path)
+ # Adds '\\\\?\\' when given an absolute path so the MAX_PATH (260) limit is
+ # not enforced.
+ if os.path.isabs(short_path) and not short_path.startswith('\\\\?\\'):
+ short_path = '\\\\?\\' + short_path
+ chars = windll.kernel32.GetLongPathNameW(short_path, None, 0)
+ if chars:
+ p = create_unicode_buffer(chars)
+ if windll.kernel32.GetLongPathNameW(short_path, p, chars):
+ return p.value
+
+ err = GetLastError()
+ if err:
+ # pylint: disable=E0602
+ raise WindowsError(
+ err,
+ 'GetLongPathName(%s): %s (%d)' % (
+ str(short_path), FormatError(err), err))
+
+
def get_current_encoding():
"""Returns the 'ANSI' code page associated to the process."""
return 'cp%d' % int(windll.kernel32.GetACP())
@@ -83,6 +115,9 @@ if sys.platform == 'win32':
def __init__(self):
if not self._MAPPING:
+ # This is related to UNC resolver on windows. Ignore that.
+ self._MAPPING['\\Device\\Mup'] = None
+
for letter in (chr(l) for l in xrange(ord('C'), ord('Z')+1)):
try:
letter = '%s:' % letter
@@ -98,14 +133,36 @@ if sys.platform == 'win32':
def to_dos(self, path):
"""Converts a native NT path to DOS path."""
m = re.match(r'(^\\Device\\[a-zA-Z0-9]+)(\\.*)?$', path)
- if not m or m.group(1) not in self._MAPPING:
- assert False, path
+ assert m, path
+ assert m.group(1) in self._MAPPING, (path, self._MAPPING)
drive = self._MAPPING[m.group(1)]
- if not m.group(2):
+ if not drive or not m.group(2):
return drive
return drive + m.group(2)
+def get_native_path_case(root, relative_path):
+ """Returns the native path case."""
+ if sys.platform == '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.
+ # First process root.
+ if root:
+ root = GetLongPathName(GetShortPathName(root)) + os.path.sep
+ path = os.path.join(root, relative_path) if root else relative_path
+ # Go figure why GetShortPathName() is needed.
+ return GetLongPathName(GetShortPathName(path))[len(root):]
+ elif sys.platform == 'darwin':
+ # Technically, it's only HFS+ on OSX that is case insensitive. It's
+ # the default setting on HFS+ but can be changed.
+ root_ref, _ = Carbon.File.FSPathMakeRef(root)
+ rel_ref, _ = Carbon.File.FSPathMakeRef(os.path.join(root, relative_path))
+ return rel_ref.FSRefMakePath()[len(root_ref.FSRefMakePath())+1:]
+ else:
+ # Give up on cygwin, as GetLongPathName() can't be called.
+ return relative_path
+
+
def get_flavor():
"""Returns the system default flavor. Copied from gyp/pylib/gyp/common.py."""
flavors = {
@@ -837,7 +894,7 @@ class LogmanTrace(object):
def handle_FileIo_Create(self, line):
m = re.match(r'^\"(.+)\"$', line[self.FILE_PATH])
- self._handle_file(self._drive_map.to_dos(m.group(1)).lower())
+ self._handle_file(self._drive_map.to_dos(m.group(1)))
def handle_FileIo_Rename(self, line):
# TODO(maruel): Handle?
@@ -913,7 +970,7 @@ class LogmanTrace(object):
def __init__(self):
# Most ignores need to be determined at runtime.
- self.IGNORED = set([os.path.dirname(sys.executable).lower()])
+ self.IGNORED = set([os.path.dirname(sys.executable)])
# Add many directories from environment variables.
vars_to_ignore = (
'APPDATA',
@@ -928,11 +985,11 @@ class LogmanTrace(object):
)
for i in vars_to_ignore:
if os.environ.get(i):
- self.IGNORED.add(os.environ[i].lower())
+ self.IGNORED.add(os.environ[i])
# Also add their short path name equivalents.
for i in list(self.IGNORED):
- self.IGNORED.add(GetShortPathName(i).lower())
+ self.IGNORED.add(GetShortPathName(i))
# Add this one last since it has no short path name equivalent.
self.IGNORED.add('\\systemroot')
@@ -1225,16 +1282,6 @@ def trace_inputs(logfile, cmd, root_dir, cwd_dir, product_dir, force_trace):
# Resolve any symlink
root_dir = os.path.realpath(root_dir)
- if sys.platform == 'win32':
- # Help ourself and lowercase all the paths.
- # TODO(maruel): handle short path names by converting them to long path name
- # as needed.
- root_dir = root_dir.lower()
- if cwd_dir:
- cwd_dir = cwd_dir.lower()
- if product_dir:
- product_dir = product_dir.lower()
-
def print_if(txt):
if cwd_dir is None:
print(txt)
@@ -1287,6 +1334,9 @@ def trace_inputs(logfile, cmd, root_dir, cwd_dir, product_dir, force_trace):
for f in unexpected:
print_if(' %s' % f)
+ # In case the file system is case insensitive.
+ expected = sorted(set(get_native_path_case(root_dir, f) for f in expected))
+
simplified = extract_directories(expected, root_dir)
print_if('Interesting: %d reduced to %d' % (len(expected), len(simplified)))
for f in simplified:
@@ -1312,8 +1362,7 @@ def trace_inputs(logfile, cmd, root_dir, cwd_dir, product_dir, force_trace):
"""Bases the file on the most restrictive variable."""
logging.debug('fix(%s)' % f)
# Important, GYP stores the files with / and not \.
- if sys.platform == 'win32':
- f = f.replace('\\', '/')
+ f = f.replace(os.path.sep, '/')
if product_dir and f.startswith(product_dir):
return '<(PRODUCT_DIR)/%s' % f[len(product_dir):]
« no previous file with comments | « tools/isolate/isolate_test.py ('k') | tools/isolate/trace_inputs_smoke_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698