Skip to content
This repository was archived by the owner on Nov 16, 2023. It is now read-only.

Make Sage relocatable #27

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 68 additions & 12 deletions binary_pkg/templates/relocate-once.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Rewrite Paths

This script can be used exactly once to move the directory to a
different location.
This script replaces incidences of the root path installed by buildbot with the
path to a symlink which points to the root of this installation. The installation
is identified by a uuid created in this script, which runs only once because it
deletes itself upon successful completion.
"""

from __future__ import (absolute_import, division, print_function,
Expand All @@ -13,21 +15,23 @@
import os
import getopt
import sys
import uuid

buildbot_path = "{{search_string}}"

def usage():
print("relocate-once.py -d <destination>")
print("relocate-once.py -d<destination>")


try:
opts, args = getopt.getopt(sys.argv[1:], "hd:", ["help", "destination="])
except getopt.GetoptError:
usage()
sys.exit(2)

ROOT_PATH = DESTINATION = os.path.abspath(os.path.dirname(__file__))
ROOT_PATH = os.path.abspath(os.path.dirname(__file__))
DESTINATION = ""

for opt, arg in opts:
if opt in ('-h', '--help'):
usage()
Expand All @@ -38,14 +42,60 @@ def usage():

{% include 'patch.py' %}

if not DESTINATION:
print("""
This appears to be a brand new Sage installation. Some configuration is needed
before it can be used.
""")
# Generate an identifier for this Sage installation.
install_uuid = uuid.uuid4().hex
if os.geteuid() == 0:
# Always make the installation public if Sage is being installed by root.
DESTINATION = '/var/tmp/sage-%s'%install_uuid
else:
print("""
Normally Sage is installed for use by all users. In that case an administrator
password is needed to complete the configuration process. If you are not an
administrator for this system you may install a private version of Sage.
""")
answer = None
print("Would you like to create a private Sage installation?")
try:
while answer not in ("yes", "no"):
answer = input("Please answer yes or no (or ^C to exit): ")
except KeyboardInterrupt:
sys.exit(3)
if answer == "yes":
print("Creating a private Sage installation for %s."%os.environ["USER"])
home = os.getenv("HOME")
if not home or not os.path.exists(home):
print("No home directory! Private installation is not possible.")
sys.exit(1)
dot_sage = os.path.join(home, '.sage')
if not os.path.exists(dot_sage):
os.mkdir(dot_sage, mode=0o700)
locations = os.path.join(home, '.sage', 'locations')
os.mkdir(locations, mode=0o755)
DESTINATION = os.path.join(locations, install_uuid)
else:
DESTINATION = '/var/tmp/sage-%s'%install_uuid
# Save the installation-specific symlink in a bash script which
# can be sourced by the sage startup script.
script_path = os.path.join(ROOT_PATH, "runpath.sh")
with open(script_path, "w") as script:
script.write('SAGE_SYMLINK="%s"\n'%DESTINATION)
os.chmod(script_path, 0o755)
# Create the symlink.
os.symlink(ROOT_PATH, DESTINATION)

print("""
Rewriting paths for your new installation directory
===================================================
Configuring your new Sage installation
======================================

This might take a few minutes but only has to be done once.
""")
p = SearchAndReplace(ROOT_PATH, '{{search_string}}', DESTINATION)

p = SearchAndReplace(ROOT_PATH, buildbot_path, DESTINATION)

{% for filename, patches in patches.items() %}
{% if isinstance(patches, SearchReplacePatch) %}
Expand All @@ -60,3 +110,9 @@ def usage():
{% endfor %}

os.remove(__file__)

# If we are being run as root, exit with status 2 as a signal to the sage
# script that it should exit, to avoid messing up the permissions on the
# user's .sage directory.
if os.geteuid() == 0:
sys.exit(2)
75 changes: 75 additions & 0 deletions relocate-sage.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
diff --git a/sage b/sage
index 3fad670c83..871c02cca7 100755
--- a/sage
+++ b/sage
@@ -124,16 +124,46 @@ fi

export SAGE_ROOT

-# If this is a freshly-unpacked binary tarball then run the installer
+# If this is a freshly-unpacked binary tarball then run the installer.
+# For multi-user installations this must be done by a superuser, since
+# it will create the symlink for this Sage installation.
# Note: relocate-once.py deletes itself upon successful completion
if [ -x "$SAGE_ROOT/relocate-once.py" ]; then
"$SAGE_ROOT/relocate-once.py"
+ if [ $? -eq 3 ]; then
+ echo >&2 "\nAborted."
+ exit 1
+ fi
+ if [ $? -eq 2 ]; then
+ echo >&2 "You may now restart sage as a normal user."
+ exit 0
+ fi
if [ $? -ne 0 ]; then
echo >&2 "Error running the script 'relocate-once.py'."
exit 1
fi
fi

+# Check that the installation-specific symlink points to this sage
+# root directory and reset it if necessessary. If the symlink is
+# in /var/tmp then it must be owned by root, so we use sudo
+# to reset it.
+. "$SAGE_ROOT"/runpath.sh
+OLD_ROOT=`readlink $SAGE_SYMLINK`
+if [ "$SAGE_ROOT" != "$OLD_ROOT" ]; then
+ echo "This sage installation has been moved!"
+ echo old location: $OLD_ROOT
+ echo new location: $SAGE_ROOT
+ echo "Reconfiguring Sage for its new home ..."
+ if [ "$(dirname "$SAGE_SYMLINK")" == "/var/tmp" ]; then
+ sudo -p "Please enter your admin password: " rm -f $SAGE_SYMLINK
+ sudo ln -s "$SAGE_ROOT" "$SAGE_SYMLINK"
+ else
+ rm -f $SAGE_SYMLINK
+ ln -s "$SAGE_ROOT" "$SAGE_SYMLINK"
+ fi
+fi
+
# Run the actual Sage script
if [ -x "$SAGE_ROOT/src/bin/sage" ]; then
exec "$SAGE_ROOT/src/bin/sage" "$@"
diff --git a/src/bin/sage-env b/src/bin/sage-env
index 1f02564f5c..6ac935ce25 100644
--- a/src/bin/sage-env
+++ b/src/bin/sage-env
@@ -138,12 +138,14 @@ NEW_SAGE_ROOT=`cd "$NEW_SAGE_ROOT" && pwd -P`

# Warn if NEW_SAGE_ROOT does not equal the old SAGE_ROOT
if [ "$SAGE_ROOT" != "$NEW_SAGE_ROOT" -a -n "$SAGE_ROOT" ]; then
- echo >&2 "Warning: overwriting SAGE_ROOT environment variable:"
- echo >&2 "Old SAGE_ROOT=$SAGE_ROOT"
- echo >&2 "New SAGE_ROOT=$NEW_SAGE_ROOT"
+ # But don't warn if we are just dereferencing the symlink
+ if ! [[ -L "$SAGE_ROOT" ]]; then
+ echo >&2 "Warning: overwriting SAGE_ROOT environment variable:"
+ echo >&2 "Old SAGE_ROOT=$SAGE_ROOT"
+ echo >&2 "New SAGE_ROOT=$NEW_SAGE_ROOT"
+ fi
fi

-
# Don't execute the commands more than once for the same version of
# sage-env. Check this after checking the validity of SAGE_ROOT, but
# before modifying its value.