From 5cf4f786e8a8cb199ff1ee6d22ef5c6b4e18b8bf Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 9 Feb 2018 17:56:48 +0100 Subject: [PATCH 01/12] add assemble_subset - get_assemble_files() returns list of files needed for assembly - if buildpack.assemble_with_subset is set, only load assemble_files prior to running assembly scripts. Load the rest of the repo afterward conda opts in to this, but currently I think this works for everything *except* requirements.txt --- repo2docker/buildpacks/conda/__init__.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/repo2docker/buildpacks/conda/__init__.py b/repo2docker/buildpacks/conda/__init__.py index 8e818bc4..27446c4d 100644 --- a/repo2docker/buildpacks/conda/__init__.py +++ b/repo2docker/buildpacks/conda/__init__.py @@ -178,6 +178,18 @@ class CondaBuildPack(BaseImage): """Am I building a Python 2 kernel environment?""" return self.python_version and self.python_version.split(".")[0] == "2" + def get_assemble_files(self): + """Specify that assembly only requires environment.yml + + enables caching assembly result even when + repo contents change + """ + assemble_files = super().get_assemble_files() + environment_yml = self.binder_path('environment.yml') + if os.path.exists(environment_yml): + assemble_files.append(environment_yml) + return assemble_files + def get_assemble_scripts(self): """Return series of build-steps specific to this source repository. """ From b6ab2a99864c94a5a955c4a461f3730bfcf421ba Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 18 Sep 2018 14:42:58 +0200 Subject: [PATCH 02/12] check requirements.txt for local references allows assemble_from_subset when requirements.txt doesn't contain any local references --- repo2docker/buildpacks/python/__init__.py | 56 +++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/repo2docker/buildpacks/python/__init__.py b/repo2docker/buildpacks/python/__init__.py index 4db5c72d..0d9a5b39 100644 --- a/repo2docker/buildpacks/python/__init__.py +++ b/repo2docker/buildpacks/python/__init__.py @@ -34,6 +34,62 @@ class PythonBuildPack(CondaBuildPack): self._python_version = py_version return self._python_version + def get_assemble_files(self): + assemble_files = super().get_assemble_files() + for name in ('requirements.txt', 'requirements3.txt'): + requirements_txt = self.binder_path(name) + if os.path.exists(requirements_txt): + assemble_files.append(requirements_txt) + return assemble_files + + def _is_local_requirement(self, line): + """Return whether a line in a requirements.txt file references a local file""" + # trim comments and skip empty lines + line = line.split('#', 1)[0].strip() + if not line: + return False + if line.startswith(('-r', '-c')): + # local -r or -c references break isolation + return True + # strip off `-e, etc.` + if line.startswith('-'): + line = line.split(None, 1)[1] + if 'file://' in line: + # file references break isolation + return True + if '://' in line: + # handle git://../local/file + path = line.split('://', 1)[1] + else: + path = line + if path.startswith('.'): + # references a local file + return True + return False + + @property + def assemble_from_subset(self): + """Peek in requirements.txt to determine if we can assemble from only env files + + If there are any local references, e.g. `-e .`, + stage the whole repo prior to installation. + """ + if not os.path.exists('binder') and os.path.exists('setup.py'): + # can't install from subset if we're using setup.py + return False + for name in ('requirements.txt', 'requirements3.txt'): + requirements_txt = self.binder_path(name) + if not os.path.exists(requirements_txt): + continue + with open(requirements_txt) as f: + for line in f: + if self._is_local_requirement(line): + return False + + # didn't find any local references, + # allow assembly from subset + return True + def get_assemble_scripts(self): """Return series of build-steps specific to this repository. """ From 5b12e072b1cbc2e47d3dc4f2a51477be8c08dafd Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 16 Jul 2019 08:35:35 +0200 Subject: [PATCH 03/12] move stencila to preassemble --- repo2docker/buildpacks/base.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/repo2docker/buildpacks/base.py b/repo2docker/buildpacks/base.py index 0bb9703b..6d77ad27 100644 --- a/repo2docker/buildpacks/base.py +++ b/repo2docker/buildpacks/base.py @@ -711,12 +711,8 @@ class BaseImage(BuildPack): except FileNotFoundError: pass - return scripts - - def get_assemble_scripts(self): - assemble_scripts = [] if "py" in self.stencila_contexts: - assemble_scripts.extend( + scripts.extend( [ ( "${NB_USER}", @@ -728,7 +724,7 @@ class BaseImage(BuildPack): ] ) if self.stencila_manifest_dir: - assemble_scripts.extend( + scripts.extend( [ ( "${NB_USER}", @@ -741,7 +737,11 @@ class BaseImage(BuildPack): ) ] ) - return assemble_scripts + return scripts + + def get_assemble_scripts(self): + """Return directives to run after the entire repository has been added to the image""" + return [] def get_post_build_scripts(self): post_build = self.binder_path("postBuild") From 70878082f6847eeefa818bbefb10f2b20a804a22 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 16 Jul 2019 08:36:06 +0200 Subject: [PATCH 04/12] conda install occurs in preassemble --- repo2docker/buildpacks/conda/__init__.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/repo2docker/buildpacks/conda/__init__.py b/repo2docker/buildpacks/conda/__init__.py index 27446c4d..2aa45c37 100644 --- a/repo2docker/buildpacks/conda/__init__.py +++ b/repo2docker/buildpacks/conda/__init__.py @@ -178,19 +178,19 @@ class CondaBuildPack(BaseImage): """Am I building a Python 2 kernel environment?""" return self.python_version and self.python_version.split(".")[0] == "2" - def get_assemble_files(self): - """Specify that assembly only requires environment.yml + def get_preassemble_script_files(self): + """preassembly only requires environment.yml enables caching assembly result even when repo contents change """ - assemble_files = super().get_assemble_files() - environment_yml = self.binder_path('environment.yml') + assemble_files = super().get_preassemble_script_files() + environment_yml = self.binder_path("environment.yml") if os.path.exists(environment_yml): - assemble_files.append(environment_yml) + assemble_files[environment_yml] = environment_yml return assemble_files - def get_assemble_scripts(self): + def get_preassemble_scripts(self): """Return series of build-steps specific to this source repository. """ assembly_scripts = [] @@ -209,7 +209,7 @@ class CondaBuildPack(BaseImage): ), ) ) - return super().get_assemble_scripts() + assembly_scripts + return super().get_preassemble_scripts() + assembly_scripts def detect(self): """Check if current repo should be built with the Conda BuildPack. From d6e66c886d7c88985d00f2e8fcb4e4525082605b Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 16 Jul 2019 09:02:59 +0200 Subject: [PATCH 05/12] preassemble python --- repo2docker/buildpacks/python/__init__.py | 114 +++++++++++++--------- 1 file changed, 67 insertions(+), 47 deletions(-) diff --git a/repo2docker/buildpacks/python/__init__.py b/repo2docker/buildpacks/python/__init__.py index 0d9a5b39..7b6fc5af 100644 --- a/repo2docker/buildpacks/python/__init__.py +++ b/repo2docker/buildpacks/python/__init__.py @@ -34,80 +34,47 @@ class PythonBuildPack(CondaBuildPack): self._python_version = py_version return self._python_version - def get_assemble_files(self): - assemble_files = super().get_assemble_files() - for name in ('requirements.txt', 'requirements3.txt'): - requirements_txt = self.binder_path(name) - if os.path.exists(requirements_txt): - assemble_files.append(requirements_txt) - return assemble_files - def _is_local_requirement(self, line): """Return whether a line in a requirements.txt file references a local file""" # trim comments and skip empty lines - line = line.split('#', 1)[0].strip() + line = line.split("#", 1)[0].strip() if not line: return False - if line.startswith(('-r', '-c')): + if line.startswith(("-r", "-c")): # local -r or -c references break isolation return True # strip off `-e, etc.` - if line.startswith('-'): + if line.startswith("-"): line = line.split(None, 1)[1] - if 'file://' in line: + if "file://" in line: # file references break isolation return True - if '://' in line: + if "://" in line: # handle git://../local/file - path = line.split('://', 1)[1] + path = line.split("://", 1)[1] else: path = line - if path.startswith('.'): + if path.startswith("."): # references a local file return True return False - @property - def assemble_from_subset(self): - """Peek in requirements.txt to determine if we can assemble from only env files + def _get_pip_scripts(self): + """Get pip install scripts - If there are any local references, e.g. `-e .`, - stage the whole repo prior to installation. + added to preassemble unless local references are found, + in which case this happens in assemble. """ - if not os.path.exists('binder') and os.path.exists('setup.py'): - # can't install from subset if we're using setup.py - return False - for name in ('requirements.txt', 'requirements3.txt'): - requirements_txt = self.binder_path(name) - if not os.path.exists(requirements_txt): - continue - with open(requirements_txt) as f: - for line in f: - if self._is_local_requirement(line): - return False - - # didn't find any local references, - # allow assembly from subset - return True - - def get_assemble_scripts(self): - """Return series of build-steps specific to this repository. - """ - # If we have a runtime.txt & that's set to python-2.7, - # requirements.txt will be installed in the *kernel* env - # and requirements3.txt (if it exists) - # will be installed in the python 3 notebook server env. - assemble_scripts = super().get_assemble_scripts() - setup_py = "setup.py" # KERNEL_PYTHON_PREFIX is the env with the kernel, # whether it's distinct from the notebook or the same. pip = "${KERNEL_PYTHON_PREFIX}/bin/pip" + scripts = [] if self.py2: # using python 2 kernel, # requirements3.txt allows installation in the notebook server env nb_requirements_file = self.binder_path("requirements3.txt") if os.path.exists(nb_requirements_file): - assemble_scripts.append( + scripts.append( ( "${NB_USER}", # want the $NB_PYHTON_PREFIX environment variable, not for @@ -121,12 +88,65 @@ class PythonBuildPack(CondaBuildPack): # install requirements.txt in the kernel env requirements_file = self.binder_path("requirements.txt") if os.path.exists(requirements_file): - assemble_scripts.append( + scripts.append( ( "${NB_USER}", '{} install --no-cache-dir -r "{}"'.format(pip, requirements_file), ) ) + return scripts + + @property + def _should_preassemble_pip(self): + """Peek in requirements.txt to determine if we can assemble from only env files + + If there are any local references, e.g. `-e .`, + stage the whole repo prior to installation. + """ + if not os.path.exists("binder") and os.path.exists("setup.py"): + # can't install from subset if we're using setup.py + return False + for name in ("requirements.txt", "requirements3.txt"): + requirements_txt = self.binder_path(name) + if not os.path.exists(requirements_txt): + continue + with open(requirements_txt) as f: + for line in f: + if self._is_local_requirement(line): + return False + + # didn't find any local references, + # allow assembly from subset + return True + + def get_preassemble_script_files(self): + assemble_files = super().get_preassemble_script_files() + for name in ("requirements.txt", "requirements3.txt"): + requirements_txt = self.binder_path(name) + if os.path.exists(requirements_txt): + assemble_files[requirements_txt] = requirements_txt + return assemble_files + + def get_preassemble_scripts(self): + """Return scripts to run before adding the full repository""" + scripts = super().get_preassemble_scripts() + if self._should_preassemble_pip: + scripts.extend(self._get_pip_scripts()) + return scripts + + def get_assemble_scripts(self): + """Return series of build steps that require the full repository""" + # If we have a runtime.txt & that's set to python-2.7, + # requirements.txt will be installed in the *kernel* env + # and requirements3.txt (if it exists) + # will be installed in the python 3 notebook server env. + assemble_scripts = super().get_assemble_scripts() + setup_py = "setup.py" + # KERNEL_PYTHON_PREFIX is the env with the kernel, + # whether it's distinct from the notebook or the same. + pip = "${KERNEL_PYTHON_PREFIX}/bin/pip" + if not self._should_preassemble_pip: + assemble_scripts.extend(self._get_pip_scripts()) # setup.py exists *and* binder dir is not used if not self.binder_dir and os.path.exists(setup_py): From 4f3f192d2f1193ee3692ecbf5429571812deedc1 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 16 Jul 2019 09:11:38 +0200 Subject: [PATCH 06/12] preassembly for pipfiles --- repo2docker/buildpacks/pipfile/__init__.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/repo2docker/buildpacks/pipfile/__init__.py b/repo2docker/buildpacks/pipfile/__init__.py index e91e63aa..c60a1f88 100644 --- a/repo2docker/buildpacks/pipfile/__init__.py +++ b/repo2docker/buildpacks/pipfile/__init__.py @@ -65,7 +65,16 @@ class PipfileBuildPack(CondaBuildPack): self._python_version = self.major_pythons["3"] return self._python_version - def get_assemble_scripts(self): + def get_preassemble_script_files(self): + """Return files needed for preassembly""" + files = super().get_preassemble_script_files() + for name in ("requirements3.txt", "Pipfile", "Pipfile.lock"): + path = self.binder_path(name) + if os.path.exists(path): + files[path] = path + return files + + def get_preassemble_scripts(self): """Return series of build-steps specific to this repository. """ # If we have either Pipfile.lock, Pipfile, or runtime.txt declare the From 3da5543bfcaaf7f2275a5e5ad4fc0484e5d465d8 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 18 Jul 2019 14:39:35 +0200 Subject: [PATCH 07/12] check for local pip requirements in conda environments --- repo2docker/buildpacks/conda/__init__.py | 104 +++++++++++++++------- repo2docker/buildpacks/python/__init__.py | 28 +----- repo2docker/utils.py | 26 ++++++ 3 files changed, 102 insertions(+), 56 deletions(-) diff --git a/repo2docker/buildpacks/conda/__init__.py b/repo2docker/buildpacks/conda/__init__.py index 2aa45c37..87865250 100644 --- a/repo2docker/buildpacks/conda/__init__.py +++ b/repo2docker/buildpacks/conda/__init__.py @@ -6,6 +6,7 @@ from collections import Mapping from ruamel.yaml import YAML from ..base import BaseImage +from ...utils import is_local_pip_requirement # pattern for parsing conda dependency line PYTHON_REGEX = re.compile(r"python\s*=+\s*([\d\.]*)") @@ -127,6 +128,50 @@ class CondaBuildPack(BaseImage): files.update(super().get_build_script_files()) return files + _environment_yaml = None + + @property + def environment_yaml(self): + if self._environment_yaml is not None: + return self._environment_yaml + + environment_yml = self.binder_path("environment.yml") + if not os.path.exists(environment_yml): + self._environment_yaml = {} + return self._environment_yaml + + with open(environment_yml) as f: + env = YAML().load(f) + # check if the env file is empty, if so instantiate an empty dictionary. + if env is None: + env = {} + # check if the env file provided a dick-like thing not a list or other data structure. + if not isinstance(env, Mapping): + raise TypeError( + "environment.yml should contain a dictionary. Got %r" % type(env) + ) + self._environment_yaml = env + + return self._environment_yaml + + @property + def _should_preassemble_env(self): + """Check for local pip requirements in environment.yaml + + If there are any local references, e.g. `-e .`, + stage the whole repo prior to installation. + """ + dependencies = self.environment_yaml.get("dependencies", []) + pip_requirements = None + for dep in dependencies: + if isinstance(dep, dict) and dep.get("pip"): + pip_requirements = dep["pip"] + if isinstance(pip_requirements, list): + for line in pip_requirements: + if is_local_pip_requirement(line): + return False + return True + @property def python_version(self): """Detect the Python version for a given `environment.yml` @@ -135,31 +180,17 @@ class CondaBuildPack(BaseImage): or a Falsy empty string '' if not found. """ - environment_yml = self.binder_path("environment.yml") - if not os.path.exists(environment_yml): - return "" - if not hasattr(self, "_python_version"): py_version = None - with open(environment_yml) as f: - env = YAML().load(f) - # check if the env file is empty, if so instantiate an empty dictionary. - if env is None: - env = {} - # check if the env file provided a dick-like thing not a list or other data structure. - if not isinstance(env, Mapping): - raise TypeError( - "environment.yml should contain a dictionary. Got %r" - % type(env) - ) - 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 + env = self.environment_yaml + 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: @@ -185,19 +216,20 @@ class CondaBuildPack(BaseImage): repo contents change """ assemble_files = super().get_preassemble_script_files() - environment_yml = self.binder_path("environment.yml") - if os.path.exists(environment_yml): - assemble_files[environment_yml] = environment_yml + if self._should_preassemble_env: + environment_yml = self.binder_path("environment.yml") + if os.path.exists(environment_yml): + assemble_files[environment_yml] = environment_yml return assemble_files - def get_preassemble_scripts(self): + def get_env_scripts(self): """Return series of build-steps specific to this source repository. """ - assembly_scripts = [] + scripts = [] environment_yml = self.binder_path("environment.yml") env_prefix = "${KERNEL_PYTHON_PREFIX}" if self.py2 else "${NB_PYTHON_PREFIX}" if os.path.exists(environment_yml): - assembly_scripts.append( + scripts.append( ( "${NB_USER}", r""" @@ -209,7 +241,19 @@ class CondaBuildPack(BaseImage): ), ) ) - return super().get_preassemble_scripts() + assembly_scripts + return scripts + + def get_preassemble_scripts(self): + scripts = super().get_preassemble_scripts() + if self._should_preassemble_env: + scripts.extend(self.get_env_scripts()) + return scripts + + def get_assemble_scripts(self): + scripts = super().get_assemble_scripts() + if not self._should_preassemble_env: + scripts.extend(self.get_env_scripts()) + return scripts def detect(self): """Check if current repo should be built with the Conda BuildPack. diff --git a/repo2docker/buildpacks/python/__init__.py b/repo2docker/buildpacks/python/__init__.py index 7b6fc5af..72029d78 100644 --- a/repo2docker/buildpacks/python/__init__.py +++ b/repo2docker/buildpacks/python/__init__.py @@ -2,6 +2,7 @@ import os from ..conda import CondaBuildPack +from ...utils import is_local_pip_requirement class PythonBuildPack(CondaBuildPack): @@ -34,31 +35,6 @@ class PythonBuildPack(CondaBuildPack): self._python_version = py_version return self._python_version - def _is_local_requirement(self, line): - """Return whether a line in a requirements.txt file references a local file""" - # trim comments and skip empty lines - line = line.split("#", 1)[0].strip() - if not line: - return False - if line.startswith(("-r", "-c")): - # local -r or -c references break isolation - return True - # strip off `-e, etc.` - if line.startswith("-"): - line = line.split(None, 1)[1] - if "file://" in line: - # file references break isolation - return True - if "://" in line: - # handle git://../local/file - path = line.split("://", 1)[1] - else: - path = line - if path.startswith("."): - # references a local file - return True - return False - def _get_pip_scripts(self): """Get pip install scripts @@ -112,7 +88,7 @@ class PythonBuildPack(CondaBuildPack): continue with open(requirements_txt) as f: for line in f: - if self._is_local_requirement(line): + if is_local_pip_requirement(line): return False # didn't find any local references, diff --git a/repo2docker/utils.py b/repo2docker/utils.py index a53ba5ef..1c0a4334 100644 --- a/repo2docker/utils.py +++ b/repo2docker/utils.py @@ -431,3 +431,29 @@ def normalize_doi(val): (e.g. https://doi.org/10.1234/jshd123)""" m = doi_regexp.match(val) return m.group(2) + + +def is_local_pip_requirement(line): + """Return whether a pip requirement (e.g. in requirements.txt file) references a local file""" + # trim comments and skip empty lines + line = line.split("#", 1)[0].strip() + if not line: + return False + if line.startswith(("-r", "-c")): + # local -r or -c references break isolation + return True + # strip off `-e, etc.` + if line.startswith("-"): + line = line.split(None, 1)[1] + if "file://" in line: + # file references break isolation + return True + if "://" in line: + # handle git://../local/file + path = line.split("://", 1)[1] + else: + path = line + if path.startswith("."): + # references a local file + return True + return False From 654be046ac7ae45e976313b75db71a1529c686d5 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 18 Jul 2019 14:40:08 +0200 Subject: [PATCH 08/12] set permissions on repo_dir prior to preassemble --- repo2docker/buildpacks/base.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/repo2docker/buildpacks/base.py b/repo2docker/buildpacks/base.py index 6d77ad27..b2772e9e 100644 --- a/repo2docker/buildpacks/base.py +++ b/repo2docker/buildpacks/base.py @@ -132,6 +132,10 @@ COPY src/{{ src }} ${REPO_DIR}/{{ dst }} {% endfor -%} {% endif -%} +{% if preassemble_script_directives -%} +RUN chown -R ${NB_USER}:${NB_USER} ${REPO_DIR} +{% endif -%} + {% for sd in preassemble_script_directives -%} {{ sd }} {% endfor %} From 009d09815a9b94d22896ebb31be3986528353962 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 18 Jul 2019 14:40:17 +0200 Subject: [PATCH 09/12] test local pip requirements --- tests/unit/test_utils.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index 6ad1ff28..951f2085 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -110,3 +110,20 @@ def test_normalize_doi(): assert utils.normalize_doi("http://doi.org/10.1234/jshd123") == "10.1234/jshd123" assert utils.normalize_doi("https://doi.org/10.1234/jshd123") == "10.1234/jshd123" assert utils.normalize_doi("http://dx.doi.org/10.1234/jshd123") == "10.1234/jshd123" + + +@pytest.mark.parametrize( + "req, is_local", + [ + ("-r requirements.txt", True), + ("-e .", True), + ("file://subdir", True), + ("file://./subdir", True), + ("git://github.com/jupyter/repo2docker", False), + ("git+https://github.com/jupyter/repo2docker", False), + ("numpy", False), + ("# -e .", False), + ], +) +def test_local_pip_requirement(req, is_local): + assert utils.is_local_pip_requirement(req) == is_local From 8236dc8ae14410fad7998fe35614d785cea855f3 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 18 Jul 2019 16:25:04 +0200 Subject: [PATCH 10/12] only install pipenv in preassemble save preassembly of pipenv for a later patch --- repo2docker/buildpacks/pipfile/__init__.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/repo2docker/buildpacks/pipfile/__init__.py b/repo2docker/buildpacks/pipfile/__init__.py index c60a1f88..b38db08a 100644 --- a/repo2docker/buildpacks/pipfile/__init__.py +++ b/repo2docker/buildpacks/pipfile/__init__.py @@ -75,6 +75,15 @@ class PipfileBuildPack(CondaBuildPack): return files def get_preassemble_scripts(self): + """scripts to run prior to staging the repo contents""" + scripts = super().get_preassemble_scripts() + # install pipenv to install dependencies within Pipfile.lock or Pipfile + scripts.append( + ("${NB_USER}", "${KERNEL_PYTHON_PREFIX}/bin/pip install pipenv==2018.11.26") + ) + return scripts + + def get_assemble_scripts(self): """Return series of build-steps specific to this repository. """ # If we have either Pipfile.lock, Pipfile, or runtime.txt declare the @@ -113,11 +122,6 @@ class PipfileBuildPack(CondaBuildPack): # my_package_example = {path=".", editable=true} working_directory = self.binder_dir or "." - # install pipenv to install dependencies within Pipfile.lock or Pipfile - assemble_scripts.append( - ("${NB_USER}", "${KERNEL_PYTHON_PREFIX}/bin/pip install pipenv==2018.11.26") - ) - # NOTES: # - Without prioritizing the PATH to KERNEL_PYTHON_PREFIX over # NB_SERVER_PYTHON_PREFIX, 'pipenv' draws the wrong conclusion about From 31da8e32b1632f9a325bc13046bf8680b1f4e2cf Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 18 Jul 2019 17:55:38 +0200 Subject: [PATCH 11/12] run chown as root --- repo2docker/buildpacks/base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/repo2docker/buildpacks/base.py b/repo2docker/buildpacks/base.py index b2772e9e..140a1d33 100644 --- a/repo2docker/buildpacks/base.py +++ b/repo2docker/buildpacks/base.py @@ -133,6 +133,7 @@ COPY src/{{ src }} ${REPO_DIR}/{{ dst }} {% endif -%} {% if preassemble_script_directives -%} +USER root RUN chown -R ${NB_USER}:${NB_USER} ${REPO_DIR} {% endif -%} From 930e907ac6bc2a9765a081a85c75ed547f5b6909 Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 19 Jul 2019 08:56:06 +0200 Subject: [PATCH 12/12] Update repo2docker/buildpacks/conda/__init__.py Co-Authored-By: Tim Head --- repo2docker/buildpacks/conda/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/repo2docker/buildpacks/conda/__init__.py b/repo2docker/buildpacks/conda/__init__.py index 87865250..c781f00a 100644 --- a/repo2docker/buildpacks/conda/__init__.py +++ b/repo2docker/buildpacks/conda/__init__.py @@ -145,7 +145,7 @@ class CondaBuildPack(BaseImage): # check if the env file is empty, if so instantiate an empty dictionary. if env is None: env = {} - # check if the env file provided a dick-like thing not a list or other data structure. + # check if the env file provided a dict-like thing not a list or other data structure. if not isinstance(env, Mapping): raise TypeError( "environment.yml should contain a dictionary. Got %r" % type(env)