sortix-mirror/tix/tix-upgrade

274 lines
8.4 KiB
Bash
Executable File

#!/bin/sh
# Copyright (c) 2017, 2021, 2023, 2024 Jonas 'Sortie' Termansen.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# tix-upgrade
# Upgrade operating system and ports.
set -e
cachedir=""
cancel=false
clean=false
collection=/
download_only=false
fetch_options=
sysroot=""
upgrade=--upgrade
upgrade_ports=false
upgrade_system=false
wait=""
dashdash=
previous_option=
for argument do
if test -n "$previous_option"; then
eval $previous_option=\$argument
previous_option=
shift
continue
fi
case $argument in
*=?*) parameter=$(expr "X$argument" : '[^=]*=\(.*\)' || true) ;;
*=) parameter= ;;
*) parameter=yes ;;
esac
case $dashdash$argument in
--) dashdash=yes ;;
-w) wait=-w ;;
--cachedir=*) cachedir=$parameter ;;
--cachedir) previous_option=cachedir ;;
--cancel) cancel=true ;;
--clean) clean=true ;;
--collection=*) collection=$parameter ;;
--collection) previous_option=collection ;;
--download-only) download_only=true ;;
--fetch-options=*) fetch_options="$parameter" ;;
--fetch-options) previous_option=fetch_options ;;
--insecure-downgrade-to-http) fetch_options="$fetch_options $argument" ;;
--insecure-no-check-certificate) fetch_options="$fetch_options $argument" ;;
--no-upgrade) upgrade= ;;
--ports) upgrade_ports=true ;;
--system) upgrade_system=true ;;
--sysroot) previous_option=sysroot ;;
--sysroot=*) sysroot=$parameter ;;
--wait) wait=--wait ;;
-*) echo "$0: unrecognized option $argument" >&2
exit 1 ;;
*) break ;;
esac
shift
done
if test -n "$previous_option"; then
echo "$0: option '$argument' requires an argument" >&2
exit 1
fi
if [ 0 -lt $# ]; then
echo "$0: Unexpected extra operand: $1" >&2
exit 1
fi
conf() {
sed -E -e 's/([a-zA-Z0-9_]+) *? *= */\U\1=/' \
-e 's/=yes$/=true/' -e 's/no$/=false/' "$3" | \
tix-vars -d "$2" - "$4"
}
escape_extended_regex_sed() {
printf "%s\n" "$1" | sed -E -e 's/[[$()*?\+.^{|}'"$2"']/\\\0/g'
}
collection=$(cd "$collection" && pwd)
if ! $upgrade_ports && ! $upgrade_system; then
upgrade_ports=true
upgrade_system=true
if [ -e "$collection/etc/upgrade.conf" ]; then
upgrade_ports=$(conf -d true "$collection/etc/upgrade.conf" PORTS)
upgrade_system=$(conf -d true "$collection/etc/upgrade.conf" SYSTEM)
fi
fi
# If this isn't a system installation, only upgrade the ports.
if [ ! -e "$collection/tix/manifest/system" ]; then
upgrade_system=false
fi
case "$upgrade_system$upgrade_ports" in
truefalse) what_to_upgrade=--system;;
falsetrue) what_to_upgrade=--ports;;
*) what_to_upgrade=;;
esac
if [ -z "$cachedir" ]; then
cachedir="${collection%/}/var/cache/tix"
fi
if $cancel || $clean; then
echo "Removing cache directory: $cachedir"
rm -rf -- "$cachedir"
fi
if $cancel; then
sysmerge -t "$collection" --cancel
exit
fi
mkdir -p -- "$cachedir"
mkdir -p -- "$cachedir/new"
# Fetch the latest official signed release.sh and its matching sha256sum file.
tix-fetch $fetch_options \
--collection="$collection" \
--output-release-file="$cachedir/new/release.sh" \
--output-sha256sum="$cachedir/new/sha256sum" \
--output-upgrade-file="$cachedir/new/upgrade.sh" \
$upgrade
# If release.sh or sha256sum changed, clean the cache directory of downloads
# that were currently in progress as they might not have the right checksums.
if [ ! -e "$cachedir/release.sh" ] ||
[ ! -e "$cachedir/sha256sum" ] ||
[ ! -e "$cachedir/upgrade.sh" ] ||
! (cd "$cachedir/new" && sha256sum release.sh sha256sum upgrade.sh) |
(cd "$cachedir" && sha256sum -cs); then
rm -rf -- "$cachedir/boot"
rm -rf -- "$cachedir/repository"
rm -rf -- "$cachedir/sysroot"
fi
# Store the new release.sh and sha256sum files so we can resume the download
# if cancelled and these files still match.
mv -- "$cachedir/new/release.sh" "$cachedir/release.sh"
mv -- "$cachedir/new/sha256sum" "$cachedir/sha256sum"
mv -- "$cachedir/new/upgrade.sh" "$cachedir/upgrade.sh"
rm -rf -- "$cachedir/new"
# Check if we're upgrading to a new release.
UPGRADE_SIG_URL=$(tix-vars -d '' "$cachedir/upgrade.sh" UPGRADE_SIG_URL)
if [ -n "$UPGRADE_SIG_URL" ]; then
UPGRADE_CHANNEL=$(tix-vars "$cachedir/upgrade.sh" UPGRADE_CHANNEL)
UPGRADE_KEY=$(tix-vars "$cachedir/upgrade.sh" UPGRADE_KEY)
UPGRADE_NAME=$(tix-vars "$cachedir/upgrade.sh" UPGRADE_NAME)
if [ -n "$upgrade" ]; then
echo "Upgrading to $UPGRADE_NAME."
else
echo "Ignoring available upgrade to $UPGRADE_NAME."
fi
fi
# Decide what binary packages to upgrade.
installed_packages=$(LC_ALL=C ls -- "$collection/tix/tixinfo")
if $upgrade_system && $upgrade_ports; then
upgrade_packages="$installed_packages"
else
upgrade_packages=
for package in $installed_packages; do
is_system=$(tix-vars -d false "$collection/tix/tixinfo/$package" SYSTEM)
if ($upgrade_system && [ "$is_system" = true ]) ||
($upgrade_ports && [ "$is_system" = false ]); then
upgrade_packages="$upgrade_packages $package"
fi
done
fi
# TODO: Tracking sets like minimal/basic/full with new mandatory or recommended ports.
mkdir -p -- "$cachedir/repository"
tix-fetch $fetch_options \
--collection="$collection" \
--input-release-file="$cachedir/release.sh" \
--input-sha256sum="$cachedir/sha256sum" \
--repository-metadata -O "$cachedir/repository" renames.list
# Follow RENAMES recursively to handle renames, splits, and deletions.
rename() {
if grep -Eq "^$(escape_extended_regex_sed "$1"):" \
"$cachedir/repository/renames.list"; then
for new in $(grep -E "^$(escape_extended_regex_sed "$1"):" \
"$cachedir/repository/renames.list" |
grep -Eo '[^:]*$'); do
rename "$new"
done
else
echo "$1" | grep -Eo '^[^@]*'
fi
}
# Determine the final package list after the renames.
packages=""
for package in $(LC_ALL=C ls -- "$collection/tix/tixinfo"); do
edition=$(tix-vars -d 1 "$collection/tix/tixinfo/$package" EDITION)
packages="$packages $(rename "$package@$edition")"
done
# Sort and deduplicate the package list and check for existence.
packages=$(for package in $packages; do
# The package exists upstream if it has a hash.
if [ -n "$(tix-fetch $fetch_options \
--collection="$collection" \
--input-release-file="$cachedir/release.sh" \
--input-sha256sum="$cachedir/sha256sum" \
--sha256 --package -- $package)" ]; then
echo $package
fi
done | LC_ALL=C sort -u)
# Fetch each binary package from the mirror.
for package in $packages; do
tix-fetch $fetch_options \
--collection="$collection" \
--input-release-file="$cachedir/release.sh" \
--input-sha256sum="$cachedir/sha256sum" \
-c --package -O "$cachedir/repository" -- $package
done
# Stop if only downloading.
if $download_only; then
exit
fi
rm -rf -- "$cachedir/sysroot"
mkdir -p -- "$cachedir/sysroot"
# Forward the upgrade metadata.
UPGRADE_SIG_URL=$(tix-vars -d '' "$cachedir/upgrade.sh" UPGRADE_SIG_URL)
if [ -n $upgrade ] && [ -n "$UPGRADE_SIG_URL" ]; then
mkdir -p -- "$cachedir/etc"
# TODO: More flexible and simple model.
cat > "$cachedir/etc/upgrade.conf" << EOF
channel = $UPGRADE_CHANNEL
release_key = $UPGRADE_KEY
release_sig_url = $UPGRADE_SIG_URL
EOF
fi
# Extract the binary packages into the sysroot.
for package in $packages; do
echo "Extracting $package.tix.tar.xz..."
tar -C "$cachedir/sysroot" -xJf "$cachedir/repository/$package.tix.tar.xz"
rm -f "$cachedir/repository/$package.tix.tar.xz"
done
# Merge the new sysroot onto the installation.
sysmerge -t "$collection" --full $what_to_upgrade $wait "$cachedir/sysroot"
rm -rf -- "$cachedir/repository"
rm -rf -- "$cachedir/sysroot"