diff options
-rw-r--r-- | mesonbuild/wrap/wrap.py | 52 | ||||
-rwxr-xr-x | run_unittests.py | 48 |
2 files changed, 87 insertions, 13 deletions
diff --git a/mesonbuild/wrap/wrap.py b/mesonbuild/wrap/wrap.py index ef35c6d..a4e0b25 100644 --- a/mesonbuild/wrap/wrap.py +++ b/mesonbuild/wrap/wrap.py @@ -26,6 +26,7 @@ import subprocess import sys import configparser import typing as T +import textwrap from .._pathlib import Path from . import WrapMode @@ -90,9 +91,8 @@ class WrapNotFoundException(WrapException): pass class PackageDefinition: - def __init__(self, fname: str, filesdir: str = None): + def __init__(self, fname: str): self.filename = fname - self.filesdir = filesdir self.type = None # type: T.Optional[str] self.values = {} # type: T.Dict[str, str] self.provided_deps = {} # type: T.Dict[str, T.Optional[str]] @@ -103,20 +103,42 @@ class PackageDefinition: self.directory = self.name self.provided_deps[self.name] = None if self.has_wrap: - self.parse_wrap(fname) + self.parse_wrap() self.directory = self.values.get('directory', self.name) if os.path.dirname(self.directory): raise WrapException('Directory key must be a name and not a path') if self.type and self.type not in ALL_TYPES: raise WrapException('Unknown wrap type {!r}'.format(self.type)) + self.filesdir = os.path.join(os.path.dirname(self.filename), 'packagefiles') - def parse_wrap(self, fname: str) -> None: + def parse_wrap(self) -> None: try: self.config = configparser.ConfigParser(interpolation=None) - self.config.read(fname) + self.config.read(self.filename) except configparser.Error: raise WrapException('Failed to parse {}'.format(self.basename)) self.parse_wrap_section() + if self.type == 'redirect': + # [wrap-redirect] have a `filename` value pointing to the real wrap + # file we should parse instead. It must be relative to the current + # wrap file location and must be in the form foo/subprojects/bar.wrap. + dirname = Path(self.filename).parent + fname = Path(self.values['filename']) + for i, p in enumerate(fname.parts): + if i % 2 == 0: + if p == '..': + raise WrapException('wrap-redirect filename cannot contain ".."') + else: + if p != 'subprojects': + raise WrapException('wrap-redirect filename must be in the form foo/subprojects/bar.wrap') + if fname.suffix != '.wrap': + raise WrapException('wrap-redirect filename must be a .wrap file') + fname = dirname / fname + if not fname.is_file(): + raise WrapException('wrap-redirect filename does not exist') + self.filename = str(fname) + self.parse_wrap() + return self.parse_provide_section() def parse_wrap_section(self) -> None: @@ -171,7 +193,6 @@ class Resolver: self.wrap_mode = wrap_mode self.subdir_root = os.path.join(source_dir, subdir) self.cachedir = os.path.join(self.subdir_root, 'packagecache') - self.filesdir = os.path.join(self.subdir_root, 'packagefiles') self.wraps = {} # type: T.Dict[str, PackageDefinition] self.provided_deps = {} # type: T.Dict[str, PackageDefinition] self.provided_programs = {} # type: T.Dict[str, PackageDefinition] @@ -185,7 +206,7 @@ class Resolver: if not i.endswith('.wrap'): continue fname = os.path.join(self.subdir_root, i) - wrap = PackageDefinition(fname, self.filesdir) + wrap = PackageDefinition(fname) self.wraps[wrap.name] = wrap if wrap.directory in dirs: dirs.remove(wrap.directory) @@ -194,7 +215,7 @@ class Resolver: if i in ['packagecache', 'packagefiles']: continue fname = os.path.join(self.subdir_root, i) - wrap = PackageDefinition(fname, self.filesdir) + wrap = PackageDefinition(fname) self.wraps[wrap.name] = wrap for wrap in self.wraps.values(): @@ -252,13 +273,18 @@ class Resolver: # project's subproject_dir even if the wrap file comes from another # subproject. self.dirname = os.path.join(self.subdir_root, self.directory) - # Copy .wrap file into main project's subproject_dir - wrap_dir = os.path.normpath(os.path.dirname(self.wrap.filename)) - main_dir = os.path.normpath(self.subdir_root) - if wrap_dir != main_dir: + # Check if the wrap comes from the main project. + main_fname = os.path.join(self.subdir_root, self.wrap.basename) + if self.wrap.filename != main_fname: rel = os.path.relpath(self.wrap.filename, self.source_dir) mlog.log('Using', mlog.bold(rel)) - shutil.copy2(self.wrap.filename, self.subdir_root) + # Write a dummy wrap file in main project that redirect to the + # wrap we picked. + with open(main_fname, 'w') as f: + f.write(textwrap.dedent('''\ + [wrap-redirect] + filename = {} + '''.format(os.path.relpath(self.wrap.filename, self.subdir_root)))) else: # No wrap file, it's a dummy package definition for an existing # directory. Use the source code in place. diff --git a/run_unittests.py b/run_unittests.py index cfab11b..f6adcee 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -69,6 +69,8 @@ import mesonbuild.modules.pkgconfig from mesonbuild.mtest import TAPParser, TestResult +from mesonbuild.wrap.wrap import PackageDefinition, WrapException + from run_tests import ( Backend, FakeBuild, FakeCompilerOptions, ensure_backend_detects_changes, exe_suffix, get_backend_commands, @@ -5166,6 +5168,52 @@ recommended as it is not supported on some platforms''') out = self.init(testdir) self.assertNotRegex(out, r'WARNING') + def test_wrap_redirect(self): + redirect_wrap = os.path.join(self.builddir, 'redirect.wrap') + real_wrap = os.path.join(self.builddir, 'foo/subprojects/real.wrap') + os.makedirs(os.path.dirname(real_wrap)) + + # Invalid redirect, filename must have .wrap extension + with open(redirect_wrap, 'w') as f: + f.write(textwrap.dedent(''' + [wrap-redirect] + filename = foo/subprojects/real.wrapper + ''')) + with self.assertRaisesRegex(WrapException, 'wrap-redirect filename must be a .wrap file'): + PackageDefinition(redirect_wrap) + + # Invalid redirect, filename cannot be in parent directory + with open(redirect_wrap, 'w') as f: + f.write(textwrap.dedent(''' + [wrap-redirect] + filename = ../real.wrap + ''')) + with self.assertRaisesRegex(WrapException, 'wrap-redirect filename cannot contain ".."'): + PackageDefinition(redirect_wrap) + + # Invalid redirect, filename must be in foo/subprojects/real.wrap + with open(redirect_wrap, 'w') as f: + f.write(textwrap.dedent(''' + [wrap-redirect] + filename = foo/real.wrap + ''')) + with self.assertRaisesRegex(WrapException, 'wrap-redirect filename must be in the form foo/subprojects/bar.wrap'): + wrap = PackageDefinition(redirect_wrap) + + # Correct redirect + with open(redirect_wrap, 'w') as f: + f.write(textwrap.dedent(''' + [wrap-redirect] + filename = foo/subprojects/real.wrap + ''')) + with open(real_wrap, 'w') as f: + f.write(textwrap.dedent(''' + [wrap-git] + url = http://invalid + ''')) + wrap = PackageDefinition(redirect_wrap) + self.assertEqual(wrap.get('url'), 'http://invalid') + class FailureTests(BasePlatformTests): ''' Tests that test failure conditions. Build files here should be dynamically |