summaryrefslogtreecommitdiffstats
path: root/mesonbuild/modules/dlang.py
blob: b9d4299cf5867a04875d64546ecb46305207a958 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# 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.
from __future__ import annotations

import json
import os

from . import ExtensionModule, ModuleInfo
from .. import dependencies
from .. import mlog
from ..interpreterbase import typed_pos_args
from ..mesonlib import Popen_safe, MesonException

class DlangModule(ExtensionModule):
    class_dubbin = None
    init_dub = False

    INFO = ModuleInfo('dlang', '0.48.0')

    def __init__(self, interpreter):
        super().__init__(interpreter)
        self.methods.update({
            'generate_dub_file': self.generate_dub_file,
        })

    def _init_dub(self, state):
        if DlangModule.class_dubbin is None:
            self.dubbin = dependencies.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(state)
            DlangModule.class_dubbin = self.dubbin
        else:
            self.dubbin = DlangModule.class_dubbin

        if not self.dubbin:
            if not self.dubbin:
                raise MesonException('DUB not found.')

    @typed_pos_args('dlang.generate_dub_file', str, str)
    def generate_dub_file(self, state, args, kwargs):
        if not DlangModule.init_dub:
            self._init_dub(state)

        config = {
            'name': args[0]
        }

        config_path = os.path.join(args[1], 'dub.json')
        if os.path.exists(config_path):
            with open(config_path, encoding='utf-8') 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, dependencies.Dependency):
                            name = dep.get_name()
                            ret, res = self._call_dubbin(['describe', name])
                            if ret == 0:
                                version = dep.get_version()
                                if version is None:
                                    config[key][name] = ''
                                else:
                                    config[key][name] = version
                elif isinstance(value, dependencies.Dependency):
                    name = value.get_name()
                    ret, res = self._call_dubbin(['describe', name])
                    if ret == 0:
                        version = value.get_version()
                        if version is None:
                            config[key][name] = ''
                        else:
                            config[key][name] = version
            else:
                config[key] = value

        with open(config_path, 'w', encoding='utf-8') 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, state):
        dubbin = state.find_program('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)