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

pull/6556/head
Michael Hirsch, Ph.D 5 years ago committed by GitHub
parent 1682058dec
commit 00f5dadd5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 31
      mesonbuild/coredata.py
  2. 6
      run_project_tests.py
  3. 15
      run_unittests.py
  4. 3
      test cases/common/105 testframework options/meson.build
  5. 4
      test cases/failing/38 libdir must be inside prefix/meson.build

@ -463,7 +463,7 @@ class CoreData:
prefix = prefix[:-1] prefix = prefix[:-1]
return prefix 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 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 absolute path, check that it resides within prefix and return the value
@ -471,22 +471,31 @@ class CoreData:
This way everyone can do f.ex, get_option('libdir') and be sure to get This way everyone can do f.ex, get_option('libdir') and be sure to get
the library directory relative to prefix. 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: option not in builtin_dir_noprefix_options:
# Value must be a subdir of the prefix # Value must be a subdir of the prefix
# commonpath will always return a path in the native format, so we # commonpath will always return a path in the native format, so we
# must use pathlib.PurePath to do the same conversion before # must use pathlib.PurePath to do the same conversion before
# comparing. # comparing.
if os.path.commonpath([value, prefix]) != str(PurePath(prefix)): msg = ('The value of the {!r} option is {!r} which must be a '
m = 'The value of the {!r} option is {!r} which must be a ' \ 'subdir of the prefix {!r}.\nNote that if you pass a '
'subdir of the prefix {!r}.\nNote that if you pass a ' \ 'relative path, it is assumed to be a subdir of prefix.')
'relative path, it is assumed to be a subdir of prefix.' # os.path.commonpath doesn't understand case-insensitive filesystems,
raise MesonException(m.format(option, value, prefix)) # but PurePath().relative_to() does.
# Convert path to be relative to prefix try:
skip = len(prefix) + 1 value = value.relative_to(prefix)
value = value[skip:] except ValueError:
return value 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): def init_builtins(self):
# Create builtin options with default values # Create builtin options with default values

@ -381,7 +381,7 @@ def _run_test(testdir, test_build_dir, install_dir, extra_args, compiler, backen
setup_env = None setup_env = None
# Configure in-process # Configure in-process
if pass_prefix_to_test(testdir): if pass_prefix_to_test(testdir):
gen_args = ['--prefix', '/usr'] gen_args = ['--prefix', 'x:/usr'] if mesonlib.is_windows() else ['--prefix', '/usr']
else: else:
gen_args = [] gen_args = []
if pass_libdir_to_test(testdir): if pass_libdir_to_test(testdir):
@ -547,6 +547,10 @@ def skippable(suite, test):
if not suite.endswith('frameworks'): if not suite.endswith('frameworks'):
return True 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 # gtk-doc test may be skipped, pending upstream fixes for spaces in
# filenames landing in the distro used for CI # filenames landing in the distro used for CI
if test.endswith('10 gtk-doc'): if test.endswith('10 gtk-doc'):

@ -1783,7 +1783,8 @@ class AllPlatformTests(BasePlatformTests):
https://github.com/mesonbuild/meson/issues/1345 https://github.com/mesonbuild/meson/issues/1345
''' '''
testdir = os.path.join(self.common_test_dir, '90 default options') 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' libdir = 'libdir'
extra_args = ['--prefix=' + prefix, extra_args = ['--prefix=' + prefix,
# This can just be a relative path, but we want to test # This can just be a relative path, but we want to test
@ -1804,15 +1805,24 @@ class AllPlatformTests(BasePlatformTests):
''' '''
testdir = os.path.join(self.common_test_dir, '1 trivial') testdir = os.path.join(self.common_test_dir, '1 trivial')
# libdir being inside prefix is ok # libdir being inside prefix is ok
if is_windows():
args = ['--prefix', 'x:/opt', '--libdir', 'x:/opt/lib32']
else:
args = ['--prefix', '/opt', '--libdir', '/opt/lib32'] args = ['--prefix', '/opt', '--libdir', '/opt/lib32']
self.init(testdir, extra_args=args) self.init(testdir, extra_args=args)
self.wipe() self.wipe()
# libdir not being inside prefix is not ok # libdir not being inside prefix is not ok
if is_windows():
args = ['--prefix', 'x:/usr', '--libdir', 'x:/opt/lib32']
else:
args = ['--prefix', '/usr', '--libdir', '/opt/lib32'] args = ['--prefix', '/usr', '--libdir', '/opt/lib32']
self.assertRaises(subprocess.CalledProcessError, self.init, testdir, extra_args=args) self.assertRaises(subprocess.CalledProcessError, self.init, testdir, extra_args=args)
self.wipe() self.wipe()
# libdir must be inside prefix even when set via mesonconf # libdir must be inside prefix even when set via mesonconf
self.init(testdir) self.init(testdir)
if is_windows():
self.assertRaises(subprocess.CalledProcessError, self.setconf, '-Dlibdir=x:/opt', False)
else:
self.assertRaises(subprocess.CalledProcessError, self.setconf, '-Dlibdir=/opt', False) self.assertRaises(subprocess.CalledProcessError, self.setconf, '-Dlibdir=/opt', False)
def test_prefix_dependent_defaults(self): def test_prefix_dependent_defaults(self):
@ -7310,14 +7320,11 @@ def main():
import pytest # noqa: F401 import pytest # noqa: F401
# Need pytest-xdist for `-n` arg # Need pytest-xdist for `-n` arg
import xdist # noqa: F401 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 = ['-n', 'auto', './run_unittests.py']
pytest_args += convert_args(sys.argv[1:]) pytest_args += convert_args(sys.argv[1:])
return subprocess.run(python_command + ['-m', 'pytest'] + pytest_args).returncode return subprocess.run(python_command + ['-m', 'pytest'] + pytest_args).returncode
except ImportError: except ImportError:
print('pytest-xdist not found, using unittest instead') print('pytest-xdist not found, using unittest instead')
pass
# All attempts at locating pytest failed, fall back to plain unittest. # All attempts at locating pytest failed, fall back to plain unittest.
cases = ['InternalTests', 'DataTests', 'AllPlatformTests', 'FailureTests', cases = ['InternalTests', 'DataTests', 'AllPlatformTests', 'FailureTests',
'PythonTests', 'NativeFileTests', 'RewriterTests', 'CrossFileTests', 'PythonTests', 'NativeFileTests', 'RewriterTests', 'CrossFileTests',

@ -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') project('options', 'c')
assert(get_option('testoption') == 'A string with spaces', 'Incorrect value for testoption option.') assert(get_option('testoption') == 'A string with spaces', 'Incorrect value for testoption option.')

@ -1,2 +1,6 @@
project('libdir prefix', 'c', project('libdir prefix', 'c',
default_options : ['libdir=/opt/lib']) 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
Loading…
Cancel
Save