File: cmdline.py

package info (click to toggle)
meson 1.10.0-1
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 24,680 kB
  • sloc: python: 90,528; ansic: 7,377; cpp: 2,434; f90: 482; asm: 218; sh: 143; xml: 109; java: 97; cs: 62; objc: 33; lex: 13; fortran: 12; makefile: 10; yacc: 9; javascript: 6
file content (182 lines) | stat: -rw-r--r-- 7,188 bytes parent folder | download
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# SPDX-License-Identifier: Apache-2.0
# Copyright 2013-2025 The Meson development team

from __future__ import annotations

import argparse
import ast
import configparser
import os
import shlex
import typing as T
from itertools import chain

from . import options
from .mesonlib import MesonException
from .options import OptionKey

if T.TYPE_CHECKING:
    from typing_extensions import Protocol

    # typeshed
    StrOrBytesPath = T.Union[str, bytes, os.PathLike[str], os.PathLike[bytes]]

    class SharedCMDOptions(Protocol):
        """Representation of command line options from Meson setup, configure,
        and dist.

        :param cmd_line_options: command line options parsed into an OptionKey:
            str mapping
        """

        cmd_line_options: T.Dict[OptionKey, T.Optional[str]]
        cross_file: T.List[str]
        native_file: T.List[str]


class CmdLineFileParser(configparser.ConfigParser):
    def __init__(self) -> None:
        # We don't want ':' as key delimiter, otherwise it would break when
        # storing subproject options like "subproject:option=value"
        super().__init__(delimiters=['='], interpolation=None)

    def read(self, filenames: T.Union['StrOrBytesPath', T.Iterable['StrOrBytesPath']], encoding: T.Optional[str] = 'utf-8') -> T.List[str]:
        return super().read(filenames, encoding)

    def optionxform(self, optionstr: str) -> str:
        # Don't call str.lower() on keys
        return optionstr


def get_cmd_line_file(build_dir: str) -> str:
    return os.path.join(build_dir, 'meson-private', 'cmd_line.txt')

def read_cmd_line_file(build_dir: str, options: SharedCMDOptions) -> None:
    filename = get_cmd_line_file(build_dir)
    if not os.path.isfile(filename):
        return

    config = CmdLineFileParser()
    config.read(filename)

    # Do a copy because config is not really a dict. options.cmd_line_options
    # overrides values from the file.
    d = {OptionKey.from_string(k): v for k, v in config['options'].items()}
    d.update(options.cmd_line_options)
    options.cmd_line_options = d

    properties = config['properties']
    if not options.cross_file:
        options.cross_file = ast.literal_eval(properties.get('cross_file', '[]'))
    if not options.native_file:
        # This will be a string in the form: "['first', 'second', ...]", use
        # literal_eval to get it into the list of strings.
        options.native_file = ast.literal_eval(properties.get('native_file', '[]'))

def write_cmd_line_file(build_dir: str, options: SharedCMDOptions) -> None:
    filename = get_cmd_line_file(build_dir)
    config = CmdLineFileParser()

    properties: T.Dict[str, T.List[str]] = {}
    if options.cross_file:
        properties['cross_file'] = options.cross_file
    if options.native_file:
        properties['native_file'] = options.native_file

    config['options'] = {str(k): str(v) for k, v in options.cmd_line_options.items()}
    config['properties'] = {k: repr(v) for k, v in properties.items()}
    with open(filename, 'w', encoding='utf-8') as f:
        config.write(f)

def update_cmd_line_file(build_dir: str, options: SharedCMDOptions) -> None:
    filename = get_cmd_line_file(build_dir)
    config = CmdLineFileParser()
    config.read(filename)
    for k, v in options.cmd_line_options.items():
        keystr = str(k)
        if v is not None:
            config['options'][keystr] = str(v)
        elif keystr in config['options']:
            del config['options'][keystr]

    with open(filename, 'w', encoding='utf-8') as f:
        config.write(f)

def format_cmd_line_options(options: SharedCMDOptions) -> str:
    cmdline = ['-D{}={}'.format(str(k), v) for k, v in options.cmd_line_options.items()]
    if options.cross_file:
        cmdline += [f'--cross-file={f}' for f in options.cross_file]
    if options.native_file:
        cmdline += [f'--native-file={f}' for f in options.native_file]
    return ' '.join([shlex.quote(x) for x in cmdline])


class KeyNoneAction(argparse.Action):
    """
    Custom argparse Action that stores values in a dictionary as keys with value None.
    """

    def __init__(self, option_strings: str, dest: str, nargs: T.Optional[T.Union[int, str]] = None, **kwargs: T.Any) -> None:
        assert nargs is None or nargs == 1
        super().__init__(option_strings, dest, nargs=1, **kwargs)

    def __call__(self, parser: argparse.ArgumentParser, namespace: argparse.Namespace,
                 arg: T.List[str], option_string: str = None) -> None: # type: ignore[override]
        current_dict = getattr(namespace, self.dest)
        if current_dict is None:
            current_dict = {}
            setattr(namespace, self.dest, current_dict)

        key = OptionKey.from_string(arg[0])
        current_dict[key] = None


class KeyValueAction(argparse.Action):
    """
    Custom argparse Action that parses KEY=VAL arguments and stores them in a dictionary.
    """

    def __init__(self, option_strings: str, dest: str, nargs: T.Optional[T.Union[int, str]] = None, **kwargs: T.Any) -> None:
        assert nargs is None or nargs == 1
        super().__init__(option_strings, dest, nargs=1, **kwargs)

    def __call__(self, parser: argparse.ArgumentParser, namespace: argparse.Namespace,
                 arg: T.List[str], option_string: str = None) -> None: # type: ignore[override]
        current_dict = getattr(namespace, self.dest)
        if current_dict is None:
            current_dict = {}
            setattr(namespace, self.dest, current_dict)

        try:
            keystr, value = arg[0].split('=', 1)
            key = OptionKey.from_string(keystr)
            current_dict[key] = value
        except ValueError:
            parser.error(f'The argument for option {option_string!r} must be in OPTION=VALUE format.')


def register_builtin_arguments(parser: argparse.ArgumentParser) -> None:
    for n, b in options.BUILTIN_OPTIONS.items():
        options.option_to_argparse(b, n, parser, '')
    for n, b in options.BUILTIN_OPTIONS_PER_MACHINE.items():
        options.option_to_argparse(b, n, parser, ' (just for host machine)')
        options.option_to_argparse(b, n.as_build(), parser, ' (just for build machine)')
    parser.add_argument('-D', action=KeyValueAction, dest='cmd_line_options', default={}, metavar="option=value",
                        help='Set the value of an option, can be used several times to set multiple options.')

def parse_cmd_line_options(args: SharedCMDOptions) -> None:
    # Merge builtin options set with --option into the dict.
    for key in chain(
            options.BUILTIN_OPTIONS.keys(),
            (k.as_build() for k in options.BUILTIN_OPTIONS_PER_MACHINE.keys()),
            options.BUILTIN_OPTIONS_PER_MACHINE.keys(),
    ):
        name = str(key)
        value = getattr(args, name, None)
        if value is not None:
            if key in args.cmd_line_options:
                cmdline_name = options.argparse_name_to_arg(name)
                raise MesonException(
                    f'Got argument {name} as both -D{name} and {cmdline_name}. Pick one.')
            args.cmd_line_options[key] = value
            delattr(args, name)