Commits (14)
......@@ -533,6 +533,7 @@ for lib in "\$SAGE_ROOT/build/bin/sage-dist-helpers" "\$SAGE_SRC/bin/sage-env-co
exit 1
fi
done
export PATH="$SAGE_INST_LOCAL/bin:$PATH"
export SAGE_INST_LOCAL="$SAGE_INST_LOCAL"
......@@ -701,7 +702,7 @@ rm -f "$SAGE_DESTDIR_LOCAL/lib64"
# All spkgs should eventually support this, but fall back on old behavior in
# case DESTDIR=$SAGE_DESTDIR installation was not used
echo "Copying package files from temporary location $SAGE_DESTDIR to $SAGE_LOCAL"
echo "Copying package files from temporary location $SAGE_DESTDIR to $SAGE_INST_LOCAL"
if [ -d "$SAGE_DESTDIR" ]; then
# Some `find` implementations will put superfluous slashes in the
# output if we give them a directory name with a slash; so make sure
......@@ -717,8 +718,8 @@ if [ -d "$SAGE_DESTDIR" ]; then
# Generate installed file manifest
FILE_LIST="$(cd "$PREFIX" && find . -type f -o -type l | sed 's|^\./||' | sort)"
# Copy files into $SAGE_LOCAL
$SAGE_SUDO cp -Rp "$PREFIX/." "$SAGE_LOCAL"
# Copy files into $SAGE_INST_LOCAL
$SAGE_SUDO cp -Rp "$PREFIX/." "$SAGE_INST_LOCAL"
if [ $? -ne 0 ]; then
error_msg "Error copying files for $PKG_NAME."
exit 1
......@@ -784,7 +785,7 @@ fi
# Note: spkg-check tests are run after the package has been copied into
# SAGE_LOCAL. It might make more sense to run the tests before, but the
# SAGE_INST_LOCAL. It might make more sense to run the tests before, but the
# spkg-check scripts were written before use of DESTDIR installs, and so
# fail in many cases. This might be good to change later.
......
......@@ -26,10 +26,8 @@ $(error This Makefile needs to be invoked by build/make/install)
endif
endif
# Directory to keep track of which packages are installed
SAGE_SPKG_INST = $(SAGE_LOCAL)/var/lib/sage/installed
INST = $(SAGE_SPKG_INST)
# Directory to keep track of which packages are installed - relative to installation prefix
SPKG_INST_RELDIR = var/lib/sage/installed
# Aliases for mutually exclusive standard packages selected at configure time
TOOLCHAIN = @SAGE_TOOLCHAIN@
......@@ -54,6 +52,10 @@ SAGE_SPKG = sage-spkg
# These are added to SAGE_SPKG in the call
SAGE_SPKG_OPTIONS = @SAGE_SPKG_OPTIONS@
# Where the Sage distribution installs Python packages.
# This can be overridden by 'make SAGE_VENV=/some/venv'.
SAGE_VENV = @SAGE_VENV@
# Generate/install sage-specific .pc files.
# see build/pkgs/gsl/spkg-configure.m4
$(SAGE_PKGCONFIG)/gsl.pc:
......@@ -140,10 +142,9 @@ SCRIPT_PACKAGES = @SAGE_SCRIPT_PACKAGES@
# inst_git = $(INST)/.dummy
$(foreach pkgname,$(BUILT_PACKAGES),\
$(eval inst_$(pkgname) = $$(INST)/$(pkgname)-$(vers_$(pkgname))))
$(eval inst_$(pkgname) = $(foreach tree, $(trees_$(pkgname)), $($(tree))/$(SPKG_INST_RELDIR)/$(pkgname)-$(vers_$(pkgname)))))
$(foreach pkgname,$(DUMMY_PACKAGES),\
$(eval inst_$(pkgname) = $$(INST)/.dummy))
$(eval inst_$(pkgname) = $(SAGE_LOCAL)/$(SPKG_INST_RELDIR)/.dummy))
# Override this for pip packages, for which we do not keep an installation record
# in addition to what pip is already doing.
......@@ -151,7 +152,7 @@ $(foreach pkgname,$(PIP_PACKAGES),\
$(eval inst_$(pkgname) = $(pkgname)))
# Dummy target for packages which are not installed
$(INST)/.dummy:
$(SAGE_LOCAL)/$(SPKG_INST_RELDIR)/.dummy:
touch $@
......@@ -206,10 +207,10 @@ ifneq ($(PYTHON_FOR_VENV),)
ifeq ($(PYTHON),python3)
PYTHON = python3_venv
endif
inst_python3_venv = $(SAGE_LOCAL)/pyvenv.cfg
inst_python3_venv = $(SAGE_VENV)/pyvenv.cfg
$(inst_python3_venv):
$(PYTHON_FOR_VENV) $(SAGE_ROOT)/build/bin/sage-venv "$(SAGE_LOCAL)"
$(PYTHON_FOR_VENV) $(SAGE_ROOT)/build/bin/sage-venv "$(SAGE_VENV)"
endif
# Build everything and start Sage.
......@@ -521,37 +522,44 @@ pkg_deps = \
# $(1): package name
# $(2): package version
# $(3): package dependencies
# $(4): package tree variable
define NORMAL_PACKAGE_templ ##########################################
$(1)-build-deps: $(3)
$$(INST)/$(1)-$(2): $(3)
+$(MAKE_REC) $(1)-no-deps
$$($(4))/$(SPKG_INST_RELDIR)/$(1)-$(2): $(3)
+$(MAKE_REC) $(1)-$(4)-no-deps
$(1): $$(INST)/$(1)-$(2)
$(1): $$($(4))/$(SPKG_INST_RELDIR)/$(1)-$(2)
$(1)-no-deps:
+$(AM_V_at)sage-logger -p 'SAGE_CHECK=$$(SAGE_CHECK_$(1)) $$(SAGE_SPKG) $$(SAGE_SPKG_OPTIONS) \
$(1)-$(4)-no-deps:
+$(AM_V_at)sage-logger -p 'SAGE_CHECK=$$(SAGE_CHECK_$(1)) PATH=$$($(4))/bin:$$$$PATH $$(SAGE_SPKG) $$(SAGE_SPKG_OPTIONS) \
$(if $(filter $(1),$(TOOLCHAIN_DEPS)),--keep-existing) \
$(1)-$(2)' '$$(SAGE_LOGS)/$(1)-$(2).log'
$(1)-$(2) $$($(4))' '$$(SAGE_LOGS)/$(1)-$(2).log'
$(1)-clean:
$(1)-no-deps: $(1)-$(4)-no-deps
$(1)-$(4)-clean:
sage-spkg-uninstall $(if $(filter $(1),$(TOOLCHAIN_DEPS)),--keep-files) \
$(1) '$(SAGE_LOCAL)'
$(1) '$$($(4))'
$(1)-clean: $(1)-$(4)-clean
.PHONY: $(1) $(1)-clean $(1)-build-deps $(1)-no-deps
endef #################################################################
$(foreach pkgname, $(NORMAL_PACKAGES),\
$(foreach tree, $(trees_$(pkgname)), \
$(eval $(call NORMAL_PACKAGE_templ,$(pkgname),$(vers_$(pkgname)),\
$(call pkg_deps,$(pkgname)))))
$(call pkg_deps,$(pkgname)),$(tree)))))
ifdef DEBUG_RULES
$(info # Rules for standard packages)
$(foreach pkgname, $(NORMAL_PACKAGES),\
$(foreach tree, $(trees_$(pkgname)), \
$(info $(call NORMAL_PACKAGE_templ,$(pkgname),$(vers_$(pkgname)),\
$(call pkg_deps,$(pkgname)))))
$(call pkg_deps,$(pkgname)),$(tree)))))
endif
# ================================ pip packages ===============================
......@@ -617,44 +625,54 @@ endif
# $(1): package name
# $(2): package version
# $(3): package dependencies
# $(4): package tree variable
define SCRIPT_PACKAGE_templ
$(1)-build-deps: $(3)
$$(INST)/$(1)-$(2): $(3)
+$(MAKE_REC) $(1)-no-deps
$$($(4))/$(SPKG_INST_RELDIR)/$(1)-$(2): $(3)
+$(MAKE_REC) $(1)-$(4)-no-deps
$(1): $$(INST)/$(1)-$(2)
$(1): $$($(4))/$(SPKG_INST_RELDIR)/$(1)-$(2)
$(1)-no-deps:
$(1)-$(4)-no-deps:
$(AM_V_at)cd '$$(SAGE_ROOT)/build/pkgs/$(1)' && \
. '$$(SAGE_ROOT)/src/bin/sage-src-env-config' && \
. '$$(SAGE_ROOT)/src/bin/sage-env-config' && \
. '$$(SAGE_ROOT)/src/bin/sage-env' && \
. '$$(SAGE_ROOT)/build/bin/sage-build-env-config' && \
. '$$(SAGE_ROOT)/build/bin/sage-build-env' && \
SAGE_SPKG_WHEELS=$$(SAGE_LOCAL)/var/lib/sage/wheels \
SAGE_INST_LOCAL=$$(SAGE_LOCAL) \
SAGE_SPKG_WHEELS=$$($(4))/var/lib/sage/wheels \
SAGE_INST_LOCAL=$$($(4)) \
sage-logger -p '$$(SAGE_ROOT)/build/pkgs/$(1)/spkg-install' '$$(SAGE_LOGS)/$(1)-$(2).log'
touch "$$(INST)/$(1)-$(2)"
touch "$$($(4))/$(SPKG_INST_RELDIR)/$(1)-$(2)"
$(1)-no-deps: $(1)-$(4)-no-deps
$(1)-uninstall:
$(1)-$(4)-uninstall:
-$(AM_V_at)cd '$$(SAGE_ROOT)/build/pkgs/$(1)' && \
. '$$(SAGE_ROOT)/src/bin/sage-src-env-config' && \
. '$$(SAGE_ROOT)/src/bin/sage-env-config' && \
. '$$(SAGE_ROOT)/src/bin/sage-env' && \
. '$$(SAGE_ROOT)/build/bin/sage-build-env-config' && \
. '$$(SAGE_ROOT)/build/bin/sage-build-env' && \
'$$(SAGE_ROOT)/build/pkgs/$(1)/spkg-uninstall'
-rm -f "$$(INST)/$(1)-$(2)"
-rm -f "$$($(4))/$(SPKG_INST_RELDIR)/$(1)-$(2)"
$(1)-uninstall: $(1)-$(4)-uninstall
.PHONY: $(1) $(1)-uninstall $(1)-build-deps $(1)-no-deps $(1)-clean
endef
$(foreach pkgname,$(SCRIPT_PACKAGES),\
$(eval $(call SCRIPT_PACKAGE_templ,$(pkgname),$(vers_$(pkgname)),$(call pkg_deps,$(pkgname)))))
$(foreach tree, $(trees_$(pkgname)), \
$(eval $(call SCRIPT_PACKAGE_templ,$(pkgname),$(vers_$(pkgname)),$(call pkg_deps,$(pkgname)),$(tree)))))
ifdef DEBUG_RULES
$(info # Rules for script packages)
$(foreach pkgname,$(SCRIPT_PACKAGES),\
$(info $(call SCRIPT_PACKAGE_templ,$(pkgname),$(vers_$(pkgname)),$(call pkg_deps,$(pkgname)))))
$(foreach tree, $(trees_$(pkgname)), \
$(info $(call SCRIPT_PACKAGE_templ,$(pkgname),$(vers_$(pkgname)),$(call pkg_deps,$(pkgname)),$(tree)))))
endif
# sagelib depends on this so that its install script is always executed
......
$(INST)/nauty-$(vers_nauty)
$(SAGE_LOCAL)/$(SPKG_INST_RELDIR)/nauty-$(vers_nauty)
----------
All lines of this file are ignored except the first.
......
......@@ -74,6 +74,13 @@ fi
SAGE_SRC="$SAGE_ROOT/src"
SAGE_SPKG_INST="$SAGE_LOCAL/var/lib/sage/installed"
AC_ARG_WITH([sage-venv],
[AS_HELP_STRING([--with-sage-venv=SAGE_VENV],
[put Python packages into an installation hierarchy separate from prefix])],
[SAGE_VENV="$withval"],
[SAGE_VENV='${SAGE_LOCAL}'])dnl Quoted so that it is resolved at build time by shell/Makefile
AC_SUBST([SAGE_VENV])
#---------------------------------------------------------
AC_ARG_ENABLE([build-as-root],
......
......@@ -147,6 +147,7 @@ if [ -x "${SELF}-config" ]; then
fi
if [ -f "${SELF}-src-env-config" ]; then
# Not installed script, present only in src/bin/
SAGE_SRC_ENV_CONFIG=1
. "${SELF}-src-env-config" >&2
fi
if [ -z "$SAGE_VENV" -a -x "${SELF}-venv-config" ]; then
......@@ -309,7 +310,7 @@ fi
# Prepare for running Sage, either interactively or non-interactively.
sage_setup() {
# Check that we're not in a source tarball which hasn't been built yet (#13561).
if [ ! -z "$SAGE_LOCAL" ] && [ ! -x "$SAGE_LOCAL/bin/sage" ]; then
if [ "$SAGE_SRC_ENV_CONFIG" = 1 ] && [ ! -z "$SAGE_VENV" ] && [ ! -x "$SAGE_VENV/bin/sage" ]; then
echo >&2 '************************************************************************'
echo >&2 'It seems that you are attempting to run Sage from an unpacked source'
echo >&2 'tarball, but you have not compiled it yet (or maybe the build has not'
......@@ -339,7 +340,7 @@ sage_setup() {
maybe_sage_location()
{
if [ -n "$SAGE_LOCAL" -a -w "$SAGE_LOCAL" ]; then
if [ -x "$SAGE_LOCAL/bin/python" ] && [ -x "$SAGE_LOCAL/bin/sage-location" ]; then
if [ -x "$SAGE_VENV/bin/python" ] && [ -x "$SAGE_VENV/bin/sage-location" ]; then
sage-location || exit $?
fi
fi
......
......@@ -32,8 +32,8 @@
export SAGE_LOCAL="@prefix@"
# SAGE_VENV is the root of the virtual environment of sagelib.
# Currently, it is identical to SAGE_LOCAL
export SAGE_VENV="@prefix@"
# By default, it is identical to SAGE_LOCAL
export SAGE_VENV="@SAGE_VENV@"
# SAGE_ROOT is the location of the Sage source/build tree.
export SAGE_ROOT="@SAGE_ROOT@"
......@@ -169,6 +169,7 @@ SAGE_VERSION_BANNER = var("SAGE_VERSION_BANNER", version.banner)
SAGE_VENV = var("SAGE_VENV", os.path.abspath(sys.prefix))
SAGE_LIB = var("SAGE_LIB", os.path.dirname(os.path.dirname(sage.__file__)))
SAGE_EXTCODE = var("SAGE_EXTCODE", join(SAGE_LIB, "sage", "ext_data"))
SAGE_VENV_SPKG_INST = var("SAGE_VENV_SPKG_INST", join(SAGE_VENV, "var", "lib", "sage", "installed"))
# prefix hierarchy where non-Python packages are installed
SAGE_LOCAL = var("SAGE_LOCAL", SAGE_VENV)
......
......@@ -47,6 +47,7 @@ import json
import os
import subprocess
import sys
from pathlib import Path
from urllib.request import urlopen
from urllib.error import URLError
......@@ -317,6 +318,28 @@ def list_packages(*pkg_types, **opts):
return pkgs
def _spkg_inst_dirs():
"""
Generator for the installation manifest directories as resolved paths.
It yields first ``SAGE_SPKG_INST``, then ``SAGE_VENV_SPKG_INST``,
if defined; but it both resolve to the same directory, it only yields
one element.
EXAMPLES::
sage: from sage.misc.package import _spkg_inst_dirs
sage: list(_spkg_inst_dirs())
[...]
"""
last_inst_dir = None
for inst_dir in (sage.env.SAGE_SPKG_INST, sage.env.SAGE_VENV_SPKG_INST):
if inst_dir:
inst_dir = Path(inst_dir).resolve()
if inst_dir.is_dir() and inst_dir != last_inst_dir:
yield inst_dir
last_inst_dir = inst_dir
def installed_packages(exclude_pip=True):
"""
......@@ -344,10 +367,10 @@ def installed_packages(exclude_pip=True):
if not exclude_pip:
installed.update(pip_installed_packages(normalization='spkg'))
# Sage packages should override pip packages (Trac #23997)
SAGE_SPKG_INST = sage.env.SAGE_SPKG_INST
if SAGE_SPKG_INST:
for inst_dir in _spkg_inst_dirs():
try:
lp = os.listdir(SAGE_SPKG_INST)
lp = os.listdir(inst_dir)
installed.update(pkgname_split(pkgname) for pkgname in lp
if not pkgname.startswith('.'))
except FileNotFoundError:
......@@ -558,12 +581,15 @@ def package_manifest(package):
KeyError: 'dummy-package'
"""
version = installed_packages()[package]
stamp_file = os.path.join(sage.env.SAGE_SPKG_INST,
'{}-{}'.format(package, version))
with open(stamp_file) as f:
spkg_meta = json.load(f)
return spkg_meta
for inst_dir in _spkg_inst_dirs():
stamp_file = os.path.join(inst_dir,
'{}-{}'.format(package, version))
try:
with open(stamp_file) as f:
return json.load(f)
except FileNotFoundError:
pass
raise RuntimeError('package manifest directory changed at runtime')
class PackageNotFoundError(RuntimeError):
"""
......