kopia lustrzana https://github.com/jupyterhub/repo2docker
Remove support for Julia REQUIRE
it doesn't work anymore because build dependencies of the old ZMQ.jl have been removed.pull/1350/head
rodzic
a4049fda33
commit
d34f5c8039
|
@ -87,7 +87,7 @@ the `build` method of the `BuildPack` base class.
|
|||
|
||||
The **assemble** stage builds the specific environment that is requested by the repository.
|
||||
This usually means installing required libraries specified in a format native to the language
|
||||
(`requirements.txt`, `environment.yml`, `REQUIRE`, `install.R`, etc).
|
||||
(`requirements.txt`, `environment.yml`, `Project.toml`, `install.R`, etc).
|
||||
|
||||
Most of this work is done in `get_assemble_scripts` method. It can return arbitrary bash script
|
||||
lines that can be run as different users, and has access to the repository contents (unlike
|
||||
|
|
|
@ -102,14 +102,8 @@ of the Julia packages that are installed.
|
|||
``REQUIRE`` - Install a Julia environment (legacy)
|
||||
==================================================
|
||||
|
||||
A ``REQUIRE`` file can specify both the version of Julia to be used and
|
||||
which Julia packages should be used. The use of ``REQUIRE`` is only
|
||||
recommended for pre 1.0 Julia versions. The recommended way of installing
|
||||
a Julia environment that uses Julia 1.0 or newer is to use a ``Project.toml``
|
||||
file. If both a ``REQUIRE`` and a ``Project.toml`` file are detected,
|
||||
the ``REQUIRE`` file is ignored. To see an example of a Julia repository
|
||||
with ``REQUIRE`` and ``environment.yml``, visit
|
||||
`binder-examples/julia-python <https://github.com/binder-examples/julia-python>`_.
|
||||
``REQUIRE`` files no longer work, and are no longer supported.
|
||||
The recommended way of installing a Julia environment is to use a ``Project.toml`` file.
|
||||
|
||||
|
||||
.. _install.R:
|
||||
|
|
|
@ -57,7 +57,8 @@ Julia
|
|||
|
||||
All Julia versions since Julia 0.7.0 are supported via a :ref:`Project.toml <Project.toml>`
|
||||
file, and this is the recommended way to install Julia environments.
|
||||
Julia versions 0.6.x and earlier are supported via a :ref:`REQUIRE <REQUIRE>` file.
|
||||
|
||||
The older Julia REQUIRE file is no longer supported because required infrastructure has been removed.
|
||||
|
||||
R
|
||||
~
|
||||
|
|
|
@ -5,14 +5,14 @@ The Reproducible Execution Environment Specification
|
|||
====================================================
|
||||
|
||||
repo2docker scans a repository for particular :ref:`config-files`, such
|
||||
as ``requirements.txt`` or ``REQUIRE``. The collection of files, their contents,
|
||||
as ``requirements.txt`` or ``Project.toml``. The collection of files, their contents,
|
||||
and the resulting actions that repo2docker takes is known
|
||||
as the **Reproducible Execution Environment Specification** (or REES).
|
||||
|
||||
The goal of the REES is to automate and encourage existing community best practices
|
||||
for reproducible computational environments. This includes installing pacakges using
|
||||
community-standard specification files and their corresponding tools,
|
||||
such as ``requirements.txt`` (with ``pip``), ``REQUIRE`` (with Julia), or
|
||||
such as ``requirements.txt`` (with ``pip``), ``Project.toml`` (with Julia), or
|
||||
``apt.txt`` (with ``apt``). While repo2docker automates the
|
||||
creation of the environment, a human should be able to look at a REES-compliant
|
||||
repository and reproduce the environment using common, clear steps without
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
#!/bin/julia
|
||||
|
||||
# Path to potential REQUIRE file is passed on the command line.
|
||||
require_file = ARGS[1]
|
||||
|
||||
if VERSION < v"0.7-"
|
||||
pkg_dir = "$(ENV["JULIA_PKGDIR"])/v$(VERSION.major).$(VERSION.minor)"
|
||||
open("$pkg_dir/REQUIRE", "a") do io
|
||||
write(io, read(require_file))
|
||||
end
|
||||
Pkg.resolve();
|
||||
Reqs = Pkg.Reqs
|
||||
else
|
||||
using Pkg
|
||||
Reqs = Pkg.Pkg2.Reqs
|
||||
emptyversionlower = v"0.0.0-"
|
||||
for reqline in Reqs.read(require_file)
|
||||
if reqline isa Reqs.Requirement
|
||||
pkg = String(reqline.package)
|
||||
if pkg == "julia" continue end
|
||||
version = try; reqline.versions.intervals[1].lower; catch; emptyversionlower; end
|
||||
if version != emptyversionlower
|
||||
Pkg.add(PackageSpec(name=pkg, version=version))
|
||||
else
|
||||
Pkg.add(pkg)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
# Precompile the packages
|
||||
for reqline in Reqs.read(require_file)
|
||||
if reqline isa Reqs.Requirement
|
||||
pkg = reqline.package
|
||||
pkg != "julia" && eval(:(using $(Symbol(pkg))))
|
||||
end
|
||||
end
|
|
@ -1,205 +1,29 @@
|
|||
"""Generates a Dockerfile based on an input matrix with REQUIRE for legacy Julia"""
|
||||
"""
|
||||
DEPRECATED - Dependencies of REQUIRE have been removed
|
||||
"""
|
||||
|
||||
import os
|
||||
from functools import lru_cache
|
||||
|
||||
from ...semver import parse_version as V
|
||||
from ..python import PythonBuildPack
|
||||
|
||||
|
||||
class JuliaRequireBuildPack(PythonBuildPack):
|
||||
"""
|
||||
Julia build pack which uses conda and REQUIRE.
|
||||
|
||||
Now just an informative error message.
|
||||
"""
|
||||
|
||||
minor_julias = {"0.6": "0.6.4", "0.7": "0.7.0", "1.0": "1.0.4", "1.1": "1.1.1"}
|
||||
major_julias = {"1": "1.1.1"}
|
||||
|
||||
@property
|
||||
def python_version(self):
|
||||
# IJulia doesn't build on julia 0.6
|
||||
# due to old incompatibilities with Jupyter-core >= 4.5,
|
||||
# so use the similarly-old Python 3.5 base environment
|
||||
if V(self.julia_version) < V("0.7"):
|
||||
return "3.5"
|
||||
else:
|
||||
return super().python_version
|
||||
|
||||
@property
|
||||
def julia_version(self):
|
||||
require = self.binder_path("REQUIRE")
|
||||
try:
|
||||
with open(require) as f:
|
||||
julia_version_line = (
|
||||
f.readline().strip()
|
||||
) # First line is optionally a julia version
|
||||
except FileNotFoundError:
|
||||
julia_version_line = ""
|
||||
|
||||
if not julia_version_line.startswith("julia "):
|
||||
# not a Julia version line.
|
||||
# use the default Julia.
|
||||
self._julia_version = self.minor_julias["0.6"]
|
||||
return self._julia_version
|
||||
|
||||
julia_version_info = julia_version_line.split(" ", 1)[1].split(".")
|
||||
julia_version = ""
|
||||
if len(julia_version_info) == 1:
|
||||
julia_version = self.major_julias[julia_version_info[0]]
|
||||
elif len(julia_version_info) == 2:
|
||||
# get major.minor
|
||||
julia_version = self.minor_julias[".".join(julia_version_info)]
|
||||
else:
|
||||
# use supplied julia version
|
||||
julia_version = ".".join(julia_version_info)
|
||||
self._julia_version = julia_version
|
||||
return self._julia_version
|
||||
|
||||
@lru_cache()
|
||||
def get_build_env(self):
|
||||
"""Get additional environment settings for Julia and Jupyter
|
||||
|
||||
Returns:
|
||||
an ordered list of environment setting tuples
|
||||
|
||||
The tuples contain a string of the environment variable name and
|
||||
a string of the environment setting:
|
||||
- `JULIA_PATH`: base path where all Julia Binaries and libraries
|
||||
will be installed
|
||||
- `JULIA_HOME`: path where all Julia Binaries will be installed
|
||||
- `JULIA_PKGDIR`: path where all Julia libraries will be installed
|
||||
- `JULIA_DEPOT_PATH`: path where Julia libraries are installed.
|
||||
Similar to JULIA_PKGDIR, used in 1.x.
|
||||
- `JULIA_VERSION`: default version of julia to be installed
|
||||
- `JULIA_ARCH`: machine architecture used in Julia download URLs
|
||||
- `JULIA_ARCH_SHORT`: machine architecture used in Julia download URLs
|
||||
- `JUPYTER`: environment variable required by IJulia to point to
|
||||
the `jupyter` executable
|
||||
|
||||
For example, a tuple may be `('JULIA_VERSION', '0.6.0')`.
|
||||
|
||||
"""
|
||||
if self.platform == "linux/arm64":
|
||||
julia_arch = julia_arch_short = "aarch64"
|
||||
else:
|
||||
julia_arch = "x86_64"
|
||||
julia_arch_short = "x64"
|
||||
|
||||
if V(self.julia_version) < V("0.7"):
|
||||
# IJulia with Julia 0.6 isn't compatible with more recent jupyter-core
|
||||
# point it to the one in the kernel env
|
||||
# I _think_ this is only relevant during installation
|
||||
jupyter = "${KERNEL_PYTHON_PREFIX}/bin/jupyter"
|
||||
else:
|
||||
jupyter = "${NB_PYTHON_PREFIX}/bin/jupyter"
|
||||
return super().get_build_env() + [
|
||||
("JULIA_PATH", "${APP_BASE}/julia"),
|
||||
("JULIA_HOME", "${JULIA_PATH}/bin"), # julia <= 0.6
|
||||
("JULIA_BINDIR", "${JULIA_HOME}"), # julia >= 0.7
|
||||
("JULIA_PKGDIR", "${JULIA_PATH}/pkg"),
|
||||
("JULIA_DEPOT_PATH", "${JULIA_PKGDIR}"), # julia >= 0.7
|
||||
("JULIA_VERSION", self.julia_version),
|
||||
("JULIA_ARCH", julia_arch),
|
||||
("JULIA_ARCH_SHORT", julia_arch_short),
|
||||
("JUPYTER", jupyter),
|
||||
]
|
||||
|
||||
@lru_cache()
|
||||
def get_path(self):
|
||||
"""Adds path to Julia binaries to user's PATH.
|
||||
|
||||
Returns:
|
||||
an ordered list of path strings. The path to the Julia
|
||||
executable is added to the list.
|
||||
|
||||
"""
|
||||
return super().get_path() + ["${JULIA_HOME}"]
|
||||
|
||||
@lru_cache()
|
||||
def get_build_scripts(self):
|
||||
"""
|
||||
Return series of build-steps common to "ALL" Julia repositories
|
||||
|
||||
All scripts found here should be independent of contents of a
|
||||
particular repository.
|
||||
|
||||
This creates a directory with permissions for installing julia packages
|
||||
(from get_assemble_scripts).
|
||||
|
||||
"""
|
||||
return super().get_build_scripts() + [
|
||||
(
|
||||
"root",
|
||||
r"""
|
||||
mkdir -p ${JULIA_PATH} && \
|
||||
curl -sSL "https://julialang-s3.julialang.org/bin/linux/${JULIA_ARCH_SHORT}/${JULIA_VERSION%[.-]*}/julia-${JULIA_VERSION}-linux-${JULIA_ARCH}.tar.gz" | tar -xz -C ${JULIA_PATH} --strip-components 1
|
||||
""",
|
||||
),
|
||||
(
|
||||
"root",
|
||||
r"""
|
||||
mkdir -p ${JULIA_PKGDIR} && \
|
||||
chown ${NB_USER}:${NB_USER} ${JULIA_PKGDIR}
|
||||
""",
|
||||
),
|
||||
(
|
||||
"${NB_USER}",
|
||||
# HACK: Can't seem to tell IJulia to install in sys-prefix
|
||||
# FIXME: Find way to get it to install under /srv and not $HOME?
|
||||
r"""
|
||||
julia -e 'if (VERSION > v"0.7-") using Pkg; else Pkg.init(); end; Pkg.add("IJulia"); using IJulia;' && \
|
||||
mv ${HOME}/.local/share/jupyter/kernels/julia-${JULIA_VERSION%[.-]*} ${NB_PYTHON_PREFIX}/share/jupyter/kernels/julia-${JULIA_VERSION%[.-]*}
|
||||
""",
|
||||
),
|
||||
]
|
||||
|
||||
@lru_cache()
|
||||
def get_assemble_scripts(self):
|
||||
"""
|
||||
Return series of build-steps specific to "this" Julia repository
|
||||
|
||||
Precompile all Julia libraries found in the repository's REQUIRE
|
||||
file. The parent, CondaBuildPack, will add the build steps for
|
||||
any needed Python packages found in environment.yml.
|
||||
|
||||
"""
|
||||
require = self.binder_path("REQUIRE")
|
||||
return super().get_assemble_scripts() + [
|
||||
(
|
||||
"${NB_USER}",
|
||||
# Install and pre-compile all libraries if they've opted into it.
|
||||
# In v0.6, Pkg.resolve() installs all the packages, but in v0.7+, we
|
||||
# have to manually Pkg.add() each of them (since the REQUIRES file
|
||||
# format is deprecated).
|
||||
# The precompliation is done via `using {libraryname}`.
|
||||
r"""
|
||||
julia /tmp/install-repo-dependencies.jl "%(require)s"
|
||||
"""
|
||||
% {"require": require},
|
||||
# TODO: For some reason, `rm`ing the file fails with permission denied.
|
||||
# && rm /tmp/install-repo-dependencies.jl
|
||||
)
|
||||
]
|
||||
|
||||
@lru_cache()
|
||||
def get_build_script_files(self):
|
||||
files = {
|
||||
"julia/install-repo-dependencies.jl": "/tmp/install-repo-dependencies.jl"
|
||||
}
|
||||
files.update(super().get_build_script_files())
|
||||
return files
|
||||
def build(self, *args, **kwargs):
|
||||
raise ValueError(
|
||||
"Julia REQUIRE no longer supported due to removed infrastructure. Use Project.toml."
|
||||
)
|
||||
|
||||
def detect(self):
|
||||
"""
|
||||
Check if current repo should be built with the Julia Legacy Build pack
|
||||
|
||||
super().detect() is not called in this function - it would return
|
||||
false unless an `environment.yml` is present and we do not want to
|
||||
require the presence of a `environment.yml` to use Julia.
|
||||
|
||||
Instead we just check if the path to `REQUIRE` exists and that there is
|
||||
no julia 1.0 style environment
|
||||
Check if current repo exects tp be built with the Julia Legacy Build pack
|
||||
|
||||
This no longer works, but try to raise an informative error.
|
||||
"""
|
||||
return os.path.exists(self.binder_path("REQUIRE")) and not (
|
||||
os.path.exists(self.binder_path("Project.toml"))
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
julia 1
|
||||
|
||||
# Julia packages:
|
||||
PyCall
|
||||
PyPlot
|
|
@ -1 +0,0 @@
|
|||
matplotlib
|
|
@ -1,34 +0,0 @@
|
|||
#!/usr/bin/env julia
|
||||
using PyCall
|
||||
using PyPlot
|
||||
|
||||
if ! (VERSION >= v"1" && VERSION < v"2")
|
||||
println("Julia version was: ", VERSION)
|
||||
println("Julia version expected to be 1.x when pinned to 1 in a REQUIRE file")
|
||||
exit(1)
|
||||
end
|
||||
|
||||
# Make sure we are re-using the same conda python
|
||||
if ! startswith(PyCall.libpython, ENV["NB_PYTHON_PREFIX"] * "/lib")
|
||||
println("Not re-using conda python! Using " * PyCall.libpython * " instead")
|
||||
exit(1)
|
||||
end
|
||||
|
||||
# We check that PyPlot is installed inside ${JULIA_DEPOT_PATH}
|
||||
if ! isdir(ENV["JULIA_DEPOT_PATH"] * "/packages/PyPlot")
|
||||
println("PyPlot not installed under JULIA_DEPOT_PATH")
|
||||
exit(1)
|
||||
end
|
||||
|
||||
# FIXME: Julia code that worked before v1, but now fails with:
|
||||
#
|
||||
# ERROR: LoadError: UndefVarError: linspace not defined
|
||||
#
|
||||
# x = linspace(0,2*pi,1000); y = sin(3*x + 4*cos(2*x))
|
||||
# plot(x, y, color="red", linewidth=2.0, linestyle="--")
|
||||
# savefig("graph.png")
|
||||
# if isfile("graph.png")
|
||||
# exit(0)
|
||||
# else
|
||||
# exit(1)
|
||||
# end
|
|
@ -1,2 +0,0 @@
|
|||
# Julia packages:
|
||||
Compat
|
|
@ -1,19 +0,0 @@
|
|||
#!/usr/bin/env julia
|
||||
|
||||
if VERSION != v"0.6.4"
|
||||
println("Julia version was: ", VERSION)
|
||||
println("Default Julia version expected to be 0.6.4 when unspecified in a REQUIRE file")
|
||||
exit(1)
|
||||
end
|
||||
|
||||
try
|
||||
# Test that the package was installed.
|
||||
using Compat
|
||||
|
||||
# Verify that the environment variables are set correctly for julia < 0.7
|
||||
@assert "julia" ∈ readdir(Base.JULIA_HOME)
|
||||
catch
|
||||
exit(1)
|
||||
end
|
||||
|
||||
exit(0)
|
Ładowanie…
Reference in New Issue