#!/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