diff --git a/builder/app.py b/builder/app.py index f2b2f76e..74e80112 100644 --- a/builder/app.py +++ b/builder/app.py @@ -12,7 +12,7 @@ import docker import subprocess -from .detectors import BuildPack, PythonBuildPack, DockerBuildPack +from .detectors import BuildPack, PythonBuildPack, DockerBuildPack, CondaBuildPack from .utils import execute_cmd @@ -53,7 +53,7 @@ class Builder(Application): buildpacks = List( None, - [DockerBuildPack, PythonBuildPack], + [DockerBuildPack, CondaBuildPack, PythonBuildPack], config=True ) diff --git a/builder/detectors.py b/builder/detectors.py index a0b85652..710d536c 100644 --- a/builder/detectors.py +++ b/builder/detectors.py @@ -39,7 +39,6 @@ class BuildPack(LoggingConfigurable): pass - class DockerBuildPack(BuildPack): name = Unicode('Dockerfile') def detect(self, workdir): @@ -56,7 +55,43 @@ class DockerBuildPack(BuildPack): self.log.info(progress['stream'].rstrip(), extra=dict(phase='building')) -class PythonBuildPack(BuildPack): +class S2IBuildPack(BuildPack): + def s2i_build(self, workdir, ref, output_image_spec, build_image): + # Note: Ideally we'd just copy from workdir here, rather than clone and check out again + # However, setting just --copy and not specifying a ref seems to check out master for + # some reason. Investigate deeper FIXME + cmd = [ + 's2i', + 'build', + '--exclude', '""', + '--ref', ref, + workdir, + build_image, + output_image_spec, + ] + try: + for line in execute_cmd(cmd): + 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')) + sys.exit(1) + + +class CondaBuildPack(S2IBuildPack): + """Build Pack for installing from a conda environment.yml using S2I""" + + name = Unicode('conda') + build_image = Unicode('jupyterhub/singleuser-builder-conda:v0.1.5', config=True) + + def detect(self, workdir): + return os.path.exists(os.path.join(workdir, 'environment.yml')) + + def build(self, workdir, ref, output_image_spec): + return self.s2i_build(workdir, ref, output_image_spec, self.build_image) + + +class PythonBuildPack(S2IBuildPack): + """Build Pack for installing from a pip requirements.txt using S2I""" name = Unicode('python-pip') runtime_builder_map = Dict({ 'python-2.7': 'jupyterhub/singleuser-builder-venv-2.7:v0.1.5', @@ -78,21 +113,4 @@ class PythonBuildPack(BuildPack): return True def build(self, workdir, ref, output_image_spec): - # Note: Ideally we'd just copy from workdir here, rather than clone and check out again - # However, setting just --copy and not specifying a ref seems to check out master for - # some reason. Investigate deeper FIXME - cmd = [ - 's2i', - 'build', - '--exclude', '""', - '--ref', ref, - workdir, - self.runtime_builder_map[self.runtime], - output_image_spec - ] - try: - for line in execute_cmd(cmd): - 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')) - sys.exit(1) + return self.s2i_build(workdir, ref, output_image_spec, self.runtime_builder_map[self.runtime])