Files

256 lines
8.4 KiB
Bash
Executable File

#!/bin/sh
set -eu
script_dir=$(CDPATH= cd -- "$(dirname "$0")" && pwd)
bootstrap_root=$(CDPATH= cd -- "$script_dir/.." && pwd)
builder_root_default=$HOME/.local/opt/fruix-builder
builder_root=${FRUIX_BUILDER_ROOT:-$builder_root_default}
guile_prefix=${FRUIX_BUILDER_GUILE_PREFIX:-$builder_root/guile}
guile_extra_prefix=${FRUIX_BUILDER_GUILE_EXTRA_PREFIX:-$builder_root/guile-extra}
shepherd_prefix=${FRUIX_BUILDER_SHEPHERD_PREFIX:-$builder_root/shepherd}
guix_source_dir=${GUIX_SOURCE_DIR:-$builder_root/src/guix}
guix_source_url=${GUIX_SOURCE_URL:-https://git.teralink.net/tribes/guix.git}
guile_repo=${FRUIX_BOOTSTRAP_GUILE_REPO:-https://codeberg.org/guile/guile.git}
guile_commit=${FRUIX_BOOTSTRAP_GUILE_COMMIT:-bbf2baa10f6cc8dfdd9e4ea14b503d748287a03d}
fruix_channel_url=${FRUIX_CHANNEL_URL:-https://git.teralink.net/self/fruix.git}
install_host_deps=1
jobs=${JOBS:-$(sysctl -n hw.ncpu 2>/dev/null || echo 4)}
usage() {
cat <<EOF
Usage: prepare-builder.sh [OPTIONS]
Options:
--builder-root DIR Builder root (default: $builder_root_default)
--guix-source-dir DIR Guix source checkout location
--guix-source-url URL Guix source repository URL
--guile-repo URL Guile git repository URL
--guile-commit COMMIT Guile git commit to build
--skip-host-deps Do not run pkg installation
--help Show this help
EOF
}
while [ "$#" -gt 0 ]; do
case "$1" in
--builder-root)
builder_root=$2
shift 2
;;
--guix-source-dir)
guix_source_dir=$2
shift 2
;;
--guix-source-url)
guix_source_url=$2
shift 2
;;
--guile-repo)
guile_repo=$2
shift 2
;;
--guile-commit)
guile_commit=$2
shift 2
;;
--skip-host-deps)
install_host_deps=0
shift
;;
--help)
usage
exit 0
;;
*)
echo "Unknown option: $1" >&2
usage >&2
exit 1
;;
esac
done
guile_prefix=$builder_root/guile
guile_extra_prefix=$builder_root/guile-extra
shepherd_prefix=$builder_root/shepherd
state_dir=$builder_root/state
logs_dir=$builder_root/logs
mkdir -p "$builder_root" "$state_dir" "$logs_dir"
metadata_file=$builder_root/prepare-builder-metadata.txt
env_file=$builder_root/env.sh
have_working_guile() {
[ -x "$guile_prefix/bin/guile" ] || return 1
EXPECT_GUILE_SUBPROCESS_CRASH=0 \
GUILE_BIN="$guile_prefix/bin/guile" \
"$bootstrap_root/tests/guile/run-subprocess-diagnostics.sh" >/dev/null 2>&1
}
guile_module_probe() {
module_code=$1
[ -x "$guile_prefix/bin/guile" ] || return 1
guile_bin=$guile_prefix/bin/guile
guile_version=$(LD_LIBRARY_PATH="$guile_prefix/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" "$guile_bin" -c '(display (effective-version))')
site_dir=$guile_extra_prefix/share/guile/site/$guile_version
site_ccache_dir=$guile_extra_prefix/lib/guile/$guile_version/site-ccache
extensions_dir=$guile_extra_prefix/lib/guile/$guile_version/extensions
gui_load_path=${site_dir}
gui_load_compiled_path=${site_ccache_dir}
gui_extensions_path=${extensions_dir}
env \
LD_LIBRARY_PATH="$guile_extra_prefix/lib:$guile_prefix/lib:/usr/local/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" \
GUILE_LOAD_PATH="$gui_load_path" \
GUILE_LOAD_COMPILED_PATH="$gui_load_compiled_path" \
GUILE_EXTENSIONS_PATH="$gui_extensions_path" \
"$guile_bin" -c "$module_code" >/dev/null 2>&1
}
have_shepherd() {
[ -x "$shepherd_prefix/bin/shepherd" ] || return 1
[ -x "$shepherd_prefix/bin/herd" ] || return 1
guile_module_probe '(use-modules (fibers) (shepherd service)) (display "ok") (newline)'
}
run_step() {
name=$1
shift
printf '\n== %s ==\n' "$name"
"$@"
}
if [ "$install_host_deps" -eq 1 ]; then
run_step install-host-deps "$script_dir/install-host-deps.sh"
fi
if have_working_guile; then
printf '\nUsing existing working Guile at %s\n' "$guile_prefix/bin/guile"
else
run_step build-local-guile env \
FRUIX_BOOTSTRAP_GUILE_REPO="$guile_repo" \
FRUIX_BOOTSTRAP_GUILE_COMMIT="$guile_commit" \
INSTALL_PREFIX="$guile_prefix" \
JOBS="$jobs" \
METADATA_OUT="$logs_dir/local-guile-build-metadata.txt" \
ENV_OUT="$logs_dir/local-guile-env.sh" \
"$script_dir/build-local-guile.sh"
fi
run_step setup-guix-source env \
GUIX_SOURCE_URL="$guix_source_url" \
GUIX_SOURCE_DIR="$guix_source_dir" \
METADATA_OUT="$logs_dir/guix-source-metadata.txt" \
"$script_dir/setup-guix-source.sh"
if guile_module_probe '(use-modules (gnutls)) (display "ok") (newline)'; then
printf '\nGuile (gnutls) already present in %s\n' "$guile_extra_prefix"
else
run_step build-local-guile-gnutls env \
GUILE_BIN="$guile_prefix/bin/guile" \
INSTALL_PREFIX="$guile_extra_prefix" \
GUIX_SOURCE_DIR="$guix_source_dir" \
JOBS="$jobs" \
"$bootstrap_root/tests/guix/build-local-guile-gnutls.sh"
fi
if guile_module_probe '(use-modules (bytestructures guile) (git)) (display "ok") (newline)'; then
printf '\nGuile-Git stack already present in %s\n' "$guile_extra_prefix"
else
run_step build-local-guile-git env \
GUILE_BIN="$guile_prefix/bin/guile" \
INSTALL_PREFIX="$guile_extra_prefix" \
JOBS="$jobs" \
"$bootstrap_root/tests/guix/build-local-guile-git.sh"
fi
if guile_module_probe '(use-modules (json)) (display "ok") (newline)'; then
printf '\nGuile-JSON already present in %s\n' "$guile_extra_prefix"
else
run_step build-local-guile-json env \
GUILE_BIN="$guile_prefix/bin/guile" \
INSTALL_PREFIX="$guile_extra_prefix" \
GUIX_SOURCE_DIR="$guix_source_dir" \
JOBS="$jobs" \
"$bootstrap_root/tests/guix/build-local-guile-json.sh"
fi
if guile_module_probe '(use-modules (sqlite3) (gcrypt hash) (lzlib) (semver)) (display "ok") (newline)'; then
printf '\nGuile configure-time dependency modules already present in %s\n' "$guile_extra_prefix"
else
run_step build-local-guile-configure-deps env \
GUILE_BIN="$guile_prefix/bin/guile" \
INSTALL_PREFIX="$guile_extra_prefix" \
GUIX_SOURCE_DIR="$guix_source_dir" \
JOBS="$jobs" \
"$bootstrap_root/tests/guix/build-local-guile-configure-deps.sh"
fi
if guile_module_probe '(use-modules (fibers)) (display "ok") (newline)'; then
printf '\nGuile Fibers already present in %s\n' "$guile_extra_prefix"
else
run_step build-local-guile-fibers env \
GUILE_BIN="$guile_prefix/bin/guile" \
INSTALL_PREFIX="$guile_extra_prefix" \
JOBS="$jobs" \
"$bootstrap_root/tests/shepherd/build-local-guile-fibers.sh"
fi
if have_shepherd; then
printf '\nShepherd already present in %s\n' "$shepherd_prefix"
else
run_step build-local-shepherd env \
GUILE_BIN="$guile_prefix/bin/guile" \
GUILE_EXTRA_PREFIX="$guile_extra_prefix" \
INSTALL_PREFIX="$shepherd_prefix" \
GUIX_SOURCE_DIR="$guix_source_dir" \
JOBS="$jobs" \
"$bootstrap_root/tests/shepherd/build-local-shepherd.sh"
fi
guile_bin=$guile_prefix/bin/guile
guile_version=$(LD_LIBRARY_PATH="$guile_prefix/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" "$guile_bin" -c '(display (effective-version))')
site_dir=$guile_extra_prefix/share/guile/site/$guile_version
site_ccache_dir=$guile_extra_prefix/lib/guile/$guile_version/site-ccache
extensions_dir=$guile_extra_prefix/lib/guile/$guile_version/extensions
guix_commit=$(git -C "$guix_source_dir" rev-parse HEAD)
cat >"$env_file" <<EOF
export FRUIX_BUILDER_ROOT='$builder_root'
export GUILE_BIN='$guile_bin'
export GUILE_PREFIX='$guile_prefix'
export GUILE_EXTRA_PREFIX='$guile_extra_prefix'
export SHEPHERD_PREFIX='$shepherd_prefix'
export GUIX_SOURCE_DIR='$guix_source_dir'
export FRUIX_CHANNEL_URL='$fruix_channel_url'
export GUILE_AUTO_COMPILE=0
export LD_LIBRARY_PATH='$guile_extra_prefix/lib:$guile_prefix/lib:/usr/local/lib'
export GUILE_LOAD_PATH='$site_dir'
export GUILE_LOAD_COMPILED_PATH='$site_ccache_dir'
export GUILE_EXTENSIONS_PATH='$extensions_dir'
EOF
cat >"$metadata_file" <<EOF
builder_root=$builder_root
guile_repo=$guile_repo
guile_commit=$guile_commit
guile_bin=$guile_bin
guile_prefix=$guile_prefix
guile_extra_prefix=$guile_extra_prefix
shepherd_prefix=$shepherd_prefix
guile_version=$guile_version
guix_source_url=$guix_source_url
guix_source_dir=$guix_source_dir
guix_source_commit=$guix_commit
env_file=$env_file
logs_dir=$logs_dir
EOF
printf '\nPASS prepare-builder\n'
printf 'Environment file: %s\n' "$env_file"
printf 'Metadata file: %s\n' "$metadata_file"
printf '\nTo use Fruix from bootstrap or the canonical checkout, you can run:\n'
printf ' . %s\n' "$env_file"
printf '\nOr rely on the default builder root detection in ./bin/fruix.\n'
printf '%s\n' '--- metadata ---'
cat "$metadata_file"