109 lines
2.6 KiB
Python
109 lines
2.6 KiB
Python
|
"""Build a project using PEP 517 hooks.
|
||
|
"""
|
||
|
import argparse
|
||
|
import logging
|
||
|
import os
|
||
|
import contextlib
|
||
|
from pip._vendor import pytoml
|
||
|
import shutil
|
||
|
import errno
|
||
|
import tempfile
|
||
|
|
||
|
from .envbuild import BuildEnvironment
|
||
|
from .wrappers import Pep517HookCaller
|
||
|
|
||
|
log = logging.getLogger(__name__)
|
||
|
|
||
|
|
||
|
@contextlib.contextmanager
|
||
|
def tempdir():
|
||
|
td = tempfile.mkdtemp()
|
||
|
try:
|
||
|
yield td
|
||
|
finally:
|
||
|
shutil.rmtree(td)
|
||
|
|
||
|
|
||
|
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 mkdir_p(*args, **kwargs):
|
||
|
"""Like `mkdir`, but does not raise an exception if the
|
||
|
directory already exists.
|
||
|
"""
|
||
|
try:
|
||
|
return os.mkdir(*args, **kwargs)
|
||
|
except OSError as exc:
|
||
|
if exc.errno != errno.EEXIST:
|
||
|
raise
|
||
|
|
||
|
|
||
|
def build(source_dir, dist, dest=None):
|
||
|
pyproject = os.path.join(source_dir, 'pyproject.toml')
|
||
|
dest = os.path.join(source_dir, dest or 'dist')
|
||
|
mkdir_p(dest)
|
||
|
|
||
|
with open(pyproject) as f:
|
||
|
pyproject_data = pytoml.load(f)
|
||
|
# Ensure the mandatory data can be loaded
|
||
|
buildsys = pyproject_data['build-system']
|
||
|
requires = buildsys['requires']
|
||
|
backend = buildsys['build-backend']
|
||
|
|
||
|
hooks = Pep517HookCaller(source_dir, backend)
|
||
|
|
||
|
with BuildEnvironment() as env:
|
||
|
env.pip_install(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())
|