diff options
author | FFY00 <filipe.lains@gmail.com> | 2018-06-17 19:47:41 +0100 |
---|---|---|
committer | FFY00 <filipe.lains@gmail.com> | 2018-06-17 22:34:32 +0100 |
commit | 8ef4864ae482b0e1d190fbb29efc1473f1454b29 (patch) | |
tree | 68bcd06743d3e2a6b7755614903fdaf1215f7709 | |
parent | 5290f41f31439180b15600bca4ce4456983e3900 (diff) | |
download | meson-8ef4864ae482b0e1d190fbb29efc1473f1454b29.zip meson-8ef4864ae482b0e1d190fbb29efc1473f1454b29.tar.gz meson-8ef4864ae482b0e1d190fbb29efc1473f1454b29.tar.bz2 |
dependencies: add dub as a dependency method
-rw-r--r-- | mesonbuild/dependencies/base.py | 164 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 6 |
2 files changed, 169 insertions, 1 deletions
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index cc3c2d0..86d90d3 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -19,6 +19,7 @@ import copy import os import re import stat +import json import shlex import shutil import textwrap @@ -31,7 +32,6 @@ from ..mesonlib import ( MesonException, Popen_safe, version_compare_many, version_compare, listify ) - # These must be defined in this file to avoid cyclical references. packages = {} _packages_accept_language = set() @@ -59,6 +59,8 @@ class DependencyMethods(Enum): CUPSCONFIG = 'cups-config' PCAPCONFIG = 'pcap-config' LIBWMFCONFIG = 'libwmf-config' + # Misc + DUB = 'dub' class Dependency: @@ -732,6 +734,161 @@ class PkgConfigDependency(ExternalDependency): # a path rather than the raw dlname return os.path.basename(dlname) +class DubDependency(ExternalDependency): + class_dubbin = None + + def __init__(self, name, environment, kwargs): + super().__init__('dub', environment, 'd', kwargs) + self.name = name + + if 'required' in kwargs: + self.required = kwargs.get('required') + + if DubDependency.class_dubbin is None: + self.dubbin = self.check_dub() + DubDependency.class_dubbin = self.dubbin + else: + self.dubbin = DubDependency.class_dubbin + + if not self.dubbin: + if self.required: + raise DependencyException('DUB not found.') + self.is_found = False + mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO')) + return + + mlog.debug('Determining dependency {!r} with DUB executable ' + '{!r}'.format(name, self.dubbin.get_path())) + + # Ask dub for the package + ret, res = self._call_dubbin(['describe', name]) + + if ret != 0: + if self.required: + raise DependencyException('Dependency {!r} not found'.format(name)) + self.is_found = False + mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO')) + return + + j = json.loads(res) + comp = self.compiler.get_id().replace('llvm', 'ldc').replace('gcc', 'gdc') + for package in j['packages']: + if package['name'] == name: + if j['compiler'] != comp: + msg = ['Dependency', mlog.bold(name), 'found but it was compiled with'] + msg += [mlog.bold(j['compiler']), 'and we are using', mlog.bold(comp)] + mlog.error(*msg) + if self.required: + raise DependencyException('Dependency {!r} not found'.format(name)) + self.is_found = False + mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO')) + return + + self.version = package['version'] + self.pkg = package + break + + # Check if package version meets the requirements + found_msg = ['Dependency', mlog.bold(name), 'found:'] + if self.version_reqs is None: + self.is_found = True + else: + if not isinstance(self.version_reqs, (str, list)): + raise DependencyException('Version argument must be string or list.') + if isinstance(self.version_reqs, str): + self.version_reqs = [self.version_reqs] + (self.is_found, not_found, found) = \ + version_compare_many(self.version, self.version_reqs) + if not self.is_found: + found_msg += [mlog.red('NO'), + 'found {!r} but need:'.format(self.version), + ', '.join(["'{}'".format(e) for e in not_found])] + if found: + found_msg += ['; matched:', + ', '.join(["'{}'".format(e) for e in found])] + if not self.silent: + mlog.log(*found_msg) + if self.required: + m = 'Invalid version of dependency, need {!r} {!r} found {!r}.' + raise DependencyException(m.format(name, not_found, self.version)) + return + + found_msg += [mlog.green('YES'), self.version] + + if self.pkg['targetFileName'].endswith('.a'): + self.static = True + + self.compile_args = [] + for flag in self.pkg['dflags']: + self.link_args.append(flag) + for path in self.pkg['importPaths']: + self.compile_args.append('-I' + os.path.join(self.pkg['path'], path)) + + self.link_args = [] + for flag in self.pkg['lflags']: + self.link_args.append(flag) + + search_paths = [] + search_paths.append(os.path.join(self.pkg['path'], self.pkg['targetPath'])) + found, res = self.__search_paths(search_paths, self.pkg['targetFileName']) + for file in res: + self.link_args.append(file) + + if not found: + if self.required: + raise DependencyException('Dependency {!r} not found'.format(name)) + self.is_found = False + mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO')) + return + + if not self.silent: + mlog.log(*found_msg) + + def get_compiler(self): + return self.compiler + + def __search_paths(self, search_paths, target_file): + found = False + res = [] + if target_file == '': + return True, res + for path in search_paths: + if os.path.isdir(path): + for file in os.listdir(path): + if file == target_file: + res.append(os.path.join(path, file)) + found = True + return found, res + + def _call_dubbin(self, args, env=None): + p, out = Popen_safe(self.dubbin.get_command() + args, env=env)[0:2] + return p.returncode, out.strip() + + def check_dub(self): + dubbin = ExternalProgram('dub', silent=True) + if dubbin.found(): + try: + p, out = Popen_safe(dubbin.get_command() + ['--version'])[0:2] + if p.returncode != 0: + mlog.warning('Found dub {!r} but couldn\'t run it' + ''.format(' '.join(dubbin.get_command()))) + # Set to False instead of None to signify that we've already + # searched for it and not found it + dubbin = False + except (FileNotFoundError, PermissionError): + dubbin = False + else: + dubbin = False + if dubbin: + mlog.log('Found DUB:', mlog.bold(dubbin.get_path()), + '(%s)' % out.strip()) + else: + mlog.log('Found DUB:', mlog.red('NO')) + return dubbin + + @staticmethod + def get_methods(): + return [DependencyMethods.PKGCONFIG, DependencyMethods.DUB] class ExternalProgram: windows_exts = ('exe', 'msc', 'com', 'bat', 'cmd') @@ -1029,6 +1186,7 @@ def find_external_dependency(name, env, kwargs): raise DependencyException('Keyword "required" must be a boolean.') if not isinstance(kwargs.get('method', ''), str): raise DependencyException('Keyword "method" must be a string.') + method = kwargs.get('method', '') lname = name.lower() if lname in packages: if lname not in _packages_accept_language and 'language' in kwargs: @@ -1045,6 +1203,10 @@ def find_external_dependency(name, env, kwargs): if 'language' in kwargs: # Remove check when PkgConfigDependency supports language. raise DependencyException('%s dependency does not accept "language" keyword argument' % (lname, )) + if 'dub' == method: + dubdep = DubDependency(name, env, kwargs) + if dubdep.found(): + return dubdep pkg_exc = None pkgdep = None try: diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 421ddd9..40ea5a2 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -313,6 +313,7 @@ class DependencyHolder(InterpreterObject, ObjectHolder): self.methods.update({'found': self.found_method, 'type_name': self.type_name_method, 'version': self.version_method, + 'name': self.name_method, 'get_pkgconfig_variable': self.pkgconfig_method, 'get_configtool_variable': self.configtool_method, 'partial_dependency': self.partial_dependency_method, @@ -335,6 +336,11 @@ class DependencyHolder(InterpreterObject, ObjectHolder): def version_method(self, args, kwargs): return self.held_object.get_version() + @noPosargs + @permittedKwargs({}) + def name_method(self, args, kwargs): + return self.held_object.get_name() + @permittedKwargs({'define_variable'}) def pkgconfig_method(self, args, kwargs): args = listify(args) |