1# Copyright 2018 The Meson development team 2 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6 7# http://www.apache.org/licenses/LICENSE-2.0 8 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15# This file contains the detection logic for external dependencies that 16# are UI-related. 17 18import json 19import os 20 21from . import ExtensionModule 22from .. import dependencies 23from .. import mlog 24from ..mesonlib import Popen_safe, MesonException 25 26class DlangModule(ExtensionModule): 27 class_dubbin = None 28 init_dub = False 29 30 def __init__(self, interpreter): 31 super().__init__(interpreter) 32 self.methods.update({ 33 'generate_dub_file': self.generate_dub_file, 34 }) 35 36 def _init_dub(self, state): 37 if DlangModule.class_dubbin is None: 38 self.dubbin = dependencies.DubDependency.class_dubbin 39 DlangModule.class_dubbin = self.dubbin 40 else: 41 self.dubbin = DlangModule.class_dubbin 42 43 if DlangModule.class_dubbin is None: 44 self.dubbin = self.check_dub(state) 45 DlangModule.class_dubbin = self.dubbin 46 else: 47 self.dubbin = DlangModule.class_dubbin 48 49 if not self.dubbin: 50 if not self.dubbin: 51 raise MesonException('DUB not found.') 52 53 def generate_dub_file(self, state, args, kwargs): 54 if not DlangModule.init_dub: 55 self._init_dub(state) 56 57 if len(args) < 2: 58 raise MesonException('Missing arguments') 59 60 config = { 61 'name': args[0] 62 } 63 64 config_path = os.path.join(args[1], 'dub.json') 65 if os.path.exists(config_path): 66 with open(config_path, encoding='utf-8') as ofile: 67 try: 68 config = json.load(ofile) 69 except ValueError: 70 mlog.warning('Failed to load the data in dub.json') 71 72 warn_publishing = ['description', 'license'] 73 for arg in warn_publishing: 74 if arg not in kwargs and \ 75 arg not in config: 76 mlog.warning('Without', mlog.bold(arg), 'the DUB package can\'t be published') 77 78 for key, value in kwargs.items(): 79 if key == 'dependencies': 80 config[key] = {} 81 if isinstance(value, list): 82 for dep in value: 83 if isinstance(dep, dependencies.Dependency): 84 name = dep.get_name() 85 ret, res = self._call_dubbin(['describe', name]) 86 if ret == 0: 87 version = dep.get_version() 88 if version is None: 89 config[key][name] = '' 90 else: 91 config[key][name] = version 92 elif isinstance(value, dependencies.Dependency): 93 name = value.get_name() 94 ret, res = self._call_dubbin(['describe', name]) 95 if ret == 0: 96 version = value.get_version() 97 if version is None: 98 config[key][name] = '' 99 else: 100 config[key][name] = version 101 else: 102 config[key] = value 103 104 with open(config_path, 'w', encoding='utf-8') as ofile: 105 ofile.write(json.dumps(config, indent=4, ensure_ascii=False)) 106 107 def _call_dubbin(self, args, env=None): 108 p, out = Popen_safe(self.dubbin.get_command() + args, env=env)[0:2] 109 return p.returncode, out.strip() 110 111 def check_dub(self, state): 112 dubbin = state.find_program('dub', silent=True) 113 if dubbin.found(): 114 try: 115 p, out = Popen_safe(dubbin.get_command() + ['--version'])[0:2] 116 if p.returncode != 0: 117 mlog.warning('Found dub {!r} but couldn\'t run it' 118 ''.format(' '.join(dubbin.get_command()))) 119 # Set to False instead of None to signify that we've already 120 # searched for it and not found it 121 dubbin = False 122 except (FileNotFoundError, PermissionError): 123 dubbin = False 124 else: 125 dubbin = False 126 if dubbin: 127 mlog.log('Found DUB:', mlog.bold(dubbin.get_path()), 128 '(%s)' % out.strip()) 129 else: 130 mlog.log('Found DUB:', mlog.red('NO')) 131 return dubbin 132 133def initialize(*args, **kwargs): 134 return DlangModule(*args, **kwargs) 135