Revert "Revert "Add fs.relative_to()""

This reverts commit 84c8905d52.

Fixed the cygwin failure...
pull/12138/head
Tristan Partin 1 year ago committed by Xavier Claessens
parent 22f90fd469
commit 946a3561c2
  1. 14
      docs/markdown/Fs-module.md
  2. 17
      docs/markdown/snippets/fs_relative_to.md
  3. 29
      mesonbuild/modules/fs.py
  4. 25
      test cases/common/220 fs module/meson.build
  5. 5
      test cases/common/220 fs module/subdir/btgt.c
  6. 30
      test cases/common/220 fs module/subdir/meson.build

@ -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 the 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 | build_tgt`: end path
- from `str | file | custom_tgt | custom_idx | build_tgt`: start path
returns:
- a string
### copyfile

@ -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.

@ -20,19 +20,16 @@ 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 ..mesonlib import (
File,
MesonException,
has_path_sep,
path_is_in_root,
)
from ..mesonlib import File, MesonException, has_path_sep, path_is_in_root, relpath
if T.TYPE_CHECKING:
from . import ModuleState
from ..build import BuildTargetTypes
from ..interpreter import Interpreter
from ..interpreterbase import TYPE_kwargs
from ..mesonlib import FileOrString, FileMode
from typing_extensions import TypedDict
@ -75,6 +72,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:
@ -313,6 +311,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)

@ -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')

@ -0,0 +1,5 @@
int
main(void)
{
return 0;
}

@ -4,3 +4,33 @@ 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
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 = fs.copyfile('subdirfile.txt')
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('subdirfile.txt', ctgt[0]) == '..\\@0@\\subdirfile.txt'.format(build_to_src))
assert(fs.relative_to(ctgt[0], 'subdirfile.txt') == '..\\@0@\\subdirfile.txt'.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@\\@1@'.format(src_to_build, fs.name(btgt.full_path())))
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('subdirfile.txt', ctgt[0]) == '../@0@/subdirfile.txt'.format(build_to_src))
assert(fs.relative_to(ctgt[0], 'subdirfile.txt') == '../@0@/subdirfile.txt'.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@/@1@'.format(src_to_build, fs.name(btgt.full_path())))
endif

Loading…
Cancel
Save