-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #27 from pypa/feature/build-command
Add build command
- Loading branch information
Showing
2 changed files
with
118 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()) |