|
|
- """Check a project and backend by attempting to build using PEP 517 hooks.
- """
- import argparse
- import logging
- import os
- from os.path import isfile, join as pjoin
- from pytoml import TomlError, load as toml_load
- import shutil
- from subprocess import CalledProcessError
- import sys
- import tarfile
- from tempfile import mkdtemp
- import zipfile
-
- from .colorlog import enable_colourful_output
- from .envbuild import BuildEnvironment
- from .wrappers import Pep517HookCaller
-
- log = logging.getLogger(__name__)
-
- def check_build_sdist(hooks):
- with BuildEnvironment() as env:
- try:
- env.pip_install(hooks.build_sys_requires)
- log.info('Installed static build dependencies')
- except CalledProcessError:
- log.error('Failed to install static build dependencies')
- return False
-
- try:
- reqs = hooks.get_requires_for_build_sdist({})
- log.info('Got build requires: %s', reqs)
- except:
- log.error('Failure in get_requires_for_build_sdist', exc_info=True)
- return False
-
- try:
- env.pip_install(reqs)
- log.info('Installed dynamic build dependencies')
- except CalledProcessError:
- log.error('Failed to install dynamic build dependencies')
- return False
-
- td = mkdtemp()
- log.info('Trying to build sdist in %s', td)
- try:
- try:
- filename = hooks.build_sdist(td, {})
- log.info('build_sdist returned %r', filename)
- except:
- log.info('Failure in build_sdist', exc_info=True)
- return False
-
- if not filename.endswith('.tar.gz'):
- log.error("Filename %s doesn't have .tar.gz extension", filename)
- return False
-
- path = pjoin(td, filename)
- if isfile(path):
- log.info("Output file %s exists", path)
- else:
- log.error("Output file %s does not exist", path)
- return False
-
- if tarfile.is_tarfile(path):
- log.info("Output file is a tar file")
- else:
- log.error("Output file is not a tar file")
- return False
-
- finally:
- shutil.rmtree(td)
-
- return True
-
- def check_build_wheel(hooks):
- with BuildEnvironment() as env:
- try:
- env.pip_install(hooks.build_sys_requires)
- log.info('Installed static build dependencies')
- except CalledProcessError:
- log.error('Failed to install static build dependencies')
- return False
-
- try:
- reqs = hooks.get_requires_for_build_wheel({})
- log.info('Got build requires: %s', reqs)
- except:
- log.error('Failure in get_requires_for_build_sdist', exc_info=True)
- return False
-
- try:
- env.pip_install(reqs)
- log.info('Installed dynamic build dependencies')
- except CalledProcessError:
- log.error('Failed to install dynamic build dependencies')
- return False
-
- td = mkdtemp()
- log.info('Trying to build wheel in %s', td)
- try:
- try:
- filename = hooks.build_wheel(td, {})
- log.info('build_wheel returned %r', filename)
- except:
- log.info('Failure in build_wheel', exc_info=True)
- return False
-
- if not filename.endswith('.whl'):
- log.error("Filename %s doesn't have .whl extension", filename)
- return False
-
- path = pjoin(td, filename)
- if isfile(path):
- log.info("Output file %s exists", path)
- else:
- log.error("Output file %s does not exist", path)
- return False
-
- if zipfile.is_zipfile(path):
- log.info("Output file is a zip file")
- else:
- log.error("Output file is not a zip file")
- return False
-
- finally:
- shutil.rmtree(td)
-
- return True
-
-
- def check(source_dir):
- pyproject = pjoin(source_dir, 'pyproject.toml')
- if isfile(pyproject):
- log.info('Found pyproject.toml')
- else:
- log.error('Missing pyproject.toml')
- return False
-
- try:
- with open(pyproject) as f:
- pyproject_data = toml_load(f)
- # Ensure the mandatory data can be loaded
- buildsys = pyproject_data['build-system']
- requires = buildsys['requires']
- backend = buildsys['build-backend']
- log.info('Loaded pyproject.toml')
- except (TomlError, KeyError):
- log.error("Invalid pyproject.toml", exc_info=True)
- return False
-
- hooks = Pep517HookCaller(source_dir, backend)
-
- sdist_ok = check_build_sdist(hooks)
- wheel_ok = check_build_wheel(hooks)
-
- if not sdist_ok:
- log.warning('Sdist checks failed; scroll up to see')
- if not wheel_ok:
- log.warning('Wheel checks failed')
-
- return sdist_ok
-
-
- def main(argv=None):
- ap = argparse.ArgumentParser()
- ap.add_argument('source_dir',
- help="A directory containing pyproject.toml")
- args = ap.parse_args(argv)
-
- enable_colourful_output()
-
- ok = check(args.source_dir)
-
- if ok:
- print(ansi('Checks passed', 'green'))
- else:
- print(ansi('Checks failed', 'red'))
- sys.exit(1)
-
- ansi_codes = {
- 'reset': '\x1b[0m',
- 'bold': '\x1b[1m',
- 'red': '\x1b[31m',
- 'green': '\x1b[32m',
- }
- def ansi(s, attr):
- if os.name != 'nt' and sys.stdout.isatty():
- return ansi_codes[attr] + str(s) + ansi_codes['reset']
- else:
- return str(s)
-
- if __name__ == '__main__':
- main()
|