Bug 1290040 - Make find_program return short paths automatically when paths contain spaces on Windows. r=gps

Also fake enough of ctypes to keep the configure unit tests passing
after these changes.
This commit is contained in:
Mike Hommey 2016-07-29 23:16:05 +09:00
parent c2df8cd611
commit da40819e21
2 changed files with 82 additions and 3 deletions

View File

@ -61,6 +61,49 @@ def is_absolute_or_relative(path):
def normsep(path):
return mozpath.normsep(path)
@imports('ctypes')
@imports(_from='ctypes', _import='wintypes')
def get_GetShortPathNameW():
GetShortPathNameW = ctypes.windll.kernel32.GetShortPathNameW
GetShortPathNameW.argtypes = [wintypes.LPCWSTR, wintypes.LPWSTR,
wintypes.DWORD]
GetShortPathNameW.restype = wintypes.DWORD
return GetShortPathNameW
@template
@imports('ctypes')
@imports('platform')
@imports(_from='mozbuild.shellutil', _import='quote')
def normalize_path():
# Until the build system can properly handle programs that need quoting,
# transform those paths into their short version on Windows (e.g.
# c:\PROGRA~1...).
if platform.system() == 'Windows':
GetShortPathNameW = get_GetShortPathNameW()
def normalize_path(path):
path = normsep(path)
if quote(path) == path:
return path
size = 0
while True:
out = ctypes.create_unicode_buffer(size)
needed = GetShortPathNameW(path, out, size)
if size >= needed:
return normsep(out.value)
size = needed
else:
def normalize_path(path):
return normsep(path)
return normalize_path
normalize_path = normalize_path()
# Locates the given program using which, or returns the given path if it
# exists.
# The `paths` parameter may be passed to search the given paths instead of
@ -72,15 +115,15 @@ def normsep(path):
def find_program(file, paths=None):
try:
if is_absolute_or_relative(file):
return normsep(which(os.path.basename(file),
[os.path.dirname(file)]))
return normalize_path(which(os.path.basename(file),
[os.path.dirname(file)]))
if paths:
if not isinstance(paths, (list, tuple)):
die("Paths provided to find_program must be a list of strings, "
"not %r", paths)
paths = list(itertools.chain(
*(p.split(pathsep) for p in paths if p)))
return normsep(which(file, path=paths))
return normalize_path(which(file, path=paths))
except WhichError:
return None

View File

@ -120,8 +120,44 @@ class ConfigureTestSandbox(ConfigureSandbox):
if what == 'os.environ':
return self._environ
if what == 'ctypes.wintypes':
return ReadOnlyNamespace(
LPCWSTR=0,
LPWSTR=1,
DWORD=2,
)
if what == 'ctypes':
class CTypesFunc(object):
def __init__(self, func):
self._func = func
def __call__(self, *args, **kwargs):
return self._func(*args, **kwargs)
return ReadOnlyNamespace(
create_unicode_buffer=self.create_unicode_buffer,
windll=ReadOnlyNamespace(
kernel32=ReadOnlyNamespace(
GetShortPathNameW=CTypesFunc(self.GetShortPathNameW),
)
),
)
return super(ConfigureTestSandbox, self)._get_one_import(what)
def create_unicode_buffer(self, *args, **kwargs):
class Buffer(object):
def __init__(self):
self.value = ''
return Buffer()
def GetShortPathNameW(self, path_in, path_out, length):
path_out.value = path_in
return length
def which(self, command, path=None):
for parent in (path or self._search_path):
c = mozpath.abspath(mozpath.join(parent, command))