Skip to content

Commit

Permalink
Bugfix: sanitize_dir: use pathlib to handle case-insensitive filesyst…
Browse files Browse the repository at this point in the history
…ems (#6398)
  • Loading branch information
scivision authored Jan 30, 2020
1 parent 1682058 commit 00f5dad
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 19 deletions.
31 changes: 20 additions & 11 deletions mesonbuild/coredata.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,30 +463,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 @@ -381,7 +381,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 @@ -547,6 +547,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 @@ -1783,7 +1783,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 @@ -1804,16 +1805,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 @@ -7310,14 +7320,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

0 comments on commit 00f5dad

Please sign in to comment.