Skip to content

Commit

Permalink
Merge pull request #27 from pypa/feature/build-command
Browse files Browse the repository at this point in the history
Add build command
  • Loading branch information
jaraco authored Dec 17, 2018
2 parents 72d377b + 83e8c6d commit 9ca68d8
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 0 deletions.
10 changes: 10 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,13 @@ To test the build backend for a project, run in a system shell:
.. code-block:: shell
python3 -m pep517.check path/to/source # source dir containing pyproject.toml
To build a backend into source and/or binary distributions, run in a shell:

.. code-block:: shell
python -m pep517.build path/to/source # source dir containing pyproject.toml
This 'build' module should be considered experimental while the PyPA `decides
on the best place for this functionality
<https://github.com/pypa/packaging-problems/issues/219>`_.
108 changes: 108 additions & 0 deletions pep517/build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
"""Build a project using PEP 517 hooks.
"""
import argparse
import logging
import os
import contextlib
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())

0 comments on commit 9ca68d8

Please sign in to comment.