mirror of
https://github.com/mesonbuild/meson.git
synced 2026-06-24 08:48:03 +00:00
This was generated with a regex search/replace in vscode using: `(open\(.*, 'w\+?')` -> `$1, encoding='utf-8')` This should silence a bunch of warnings, and seems to fix issues seen in the Windows CI. This seems to likely be to a "helpful feature" in msbuild that treats certain text in stdout/stderr as errors, which it sometimes decides that the warning about not having the encoding set triggers.
234 lines
9.9 KiB
Python
Executable File
234 lines
9.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
# Copyright 2018 The Meson development team
|
|
|
|
import os
|
|
import tempfile
|
|
import unittest
|
|
import subprocess
|
|
import zipapp
|
|
import sysconfig
|
|
from pathlib import Path
|
|
|
|
from mesonbuild.mesonlib import windows_proof_rmtree, python_command, is_windows
|
|
from mesonbuild.coredata import version as meson_version
|
|
|
|
scheme = None
|
|
|
|
def needs_debian_path_hack():
|
|
try:
|
|
import setuptools
|
|
return int(setuptools.__version__.split('.')[0]) < 65
|
|
except ModuleNotFoundError:
|
|
return False
|
|
|
|
if needs_debian_path_hack():
|
|
# Handle the scheme that Debian patches in the as default
|
|
# This function was renamed and made public in Python 3.10
|
|
if hasattr(sysconfig, 'get_default_scheme'):
|
|
scheme = sysconfig.get_default_scheme()
|
|
else:
|
|
scheme = sysconfig._get_default_scheme()
|
|
if scheme == 'posix_local':
|
|
scheme = 'posix_prefix'
|
|
|
|
def get_pypath():
|
|
if scheme:
|
|
pypath = sysconfig.get_path('purelib', scheme=scheme, vars={'base': ''})
|
|
else:
|
|
pypath = sysconfig.get_path('purelib', vars={'base': ''})
|
|
# Ensure that / is the path separator and not \, then strip /
|
|
return Path(pypath).as_posix().strip('/')
|
|
|
|
def get_pybindir():
|
|
# 'Scripts' on Windows and 'bin' on other platforms including MSYS
|
|
if scheme:
|
|
return sysconfig.get_path('scripts', scheme=scheme, vars={'base': ''}).strip('\\/')
|
|
return sysconfig.get_path('scripts', vars={'base': ''}).strip('\\/')
|
|
|
|
def has_python_module(module: str) -> bool:
|
|
result = subprocess.run(python_command + ['-c', f'import {module}'])
|
|
return result.returncode == 0
|
|
|
|
|
|
class CommandTests(unittest.TestCase):
|
|
'''
|
|
Test that running meson in various ways works as expected by checking the
|
|
value of mesonlib.meson_command that was set during configuration.
|
|
'''
|
|
|
|
def setUp(self):
|
|
super().setUp()
|
|
self.orig_env = os.environ.copy()
|
|
self.orig_dir = os.getcwd()
|
|
os.environ['MESON_COMMAND_TESTS'] = '1'
|
|
self.tmpdir = Path(tempfile.mkdtemp()).resolve()
|
|
self.src_root = Path(__file__).resolve().parent
|
|
self.testdir = str(self.src_root / 'test cases/common/1 trivial')
|
|
self.meson_args = ['--backend=ninja']
|
|
|
|
def tearDown(self):
|
|
try:
|
|
windows_proof_rmtree(str(self.tmpdir))
|
|
except FileNotFoundError:
|
|
pass
|
|
os.environ.clear()
|
|
os.environ.update(self.orig_env)
|
|
os.chdir(str(self.orig_dir))
|
|
super().tearDown()
|
|
|
|
def _run(self, command, workdir=None, env=None):
|
|
'''
|
|
Run a command while printing the stdout, and also return a copy of it
|
|
'''
|
|
# If this call hangs CI will just abort. It is very hard to distinguish
|
|
# between CI issue and test bug in that case. Set timeout and fail loud
|
|
# instead.
|
|
p = subprocess.run(command,
|
|
stdout=subprocess.PIPE,
|
|
env=env,
|
|
encoding='utf-8',
|
|
text=True,
|
|
cwd=workdir,
|
|
timeout=60 * 5)
|
|
print(p.stdout)
|
|
if p.returncode != 0:
|
|
raise subprocess.CalledProcessError(p.returncode, command)
|
|
return p.stdout
|
|
|
|
def assertMesonCommandIs(self, line, cmd):
|
|
self.assertTrue(line.startswith('meson_command '), msg=line)
|
|
self.assertEqual(line, f'meson_command is {cmd!r}')
|
|
|
|
def test_meson_uninstalled(self):
|
|
# This is what the meson command must be for all these cases
|
|
resolved_meson_command = python_command + [str(self.src_root / 'meson.py')]
|
|
# Absolute path to meson.py
|
|
os.chdir('/')
|
|
builddir = str(self.tmpdir / 'build1')
|
|
meson_py = str(self.src_root / 'meson.py')
|
|
meson_setup = [meson_py, 'setup']
|
|
meson_command = python_command + meson_setup + self.meson_args
|
|
stdo = self._run(meson_command + [self.testdir, builddir])
|
|
self.assertMesonCommandIs(stdo.split('\n')[0], resolved_meson_command)
|
|
# ./meson.py
|
|
os.chdir(str(self.src_root))
|
|
builddir = str(self.tmpdir / 'build2')
|
|
meson_py = './meson.py'
|
|
meson_setup = [meson_py, 'setup']
|
|
meson_command = python_command + meson_setup + self.meson_args
|
|
stdo = self._run(meson_command + [self.testdir, builddir])
|
|
self.assertMesonCommandIs(stdo.split('\n')[0], resolved_meson_command)
|
|
# Symlink to meson.py
|
|
if is_windows():
|
|
# Symlinks require admin perms
|
|
return
|
|
os.chdir(str(self.src_root))
|
|
builddir = str(self.tmpdir / 'build3')
|
|
# Create a symlink to meson.py in bindir, and add it to PATH
|
|
bindir = (self.tmpdir / 'bin')
|
|
bindir.mkdir()
|
|
(bindir / 'meson').symlink_to(self.src_root / 'meson.py')
|
|
(bindir / 'python3').symlink_to(python_command[0])
|
|
os.environ['PATH'] = str(bindir) + os.pathsep + os.environ['PATH']
|
|
# use our overridden PATH-compatible python
|
|
path_resolved_meson_command = [str(bindir / 'meson')]
|
|
# See if it works!
|
|
meson_py = 'meson'
|
|
meson_setup = [meson_py, 'setup']
|
|
meson_command = meson_setup + self.meson_args
|
|
stdo = self._run(meson_command + [self.testdir, builddir])
|
|
self.assertMesonCommandIs(stdo.split('\n')[0], path_resolved_meson_command)
|
|
|
|
def test_meson_installed(self):
|
|
# Install meson
|
|
prefix = self.tmpdir / 'prefix'
|
|
pylibdir = prefix / get_pypath()
|
|
bindir = prefix / get_pybindir()
|
|
pylibdir.mkdir(parents=True)
|
|
# XXX: join with empty name so it always ends with os.sep otherwise
|
|
# distutils complains that prefix isn't contained in PYTHONPATH
|
|
os.environ['PYTHONPATH'] = os.path.join(str(pylibdir), '')
|
|
os.environ['PATH'] = str(bindir) + os.pathsep + os.environ['PATH']
|
|
if has_python_module('gpep517'):
|
|
self._run(python_command + ['-m', 'gpep517', 'install-from-source', '--destdir', '/', '--prefix', str(prefix)])
|
|
elif has_python_module('pip'):
|
|
self._run(python_command + ['-m', 'pip', 'install', '--prefix', str(prefix), '.'])
|
|
else:
|
|
# Legacy deprecated setuptools command used as fallback
|
|
self._run(python_command + ['setup.py', 'install', '--prefix', str(prefix)])
|
|
# Fix importlib-metadata by appending all dirs in pylibdir
|
|
PYTHONPATHS = [pylibdir] + [x for x in pylibdir.iterdir() if x.name.endswith('.egg')]
|
|
PYTHONPATHS = [os.path.join(str(x), '') for x in PYTHONPATHS]
|
|
os.environ['PYTHONPATH'] = os.pathsep.join(PYTHONPATHS)
|
|
# Check that all the files were installed correctly
|
|
self.assertTrue(bindir.is_dir())
|
|
self.assertTrue(pylibdir.is_dir())
|
|
# Run `meson`
|
|
os.chdir('/')
|
|
resolved_meson_command = [str(bindir / 'meson')]
|
|
builddir = str(self.tmpdir / 'build1')
|
|
meson_setup = ['meson', 'setup']
|
|
meson_command = meson_setup + self.meson_args
|
|
stdo = self._run(meson_command + [self.testdir, builddir])
|
|
self.assertMesonCommandIs(stdo.split('\n')[0], resolved_meson_command)
|
|
# Run `/path/to/meson`
|
|
builddir = str(self.tmpdir / 'build2')
|
|
meson_setup = [str(bindir / 'meson'), 'setup']
|
|
meson_command = meson_setup + self.meson_args
|
|
stdo = self._run(meson_command + [self.testdir, builddir])
|
|
self.assertMesonCommandIs(stdo.split('\n')[0], resolved_meson_command)
|
|
# Run `python3 -m mesonbuild.mesonmain`
|
|
resolved_meson_command = python_command + ['-m', 'mesonbuild.mesonmain']
|
|
builddir = str(self.tmpdir / 'build3')
|
|
meson_setup = ['-m', 'mesonbuild.mesonmain', 'setup']
|
|
meson_command = python_command + meson_setup + self.meson_args
|
|
stdo = self._run(meson_command + [self.testdir, builddir])
|
|
self.assertMesonCommandIs(stdo.split('\n')[0], resolved_meson_command)
|
|
if is_windows():
|
|
# Next part requires a shell
|
|
return
|
|
# `meson` is a wrapper to `meson.real`
|
|
resolved_meson_command = [str(bindir / 'meson.real')]
|
|
builddir = str(self.tmpdir / 'build4')
|
|
(bindir / 'meson').rename(bindir / 'meson.real')
|
|
wrapper = (bindir / 'meson')
|
|
wrapper.write_text('#!/bin/sh\n\nmeson.real "$@"', encoding='utf-8')
|
|
wrapper.chmod(0o755)
|
|
meson_setup = [str(wrapper), 'setup']
|
|
meson_command = meson_setup + self.meson_args
|
|
stdo = self._run(meson_command + [self.testdir, builddir])
|
|
self.assertMesonCommandIs(stdo.split('\n')[0], resolved_meson_command)
|
|
|
|
def test_meson_exe_windows(self):
|
|
raise unittest.SkipTest('NOT IMPLEMENTED')
|
|
|
|
def test_meson_zipapp(self):
|
|
if is_windows():
|
|
raise unittest.SkipTest('NOT IMPLEMENTED')
|
|
source = Path(__file__).resolve().parent
|
|
target = self.tmpdir / 'meson.pyz'
|
|
script = source / 'packaging' / 'create_zipapp.py'
|
|
self._run([script.as_posix(), source, '--outfile', target, '--interpreter', python_command[0]])
|
|
self._run([target.as_posix(), '--help'])
|
|
|
|
def test_meson_runpython(self):
|
|
meson_command = str(self.src_root / 'meson.py')
|
|
script_file = str(self.src_root / 'foo.py')
|
|
test_command = 'import sys; print(sys.argv[1])'
|
|
env = os.environ.copy()
|
|
del env['MESON_COMMAND_TESTS']
|
|
with open(script_file, 'w', encoding='utf-8') as f:
|
|
f.write('#!/usr/bin/env python3\n\n')
|
|
f.write(f'{test_command}\n')
|
|
self.addCleanup(os.remove, script_file)
|
|
|
|
for cmd in [['-c', test_command, 'fake argument'], [script_file, 'fake argument']]:
|
|
pyout = self._run(python_command + cmd)
|
|
mesonout = self._run(python_command + [meson_command, 'runpython'] + cmd, env=env)
|
|
self.assertEqual(pyout, mesonout)
|
|
|
|
if __name__ == '__main__':
|
|
print('Meson build system', meson_version, 'Command Tests')
|
|
raise SystemExit(unittest.main(buffer=True))
|