diff --git a/.gitignore b/.gitignore index 64598c69..d38e77f0 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,9 @@ .#* +dist +build +*.tar.gz +*.egg-info +*.py[co] +__pycache__ + +repo2docker/s2i diff --git a/Dockerfile b/Dockerfile index a47b95db..8133e5e4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,6 +12,8 @@ RUN apt-get update && \ COPY install-s2i.bash /usr/local/bin/install-s2i.bash RUN /usr/local/bin/install-s2i.bash +RUN pip3 install --upgrade pip wheel + RUN mkdir /tmp/src ADD . /tmp/src RUN pip3 install /tmp/src diff --git a/repo2docker/app.py b/repo2docker/app.py index 786e20d5..89a43e9d 100644 --- a/repo2docker/app.py +++ b/repo2docker/app.py @@ -144,7 +144,7 @@ class Repo2Docker(Application): sys.exit(1) try: - for line in execute_cmd(['git', 'reset', '--hard', ref], checkout_path): + for line in execute_cmd(['git', 'reset', '--hard', ref], cwd=checkout_path): self.log.info(line, extra=dict(phase='fetching')) except subprocess.CalledProcessError: self.log.error('Failed to check out ref %s', ref, extra=dict(phase='failed')) diff --git a/repo2docker/detectors.py b/repo2docker/detectors.py index 66d60d3a..7c5c51d9 100644 --- a/repo2docker/detectors.py +++ b/repo2docker/detectors.py @@ -12,6 +12,7 @@ from pythonjsonlogger import jsonlogger from .utils import execute_cmd +here = os.path.abspath(os.path.dirname(__file__)) class BuildPack(LoggingConfigurable): name = Unicode() @@ -73,8 +74,12 @@ class S2IBuildPack(BuildPack): build_image, output_image_spec, ] + env = os.environ.copy() + # add bundled s2i to *end* of PATH, + # in case user doesn't have s2i + env['PATH'] = os.pathsep.join([env.get('PATH') or os.defpath, here]) try: - for line in execute_cmd(cmd, cwd=workdir): + for line in execute_cmd(cmd, cwd=workdir, env=env): self.log.info(line, extra=dict(phase='building', builder=self.name)) except subprocess.CalledProcessError: self.log.error('Failed to build image!', extra=dict(phase='failed')) diff --git a/repo2docker/utils.py b/repo2docker/utils.py index 823e5545..1e18016f 100644 --- a/repo2docker/utils.py +++ b/repo2docker/utils.py @@ -1,10 +1,10 @@ import subprocess -def execute_cmd(cmd, cwd=None): +def execute_cmd(cmd, **kwargs): """ Call given command, yielding output line by line """ - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, cwd=cwd) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, **kwargs) try: for line in iter(proc.stdout.readline, ''): diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 00000000..d7de2b16 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[wheel] +universal=1 \ No newline at end of file diff --git a/setup.py b/setup.py index cd78ec66..88341718 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,95 @@ +from __future__ import print_function + +import hashlib +import os +import sys +import tarfile + +try: + from urllib.request import urlopen +except ImportError: + from urllib import urlopen + from setuptools import setup, find_packages +tgz = 'source-to-image-v1.1.6-f519129-{}-amd64.tar.gz'.format(sys.platform) +s2i_bin_url = 'https://github.com/openshift/source-to-image/releases/download/v1.1.6/' + tgz + +checksums = { + 'darwin': '0398bb5cd1d77a59ed9780ec4e2edd3b0c70e973d66b6ae5c072a8830029d703', + 'linux': '85ed735d141da1fe3def7826910c0c0baf587df6c727529b52d2c5cd98dcb641', +} + + +def download_s2i(): + if os.path.exists(tgz): + print("Already have %s" % tgz) + return + print("Downloading %s" % s2i_bin_url) + reader = urlopen(s2i_bin_url) + with open(tgz, 'wb') as f: + f.write(reader.read()) + reader.close() + + +def stage_s2i(): + """Stage s2i binary into repo2docker""" + print("Staging %s" % s2i_dest) + with tarfile.open(tgz) as f: + f.extract('./s2i', pkg) + + +def checksum_s2i(): + """Check the checksum of the s2i binary""" + with open(s2i_dest, 'rb') as f: + found_hash = hashlib.sha256(f.read()).hexdigest() + expected = checksums[sys.platform] + if found_hash != expected: + print("Checksum mismatch %s != %s" % (found_hash, expected)) + return found_hash == expected + + +def have_s2i(): + """Do we already have s2i?""" + if not os.path.exists(s2i_dest): + return False + return checksum_s2i() + + +here = os.path.dirname(os.path.abspath(__file__)) +pkg = os.path.join(here, 'repo2docker') + +s2i_dest = os.path.join(pkg, 's2i') + +if sys.platform in checksums: + if not have_s2i(): + download_s2i() + stage_s2i() + + if not checksum_s2i(): + print("s2i checksum failed", file=sys.stderr) + sys.exit(1) +else: + print("I don't know how to bundle s2i for %s" % sys.platform) + +cmdclass = {} +try: + from wheel.bdist_wheel import bdist_wheel + from wheel.pep425tags import get_platform +except ImportError: + # no wheel + pass +else: + # apply current platform tag + # because we bundle platform-specific s2i binaries + class PlatformBDistWheel(bdist_wheel): + def initialize_options(self): + super(PlatformBDistWheel, self).initialize_options() + if self.plat_name is None: + self.plat_name = get_platform() + + cmdclass['bdist_wheel'] = PlatformBDistWheel + setup( name='jupyter-repo2docker', version='0.1', @@ -12,6 +102,10 @@ setup( author='Yuvi Panda', author_email='yuvipanda@gmail.com', license='BSD', + cmdclass=cmdclass, + package_data={ + 'repo2docker': ['s2i'], + }, packages=find_packages(), entry_points={ 'console_scripts': [