#!/usr/bin/env bash
# 在线包的唯一环境准备入口；安装器后台启动，编译入口等待同一把锁。
set -euo pipefail
package=$(cd -- "$(dirname -- "$0")/.." && pwd -P)
tools="$package/toolchain"
root=$(cd "$package/../.." && pwd -P)
[[ ! -f $tools/ready ]] || exit 0
exec 9>"$root/.prepare.lock"
previous=
until flock -w 1 9; do
    status='Waiting for Dever environment preparation...'
    if [[ -f $tools/status ]]; then read -r status < "$tools/status" || true; fi
    if [[ $status != "$previous" ]]; then printf '%s\n' "$status" >&2; previous=$status; fi
done
[[ ! -f $tools/ready ]] || exit 0
exec 3>&2
exec >"$tools/prepare.log" 2>&1
stage=
rust_stage=
phase='Preparing Dever environment'
finish() {
    local code=$?
    if (( code )); then
        printf 'Failed: %s (exit %s). Details: %s\n' "$phase" "$code" "$tools/prepare.log" > "$tools/status"
        cat "$tools/status" >&3
    fi
    if [[ -n $stage ]]; then rm -rf -- "$stage"; fi
    if [[ -n $rust_stage ]]; then rm -rf -- "$rust_stage"; fi
}
trap finish EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
progress() {
    phase=$1
    printf '%s\n' "$phase" > "$tools/status"
    printf '%s\n' "$phase" >&3
}
read -r rust_version native_id < "$tools/online"
mapfile -t sources < "$tools/sources"
release_url=${sources[0]}
rust_dist=${sources[1]}
triple=x86_64-unknown-linux-gnu
rust_root="$root/toolchains/rust-$rust_version-$triple"
native_root="$root/toolchains/native-$native_id"
downloads="$root/cache/downloads"
mkdir -p "$downloads"
stage=$(mktemp -d "$root/.prepare.XXXXXX")
transfers=()
archives=()
queue() {
    local url=$1 name=$2
    archives+=("$name")
    if (( ${#transfers[@]} )); then transfers+=(--next); fi
    transfers+=(--fail --location --silent --show-error --retry 2 --connect-timeout 15
        --speed-limit 1024 --speed-time 60 --continue-at - --output "$downloads/$name.part" "$url")
    transfers+=(--next --fail --location --silent --show-error --retry 2 --connect-timeout 15
        --output "$downloads/$name.sha256" "$url.sha256")
}
native_archive="dever-native-linux-x86_64-$native_id.tar.xz"
if [[ ! -d $native_root ]]; then queue "$release_url/$native_archive" "$native_archive"; fi
if [[ ! -d $rust_root ]]; then
    for component in rustc rust-std cargo; do
        name="$component-$rust_version-$triple.tar.xz"
        queue "$rust_dist/dist/$name" "$name"
    done
fi
if (( ${#archives[@]} )); then
    progress 'Downloading Dever build environment...'
    curl --parallel --parallel-immediate --parallel-max 3 --fail-early "${transfers[@]}"
    progress 'Verifying Dever build environment...'
    for name in "${archives[@]}"; do
        read -r expected remainder < "$downloads/$name.sha256"
        if [[ $name == "$native_archive" && $expected != "$native_id" ]] ||
            ! printf '%s  %s\n' "$expected" "$downloads/$name.part" | sha256sum --check --status; then
            rm -f -- "$downloads/$name.part" "$downloads/$name.sha256"
            echo "Checksum mismatch: $name" >&2
            exit 1
        fi
    done
fi
progress 'Installing Dever build environment...'
if [[ ! -d $rust_root ]]; then
    # 官方脚本不支持含空格的 prefix；先在独占临时目录安装，再原子发布。
    rust_stage=$(mktemp -d /tmp/dever-toolchain.XXXXXX)
    for component in rustc rust-std cargo; do
        name="$component-$rust_version-$triple"
        tar -xJf "$downloads/$name.tar.xz.part" -C "$rust_stage"
        bash "$rust_stage/$name/install.sh" --prefix="$rust_stage/toolchain" --disable-ldconfig
        rm -rf -- "$rust_stage/$name"
    done
    mv "$rust_stage/toolchain" "$stage/rust"
    mv "$stage/rust" "$rust_root"
fi
if [[ ! -d $native_root ]]; then
    tar -xJf "$downloads/$native_archive.part" -C "$stage"
    mv "$stage/native-tools" "$native_root"
fi
"$tools/bin/rustc" --version
progress 'Preparing Dever project dependencies...'
"$tools/bin/cargo" fetch --locked --target "$triple" --manifest-path "$tools/project/Cargo.toml"
for name in "$native_archive" "rustc-$rust_version-$triple.tar.xz" \
    "rust-std-$rust_version-$triple.tar.xz" "cargo-$rust_version-$triple.tar.xz"; do
    rm -f -- "$downloads/$name.part" "$downloads/$name.sha256"
done
touch "$tools/ready"
progress 'Dever build environment is ready.'
