diff options
author | Jussi Pakkanen <jpakkane@gmail.com> | 2018-07-21 02:46:11 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-07-21 02:46:11 +0300 |
commit | 306fa07f62bd6d2833af80a654411740a4626dd7 (patch) | |
tree | f65d93cc77536f34687e1b1a94d33c986db745b6 /mesonbuild | |
parent | f67630d26cf128cb1b659638918968a21955270e (diff) | |
parent | 0173b2457d9840ae63fff96aa30f387570e985cf (diff) | |
download | meson-306fa07f62bd6d2833af80a654411740a4626dd7.zip meson-306fa07f62bd6d2833af80a654411740a4626dd7.tar.gz meson-306fa07f62bd6d2833af80a654411740a4626dd7.tar.bz2 |
Merge pull request #3893 from FFY00/master
Add dlang module (dub support)
Diffstat (limited to 'mesonbuild')
-rw-r--r-- | mesonbuild/dependencies/base.py | 166 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 6 | ||||
-rw-r--r-- | mesonbuild/modules/dlang.py | 141 |
3 files changed, 312 insertions, 1 deletions
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 0fe702f..864fd73 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 ..compilers import clib_langs from ..mesonlib import MesonException, OrderedSet from ..mesonlib import 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: @@ -790,6 +792,162 @@ 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 + self.compiler = super().get_compiler() + + 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') @@ -1097,6 +1255,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: @@ -1113,6 +1272,11 @@ 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 required and not dubdep.found(): + mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO')) + return dubdep pkg_exc = None pkgdep = None try: diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 94f7bfe..a3430aa 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -376,6 +376,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, @@ -398,6 +399,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) diff --git a/mesonbuild/modules/dlang.py b/mesonbuild/modules/dlang.py new file mode 100644 index 0000000..d4f62e4 --- /dev/null +++ b/mesonbuild/modules/dlang.py @@ -0,0 +1,141 @@ +# Copyright 2018 The Meson development team + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file contains the detection logic for external dependencies that +# are UI-related. + +import json +import os + +from . import ExtensionModule + +from .. import mlog + +from ..mesonlib import ( + Popen_safe, MesonException +) + +from ..dependencies.base import ( + ExternalProgram, DubDependency +) + +from ..interpreter import DependencyHolder + +class DlangModule(ExtensionModule): + class_dubbin = None + init_dub = False + + def __init__(self, interpreter): + super().__init__(interpreter) + self.snippets.add('generate_dub_file') + + def _init_dub(self): + if DlangModule.class_dubbin is None: + self.dubbin = DubDependency.class_dubbin + DlangModule.class_dubbin = self.dubbin + else: + self.dubbin = DlangModule.class_dubbin + + if DlangModule.class_dubbin is None: + self.dubbin = self.check_dub() + DlangModule.class_dubbin = self.dubbin + else: + self.dubbin = DlangModule.class_dubbin + + if not self.dubbin: + if not self.dubbin: + raise MesonException('DUB not found.') + + def generate_dub_file(self, interpreter, state, args, kwargs): + if not DlangModule.init_dub: + self._init_dub() + + if len(args) < 2: + raise MesonException('Missing arguments') + + config = { + 'name': args[0] + } + + config_path = os.path.join(args[1], 'dub.json') + if os.path.exists(config_path): + with open(config_path, 'r', encoding='utf8') as ofile: + try: + config = json.load(ofile) + except ValueError: + mlog.warning('Failed to load the data in dub.json') + + warn_publishing = ['description', 'license'] + for arg in warn_publishing: + if arg not in kwargs and \ + arg not in config: + mlog.warning('Without', mlog.bold(arg), 'the DUB package can\'t be published') + + for key, value in kwargs.items(): + if key == 'dependencies': + config[key] = {} + if isinstance(value, list): + for dep in value: + if isinstance(dep, DependencyHolder): + name = dep.method_call('name', [], []) + ret, res = self._call_dubbin(['describe', name]) + if ret == 0: + version = dep.method_call('version', [], []) + if version is None: + config[key][name] = '' + else: + config[key][name] = version + elif isinstance(value, DependencyHolder): + name = value.method_call('name', [], []) + ret, res = self._call_dubbin(['describe', name]) + if ret == 0: + version = value.method_call('version', [], []) + if version is None: + config[key][name] = '' + else: + config[key][name] = version + else: + config[key] = value + + with open(config_path, 'w', encoding='utf8') as ofile: + ofile.write(json.dumps(config, indent=4, ensure_ascii=False)) + + 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 + +def initialize(*args, **kwargs): + return DlangModule(*args, **kwargs) |