diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2025-01-10 15:10:09 +0100 |
---|---|---|
committer | Eli Schwartz <eschwartz93@gmail.com> | 2025-03-09 13:05:08 -0400 |
commit | 528696300afd3236e173242e1e09d1ac80dfec81 (patch) | |
tree | f3989f6d6c49e188201719dd13468e10128a755d | |
parent | 9c125a26dbf1b6ecc674df2bd1abc02ca48da2cd (diff) | |
download | meson-528696300afd3236e173242e1e09d1ac80dfec81.zip meson-528696300afd3236e173242e1e09d1ac80dfec81.tar.gz meson-528696300afd3236e173242e1e09d1ac80dfec81.tar.bz2 |
mesonlib: extract and optimize is_parent_path
Introduce an alternative to os.path.commonpath(name, path) == path,
which is a common idiom throughout Meson. Call it is_parent_path
just like the existing static method in Generator.
It is a bit faster and handles drives on Windows without the need
for an exception handler.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r-- | mesonbuild/backend/backends.py | 10 | ||||
-rw-r--r-- | mesonbuild/backend/ninjabackend.py | 4 | ||||
-rw-r--r-- | mesonbuild/build.py | 12 | ||||
-rw-r--r-- | mesonbuild/scripts/gtkdochelper.py | 7 | ||||
-rw-r--r-- | mesonbuild/utils/universal.py | 21 |
5 files changed, 33 insertions, 21 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 88b3357..9326127 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -28,7 +28,8 @@ from ..compilers import LANGUAGES_USING_LDFLAGS, detect, lang_suffixes from ..mesonlib import ( File, MachineChoice, MesonException, MesonBugException, OrderedSet, ExecutableSerialisation, EnvironmentException, - classify_unity_sources, get_compiler_for_source + classify_unity_sources, get_compiler_for_source, + is_parent_path, ) from ..options import OptionKey @@ -797,12 +798,7 @@ class Backend: ): continue - try: - commonpath = os.path.commonpath((libdir, srcdir)) - except ValueError: # when paths are on different drives on Windows - commonpath = '' - - if commonpath == srcdir: + if is_parent_path(srcdir, libdir): rel_to_src = libdir[len(srcdir) + 1:] assert not os.path.isabs(rel_to_src), f'rel_to_src: {rel_to_src} is absolute' paths.add(os.path.join(self.build_to_src, rel_to_src)) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 316d225..251e63f 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -31,7 +31,7 @@ from ..mesonlib import ( File, LibType, MachineChoice, MesonBugException, MesonException, OrderedSet, PerMachine, ProgressBar, quote_arg ) -from ..mesonlib import get_compiler_for_source, has_path_sep +from ..mesonlib import get_compiler_for_source, has_path_sep, is_parent_path from ..options import OptionKey from .backends import CleanTrees from ..build import GeneratedList, InvalidArguments @@ -1713,7 +1713,7 @@ class NinjaBackend(backends.Backend): # Check if the vala file is in a subdir of --basedir abs_srcbasedir = os.path.join(self.environment.get_source_dir(), target.get_subdir()) abs_vala_file = os.path.join(self.environment.get_build_dir(), vala_file) - if PurePath(os.path.commonpath((abs_srcbasedir, abs_vala_file))) == PurePath(abs_srcbasedir): + if is_parent_path(abs_srcbasedir, abs_vala_file): vala_c_subdir = PurePath(abs_vala_file).parent.relative_to(abs_srcbasedir) vala_c_file = os.path.join(str(vala_c_subdir), vala_c_file) else: diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 9f3af9f..6463c6f 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -24,7 +24,7 @@ from .mesonlib import ( File, MesonException, MachineChoice, PerMachine, OrderedSet, listify, extract_as_list, typeslistify, stringlistify, classify_unity_sources, get_filenames_templates_dict, substitute_values, has_path_sep, - PerMachineDefaultable, + is_parent_path, PerMachineDefaultable, MesonBugException, EnvironmentVariables, pickle_load, lazy_property, ) from .options import OptionKey @@ -1824,14 +1824,6 @@ class Generator(HoldableObject): basename = os.path.splitext(plainname)[0] return [x.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname) for x in self.arglist] - @staticmethod - def is_parent_path(parent: str, trial: str) -> bool: - try: - common = os.path.commonpath((parent, trial)) - except ValueError: # Windows on different drives - return False - return pathlib.PurePath(common) == pathlib.PurePath(parent) - def process_files(self, files: T.Iterable[T.Union[str, File, 'CustomTarget', 'CustomTargetIndex', 'GeneratedList']], state: T.Union['Interpreter', 'ModuleState'], preserve_path_from: T.Optional[str] = None, @@ -1861,7 +1853,7 @@ class Generator(HoldableObject): for f in fs: if preserve_path_from: abs_f = f.absolute_path(state.environment.source_dir, state.environment.build_dir) - if not self.is_parent_path(preserve_path_from, abs_f): + if not is_parent_path(preserve_path_from, abs_f): raise InvalidArguments('generator.process: When using preserve_path_from, all input files must be in a subdirectory of the given dir.') f = FileMaybeInTargetPrivateDir(f) output.add_file(f, state) diff --git a/mesonbuild/scripts/gtkdochelper.py b/mesonbuild/scripts/gtkdochelper.py index 0684428..a0b0905 100644 --- a/mesonbuild/scripts/gtkdochelper.py +++ b/mesonbuild/scripts/gtkdochelper.py @@ -7,7 +7,10 @@ import sys, os import subprocess import shutil import argparse -from ..mesonlib import MesonException, Popen_safe, is_windows, is_cygwin, split_args +from ..mesonlib import ( + MesonException, Popen_safe, is_windows, is_cygwin, is_parent_path, + split_args, +) from . import destdir_join import typing as T @@ -112,7 +115,7 @@ def build_gtkdoc(source_root: str, build_root: str, doc_subdir: str, src_subdirs # FIXME: Use mesonlib.File objects so we don't need to do this if not os.path.isabs(f): f = os.path.join(doc_src, f) - elif os.path.commonpath([f, build_root]) == build_root: + elif is_parent_path(build_root, f): continue shutil.copyfile(f, os.path.join(abs_out, os.path.basename(f))) diff --git a/mesonbuild/utils/universal.py b/mesonbuild/utils/universal.py index 45c0b7c..3481aaa 100644 --- a/mesonbuild/utils/universal.py +++ b/mesonbuild/utils/universal.py @@ -124,6 +124,7 @@ __all__ = [ 'is_netbsd', 'is_openbsd', 'is_osx', + 'is_parent_path', 'is_qnx', 'is_sunos', 'is_windows', @@ -1113,6 +1114,26 @@ def determine_worker_count(varnames: T.Optional[T.List[str]] = None) -> int: num_workers = 1 return num_workers +def is_parent_path(parent: str, trial: str) -> bool: + '''Checks if @trial is a file under the directory @parent. Both @trial and @parent should be + adequately normalized, though empty and '.' segments in @parent and @trial are accepted + and discarded, matching the behavior of os.path.commonpath. Either both or none should + be absolute.''' + assert os.path.isabs(parent) == os.path.isabs(trial) + if is_windows(): + parent = parent.replace('\\', '/') + trial = trial.replace('\\', '/') + + split_parent = parent.split('/') + split_trial = trial.split('/') + + split_parent = [c for c in split_parent if c and c != '.'] + split_trial = [c for c in split_trial if c and c != '.'] + + components = len(split_parent) + return len(split_trial) >= components and split_trial[:components] == split_parent + + def has_path_sep(name: str, sep: str = '/\\') -> bool: 'Checks if any of the specified @sep path separators are in @name' for each in sep: |