Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix: sanitize_dir: use pathlib to handle case-insensitive filesystems #6398

Merged
merged 6 commits into from
Jan 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 20 additions & 11 deletions mesonbuild/coredata.py
Original file line number Diff line number Diff line change
Expand Up @@ -466,30 +466,39 @@ def sanitize_prefix(self, prefix):
prefix = prefix[:-1]
return prefix

def sanitize_dir_option_value(self, prefix, option, value):
def sanitize_dir_option_value(self, prefix: str, option: str, value: Any) -> Any:
'''
If the option is an installation directory option and the value is an
absolute path, check that it resides within prefix and return the value
as a path relative to the prefix.

This way everyone can do f.ex, get_option('libdir') and be sure to get
the library directory relative to prefix.

.as_posix() keeps the posix-like file seperators Meson uses.
'''
if option.endswith('dir') and os.path.isabs(value) and \
try:
value = PurePath(value)
except TypeError:
return value
if option.endswith('dir') and value.is_absolute() and \
option not in builtin_dir_noprefix_options:
# Value must be a subdir of the prefix
# commonpath will always return a path in the native format, so we
# must use pathlib.PurePath to do the same conversion before
# comparing.
if os.path.commonpath([value, prefix]) != str(PurePath(prefix)):
m = 'The value of the {!r} option is {!r} which must be a ' \
'subdir of the prefix {!r}.\nNote that if you pass a ' \
'relative path, it is assumed to be a subdir of prefix.'
raise MesonException(m.format(option, value, prefix))
# Convert path to be relative to prefix
skip = len(prefix) + 1
value = value[skip:]
return value
msg = ('The value of the {!r} option is {!r} which must be a '
'subdir of the prefix {!r}.\nNote that if you pass a '
'relative path, it is assumed to be a subdir of prefix.')
# os.path.commonpath doesn't understand case-insensitive filesystems,
# but PurePath().relative_to() does.
try:
value = value.relative_to(prefix)
except ValueError:
raise MesonException(msg.format(option, value, prefix))
if '..' in str(value):
raise MesonException(msg.format(option, value, prefix))
return value.as_posix()

def init_builtins(self):
# Create builtin options with default values
Expand Down
6 changes: 5 additions & 1 deletion run_project_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ def _run_test(testdir, test_build_dir, install_dir, extra_args, compiler, backen
setup_env = None
# Configure in-process
if pass_prefix_to_test(testdir):
gen_args = ['--prefix', '/usr']
gen_args = ['--prefix', 'x:/usr'] if mesonlib.is_windows() else ['--prefix', '/usr']
else:
gen_args = []
if pass_libdir_to_test(testdir):
Expand Down Expand Up @@ -545,6 +545,10 @@ def skippable(suite, test):
if not suite.endswith('frameworks'):
return True

# this test assumptions aren't valid for Windows paths
if test.endswith('38 libdir must be inside prefix'):
return True

# gtk-doc test may be skipped, pending upstream fixes for spaces in
# filenames landing in the distro used for CI
if test.endswith('10 gtk-doc'):
Expand Down
21 changes: 14 additions & 7 deletions run_unittests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1750,7 +1750,8 @@ def test_absolute_prefix_libdir(self):
https://github.com/mesonbuild/meson/issues/1345
'''
testdir = os.path.join(self.common_test_dir, '90 default options')
prefix = '/someabs'
# on Windows, /someabs is *not* an absolute path
prefix = 'x:/someabs' if is_windows() else '/someabs'
libdir = 'libdir'
extra_args = ['--prefix=' + prefix,
# This can just be a relative path, but we want to test
Expand All @@ -1771,16 +1772,25 @@ def test_libdir_must_be_inside_prefix(self):
'''
testdir = os.path.join(self.common_test_dir, '1 trivial')
# libdir being inside prefix is ok
args = ['--prefix', '/opt', '--libdir', '/opt/lib32']
if is_windows():
args = ['--prefix', 'x:/opt', '--libdir', 'x:/opt/lib32']
else:
args = ['--prefix', '/opt', '--libdir', '/opt/lib32']
self.init(testdir, extra_args=args)
self.wipe()
# libdir not being inside prefix is not ok
args = ['--prefix', '/usr', '--libdir', '/opt/lib32']
if is_windows():
args = ['--prefix', 'x:/usr', '--libdir', 'x:/opt/lib32']
else:
args = ['--prefix', '/usr', '--libdir', '/opt/lib32']
self.assertRaises(subprocess.CalledProcessError, self.init, testdir, extra_args=args)
self.wipe()
# libdir must be inside prefix even when set via mesonconf
self.init(testdir)
self.assertRaises(subprocess.CalledProcessError, self.setconf, '-Dlibdir=/opt', False)
if is_windows():
self.assertRaises(subprocess.CalledProcessError, self.setconf, '-Dlibdir=x:/opt', False)
else:
self.assertRaises(subprocess.CalledProcessError, self.setconf, '-Dlibdir=/opt', False)

def test_prefix_dependent_defaults(self):
'''
Expand Down Expand Up @@ -7155,14 +7165,11 @@ def main():
import pytest # noqa: F401
# Need pytest-xdist for `-n` arg
import xdist # noqa: F401
if sys.version_info.major <= 3 and sys.version_info.minor <= 5:
raise ImportError('pytest with python <= 3.5 is causing issues on the CI')
pytest_args = ['-n', 'auto', './run_unittests.py']
pytest_args += convert_args(sys.argv[1:])
return subprocess.run(python_command + ['-m', 'pytest'] + pytest_args).returncode
except ImportError:
print('pytest-xdist not found, using unittest instead')
pass
# All attempts at locating pytest failed, fall back to plain unittest.
cases = ['InternalTests', 'DataTests', 'AllPlatformTests', 'FailureTests',
'PythonTests', 'NativeFileTests', 'RewriterTests', 'CrossFileTests',
Expand Down
3 changes: 3 additions & 0 deletions test cases/common/105 testframework options/meson.build
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# normally run only from run_tests.py or run_project_tests.py
# else do like
# meson build '-Dtestoption=A string with spaces' -Dother_one=true -Dcombo_opt=one -Dprefix=/usr -Dlibdir=lib -Dbackend=ninja -Dwerror=True
project('options', 'c')

assert(get_option('testoption') == 'A string with spaces', 'Incorrect value for testoption option.')
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
project('libdir prefix', 'c',
default_options : ['libdir=/opt/lib'])

if host_machine.system() == 'windows'
error('MESON_SKIP_TEST: this test does not work on Windows since /foo is not absolute')
endif