aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/dependencies.py
diff options
context:
space:
mode:
authorNirbheek Chauhan <nirbheek@centricular.com>2016-07-30 15:19:11 +0530
committerNirbheek Chauhan <nirbheek@centricular.com>2016-07-30 15:20:01 +0530
commit577b6dfdf63cde697ff33226950175a93578e2b8 (patch)
tree48058766e57be3559518295db3d9c908489734c4 /mesonbuild/dependencies.py
parent4a92b78e6e4508afb8ca988cb47c91ea4a765fee (diff)
downloadmeson-577b6dfdf63cde697ff33226950175a93578e2b8.zip
meson-577b6dfdf63cde697ff33226950175a93578e2b8.tar.gz
meson-577b6dfdf63cde697ff33226950175a93578e2b8.tar.bz2
find_program: Find scripts without extensions on Windows
Because of how files and executables work on Windows, scripts that use an interpreter must have an extension, and that extension must be associated with an interpreter. The full list of executable extensions is available in the PATHEXT environment variable. However, UNIX-like OSes use an executable bit and read the shebang to figure out what interpreter to use, and the scripts don't need to have extensions. We can now detect these scripts using find_program by manually searching in PATH and reading the shebang.
Diffstat (limited to 'mesonbuild/dependencies.py')
-rw-r--r--mesonbuild/dependencies.py87
1 files changed, 62 insertions, 25 deletions
diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py
index 3f1e214..b4f825b 100644
--- a/mesonbuild/dependencies.py
+++ b/mesonbuild/dependencies.py
@@ -353,37 +353,13 @@ class WxDependency(Dependency):
class ExternalProgram():
def __init__(self, name, fullpath=None, silent=False, search_dir=None):
self.name = name
- self.fullpath = None
if fullpath is not None:
if not isinstance(fullpath, list):
self.fullpath = [fullpath]
else:
self.fullpath = fullpath
else:
- self.fullpath = [shutil.which(name)]
- 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
+ self.fullpath = self._search(name, search_dir)
if not silent:
if self.found():
mlog.log('Program', mlog.bold(name), 'found:', mlog.green('YES'),
@@ -391,6 +367,67 @@ class ExternalProgram():
else:
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):
return self.fullpath[0] is not None