123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- """Check a project and backend by attempting to build using PEP 517 hooks.
- """
- import argparse
- import io
- import logging
- import os
- from os.path import isfile, join as pjoin
- import shutil
- from subprocess import CalledProcessError
- import sys
- import tarfile
- from tempfile import mkdtemp
- import zipfile
- from .colorlog import enable_colourful_output
- from .compat import TOMLDecodeError, toml_load
- from .envbuild import BuildEnvironment
- from .wrappers import Pep517HookCaller
- log = logging.getLogger(__name__)
- def check_build_sdist(hooks, build_sys_requires):
- with BuildEnvironment() as env:
- try:
- env.pip_install(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 Exception:
- 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 Exception:
- 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, build_sys_requires):
- with BuildEnvironment() as env:
- try:
- env.pip_install(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 Exception:
- 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 Exception:
- 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 io.open(pyproject, 'rb') 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']
- backend_path = buildsys.get('backend-path')
- log.info('Loaded pyproject.toml')
- except (TOMLDecodeError, KeyError):
- log.error("Invalid pyproject.toml", exc_info=True)
- return False
- hooks = Pep517HookCaller(source_dir, backend, backend_path)
- sdist_ok = check_build_sdist(hooks, requires)
- wheel_ok = check_build_wheel(hooks, requires)
- 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):
- log.warning('pep517.check is deprecated. '
- 'Consider switching to https://pypi.org/project/build/')
- 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()
|