Merge pull request #659 from centricular/find-program-scripts-windows
find_program: Find scripts without extensions on Windows
This commit is contained in:
commit
fb3f4420b2
|
@ -353,37 +353,13 @@ class WxDependency(Dependency):
|
||||||
class ExternalProgram():
|
class ExternalProgram():
|
||||||
def __init__(self, name, fullpath=None, silent=False, search_dir=None):
|
def __init__(self, name, fullpath=None, silent=False, search_dir=None):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.fullpath = None
|
|
||||||
if fullpath is not None:
|
if fullpath is not None:
|
||||||
if not isinstance(fullpath, list):
|
if not isinstance(fullpath, list):
|
||||||
self.fullpath = [fullpath]
|
self.fullpath = [fullpath]
|
||||||
else:
|
else:
|
||||||
self.fullpath = fullpath
|
self.fullpath = fullpath
|
||||||
else:
|
else:
|
||||||
self.fullpath = [shutil.which(name)]
|
self.fullpath = self._search(name, search_dir)
|
||||||
if self.fullpath[0] is None and search_dir is not None:
|
|
||||||
trial = os.path.join(search_dir, name)
|
|
||||||
suffix = os.path.splitext(trial)[-1].lower()[1:]
|
|
||||||
if mesonlib.is_windows() and (suffix == 'exe' or suffix == 'com'\
|
|
||||||
or suffix == 'bat'):
|
|
||||||
self.fullpath = [trial]
|
|
||||||
elif not mesonlib.is_windows() and os.access(trial, os.X_OK):
|
|
||||||
self.fullpath = [trial]
|
|
||||||
else:
|
|
||||||
# Now getting desperate. Maybe it is a script file that is a) not chmodded
|
|
||||||
# executable or b) we are on windows so they can't be directly executed.
|
|
||||||
try:
|
|
||||||
first_line = open(trial).readline().strip()
|
|
||||||
if first_line.startswith('#!'):
|
|
||||||
commands = first_line[2:].split('#')[0].strip().split()
|
|
||||||
if mesonlib.is_windows():
|
|
||||||
# Windows does not have /usr/bin.
|
|
||||||
commands[0] = commands[0].split('/')[-1]
|
|
||||||
if commands[0] == 'env':
|
|
||||||
commands = commands[1:]
|
|
||||||
self.fullpath = commands + [trial]
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
if not silent:
|
if not silent:
|
||||||
if self.found():
|
if self.found():
|
||||||
mlog.log('Program', mlog.bold(name), 'found:', mlog.green('YES'),
|
mlog.log('Program', mlog.bold(name), 'found:', mlog.green('YES'),
|
||||||
|
@ -391,6 +367,67 @@ class ExternalProgram():
|
||||||
else:
|
else:
|
||||||
mlog.log('Program', mlog.bold(name), 'found:', mlog.red('NO'))
|
mlog.log('Program', mlog.bold(name), 'found:', mlog.red('NO'))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _shebang_to_cmd(script):
|
||||||
|
"""
|
||||||
|
Windows does not understand shebangs, so we check if the file has a
|
||||||
|
shebang and manually parse it to figure out the interpreter to use
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
first_line = open(script).readline().strip()
|
||||||
|
if first_line.startswith('#!'):
|
||||||
|
commands = first_line[2:].split('#')[0].strip().split()
|
||||||
|
if mesonlib.is_windows():
|
||||||
|
# Windows does not have /usr/bin.
|
||||||
|
commands[0] = commands[0].split('/')[-1]
|
||||||
|
if commands[0] == 'env':
|
||||||
|
commands = commands[1:]
|
||||||
|
return commands + [script]
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _is_executable(path):
|
||||||
|
suffix = os.path.splitext(path)[-1].lower()[1:]
|
||||||
|
if mesonlib.is_windows():
|
||||||
|
if suffix == 'exe' or suffix == 'com' or suffix == 'bat':
|
||||||
|
return True
|
||||||
|
elif os.access(path, os.X_OK):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _search_dir(self, name, search_dir):
|
||||||
|
if search_dir is None:
|
||||||
|
return False
|
||||||
|
trial = os.path.join(search_dir, name)
|
||||||
|
if not os.path.exists(trial):
|
||||||
|
return False
|
||||||
|
if self._is_executable(trial):
|
||||||
|
return [trial]
|
||||||
|
# Now getting desperate. Maybe it is a script file that is a) not chmodded
|
||||||
|
# executable or b) we are on windows so they can't be directly executed.
|
||||||
|
return self._shebang_to_cmd(trial)
|
||||||
|
|
||||||
|
def _search(self, name, search_dir):
|
||||||
|
commands = self._search_dir(name, search_dir)
|
||||||
|
if commands:
|
||||||
|
return commands
|
||||||
|
# Do a standard search in PATH
|
||||||
|
fullpath = shutil.which(name)
|
||||||
|
if fullpath or not mesonlib.is_windows():
|
||||||
|
# On UNIX-like platforms, the standard PATH search is enough
|
||||||
|
return [fullpath]
|
||||||
|
# On Windows, interpreted scripts must have an extension otherwise they
|
||||||
|
# cannot be found by a standard PATH search. So we do a custom search
|
||||||
|
# where we manually search for a script with a shebang in PATH.
|
||||||
|
search_dirs = os.environ.get('PATH', '').split(';')
|
||||||
|
for search_dir in search_dirs:
|
||||||
|
commands = self._search_dir(name, search_dir)
|
||||||
|
if commands:
|
||||||
|
return commands
|
||||||
|
return [None]
|
||||||
|
|
||||||
def found(self):
|
def found(self):
|
||||||
return self.fullpath[0] is not None
|
return self.fullpath[0] is not None
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
project('find program', 'c')
|
||||||
|
|
||||||
|
prog = find_program('test-script')
|
||||||
|
test('script', prog)
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
print('1')
|
Loading…
Reference in New Issue