Run all tests on the full frozen build using the frozen launcher

Much more comprehensive test coverage at the cost of slightly increasing
the frozen build size.
This commit is contained in:
Kovid Goyal 2021-02-19 17:57:59 +05:30
parent e06d40cb31
commit c2a924a5ea
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
8 changed files with 51 additions and 79 deletions

View File

@ -4,6 +4,7 @@
import os
import re
import shlex
import shutil
import subprocess
import sys
@ -41,6 +42,7 @@ def run(*args, **extra_env):
if ismacos:
env['PKGCONFIG_EXE'] = os.path.join(PREFIX, 'bin', 'pkg-config')
cwd = env.pop('cwd', KITTY_DIR)
print(' '.join(map(shlex.quote, args)), flush=True)
return subprocess.call(list(args), env=env, cwd=cwd)
@ -55,72 +57,47 @@ def build_frozen_launcher(extra_include_dirs):
return build_frozen_launcher.writeable_src_dir
def check_build(kitty_exe):
def run_tests(kitty_exe):
with tempfile.TemporaryDirectory() as tdir:
env = {
'KITTY_CONFIG_DIRECTORY': os.path.join(tdir, 'conf'),
'KITTY_CACHE_DIRECTORY': os.path.join(tdir, 'cache')
}
[os.mkdir(x) for x in env.values()]
if subprocess.call([kitty_exe, '+runpy', 'from kitty.check_build import main; main()'], env=env) != 0:
if subprocess.call([kitty_exe, '+runpy', 'from kitty_tests.main import run_tests; run_tests()'], env=env) != 0:
print('Checking of kitty build failed', file=sys.stderr)
os.chdir(os.path.dirname(kitty_exe))
run_shell()
raise SystemExit('Checking of kitty build failed')
def sanitize_source_folder(path: str) -> None:
for q in walk(path):
if os.path.splitext(q)[1] not in ('.py', '.glsl', '.ttf', '.otf'):
os.unlink(q)
def build_c_extensions(ext_dir, args):
writeable_src_dir = os.path.join(ext_dir, 'src')
build_frozen_launcher.writeable_src_dir = writeable_src_dir
shutil.copytree(
KITTY_DIR, writeable_src_dir, symlinks=True,
ignore=shutil.ignore_patterns('b', 'build', 'dist', '*_commands.json', '*.o'))
ignore=shutil.ignore_patterns('b', 'build', 'dist', '*_commands.json', '*.o', '*.so', '*.dylib', '*.pyd'))
# Build the launcher as it is needed for the spawn test
with suppress(FileNotFoundError):
os.remove(os.path.join(writeable_src_dir, 'kitty', 'launcher', 'kitty'))
if run(PYTHON, 'setup.py', 'build-launcher', cwd=writeable_src_dir) != 0:
print('Building of kitty launcher failed', file=sys.stderr)
os.chdir(KITTY_DIR)
run_shell()
raise SystemExit('Building of kitty launcher failed')
os.unlink(os.path.join(writeable_src_dir, 'kitty', 'launcher', 'kitty'))
for x in walk(writeable_src_dir):
if x.rpartition('.') in ('o', 'so', 'dylib', 'pyd'):
os.unlink(x)
cmd = [PYTHON, 'setup.py']
if run(*cmd, cwd=writeable_src_dir) != 0:
print('Building of kitty failed', file=sys.stderr)
os.chdir(KITTY_DIR)
run_shell()
raise SystemExit('Building of kitty package failed')
bundle = 'macos-freeze' if ismacos else 'linux-freeze'
cmd.append(bundle)
cmd = [PYTHON, 'setup.py', 'macos-freeze' if ismacos else 'linux-freeze']
dest = kitty_constants['appname'] + ('.app' if ismacos else '')
dest = build_frozen_launcher.prefix = os.path.join(ext_dir, dest)
cmd += ['--prefix', dest]
cmd += ['--prefix', dest, '--full']
if run(*cmd, cwd=writeable_src_dir) != 0:
print('Building of kitty package failed', file=sys.stderr)
os.chdir(KITTY_DIR)
os.chdir(writeable_src_dir)
run_shell()
raise SystemExit('Building of kitty package failed')
return ext_dir
def run_tests(path_to_kitty, cwd_on_failure):
kw = {'cwd': cwd_on_failure}
if not ismacos:
# this is needed for the spawn test which starts an interpreter
# using the kitty launcher.
kw['PYTHONHOME'] = PREFIX
ret = run(PYTHON, 'test.py', **kw)
if ret != 0:
os.chdir(cwd_on_failure)
print(
'running kitty tests failed with return code:', ret, file=sys.stderr)
run_shell()
raise SystemExit('running kitty tests failed')
if __name__ == 'program':
kitty_constants = initialize_constants()

View File

@ -8,7 +8,6 @@ import shutil
import stat
import subprocess
import tarfile
import tempfile
import time
from bypy.constants import (
@ -107,10 +106,11 @@ def copy_python(env):
srcdir = j(srcdir, 'site-packages')
site_packages_dir = j(env.py_dir, 'site-packages')
import_site_packages(srcdir, site_packages_dir)
pdir = os.path.join(env.lib_dir, 'kitty-extensions')
os.makedirs(pdir, exist_ok=True)
kitty_dir = os.path.join(env.base, 'lib', 'kitty')
bases = ('kitty', 'kittens')
kitty_dir = os.path.join(env.lib_dir, 'kitty')
bases = ('kitty', 'kittens', 'kitty_tests')
for x in bases:
dest = os.path.join(env.py_dir, x)
os.rename(os.path.join(kitty_dir, x), dest)
@ -122,9 +122,7 @@ def copy_python(env):
ext_map = extract_extension_modules(env.py_dir, pdir)
shutil.copy(os.path.join(os.path.dirname(self_dir), 'site.py'), os.path.join(env.py_dir, 'site.py'))
for x in bases:
for q in walk(os.path.join(env.py_dir, x)):
if os.path.splitext(q)[1] not in ('.py', '.glsl'):
os.unlink(q)
iv['sanitize_source_folder'](os.path.join(env.py_dir, x))
py_compile(env.py_dir)
freeze_python(env.py_dir, pdir, env.obj_dir, ext_map, develop_mode_env_var='KITTY_DEVELOP_FROM')
@ -214,14 +212,6 @@ def create_tarfile(env, compression_level='9'):
def main():
args = globals()['args']
ext_dir = globals()['ext_dir']
if not args.skip_tests:
run_tests = iv['run_tests']
with tempfile.TemporaryDirectory() as tdir:
os.environ['KITTY_CACHE_DIRECTORY'] = tdir
try:
run_tests(None, os.path.join(ext_dir, 'src'))
finally:
del os.environ['KITTY_CACHE_DIRECTORY']
env = Env(os.path.join(ext_dir, kitty_constants['appname']))
copy_libs(env)
copy_python(env)
@ -230,7 +220,8 @@ def main():
fix_permissions(files)
if not args.dont_strip:
strip_binaries(files)
iv['check_build'](os.path.join(env.base, 'bin', 'kitty'))
if not args.skip_tests:
iv['run_tests'](os.path.join(env.base, 'bin', 'kitty'))
create_tarfile(env, args.compression_level)

View File

@ -141,8 +141,9 @@ class Freeze(object):
FID = '@executable_path/../Frameworks'
def __init__(self, build_dir, dont_strip=False, sign_installers=False, notarize=False):
def __init__(self, build_dir, dont_strip=False, sign_installers=False, notarize=False, skip_tests=False):
self.build_dir = build_dir
self.skip_tests = skip_tests
self.sign_installers = sign_installers
self.notarize = notarize
self.dont_strip = dont_strip
@ -171,7 +172,8 @@ class Freeze(object):
self.freeze_python()
if not self.dont_strip:
self.strip_files()
self.check_build()
if not self.skip_tests:
self.run_tests()
# self.run_shell()
ret = self.makedmg(self.build_dir, APPNAME + '-' + VERSION)
@ -184,8 +186,8 @@ class Freeze(object):
strip_files(self.to_strip)
@flush
def check_build(self):
iv['check_build'](os.path.join(self.contents_dir, 'MacOS', 'kitty'))
def run_tests(self):
iv['run_tests'](os.path.join(self.contents_dir, 'MacOS', 'kitty'))
@flush
def set_id(self, path_to_lib, new_id):
@ -331,7 +333,7 @@ class Freeze(object):
def freeze_python(self):
print('\nFreezing python')
kitty_dir = join(self.resources_dir, 'kitty')
bases = ('kitty', 'kittens')
bases = ('kitty', 'kittens', 'kitty_tests')
for x in bases:
dest = os.path.join(self.python_stdlib, x)
os.rename(os.path.join(kitty_dir, x), dest)
@ -345,9 +347,7 @@ class Freeze(object):
ext_map = extract_extension_modules(self.python_stdlib, pdir)
shutil.copy(os.path.join(os.path.dirname(self_dir), 'site.py'), os.path.join(self.python_stdlib, 'site.py'))
for x in bases:
for q in walk(os.path.join(self.python_stdlib, x)):
if os.path.splitext(q)[1] not in ('.py', '.glsl'):
os.unlink(q)
iv['sanitize_source_folder'](os.path.join(self.python_stdlib, x))
self.compile_py_modules()
freeze_python(self.python_stdlib, pdir, self.obj_dir, ext_map, develop_mode_env_var='KITTY_DEVELOP_FROM')
iv['build_frozen_launcher']([path_to_freeze_dir(), self.obj_dir])
@ -469,14 +469,12 @@ class Freeze(object):
def main():
args = globals()['args']
ext_dir = globals()['ext_dir']
if not args.skip_tests:
run_tests = iv['run_tests']
run_tests(None, os.path.join(ext_dir, 'src'))
Freeze(
os.path.join(ext_dir, kitty_constants['appname'] + '.app'),
dont_strip=args.dont_strip,
sign_installers=args.sign_installers,
notarize=args.notarize
notarize=args.notarize,
skip_tests=args.skip_tests
)

View File

@ -18,8 +18,14 @@ orig_executable = spawn.get_executable()
def spawnv_passfds(path: str, args: List[str], passfds: List[int]) -> Any:
idx = args.index('-c')
patched_args = [spawn.get_executable(), '+runpy'] + args[idx + 1:]
if '-c' in args:
idx = args.index('-c')
patched_args = [spawn.get_executable(), '+runpy'] + args[idx + 1:]
else:
idx = args.index('--multiprocessing-fork')
prog = 'from multiprocessing.spawn import spawn_main; spawn_main(%s)'
prog %= ', '.join(item for item in args[idx+1:])
patched_args = [spawn.get_executable(), '+runpy', prog]
return orig_spawn_passfds(kitty_exe(), patched_args, passfds)

View File

@ -89,7 +89,7 @@ class Rendering(BaseTest):
return font_path_cache[name]
def ss(text, font=None):
path = f'kitty_tests/{font}' if font else None
path = path_for_font(font) if font else None
return shape_string(text, path=path)
def groups(text, font=None):

View File

@ -23,12 +23,13 @@ def itertests(suite: unittest.TestSuite) -> Generator[unittest.TestCase, None, N
yield test
def find_all_tests(package: str = '', excludes: Sequence[str] = ('main.py', 'gr.py')) -> unittest.TestSuite:
def find_all_tests(package: str = '', excludes: Sequence[str] = ('main', 'gr')) -> unittest.TestSuite:
suits = []
if not package:
package = __name__.rpartition('.')[0] if '.' in __name__ else 'kitty_tests'
for x in contents(package):
if x.endswith('.py') and x not in excludes:
name, ext = os.path.splitext(x)
if ext in ('.py', '.pyc') and name not in excludes:
m = importlib.import_module(package + '.' + x.partition('.')[0])
suits.append(unittest.defaultTestLoader.loadTestsFromModule(m))
return unittest.TestSuite(suits)

View File

@ -66,7 +66,6 @@ class Options(argparse.Namespace):
prefix: str = './linux-package'
incremental: bool = True
profile: bool = False
for_freeze: bool = False
libdir_name: str = 'lib'
extra_logging: List[str] = []
extra_include_dirs: List[str] = []
@ -1026,6 +1025,7 @@ def create_macos_bundle_gunk(dest: str) -> None:
def package(args: Options, bundle_type: str) -> None:
ddir = args.prefix
for_freeze = bundle_type.endswith('-freeze')
if bundle_type == 'linux-freeze':
args.libdir_name = 'lib'
libdir = os.path.join(ddir, args.libdir_name.strip('/'), 'kitty')
@ -1033,7 +1033,9 @@ def package(args: Options, bundle_type: str) -> None:
shutil.rmtree(libdir)
launcher_dir = os.path.join(ddir, 'bin')
safe_makedirs(launcher_dir)
if not bundle_type.endswith('-freeze'): # freeze launcher is built separately
if for_freeze: # freeze launcher is built separately
args.compilation_database.build_all()
else:
build_launcher(args, launcher_dir, bundle_type)
os.makedirs(os.path.join(libdir, 'logo'))
build_terminfo = runpy.run_path('build-terminfo', run_name='import_build') # type: ignore
@ -1046,16 +1048,19 @@ def package(args: Options, bundle_type: str) -> None:
shutil.copy2('logo/kitty.png', os.path.join(libdir, 'logo'))
shutil.copy2('logo/beam-cursor.png', os.path.join(libdir, 'logo'))
shutil.copy2('logo/beam-cursor@2x.png', os.path.join(libdir, 'logo'))
allowed_extensions = frozenset('py glsl so'.split())
def src_ignore(parent: str, entries: Iterable[str]) -> List[str]:
return [
x for x in entries
if '.' in x and x.rpartition('.')[2] not in
('py', 'so', 'glsl')
allowed_extensions
]
shutil.copytree('kitty', os.path.join(libdir, 'kitty'), ignore=src_ignore)
shutil.copytree('kittens', os.path.join(libdir, 'kittens'), ignore=src_ignore)
if for_freeze:
shutil.copytree('kitty_tests', os.path.join(libdir, 'kitty_tests'))
if args.update_check_interval != 24.0:
with open(os.path.join(libdir, 'kitty/config_data.py'), 'r+', encoding='utf-8') as f:
raw = f.read()
@ -1150,12 +1155,6 @@ def option_parser() -> argparse.ArgumentParser: # {{{
action='store_true',
help='Use the -pg compile flag to add profiling information'
)
p.add_argument(
'--for-freeze',
default=Options.for_freeze,
action='store_true',
help='Internal use'
)
p.add_argument(
'--libdir-name',
default=Options.libdir_name,