| 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):]
|
|
|