123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- """Build a project using PEP 517 hooks.
- """
- import argparse
- import logging
- import os
- from pip._vendor import toml
- import shutil
- from .envbuild import BuildEnvironment
- from .wrappers import Pep517HookCaller
- from .dirtools import tempdir, mkdir_p
- from .compat import FileNotFoundError
- log = logging.getLogger(__name__)
- def validate_system(system):
- """
- Ensure build system has the requisite fields.
- """
- required = {'requires', 'build-backend'}
- if not (required <= set(system)):
- message = "Missing required fields: {missing}".format(
- missing=required-set(system),
- )
- raise ValueError(message)
- def load_system(source_dir):
- """
- Load the build system from a source dir (pyproject.toml).
- """
- pyproject = os.path.join(source_dir, 'pyproject.toml')
- with open(pyproject) as f:
- pyproject_data = toml.load(f)
- return pyproject_data['build-system']
- def compat_system(source_dir):
- """
- Given a source dir, attempt to get a build system backend
- and requirements from pyproject.toml. Fallback to
- setuptools but only if the file was not found or a build
- system was not indicated.
- """
- try:
- system = load_system(source_dir)
- except (FileNotFoundError, KeyError):
- system = {}
- system.setdefault(
- 'build-backend',
- 'setuptools.build_meta:__legacy__',
- )
- system.setdefault('requires', ['setuptools', 'wheel'])
- return system
- def _do_build(hooks, env, dist, dest):
- get_requires_name = 'get_requires_for_build_{dist}'.format(**locals())
- get_requires = getattr(hooks, get_requires_name)
- reqs = get_requires({})
- log.info('Got build requires: %s', reqs)
- env.pip_install(reqs)
- log.info('Installed dynamic build dependencies')
- with tempdir() as td:
- log.info('Trying to build %s in %s', dist, td)
- build_name = 'build_{dist}'.format(**locals())
- build = getattr(hooks, build_name)
- filename = build(td, {})
- source = os.path.join(td, filename)
- shutil.move(source, os.path.join(dest, os.path.basename(filename)))
- def build(source_dir, dist, dest=None, system=None):
- system = system or load_system(source_dir)
- dest = os.path.join(source_dir, dest or 'dist')
- mkdir_p(dest)
- validate_system(system)
- hooks = Pep517HookCaller(
- source_dir, system['build-backend'], system.get('backend-path')
- )
- with BuildEnvironment() as env:
- env.pip_install(system['requires'])
- _do_build(hooks, env, dist, dest)
- parser = argparse.ArgumentParser()
- parser.add_argument(
- 'source_dir',
- help="A directory containing pyproject.toml",
- )
- parser.add_argument(
- '--binary', '-b',
- action='store_true',
- default=False,
- )
- parser.add_argument(
- '--source', '-s',
- action='store_true',
- default=False,
- )
- parser.add_argument(
- '--out-dir', '-o',
- help="Destination in which to save the builds relative to source dir",
- )
- def main(args):
- # determine which dists to build
- dists = list(filter(None, (
- 'sdist' if args.source or not args.binary else None,
- 'wheel' if args.binary or not args.source else None,
- )))
- for dist in dists:
- build(args.source_dir, dist, args.out_dir)
- if __name__ == '__main__':
- main(parser.parse_args())
|