diff --git a/build/bin/sage-spkg b/build/bin/sage-spkg index b540c8e866f..19553b3c139 100755 --- a/build/bin/sage-spkg +++ b/build/bin/sage-spkg @@ -9,21 +9,7 @@ # # sage-spkg [] # -# Options can be: -# -s: do not delete temporary build directory -# -k: do not uninstall existing installation of this package before -# installing; instead simply overwrite existing files. -# -c: after installing, run the test suite for the spkg. This should -# override the settings of SAGE_CHECK. -# Exit with an error if the test suite fails. -# -w: after installing, run the test suite for the spkg. This should -# override the settings of SAGE_CHECK. -# Print a warning if the test suite fails. -# -d: only download the package -# -y: automatically reply "y" for all prompts regarding -# experimental and old-style packages -# -n: automatically reply "n" for all prompts regarding -# experimental and old-style packages +# Options: see usage() below. # # A package may assume that the following environment # variables are defined: @@ -89,13 +75,22 @@ Usage: sage {-i|-p} Search Sage's list of packages (see 'sage --package list') for a matching package, and if a match is found, install it. -Options: - -s: do not delete the temporary build directory - -c: after installing, run the test suite for the package; - exit with an error on test suite failures - -w: after installing, run the test suite for the package; - print a warning on test suite failures - -d: only download the package +Modes of operation (provide at most one): + -d, --download-only: only download the package + -b, --build-and-stage-only: build and install (stage) only, + do not run post-install or check + -p, --post-install-only: unload the staged installation + directory and run other post-installation steps only + -x, --check-only: exclusively run the test suite; + this may assume that: + * the package has been installed already and/or that + * the temporary build directory has not been deleted + -e, --erase-build-directory-only: erase (delete) the temporary + build directory only + --info: print information on the package only + --help: print this help only + +Other options: -y: automatically reply "y" for all prompts regarding experimental and old-style packages; warning: there is no guarantee that these packages will build correctly; @@ -104,6 +99,12 @@ Options: experimental and old-style packages -o: allow fetching the package from its upstream URL when it is not available from the Sage mirrors (yet) + -c: after installing, run the test suite for the package; + exit with an error on test suite failures + -w: after installing, run the test suite for the package; + print a warning on test suite failures + -s: save (do not delete) the temporary build directory, + even when the installation was successful EOF } @@ -230,15 +231,24 @@ fi INFO=0 YES=0 KEEP_EXISTING=0 +INSTALL=1 +POST_INSTALL=1 +ERASE_ONLY=0 +MODE_SWITCHES= while true; do case "$1" in --info) + MODE_SWITCHES+=", $1" INFO=1;; + --help) + usage + exit 0;; -y) YES=1;; -n) YES=-1;; - -d) + -d|--download-only) + MODE_SWITCHES+=", $1" SAGE_INSTALL_FETCH_ONLY=1;; -s) export SAGE_KEEP_BUILT_SPKGS=yes;; @@ -246,8 +256,20 @@ while true; do export SAGE_CHECK=yes;; -w|--check-warning-only) export SAGE_CHECK=warn;; + -b|--build-and-stage-only) + MODE_SWITCHES+=", $1" + POST_INSTALL=0; export SAGE_CHECK=no;; + -p|--post-install-only) + MODE_SWITCHES+=", $1" + INSTALL=0; export SAGE_CHECK=no;; + -x|--check-only) + MODE_SWITCHES+=", $1" + INSTALL=0; POST_INSTALL=0; export SAGE_CHECK=yes;; -k|--keep-existing) KEEP_EXISTING=yes;; + -e|--erase-build-directory-only) + MODE_SWITCHES+=", $1" + ERASE_ONLY=1;; -o|--allow-upstream) SAGE_DOWNLOAD_FILE_OPTIONS+=" --allow-upstream";; -*) @@ -257,11 +279,15 @@ while true; do esac shift done - - -################################################################## -# Figure out the package filename, download it if needed. -################################################################## +MODE_SWITCHES=${MODE_SWITCHES#, } +case "$MODE_SWITCHES" in + *,*) + echo >&2 "Error: at most one of the mode switches may be given, got $MODE_SWITCHES" + echo >&2 + usage + exit 1 + ;; +esac # One should be able to install a package using # sage -i @@ -313,8 +339,23 @@ fi PKG_BASE_VER=`echo $PKG_VER | sed 's/\.p[0-9][0-9]*$//'` PKG_NAME_UPSTREAM=`lookup_param tarball "$PKG_SCRIPTS/checksums.ini" | sed "s/VERSION/$PKG_BASE_VER/"` -# Warning for experimental packages -if [ x`cat "$PKG_SCRIPTS/type"` = x"experimental" -a $INFO = 0 ]; then +# Set the $SAGE_DESTDIR variable to be passed to the spkg-install +# script (the script itself could set this, but better to standardize +# this in one place) +export SAGE_DESTDIR="${SAGE_BUILD_DIR}/${PKG_NAME}/inst" + +# The actual prefix where the installation will be staged. This is the +# directory that you need to work in if you want to change the staged +# installation tree (before final installation to $SAGE_INST_LOCAL) at the +# end of spkg-install. +export SAGE_DESTDIR_LOCAL="${SAGE_DESTDIR}${SAGE_INST_LOCAL}" + +INSTALLED_SCRIPTS="prerm piprm postrm" +WRAPPED_SCRIPTS="build install check preinst postinst $INSTALLED_SCRIPTS" + + +warning_for_experimental_packages() { ############################ +if [ x`cat "$PKG_SCRIPTS/type"` = x"experimental" ]; then if [ $YES != 1 ]; then # We use /dev/tty here because our output may be redirected # to a logfile, or line-buffered. @@ -344,11 +385,9 @@ EOF echo > /dev/tty "OK, installing $PKG_NAME now..." fi fi +} ############################## warning_for_experimental_packages -if [ $INFO -ne 0 ]; then - exec sage-spkg-info $PKG_BASE -fi - +ensure_pkg_src() { ############################################### # If we haven't found the package yet, we must download it if [ ! -f "$PKG_SRC" ]; then if [ -n "$PKG_NAME_UPSTREAM" ]; then @@ -385,13 +424,9 @@ if [ -n "$SAGE_SPKG_COPY_UPSTREAM" ]; then exit 1 fi fi -if [ -n "$SAGE_INSTALL_FETCH_ONLY" ]; then - exit 0 -fi +} ################################################# ensure_pkg_src -################################################################## -# Setup directories -################################################################## +setup_directories() { ############################################ for dir in "$SAGE_SPKG_INST" "$SAGE_SPKG_SCRIPTS" "$SAGE_BUILD_DIR"; do mkdir -p "$dir" @@ -442,15 +477,19 @@ if [ -e "$PKG_NAME" ]; then error_msg "Error (re)moving $PKG_NAME" exit 1 fi +} ############################################## setup_directories -################################################################## -# Extract the package -################################################################## +extract_the_package() { ########################################## +cd "$SAGE_BUILD_DIR" || exit $? echo "Setting up build directory for $PKG_NAME" cp -RLp "$PKG_SCRIPTS" "$PKG_NAME" cd "$PKG_NAME" || exit $? +if [ "$SAGE_KEEP_BUILT_SPKGS" = "yes" ]; then + touch .keep +fi + case "$PKG_SRC" in *.whl) # (Platform-independent) wheel @@ -476,10 +515,10 @@ case "$PKG_SRC" in cd .. ;; esac +} ############################################ extract_the_package -################################################################## -# The package has been extracted, prepare for installation -################################################################## +# The package has been extracted, +prepare_for_installation() { ##################################### # Rewrites the given bash pseudo-script with a boilerplate header that includes # the shebang line and sourcing sage-env. Make sure the name of the script is @@ -542,10 +581,6 @@ __EOF__ trap - ERR } - -INSTALLED_SCRIPTS="prerm piprm postrm" -WRAPPED_SCRIPTS="build install check preinst postinst $INSTALLED_SCRIPTS" - # Prepare script for uninstallation of packages that use sdh_pip_install # or sdh_store_and_pip_install_wheel. echo 'sdh_pip_uninstall -r $SAGE_SPKG_SCRIPTS/$PKG_BASE/spkg-requirements.txt' > spkg-piprm.in @@ -566,6 +601,9 @@ for script in $WRAPPED_SCRIPTS; do write_script_wrapper "$(pwd)/$script" "$script_dir" fi done +} ####################################### prepare_for_installation + +actually_build_and_install() { ################################### echo "****************************************************" echo "Host system:" @@ -576,15 +614,12 @@ echo "C compiler version:" $CC -v echo "****************************************************" -################################################################## # Poison the proxy variable to forbid downloads in spkg-install -################################################################## export http_proxy=http://192.0.2.0:5187/ export https_proxy=$http_proxy export ftp_proxy=$http_proxy export rsync_proxy=$http_proxy -################################################################## # We need to run sage-rebase.sh for each package installed, but it # can be dangerous to do this while other packages are installing # so we need to use a lock to manage when rebase is allowed to @@ -594,8 +629,6 @@ export rsync_proxy=$http_proxy # that. This also unfortunately slows down parallel builds since # all packages will eventually need to wait for this lock, but # again there's no simple way around that. -################################################################## - if [ "$UNAME" = "CYGWIN" ]; then # This is a global lock - so we use SAGE_LOCAL, not SAGE_INST_LOCAL. if [ ! -d "$SAGE_LOCAL/var/lock" ]; then @@ -605,21 +638,6 @@ if [ "$UNAME" = "CYGWIN" ]; then sage-flock -s $lock_type 200 fi -################################################################## -# Actually install -################################################################## - -# Set the $SAGE_DESTDIR variable to be passed to the spkg-install -# script (the script itself could set this, but better to standardize -# this in one place) -export SAGE_DESTDIR="${SAGE_BUILD_DIR}/${PKG_NAME}/inst" - -# The actual prefix where the installation will be staged. This is the -# directory that you need to work in if you want to change the staged -# installation tree (before final installation to $SAGE_INST_LOCAL) at the -# end of spkg-install. -export SAGE_DESTDIR_LOCAL="${SAGE_DESTDIR}${SAGE_INST_LOCAL}" - # First uninstall the previous version of this package, if any if [ "$KEEP_EXISTING" != "yes" ]; then sage-spkg-uninstall "$PKG_BASE" "$SAGE_INST_LOCAL" @@ -658,14 +676,17 @@ else exit 1 fi fi +} ##################################### actually_build_and_install -# To work around #26996: Remove the symlink set, or we get "cp: cannot overwrite directory" +unload_destdir() { ############################################### +# To work around #26996: Remove the symlink set, +# or we get "cp: cannot overwrite directory" 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_INST_LOCAL" if [ -d "$SAGE_DESTDIR" ]; then + echo "Moving package files from temporary location $SAGE_DESTDIR to $SAGE_INST_LOCAL" # Some `find` implementations will put superfluous slashes in the # output if we give them a directory name with a slash; so make sure # any trailing slash is removed; https://github.com/sagemath/sage/issues/26013 @@ -683,22 +704,25 @@ if [ -d "$SAGE_DESTDIR" ]; then # 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." + error_msg "Error moving files for $PKG_NAME." exit 1 fi # Remove the $SAGE_DESTDIR entirely once all files have been moved to their # final location. rm -rf "$SAGE_DESTDIR" +else + echo "The temporary location $SAGE_DESTDIR does not exist; has it been unloaded already?" + exit 1 fi - # At this stage the path in $SAGE_DESTDIR no longer exists, so the variable # should be unset unset SAGE_DESTDIR unset SAGE_DESTDIR_LOCAL +} ################################################# unload_destdir - +install_scripts() { ############################################## # Some spkg scripts, if they exist, should also be installed to # $SAGE_SPKG_SCRIPTS; they are not included in the package's manifest, but are # removed by sage-spkg-uninstall @@ -726,8 +750,9 @@ for script in $INSTALLED_SCRIPTS; do fi fi done +} ################################################ install_scripts - +post_install() { ################################################# # Run the post-install script, if any if [ -f spkg-postinst ]; then echo "Running post-install script for $PKG_NAME." @@ -750,8 +775,9 @@ if [ "$UNAME" = "CYGWIN" ]; then sage-flock -x "$SAGE_LOCAL/var/lock/rebase.lock" \ sage-rebase.sh "$SAGE_LOCAL" 2>/dev/null fi +} ################################################### post_install - +run_test_suite() { ############################################### # Note: spkg-check tests are run after the package has been copied into # 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 @@ -764,7 +790,8 @@ if [ "$SAGE_CHECK" = "yes" -o "$SAGE_CHECK" = "warn" ]; then if [ $? -ne 0 ]; then TEST_SUITE_RESULT="failed" if [ "$SAGE_CHECK" = "warn" ]; then - # The following warning message must be consistent with SAGE_ROOT/build/make/install (see trac:32781) + # The following warning message must be consistent + # with SAGE_ROOT/build/make/install (see #32781) error_msg "Warning: Failures testing package $PKG_NAME (ignored)" "make check" else error_msg "Error testing package $PKG_NAME" "make check" @@ -779,7 +806,9 @@ if [ "$SAGE_CHECK" = "yes" -o "$SAGE_CHECK" = "warn" ]; then TEST_SUITE_RESULT="not available" fi fi +} ################################################# run_test_suite +write_installation_record() { #################################### # For each line in $FILE_LIST, enclose in double quotes: NEW_LIST="" for f in $FILE_LIST; do @@ -806,25 +835,69 @@ cat > "$PKG_NAME_INSTALLED" << __EOF__ ] } __EOF__ +} ###################################### write_installation_record - -echo "Successfully installed $PKG_NAME" - - -################################################################## -# Delete the temporary build directory if required -################################################################## -if [ "x$SAGE_KEEP_BUILT_SPKGS" != "xyes" ]; then +delete_the_temporary_build_directory() { ######################### echo "Deleting temporary build directory" echo "$SAGE_BUILD_DIR/$PKG_NAME" # On Solaris, the current working directory cannot be deleted, # so we "cd" out of $SAGE_BUILD_DIR/$PKG_NAME. See #12637. cd "$SAGE_BUILD_DIR" rm -rf "$SAGE_BUILD_DIR/$PKG_NAME" +} ########################### delete_the_temporary_build_directory + +delete_the_temporary_build_directory_if_required() { ############# +if [ ! -e "$SAGE_BUILD_DIR/$PKG_NAME/.keep" ]; then + delete_the_temporary_build_directory else echo "You can safely delete the temporary build directory" echo "$SAGE_BUILD_DIR/$PKG_NAME" fi +} ############### delete_the_temporary_build_directory_if_required + + +################################################################## +# MAIN +################################################################## + +if [ $INFO -ne 0 ]; then + exec sage-spkg-info $PKG_BASE +fi + +if [ $ERASE_ONLY = 1 ]; then + delete_the_temporary_build_directory + exit 0 +fi +if [ $INSTALL = 1 ]; then + warning_for_experimental_packages + ensure_pkg_src +fi -echo "Finished installing $PKG_NAME" +if [ -n "$SAGE_INSTALL_FETCH_ONLY" ]; then + exit 0 +fi + +if [ $INSTALL = 1 ]; then + setup_directories + extract_the_package + prepare_for_installation + actually_build_and_install +else + cd "$SAGE_BUILD_DIR/$PKG_NAME" || exit $? +fi + +if [ $POST_INSTALL = 1 ]; then + unload_destdir + install_scripts + post_install +fi + +run_test_suite + +if [ $POST_INSTALL = 1 ]; then + write_installation_record + echo "Successfully installed $PKG_NAME" + delete_the_temporary_build_directory_if_required + echo "Finished installing $PKG_NAME" +fi