diff options
author | Tristan Partin <tristan@partin.io> | 2023-08-07 12:30:15 -0500 |
---|---|---|
committer | Xavier Claessens <xclaesse@gmail.com> | 2023-08-17 17:05:49 -0400 |
commit | f52bcaa27fc125ab9ae583af466ba99c164169f3 (patch) | |
tree | 34ecddd4e69581075035f405ff1fddcada6f252f | |
parent | cbf8e67f19e384e5f8eb7f65d3020551769de545 (diff) | |
download | meson-f52bcaa27fc125ab9ae583af466ba99c164169f3.zip meson-f52bcaa27fc125ab9ae583af466ba99c164169f3.tar.gz meson-f52bcaa27fc125ab9ae583af466ba99c164169f3.tar.bz2 |
Add fs.relative_to()
Returns a relative path from arg 2 to arg 1 similar to
os.path.relpath().
-rw-r--r-- | docs/markdown/Fs-module.md | 14 | ||||
-rw-r--r-- | docs/markdown/snippets/fs_relative_to.md | 17 | ||||
-rw-r--r-- | mesonbuild/modules/fs.py | 23 | ||||
-rw-r--r-- | test cases/common/220 fs module/meson.build | 25 | ||||
-rw-r--r-- | test cases/common/220 fs module/subdir/btgt.c | 5 | ||||
-rw-r--r-- | test cases/common/220 fs module/subdir/meson.build | 50 |
6 files changed, 132 insertions, 2 deletions
diff --git a/docs/markdown/Fs-module.md b/docs/markdown/Fs-module.md index cc67355..bf9ddba 100644 --- a/docs/markdown/Fs-module.md +++ b/docs/markdown/Fs-module.md @@ -224,6 +224,20 @@ fs.stem('foo/bar/baz.dll.a') # baz.dll project. If the file specified by `path` is a `files()` object it cannot refer to a built file. +### relative_to + +*Since 1.3.0* + +Return a relative filepath. In event a relative path could not be found, the +absolute path of `to` is returned. Relative path arguments will be assumed to be +relative to `meson.current_source_dir()`. + +Has the following positional arguments: + - to `str | file | custom_tgt | custom_idx | tgt`: end path + - from `str | file | custom_tgt | custom_idx | tgt`: start path + +returns: + - a string ### copyfile diff --git a/docs/markdown/snippets/fs_relative_to.md b/docs/markdown/snippets/fs_relative_to.md new file mode 100644 index 0000000..82e6a42 --- /dev/null +++ b/docs/markdown/snippets/fs_relative_to.md @@ -0,0 +1,17 @@ +## `fs.relative_to()` + +The `fs` module now has a `relative_to` method. The method will return the +relative path from argument one to argument two, if one exists. Otherwise, the +absolute path to argument one is returned. + +```meson +assert(fs.relative_to('c:\\prefix\\lib', 'c:\\prefix\\bin') == '..\\lib') +assert(fs.relative_to('c:\\proj1\\foo', 'd:\\proj1\\bar') == 'c:\\proj1\\foo') +assert(fs.relative_to('prefix\\lib\\foo', 'prefix') == 'lib\\foo') + +assert(fs.relative_to('/prefix/lib', '/prefix/bin') == '../lib') +assert(fs.relative_to('prefix/lib/foo', 'prefix') == 'lib/foo') +``` + +In addition to strings, it can handle files, custom targets, custom target +indices, and build targets. diff --git a/mesonbuild/modules/fs.py b/mesonbuild/modules/fs.py index 53174d2..a2dbdf2 100644 --- a/mesonbuild/modules/fs.py +++ b/mesonbuild/modules/fs.py @@ -20,18 +20,21 @@ import typing as T from . import ExtensionModule, ModuleReturnValue, ModuleInfo from .. import mlog -from ..build import CustomTarget, InvalidArguments +from ..build import BuildTarget, CustomTarget, CustomTargetIndex, InvalidArguments from ..interpreter.type_checking import INSTALL_KW, INSTALL_MODE_KW, INSTALL_TAG_KW, NoneType from ..interpreterbase import FeatureNew, KwargInfo, typed_kwargs, typed_pos_args, noKwargs +from ..interpreterbase.baseobjects import TYPE_kwargs from ..mesonlib import ( File, MesonException, has_path_sep, path_is_in_root, ) +from ..utils.universal import relpath if T.TYPE_CHECKING: from . import ModuleState + from ..build import BuildTargetTypes from ..interpreter import Interpreter from ..mesonlib import FileOrString, FileMode @@ -75,6 +78,7 @@ class FSModule(ExtensionModule): 'stem': self.stem, 'read': self.read, 'copyfile': self.copyfile, + 'relative_to': self.relative_to, }) def _absolute_dir(self, state: 'ModuleState', arg: 'FileOrString') -> Path: @@ -312,6 +316,23 @@ class FSModule(ExtensionModule): return ModuleReturnValue(ct, [ct]) + @FeatureNew('fs.relative_to', '1.3.0') + @typed_pos_args('fs.relative_to', (str, File, CustomTarget, CustomTargetIndex, BuildTarget), (str, File, CustomTarget, CustomTargetIndex, BuildTarget)) + @noKwargs + def relative_to(self, state: ModuleState, args: T.Tuple[T.Union[FileOrString, BuildTargetTypes], T.Union[FileOrString, BuildTargetTypes]], kwargs: TYPE_kwargs) -> str: + def to_path(arg: T.Union[FileOrString, CustomTarget, CustomTargetIndex, BuildTarget]) -> str: + if isinstance(arg, File): + return arg.absolute_path(state.environment.source_dir, state.environment.build_dir) + elif isinstance(arg, (CustomTarget, CustomTargetIndex, BuildTarget)): + return state.backend.get_target_filename_abs(arg) + else: + return os.path.join(state.environment.source_dir, state.subdir, arg) + + t = to_path(args[0]) + f = to_path(args[1]) + + return relpath(t, f) + def initialize(*args: T.Any, **kwargs: T.Any) -> FSModule: return FSModule(*args, **kwargs) diff --git a/test cases/common/220 fs module/meson.build b/test cases/common/220 fs module/meson.build index b860fc8..7f113d6 100644 --- a/test cases/common/220 fs module/meson.build +++ b/test cases/common/220 fs module/meson.build @@ -1,4 +1,4 @@ -project('fs module test') +project('fs module test', 'c') is_windows = build_machine.system() == 'windows' @@ -139,6 +139,29 @@ assert(fs.name('foo/bar/baz.dll.a') == 'baz.dll.a', 'failed to get basename with assert(fs.stem('foo/bar/baz.dll') == 'baz', 'failed to get stem with suffix') assert(fs.stem('foo/bar/baz.dll.a') == 'baz.dll', 'failed to get stem with compound suffix') +# relative_to +if build_machine.system() == 'windows' + # strings + assert(fs.relative_to('c:\\prefix\\lib\\foo', 'c:\\prefix') == 'lib\\foo') + assert(fs.relative_to('c:\\prefix\\lib', 'c:\\prefix\\bin') == '..\\lib') + assert(fs.relative_to('c:\\proj1\\foo', 'd:\\proj1\\bar') == 'c:\\proj1\\foo') + assert(fs.relative_to('prefix\\lib\\foo', 'prefix') == 'lib\\foo') + assert(fs.relative_to('prefix\\lib', 'prefix\\bin') == '..\\lib') + assert(fs.relative_to('proj1\\foo', 'proj1\\bar') == '..\\foo') + assert(fs.relative_to('subdir/subdirfile.txt', meson.current_source_dir()) == 'subdir\\subdirfile.txt') + assert(fs.relative_to(files('meson.build'), files('subdir/meson.build')) == '..\\..\\meson.build') + assert(fs.relative_to(files('meson.build'), 'subdir/meson.build') == '..\\..\\meson.build') +else + # strings + assert(fs.relative_to('/prefix/lib/foo', '/prefix') == 'lib/foo') + assert(fs.relative_to('/prefix/lib', '/prefix/bin') == '../lib') + assert(fs.relative_to('prefix/lib/foo', 'prefix') == 'lib/foo') + assert(fs.relative_to('prefix/lib', 'prefix/bin') == '../lib') + assert(fs.relative_to('subdir/subdirfile.txt', meson.current_source_dir()) == 'subdir/subdirfile.txt') + assert(fs.relative_to(files('meson.build'), files('subdir/meson.build')) == '../../meson.build') + assert(fs.relative_to(files('meson.build'), 'subdir/meson.build') == '../../meson.build') +endif + subdir('subdir') subproject('subbie') diff --git a/test cases/common/220 fs module/subdir/btgt.c b/test cases/common/220 fs module/subdir/btgt.c new file mode 100644 index 0000000..8479e67 --- /dev/null +++ b/test cases/common/220 fs module/subdir/btgt.c @@ -0,0 +1,5 @@ +int +main(void) +{ + return 0; +} diff --git a/test cases/common/220 fs module/subdir/meson.build b/test cases/common/220 fs module/subdir/meson.build index 0cd2475..3ea902c 100644 --- a/test cases/common/220 fs module/subdir/meson.build +++ b/test cases/common/220 fs module/subdir/meson.build @@ -4,3 +4,53 @@ assert(fs.is_samepath(meson.project_source_root(), '..'), 'is_samepath not detec assert(fs.is_samepath(meson.project_build_root(), meson.current_build_dir() / '..'), 'is_samepath not detecting same directory') assert(fs.is_samepath(subdirfiles[0], 'subdirfile.txt'), 'is_samepath not detecting same directory when using File and str') + +# More relative_to to test subdir/builddir components + +python3 = find_program('python3') +build_to_src = fs.relative_to(meson.current_source_dir(), meson.current_build_dir()) +src_to_build = fs.relative_to(meson.current_build_dir(), meson.current_source_dir()) + +btgt = executable('btgt', 'btgt.c') +ctgt = custom_target( + 'copied-files', + command: [ + python3, + '-c', + 'import shutil; shutil.copyfile("@INPUT0@", "@OUTPUT0@"); shutil.copyfile("@INPUT1@", "@OUTPUT1@")' + ], + input: [ + 'subdirfile.txt', + 'meson.build', + ], + output: [ + 'subdirfile.txt', + 'meson.build', + ], +) + +if build_machine.system() == 'windows' + # Test that CustomTarget works + assert(fs.relative_to('subdirfile.txt', ctgt) == '..\\@0@\\subdirfile.txt'.format(build_to_src)) + assert(fs.relative_to(ctgt, 'subdirfile.txt') == '..\\@0@\\subdirfile.txt'.format(src_to_build)) + # Test that CustomTargetIndex works + assert(fs.relative_to('meson.build', ctgt[1]) == '..\\@0@\\meson.build'.format(build_to_src)) + assert(fs.relative_to(ctgt[1], 'meson.build') == '..\\@0@\\meson.build'.format(src_to_build)) + # Test that BuildTarget works + assert(fs.relative_to('subdirfile.txt', btgt) == '..\\@0@\\subdirfile.txt'.format(build_to_src)) + assert(fs.relative_to(btgt, 'subdirfile.txt') == '..\\@0@\\btgt.exe'.format(src_to_build)) +else + # Test that CustomTarget works + assert(fs.relative_to('subdirfile.txt', ctgt) == '../@0@/subdirfile.txt'.format(build_to_src)) + assert(fs.relative_to(ctgt, 'subdirfile.txt') == '../@0@/subdirfile.txt'.format(src_to_build)) + # Test that CustomTargetIndex works + assert(fs.relative_to('meson.build', ctgt[1]) == '../@0@/meson.build'.format(build_to_src)) + assert(fs.relative_to(ctgt[1], 'meson.build') == '../@0@/meson.build'.format(src_to_build)) + # Test that BuildTarget works + assert(fs.relative_to('subdirfile.txt', btgt) == '../@0@/subdirfile.txt'.format(build_to_src)) + if host_machine.system() == 'windows' + assert(fs.relative_to(btgt, 'subdirfile.txt') == '../@0@/btgt.exe'.format(src_to_build)) + else + assert(fs.relative_to(btgt, 'subdirfile.txt') == '../@0@/btgt'.format(src_to_build)) + endif +endif |