sortix-mirror/tix/tix-port
2023-07-16 12:58:45 +02:00

537 lines
16 KiB
Bash
Executable file

#!/bin/sh
# Copyright (c) 2022, 2023 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-port
# Download, patch, build, install, and clean ports.
set -e
unset build
cache_package=false
unset collection
destination=.
unset end
unset exec_prefix
unset generation
unset host
unset make
unset makeflags
unset prefix
unset source_port
unset start
unset sysroot
unset tar
unset target
unset tmp
unset mirror
unset mirror_directory
unset port
operand=1
dashdash=
previous_option=
for argument do
if [ -n "$previous_option" ]; then
eval $previous_option=\$argument
previous_option=
continue
fi
case $argument in
*=?*) parameter=$(expr "X$argument" : '[^=]*=\(.*\)' || true) ;;
*=) parameter= ;;
*) parameter=yes ;;
esac
case $dashdash$argument in
--) dashdash=yes ;;
--build=*) build=$parameter ;;
--build) previous_option=build ;;
--cache-package) cache_package=true ;;
--collection=*) collection=$parameter ;;
--collection) previous_option=collection ;;
--destination=*) destination=$parameter ;;
--destination) previous_option=destination ;;
--end=*) end=$parameter ;;
--end) previous_option=end ;;
--exec-prefix=*) exec_prefix=$parameter ;;
--exec-prefix) previous_option=exec_prefix ;;
--generation=*) generation=$parameter ;;
--generation) previous_option=generation ;;
--host=*) host=$parameter ;;
--host) previous_option=host ;;
--make=*) make=$parameter ;;
--make) previous_option=make ;;
--makeflags=*) makeflags=$parameter ;;
--makeflags) previous_option=makeflags ;;
--prefix=*) prefix=$parameter ;;
--prefix) previous_option=prefix ;;
--source-port=*) source_port=$parameter ;;
--source-port) previous_option=source_port ;;
--start=*) start=$parameter ;;
--start) previous_option=start ;;
--sysroot=*) sysroot=$parameter ;;
--sysroot) previous_option=sysroot ;;
--tar=*) tar=$parameter ;;
--tar) previous_option=tar ;;
--target=*) target=$parameter ;;
--target) previous_option=target ;;
--tmp=*) tmp=$parameter ;;
--tmp) previous_option=tmp ;;
--mirror=*) mirror=$parameter ;;
--mirror) previous_option=mirror ;;
--mirror-directory=*) mirror_directory=$parameter ;;
--mirror-directory) previous_option=mirror_directory ;;
-*) echo "$0: unrecognized option $argument" >&2
exit 1 ;;
*)
if [ $operand = 1 ]; then
port="$argument"
operand=2
else
echo "$0: unexpected extra operand $argument" >&2
exit 1
fi
;;
esac
done
if [ -n "$previous_option" ]; then
echo "$0: option '$argument' requires an argument" >&2
exit 1
fi
if [ -z "$port" ]; then
echo "$0: error: No port was specified" >&2
exit 1
fi
if [ ! -e "$port.port" ]; then
echo "$0: error: Port file doesn't exist: $port.port" >&2
exit 1
fi
port_dirname=$(dirname -- "$port" )
if [ "${collection+x}" = "" -a \
'(' "${sysroot+x}" = x -o "${prefix+x}" = x ')' ]; then
collection="$sysroot$prefix"
fi
NAME=$(tix-vars "$port.port" NAME)
SOURCE_PORT=$(tix-vars -d '' "$port.port" SOURCE_PORT)
DEVELOPMENT=$(tix-vars -d false "$port.port" DEVELOPMENT)
if [ -z "$NAME" ]; then
echo "$0: error: NAME must be set: $port.port" >&2
exit 1
fi
if [ -n "$SOURCE_PORT" ]; then
if [ -z "${source_port+x}" ]; then
source_port="$port_dirname/../$SOURCE_PORT/$SOURCE_PORT"
fi
if [ ! -e "$source_port.port" ]; then
echo "$0: error: Port file for source port $SOURCE_PORT doesn't exist:" \
"$source_port.port" >&2
exit 1
fi
fi
step_number() {
nl << EOF | grep -E -- " $1$" | grep -Eo '[0-9]+'
start
download
extract
tix-build-start
clean
pre-clean
configure
build
install
post-install
post-clean
package
tix-build-end
strip
diff
tix-install
end
EOF
}
if [ -n "$start" ] && [ -z "$(step_number "$start")" ]; then
echo "$0: error: Invalid --start: $start" >&2
exit 1
fi
if [ -n "$end" ] && [ -z "$(step_number "$end")" ]; then
echo "$0: error: Invalid --end: $end" >&2
exit 1
fi
should_run_step() {
([ -z "$start" ] || [ $(step_number "$start") -le $(step_number "$1") ]) &&
([ -z "$end" ] || [ $(step_number "$end") -ge $(step_number "$1") ])
}
announce() {
cat << EOF
================================================================================
==== $1
================================================================================
EOF
}
download_archive_from_url() {(
port="$1"
name="$2"
archive="$3"
url="$4"
sha256sum="$5"
if [ -z "$mirror_directory" ]; then
mirror_directory="$port.mirror"
fi
mirror_directory="$mirror_directory/$name"
mkdir -p -- "$mirror_directory"
if [ ! -e "$mirror_directory/$archive.sha256sum" ]; then
announce "Downloading $1: $archive"
(if echo "$url" | grep -Eq '^[a-z][a-z0-9.+-]*://'; then
if ! wget -O "$mirror_directory/$archive.untrusted" -- "$url"; then
echo "$0: warning: Failed to download $archive from $url" >&2
exit 1
fi
else
if ! cp -- "$url" "$mirror_directory/$archive.untrusted"; then
echo "$0: warning: Failed to copy $archive from $url" >&2
exit 1
fi
fi
if ! echo "$sha256sum $mirror_directory/$archive.untrusted" | \
sha256sum -c; then
sha256sum "$mirror_directory/$archive.untrusted"
echo "$0: warning: $port.port: Wrong sha256sum downloading $archive from $url" >&2
exit 1
fi
mv "$mirror_directory/$archive.untrusted" "$mirror_directory/$archive"
echo "$url" > "$mirror_directory/$archive.url"
echo "$SHA256SUM $archive" > "$mirror_directory/$archive.sha256sum.new"
mv "$mirror_directory/$archive.sha256sum.new" \
"$mirror_directory/$archive.sha256sum"
) || (
rm -f "$mirror_directory/$archive.untrusted"
rm -f "$mirror_directory/$archive.url"
rm -f "$mirror_directory/$archive.sha256sum.new"
rm -f "$mirror_directory/$archive.sha256sum"
exit 1
)
fi
)}
download_archive() {(
port="$1"
name="$2"
archive="$3"
upstream_site="$4"
upstream_archive="$5"
sha256sum="$6"
if ! ([ -n "$mirror" ] &&
download_archive_from_url "$port" "$name" "$archive" \
"$mirror/$name/$archive" "$sha256sum") &&
! download_archive_from_url "$port" "$name" "$archive" \
"$upstream_site/$upstream_archive" \
"$sha256sum"; then
echo "$0: error: Failed to download $archive with sha256sum $sha256sum" >&2
false
fi
)}
download_port() {(
port="$1"
NAME=$(tix-vars "$port.port" NAME)
ARCHIVE=$(tix-vars -d '' "$port.port" ARCHIVE)
if [ -n "$ARCHIVE" ]; then
UPSTREAM_SITE=$(tix-vars "$port.port" UPSTREAM_SITE)
UPSTREAM_ARCHIVE=$(tix-vars "$port.port" UPSTREAM_ARCHIVE)
SHA256SUM=$(tix-vars "$port.port" SHA256SUM)
download_archive "$port" "$NAME" "$ARCHIVE" "$UPSTREAM_SITE" \
"$UPSTREAM_ARCHIVE" "$SHA256SUM"
ARCHIVE_2=$(tix-vars -d '' "$port.port" ARCHIVE_2)
if [ -n "$ARCHIVE_2" ]; then
UPSTREAM_SITE_2=$(tix-vars "$port.port" UPSTREAM_SITE_2)
UPSTREAM_ARCHIVE_2=$(tix-vars "$port.port" UPSTREAM_ARCHIVE_2)
SHA256SUM_2=$(tix-vars "$port.port" SHA256SUM_2)
download_archive "$port" "$NAME" "$ARCHIVE_2" \
"$UPSTREAM_SITE_2" "$UPSTREAM_ARCHIVE_2" "$SHA256SUM_2"
fi
fi
)}
desired_version() {(
port="$1"
ARCHIVE=$(tix-vars -d '' "$port.port" ARCHIVE)
stamp="$NAME"
if [ -n "$ARCHIVE" ]; then
VERSION=$(tix-vars "$port.port" VERSION)
SHA256SUM=$(tix-vars "$port.port" SHA256SUM)
stamp="$stamp.$VERSION.$SHA256SUM"
ARCHIVE_2=$(tix-vars -d '' "$port.port" ARCHIVE_2)
if [ -n "$ARCHIVE_2" ]; then
VERSION_2=$(tix-vars "$port.port" VERSION_2)
SHA256SUM_2=$(tix-vars "$port.port" SHA256SUM_2)
stamp="$stamp.$VERSION_2.$SHA256SUM_2"
fi
fi
if [ -f "$port.patch" ]; then
stamp="$stamp.$(cat "$port.patch" | sha256sum | grep -Eo '^[^ ]*')"
fi
if [ -f "$port.execpatch" ]; then
stamp="$stamp.$(cat "$port.execpatch" | sha256sum | grep -Eo '^[^ ]*')"
fi
if [ -f "$port.rmpatch" ]; then
stamp="$stamp.$(cat "$port.rmpatch" | sha256sum | grep -Eo '^[^ ]*')"
fi
if [ -f "$port.post-install" ]; then
stamp="$stamp.$(cat "$port.post-install" | sha256sum | grep -Eo '^[^ ]*')"
fi
DEVELOPMENT=$(tix-vars -d false "$port.port" DEVELOPMENT)
if [ "$DEVELOPMENT" = true ]; then
stamp="$stamp.development"
fi
echo "$stamp"
)}
diff_package() {(
port="$1"
cd "$(dirname -- "$port")"
base=$(basename -- "$port")
if [ -e "$base.upstream" ]; then
announce "diff $base.upstream $base"
LC_ALL=C diff -Paur --no-dereference -- "$base.upstream" "$base" |
sed -E -e '/^Only in.*$/d' -e 's/^((---|\+\+\+)[^\t]+)\t.*/\1/' \
> "$base.patch"
if [ ! -s "$base.patch" ]; then rm "$base.patch"; fi
tix-execdiff -- "$base.upstream" "$base" |
LC_ALL=C sort > "$base.execpatch"
if [ ! -s "$base.execpatch" ]; then rm "$base.execpatch"; fi
tix-rmdiff -- "$base.upstream" "$base" |
LC_ALL=C sort > "$base.rmpatch"
if [ ! -s "$base.rmpatch" ]; then rm "$base.rmpatch"; fi
desired_version "$base" > "$base.version"
fi
)}
extract_package() {(
port="$1"
NAME=$(tix-vars "$port.port" NAME)
DEVELOPMENT=$(tix-vars -d false "$port.port" DEVELOPMENT)
NEED_WRITABLE=$(tix-vars -d false "$port.port" NEED_WRITABLE)
ARCHIVE=$(tix-vars -d '' "$port.port" ARCHIVE)
ARCHIVE_2=$(tix-vars -d '' "$port.port" ARCHIVE_2)
if [ -z "$mirror_directory" ]; then
mirror_directory="$port.mirror"
fi
mirror_directory="$mirror_directory/$NAME"
version_stamp="$(desired_version "$port")"
if [ ! -e "$port.version" ] ||
[ "$(cat "$port.version")" != "$version_stamp" ] ||
[ ! -e "$port.version" ]; then
if [ -e "$port.version" ]; then
old_version_stamp="$(cat "$port.version")"
case "$old_version_stamp" in
*.development)
if [ "$DEVELOPMENT" = true ]; then
echo "$0: error: $NAME: Refusing to delete port in development" >&2
echo "$0: error: $NAME: .version is currently: $old_version_stamp" >&2
echo "$0: error: $NAME: .version should be: $version_stamp" >&2
exit 1
fi
esac
fi
echo "$version_stamp" > "$port.version.new"
rm -rf "$port"
rm -rf "$port.upstream"
mkdir "$port"
if [ "$DEVELOPMENT" = true ]; then
mkdir "$port.upstream"
fi
if [ -n "$ARCHIVE" ]; then
announce "Extracting $1: $ARCHIVE"
tar -C "$port" -xf "$mirror_directory/$ARCHIVE" --strip-components=1
if [ "$DEVELOPMENT" = true ]; then
tar -C "$port.upstream" -xf "$mirror_directory/$ARCHIVE" \
--strip-components=1
fi
if [ -n "$ARCHIVE_2" ]; then
announce "Extracting $1: $ARCHIVE_2"
tar -C "$port" -xf "$mirror_directory/$ARCHIVE_2" --strip-components=1
if [ "$DEVELOPMENT" = true ]; then
tar -C "$port.upstream" -xf "$mirror_directory/$ARCHIVE_2" \
--strip-components=1
fi
fi
fi
if [ -f "$port.patch" ]; then
if [ "$DEVELOPMENT" = true ]; then
patch -f -d "$port" -p1 < "$port.patch" || true
# .rej files might already have been applied
(cd "$port" &&
find \
-name '*.rej' \
-exec sh -c 'patch -fRs -p0 --dry-run < "$0" >/dev/null 2>&1' \
'{}' ';' -delete)
# .orig files aren't useful unless part of the patch got rejected.
find "$port" \
-name '*.orig' \
-exec sh -c 'test ! -e "$(echo "$0" | sed -E "s,\\.orig$,.rej,")"' \
'{}' ';' -delete
else
patch -d "$port" -p1 < "$port.patch"
fi
fi
if [ -f "$port.execpatch" ]; then
tix-execpatch --directory "$port" "$port.execpatch"
fi
if [ -f "$port.rmpatch" ]; then
tix-rmpatch --directory "$port" "$port.rmpatch"
fi
if [ "$DEVELOPMENT" != true -a "$NEED_WRITABLE" != true ]; then
find "$port" '!' -type d -exec chmod a-w '{}' +
fi
mv "$port.version.new" "$port.version"
if [ "$DEVELOPMENT" = true ]; then
REJECTS="$(find "$port" -name '*.rej' -o -name '*.orig' | sort)"
if [ -n "$REJECTS" ]; then
echo >&2
echo "$REJECTS" >&2
echo "$0: error: $NAME: The above patch hunks were rejected" >&2
exit 1
fi
fi
fi
)}
# TODO: This adds another decompression and compression to the build time, this
# should be done as a tix post installation step. Also this might miss
# programs in unusual locations, so a thorough search and strip is needed.
strip_tix() {(
strip=${host+$host-}strip
dir=$(mktemp -d)
tar -C "$dir" -xf "$1"
# TODO: After releasing Sortix 1.1, remove the data directory compatibility.
if [ -e "$dir/data" ]; then
data_dir="$dir/data"
else
data_dir="$dir"
fi
$strip -d "$data_dir/bin/"* 2>/dev/null || true
$strip -d "$data_dir/lib/"* 2>/dev/null || true
$strip -d "$data_dir/libexec"* 2>/dev/null || true
$strip -d "$data_dir/libexec/git-core/"* 2>/dev/null || true
$strip -d "$data_dir/sbin/"* 2>/dev/null || true
(cd "$dir" &&
LC_ALL=C ls -A | grep -Ev '^tix$' |
tar --numeric-owner --owner=0 --group=0 -cJf "$1" tix -T -)
rm -rf "$dir"
)}
if $cache_package &&
[ -f "$destination/$NAME.tix.tar.xz" -a \
-f "$destination/$NAME.version" ] &&
[ "$(cat $destination/$NAME.version)" = "$(desired_version $port)" ]; then
start=tix-install
fi
if should_run_step download; then
if [ -n "$SOURCE_PORT" ]; then
download_port "$source_port"
fi
download_port "$port"
fi
if should_run_step extract; then
if [ -n "$SOURCE_PORT" ]; then
extract_package "$source_port"
fi
extract_package "$port"
fi
update_version=false
if [ $(step_number "${start-start}") -lt $(step_number tix-build-end) ] &&
[ $(step_number "${end-end}") -gt $(step_number tix-build-start) ]; then
announce "Building $NAME"
unset tix_build_start
unset tix_build_end
if [ -n "$start" ]; then
if [ $(step_number "$start") -le $(step_number tix-build-start) ]; then
tix_build_start=start
else
tix_build_start="$start"
fi
fi
if [ -n "$end" ]; then
if [ $(step_number "$end") -ge $(step_number tix-build-end) ]; then
tix_build_end=end
else
tix_build_end="$end"
fi
fi
if should_run_step package; then
mkdir -p "$destination"
fi
tix-build \
${build+--build="$build"} \
${destination+--destination="$destination"} \
${tix_build_end+--end="$tix_build_end"} \
${exec_prefix+--exec-prefix="$exec_prefix"} \
${generation+--generation="$generation"} \
${host+--host="$host"} \
${make+--make="$make"} \
${makeflags+--makeflags="$makeflags"} \
${prefix+--prefix="$prefix"} \
${source_port+--source-port="$source_port"} \
${tix_build_start+--start="$tix_build_start"} \
${sysroot+--sysroot="$sysroot"} \
${tar+--tar="$tar"} \
${target+--target="$target"} \
${tmp+--tmp="$tmp"} \
"$port"
update_version=true
fi
if should_run_step strip; then
strip_tix "$destination/$NAME.tix.tar.xz"
update_version=true
fi
if should_run_step diff; then
if [ "$DEVELOPMENT" = true ]; then
diff_package "$port"
fi
update_version=true
fi
if $update_version && [ "${destination-.}" != "." ]; then
cp "$port.version" "$destination/$NAME.version"
fi
if should_run_step tix-install; then
announce "Installing $NAME"
tix-install \
${collection+--collection="$collection"} \
--reinstall \
"$destination/$NAME.tix.tar.xz"
fi