Skip to content

Commit 2dfd952

Browse files
xclaesseeli-schwartz
authored andcommitted
Move classes used by scripts to their own module
Those classes are used by wrapper scripts and we should not have to import the rest of mesonlib, build.py, and all their dependencies for that. This renames mesonlib/ directory to utils/ and add a mesonlib.py module that imports everything from utils/ to not have to change `import mesonlib` everywhere. It allows to import utils.core without importing the rest of mesonlib.
1 parent a58ec32 commit 2dfd952

20 files changed

+247
-150
lines changed

.flake8

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@ extend-ignore =
2929
# A003: builtin class attribute
3030
A003
3131
per-file-ignores =
32-
mesonbuild/mesonlib/__init__.py:F401,F403
32+
mesonbuild/mesonlib.py:F401,F403
3333
max-line-length = 120

meson.py

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
# See the License for the specific language governing permissions and
1515
# limitations under the License.
1616

17+
# This file is an entry point for all commands, including scripts. Include the
18+
# strict minimum python modules for performance reasons.
1719
import sys
1820

1921
# Check python version before importing anything else, we might have an older

mesonbuild/backend/backends.py

+2-22
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434
from ..compilers import LANGUAGES_USING_LDFLAGS, detect
3535
from ..mesonlib import (
3636
File, MachineChoice, MesonException, OrderedSet,
37-
classify_unity_sources, OptionKey, join_args
37+
classify_unity_sources, OptionKey, join_args,
38+
ExecutableSerialisation
3839
)
3940

4041
if T.TYPE_CHECKING:
@@ -185,27 +186,6 @@ def __init__(self, path: str, install_path: str, install_path_name: str,
185186
super().__init__(path, install_path, install_path_name, install_mode, subproject, tag, data_type)
186187
self.exclude = exclude
187188

188-
@dataclass(eq=False)
189-
class ExecutableSerialisation:
190-
191-
# XXX: should capture and feed default to False, instead of None?
192-
193-
cmd_args: T.List[str]
194-
env: T.Optional[build.EnvironmentVariables] = None
195-
exe_wrapper: T.Optional['programs.ExternalProgram'] = None
196-
workdir: T.Optional[str] = None
197-
extra_paths: T.Optional[T.List] = None
198-
capture: T.Optional[bool] = None
199-
feed: T.Optional[bool] = None
200-
tag: T.Optional[str] = None
201-
verbose: bool = False
202-
203-
def __post_init__(self) -> None:
204-
if self.exe_wrapper is not None:
205-
assert isinstance(self.exe_wrapper, programs.ExternalProgram)
206-
self.pickled = False
207-
self.skip_if_destdir = False
208-
self.subproject = ''
209189

210190
@dataclass(eq=False)
211191
class TestSerialisation:

mesonbuild/build.py

+1-66
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
extract_as_list, typeslistify, stringlistify, classify_unity_sources,
3737
get_filenames_templates_dict, substitute_values, has_path_sep,
3838
OptionKey, PerMachineDefaultable, OptionOverrideProxy,
39-
MesonBugException
39+
MesonBugException, EnvironmentVariables
4040
)
4141
from .compilers import (
4242
is_object, clink_langs, sort_clink, all_languages,
@@ -502,71 +502,6 @@ def needs_copy(self) -> bool:
502502
return False
503503

504504

505-
EnvInitValueType = T.Dict[str, T.Union[str, T.List[str]]]
506-
507-
508-
class EnvironmentVariables(HoldableObject):
509-
def __init__(self, values: T.Optional[EnvInitValueType] = None,
510-
init_method: Literal['set', 'prepend', 'append'] = 'set', separator: str = os.pathsep) -> None:
511-
self.envvars: T.List[T.Tuple[T.Callable[[T.Dict[str, str], str, T.List[str], str], str], str, T.List[str], str]] = []
512-
# The set of all env vars we have operations for. Only used for self.has_name()
513-
self.varnames: T.Set[str] = set()
514-
515-
if values:
516-
init_func = getattr(self, init_method)
517-
for name, value in values.items():
518-
init_func(name, listify(value), separator)
519-
520-
def __repr__(self) -> str:
521-
repr_str = "<{0}: {1}>"
522-
return repr_str.format(self.__class__.__name__, self.envvars)
523-
524-
def hash(self, hasher: T.Any):
525-
myenv = self.get_env({})
526-
for key in sorted(myenv.keys()):
527-
hasher.update(bytes(key, encoding='utf-8'))
528-
hasher.update(b',')
529-
hasher.update(bytes(myenv[key], encoding='utf-8'))
530-
hasher.update(b';')
531-
532-
def has_name(self, name: str) -> bool:
533-
return name in self.varnames
534-
535-
def get_names(self) -> T.Set[str]:
536-
return self.varnames
537-
538-
def set(self, name: str, values: T.List[str], separator: str = os.pathsep) -> None:
539-
self.varnames.add(name)
540-
self.envvars.append((self._set, name, values, separator))
541-
542-
def append(self, name: str, values: T.List[str], separator: str = os.pathsep) -> None:
543-
self.varnames.add(name)
544-
self.envvars.append((self._append, name, values, separator))
545-
546-
def prepend(self, name: str, values: T.List[str], separator: str = os.pathsep) -> None:
547-
self.varnames.add(name)
548-
self.envvars.append((self._prepend, name, values, separator))
549-
550-
@staticmethod
551-
def _set(env: T.Dict[str, str], name: str, values: T.List[str], separator: str) -> str:
552-
return separator.join(values)
553-
554-
@staticmethod
555-
def _append(env: T.Dict[str, str], name: str, values: T.List[str], separator: str) -> str:
556-
curr = env.get(name)
557-
return separator.join(values if curr is None else [curr] + values)
558-
559-
@staticmethod
560-
def _prepend(env: T.Dict[str, str], name: str, values: T.List[str], separator: str) -> str:
561-
curr = env.get(name)
562-
return separator.join(values if curr is None else values + [curr])
563-
564-
def get_env(self, full_env: T.MutableMapping[str, str]) -> T.Dict[str, str]:
565-
env = full_env.copy()
566-
for method, name, values, separator in self.envvars:
567-
env[name] = method(env, name, values, separator)
568-
return env
569-
570505
@dataclass(eq=False)
571506
class Target(HoldableObject):
572507

mesonbuild/dependencies/dub.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414

1515
from .base import ExternalDependency, DependencyException, DependencyTypeName
1616
from .pkgconfig import PkgConfigDependency
17-
from ..mesonlib import (Popen_safe, OptionKey)
18-
from ..mesonlib.universal import join_args
17+
from ..mesonlib import (Popen_safe, OptionKey, join_args)
1918
from ..programs import ExternalProgram
2019
from .. import mlog
2120
import re

mesonbuild/interpreter/type_checking.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
import typing as T
99

1010
from .. import compilers
11-
from ..build import (EnvironmentVariables, EnvInitValueType, CustomTarget, BuildTarget,
11+
from ..build import (CustomTarget, BuildTarget,
1212
CustomTargetIndex, ExtractedObjects, GeneratedList, IncludeDirs,
1313
BothLibraries, SharedLibrary, StaticLibrary, Jar, Executable)
1414
from ..coredata import UserFeatureOption
1515
from ..dependencies import Dependency, InternalDependency
1616
from ..interpreterbase.decorators import KwargInfo, ContainerTypeInfo
17-
from ..mesonlib import File, FileMode, MachineChoice, listify, has_path_sep, OptionKey
17+
from ..mesonlib import (
18+
File, FileMode, MachineChoice, listify, has_path_sep, OptionKey,
19+
EnvInitValueType, EnvironmentVariables)
1820
from ..programs import ExternalProgram
1921

2022
# Helper definition for type checks that are `Optional[T]`

mesonbuild/mesonlib/__init__.py mesonbuild/mesonlib.py

+8-5
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,22 @@
1414
# See the License for the specific language governing permissions and
1515
# limitations under the License.
1616

17+
# pylint: skip-file
1718

1819
"""Helper functions and classes."""
1920

2021
import os
2122

22-
from .universal import *
23-
from .vsenv import setup_vsenv
23+
from .utils.core import *
24+
from .utils.vsenv import *
25+
26+
from .utils.universal import *
2427

2528
# Here we import either the posix implementations, the windows implementations,
2629
# or a generic no-op implementation
2730
if os.name == 'posix':
28-
from .posix import *
31+
from .utils.posix import *
2932
elif os.name == 'nt':
30-
from .win32 import *
33+
from .utils.win32 import *
3134
else:
32-
from .platform import *
35+
from .utils.platform import *

mesonbuild/mesonmain.py

+13-7
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,18 @@
1818
import sys
1919
sys.modules['pathlib'] = _pathlib
2020

21+
# This file is an entry point for all commands, including scripts. Include the
22+
# strict minimum python modules for performance reasons.
2123
import os.path
2224
import platform
2325
import importlib
24-
import traceback
2526
import argparse
26-
import shutil
2727

28-
from . import mesonlib
28+
from .utils.core import MesonException, MesonBugException
2929
from . import mlog
30-
from .mesonlib import MesonException, MesonBugException
3130

3231
def errorhandler(e, command):
32+
import traceback
3333
if isinstance(e, MesonException):
3434
mlog.exception(e)
3535
logfile = mlog.shutdown()
@@ -72,6 +72,7 @@ def __init__(self):
7272
from . import mconf, mdist, minit, minstall, mintro, msetup, mtest, rewriter, msubprojects, munstable_coredata, mcompile, mdevenv
7373
from .scripts import env2mfile
7474
from .wrap import wraptool
75+
import shutil
7576

7677
self.term_width = shutil.get_terminal_size().columns
7778
self.formatter = lambda prog: argparse.HelpFormatter(prog, max_help_position=int(self.term_width / 2), width=self.term_width)
@@ -176,6 +177,7 @@ def run(self, args):
176177
parser = self.parser
177178
command = None
178179

180+
from . import mesonlib
179181
args = mesonlib.expand_arguments(args)
180182
options = parser.parse_args(args)
181183

@@ -228,6 +230,11 @@ def ensure_stdout_accepts_unicode():
228230
if sys.stdout.encoding and not sys.stdout.encoding.upper().startswith('UTF-'):
229231
sys.stdout.reconfigure(errors='surrogateescape')
230232

233+
def set_meson_command(mainfile):
234+
# Set the meson command that will be used to run scripts and so on
235+
from . import mesonlib
236+
mesonlib.set_meson_command(mainfile)
237+
231238
def run(original_args, mainfile):
232239
if sys.version_info >= (3, 10) and os.environ.get('MESON_RUNNING_IN_PROJECT_TESTS'):
233240
# workaround for https://bugs.python.org/issue34624
@@ -245,15 +252,13 @@ def run(original_args, mainfile):
245252
mlog.error('Please install and use mingw-w64-x86_64-python3 and/or mingw-w64-x86_64-meson with Pacman')
246253
return 2
247254

248-
# Set the meson command that will be used to run scripts and so on
249-
mesonlib.set_meson_command(mainfile)
250-
251255
args = original_args[:]
252256

253257
# Special handling of internal commands called from backends, they don't
254258
# need to go through argparse.
255259
if len(args) >= 2 and args[0] == '--internal':
256260
if args[1] == 'regenerate':
261+
set_meson_command(mainfile)
257262
from . import msetup
258263
try:
259264
return msetup.run(['--reconfigure'] + args[2:])
@@ -262,6 +267,7 @@ def run(original_args, mainfile):
262267
else:
263268
return run_script_command(args[1], args[2:])
264269

270+
set_meson_command(mainfile)
265271
return CommandLineParser().run(args)
266272

267273
def main():

mesonbuild/scripts/meson_exe.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@
2020
import typing as T
2121
import locale
2222

23-
from .. import mesonlib
24-
from ..backend.backends import ExecutableSerialisation
23+
from ..utils.core import ExecutableSerialisation
2524

2625
def buildparser() -> argparse.ArgumentParser:
2726
parser = argparse.ArgumentParser(description='Custom executable wrapper for Meson. Do not run on your own, mmm\'kay?')
@@ -46,7 +45,8 @@ def run_exe(exe: ExecutableSerialisation, extra_env: T.Optional[T.Dict[str, str]
4645
if exe.extra_paths:
4746
child_env['PATH'] = (os.pathsep.join(exe.extra_paths + ['']) +
4847
child_env['PATH'])
49-
if exe.exe_wrapper and mesonlib.substring_is_in_list('wine', exe.exe_wrapper.get_command()):
48+
if exe.exe_wrapper and any('wine' in i for i in exe.exe_wrapper.get_command()):
49+
from .. import mesonlib
5050
child_env['WINEPATH'] = mesonlib.get_wine_shortpath(
5151
exe.exe_wrapper.get_command(),
5252
['Z:' + p for p in exe.extra_paths] + child_env.get('WINEPATH', '').split(';'),
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import sys
2+
import json
3+
import typing as T
4+
from . import meson_exe
5+
6+
# This script is used by run_unittests.py to verify we don't load too many
7+
# modules when executing a wrapped command.
8+
def run(args: T.List[str]) -> int:
9+
meson_exe.run(args)
10+
print(json.dumps(list(sys.modules.keys())))
11+
return 0

mesonbuild/utils/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)