kopia lustrzana https://github.com/jupyterhub/repo2docker
select frozen env based on Python found in environment.yml
if env specifies a version of Python other than the default, a different base env will be selected. This should fix some issues where switching Python versions on the base env with a bunch of packages installed can fail, and will always produce a huge amount of churn. Future change: - place py2 in a separate env, like we do for requirements.txtpull/182/head
rodzic
d7dd6cd073
commit
878fc33f1d
|
@ -1,26 +1,31 @@
|
||||||
"""
|
"""
|
||||||
Generates a variety of Dockerfiles based on an input matrix
|
Buildpack for conda environments
|
||||||
"""
|
"""
|
||||||
from traitlets import default
|
import glob
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
from ruamel.yaml import YAML
|
||||||
|
from traitlets import default
|
||||||
|
|
||||||
from ..base import BuildPack
|
from ..base import BuildPack
|
||||||
|
|
||||||
|
# pattern for parsing conda dependency line
|
||||||
|
PYTHON_REGEX = re.compile(r'python\s*=+\s*([\d\.]*)')
|
||||||
|
# current directory
|
||||||
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
|
|
||||||
class CondaBuildPack(BuildPack):
|
class CondaBuildPack(BuildPack):
|
||||||
name = "conda"
|
name = "conda"
|
||||||
version = "0.1"
|
version = "0.1"
|
||||||
env = [
|
env = [
|
||||||
('CONDA_DIR', '${APP_BASE}/conda'),
|
('CONDA_DIR', '${APP_BASE}/conda'),
|
||||||
('NB_PYTHON_PREFIX', '${CONDA_DIR}')
|
('NB_PYTHON_PREFIX', '${CONDA_DIR}'),
|
||||||
]
|
]
|
||||||
|
|
||||||
path = ['${CONDA_DIR}/bin']
|
path = ['${CONDA_DIR}/bin']
|
||||||
|
|
||||||
build_script_files = {
|
|
||||||
'conda/install-miniconda.bash': '/tmp/install-miniconda.bash',
|
|
||||||
'conda/environment.frozen.yml': '/tmp/environment.yml'
|
|
||||||
}
|
|
||||||
|
|
||||||
build_scripts = [
|
build_scripts = [
|
||||||
(
|
(
|
||||||
"root",
|
"root",
|
||||||
|
@ -31,6 +36,34 @@ class CondaBuildPack(BuildPack):
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
major_pythons = {
|
||||||
|
'2': '2.7',
|
||||||
|
'3': '3.6',
|
||||||
|
}
|
||||||
|
|
||||||
|
@default('build_script_files')
|
||||||
|
def setup_build_script_files(self):
|
||||||
|
files = {
|
||||||
|
'conda/install-miniconda.bash': '/tmp/install-miniconda.bash',
|
||||||
|
}
|
||||||
|
py_version = self.detect_python_version()
|
||||||
|
self.log.info("Building conda environment for python=%s" % py_version)
|
||||||
|
# Select the frozen base environment based on Python version.
|
||||||
|
# avoids expensive and possibly conflicting upgrades when changing
|
||||||
|
# major Python versions during upgrade.
|
||||||
|
# If no version is specified or no matching X.Y version is found,
|
||||||
|
# the default base environment is used.
|
||||||
|
frozen_name = 'environment.frozen.yml'
|
||||||
|
if py_version:
|
||||||
|
py_frozen_name = \
|
||||||
|
'environment.py-{py}.frozen.yml'.format(py=py_version)
|
||||||
|
if os.path.exists(os.path.join(HERE, py_frozen_name)):
|
||||||
|
frozen_name = py_frozen_name
|
||||||
|
else:
|
||||||
|
self.log.warning("No frozen env: %s", py_frozen_name)
|
||||||
|
files['conda/' + frozen_name] = '/tmp/environment.yml'
|
||||||
|
return files
|
||||||
|
|
||||||
@default('assemble_scripts')
|
@default('assemble_scripts')
|
||||||
def setup_assembly(self):
|
def setup_assembly(self):
|
||||||
assembly_scripts = []
|
assembly_scripts = []
|
||||||
|
@ -45,5 +78,31 @@ class CondaBuildPack(BuildPack):
|
||||||
))
|
))
|
||||||
return assembly_scripts
|
return assembly_scripts
|
||||||
|
|
||||||
|
def detect_python_version(self):
|
||||||
|
"""Detect the Python version for a given environment.yml
|
||||||
|
|
||||||
|
Will return 'x.y' if found, or None.
|
||||||
|
"""
|
||||||
|
py_version = None
|
||||||
|
environment_yml = self.binder_path('environment.yml')
|
||||||
|
with open(environment_yml) as f:
|
||||||
|
env = YAML().load(f)
|
||||||
|
for dep in env.get('dependencies', []):
|
||||||
|
if not isinstance(dep, str):
|
||||||
|
continue
|
||||||
|
match = PYTHON_REGEX.match(dep)
|
||||||
|
if not match:
|
||||||
|
continue
|
||||||
|
py_version = match.group(1)
|
||||||
|
break
|
||||||
|
|
||||||
|
# extract major.minor
|
||||||
|
if py_version:
|
||||||
|
if len(py_version) == 1:
|
||||||
|
return self.major_pythons.get(py_version[0])
|
||||||
|
else:
|
||||||
|
# return major.minor
|
||||||
|
return '.'.join(py_version[:2])
|
||||||
|
|
||||||
def detect(self):
|
def detect(self):
|
||||||
return os.path.exists(self.binder_path('environment.yml')) and super().detect()
|
return os.path.exists(self.binder_path('environment.yml')) and super().detect()
|
||||||
|
|
Ładowanie…
Reference in New Issue