From f1ac1505bdb3320057574e5bb77937b4b9e7b896 Mon Sep 17 00:00:00 2001 From: "Michael Hirsch, Ph.D" Date: Mon, 30 Dec 2019 23:11:39 -0500 Subject: [PATCH 1/6] sanitize_dir: use pathlib to handle case-insensitive filesystems fixes #6395 --- mesonbuild/coredata.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 140950de9f36..76ef9d82cc53 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -466,7 +466,7 @@ 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: PurePath) -> str: ''' 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 @@ -475,21 +475,25 @@ def sanitize_dir_option_value(self, prefix, option, value): This way everyone can do f.ex, get_option('libdir') and be sure to get the library directory relative to prefix. ''' - if option.endswith('dir') and os.path.isabs(value) and \ + value = PurePath(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 str(value) def init_builtins(self): # Create builtin options with default values From d31cbf6adb1b333b5c8bad0b1654e7ab83e354c0 Mon Sep 17 00:00:00 2001 From: "Michael Hirsch, Ph.D" Date: Tue, 31 Dec 2019 16:11:40 -0500 Subject: [PATCH 2/6] unittests: remove unreachable code --- run_unittests.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/run_unittests.py b/run_unittests.py index 669c8ffeaf1b..8d28a97700e5 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -7155,14 +7155,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', From 9fa7866666ade96b0ac8365bbf700b81c5b647f4 Mon Sep 17 00:00:00 2001 From: "Michael Hirsch, Ph.D" Date: Tue, 31 Dec 2019 16:29:37 -0500 Subject: [PATCH 3/6] use .as_posix() to keep Meson's posix-like path convention. update unit test since /someabs is NOT absolute path on Windows --- mesonbuild/coredata.py | 4 +++- run_unittests.py | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 76ef9d82cc53..1f7e66a09864 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -474,6 +474,8 @@ def sanitize_dir_option_value(self, prefix: str, option: str, value: PurePath) - 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. ''' value = PurePath(value) if option.endswith('dir') and value.is_absolute() and \ @@ -493,7 +495,7 @@ def sanitize_dir_option_value(self, prefix: str, option: str, value: PurePath) - raise MesonException(msg.format(option, value, prefix)) if '..' in str(value): raise MesonException(msg.format(option, value, prefix)) - return str(value) + return value.as_posix() def init_builtins(self): # Create builtin options with default values diff --git a/run_unittests.py b/run_unittests.py index 8d28a97700e5..f89cf83ee74b 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -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 From f2a4aae10b1f3af0c875a7068d9ffa9e068fbea0 Mon Sep 17 00:00:00 2001 From: "Michael Hirsch, Ph.D" Date: Tue, 31 Dec 2019 16:36:49 -0500 Subject: [PATCH 4/6] correct another unit test for windows abspath behavior --- run_unittests.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/run_unittests.py b/run_unittests.py index f89cf83ee74b..cc40bfc44771 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -1772,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): ''' From b1aa4dcb5f2d785f04996e9edb16362f9bff57c7 Mon Sep 17 00:00:00 2001 From: "Michael Hirsch, Ph.D" Date: Tue, 31 Dec 2019 17:20:16 -0500 Subject: [PATCH 5/6] accomodate non-path values --- mesonbuild/coredata.py | 5 ++++- test cases/common/105 testframework options/meson.build | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 1f7e66a09864..8f1a6b6ce990 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -477,7 +477,10 @@ def sanitize_dir_option_value(self, prefix: str, option: str, value: PurePath) - .as_posix() keeps the posix-like file seperators Meson uses. ''' - value = PurePath(value) + 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 diff --git a/test cases/common/105 testframework options/meson.build b/test cases/common/105 testframework options/meson.build index 277373044990..827bae76aa30 100644 --- a/test cases/common/105 testframework options/meson.build +++ b/test cases/common/105 testframework options/meson.build @@ -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.') From c0b9381fe85ea7def383808e65074b7bcb002fc1 Mon Sep 17 00:00:00 2001 From: "Michael Hirsch, Ph.D" Date: Tue, 31 Dec 2019 22:44:39 -0500 Subject: [PATCH 6/6] more windows test skip --- mesonbuild/coredata.py | 2 +- run_project_tests.py | 6 +++++- .../failing/38 libdir must be inside prefix/meson.build | 4 ++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 8f1a6b6ce990..f69ce87c7e3b 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -466,7 +466,7 @@ def sanitize_prefix(self, prefix): prefix = prefix[:-1] return prefix - def sanitize_dir_option_value(self, prefix: str, option: str, value: PurePath) -> str: + 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 diff --git a/run_project_tests.py b/run_project_tests.py index 5f3c40a380f5..f86641706a41 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -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): @@ -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'): diff --git a/test cases/failing/38 libdir must be inside prefix/meson.build b/test cases/failing/38 libdir must be inside prefix/meson.build index 66272ea3fe01..4cce7f81c553 100644 --- a/test cases/failing/38 libdir must be inside prefix/meson.build +++ b/test cases/failing/38 libdir must be inside prefix/meson.build @@ -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 \ No newline at end of file