git mirror - github.com/owenewans/holy - branch master
clone: https://src.holypkg.eu/holy/

file tools/image-package-stage.sh

#!/bin/sh
set -eu
test "$#" -ge 3 || exit 2
bin=$(realpath "$1")
out=$(realpath "$2")
arch=$3
shift 3
work="$out/work"
record="$out/build.record"
test -d "$work" && test -d "$out/packages" && test -d "$out/inputs" || exit 6
case "$arch" in x86_64|i686) ;; *) exit 2 ;; esac
additional_index=0
: > "$work/additional-packages"
: > "$work/source-artifacts"
: > "$work/core-roots"
: > "$work/requested-sources"
scan_kind=
scan_alias=
for token do
    case "$scan_kind" in
        local) scan_kind= ;;
        alias) scan_alias=$token; scan_kind=package ;;
        package)
            printf '%s %s\n' "$scan_alias" "$token" >> "$work/requested-sources"
            scan_kind= ;;
        core_role) scan_kind=alias ;;
        *)
            case "$token" in
                --local) scan_kind=local ;;
                --source) scan_kind=alias ;;
                --core) scan_kind=core_role ;;
                *) exit 2 ;;
            esac ;;
    esac
done
test -z "$scan_kind" || exit 2
add_image_package() {
    input=$1
    selected_source=${2:-}
    additional_index=$((additional_index + 1))
    label=$(printf 'add-%04d' "$additional_index")
    cp "$input" "$out/inputs/$label.holy"
    "$bin" info "local:$out/inputs/$label.holy" > "$work/input-info"
    target_arch=$(sed -n 's/^arch //p' "$work/input-info")
    case "$arch:$target_arch" in
        x86_64:x86_64|x86_64:x86|x86_64:noarch|i686:x86|i686:noarch) ;;
        *) echo "additional package $label has incompatible arch $target_arch" >&2; exit 6 ;;
    esac
    cp "$out/inputs/$label.holy" "$out/packages/$label.holy"
    input_hash=$(sha256sum "$out/inputs/$label.holy")
    input_hash=${input_hash%% *}
    printf 'additional-input %s %s\n' "$label" "$input_hash" >> "$record"
    printf ' %s' "$label" >> "$work/additional-packages"
    if test -n "$selected_source"; then
        printf '%s %s\n' "$label" "$selected_source" >> "$work/add-sources"
    fi
}
prepare_resolver() {
    resolver_root="$work/resolver-root"
    if test -d "$resolver_root"; then return; fi
    test -f "$out/inputs/sources.conf" || exit 6
    mkdir "$resolver_root"
    "$bin" db init --root "$resolver_root" > "$work/resolver-init.record"
    "$bin" source plan --config "$out/inputs/sources.conf" --root "$resolver_root" \
        > "$work/resolver-source.plan"
    resolver_plan=$(sha256sum "$work/resolver-source.plan")
    "$bin" source apply "$work/resolver-source.plan" --sha256 "${resolver_plan%% *}" \
        --root "$resolver_root" > "$work/resolver-source.record"
    while IFS= read -r resolver_alias; do
        "$bin" source catalog bind "$resolver_alias" "$out/mirrors/$resolver_alias" \
            --root "$resolver_root" > "$work/resolver-bind-$resolver_alias.record"
    done < "$out/inputs/source-aliases"
}
while test "$#" -gt 0; do
    case "$1" in
        --local)
            test "$#" -ge 2 || exit 2
            add_image_package "$2"
            shift 2 ;;
        --source|--core)
            kind=$1
            if test "$kind" = --core; then
                test "$#" -ge 4 || exit 2
                role=$2
                case "$role" in busybox|dinit|mdevd|glibc|musl|kernel) ;; *) exit 2 ;; esac
                shift
            fi
            test "$#" -ge 3 && test -f "$work/source-list" || exit 2
            alias=$2
            package_name=$3
            shift 3
            case "$alias" in ''|*[!a-zA-Z0-9_-]*) exit 2 ;; esac
            case "$package_name" in ''|*[!a-zA-Z0-9._+-]*) exit 2 ;; esac
            source_id=$(awk -v name="\"$alias\"" \
                '$1 == "source" && $3 == name && $4 == "active" {print $2}' "$work/source-list")
            test "${#source_id}" -eq 64 || exit 6
            prepare_resolver
            accepted_arch=
            while :; do
                if (
                    set -- "$bin" add "$alias:$package_name" --root "$resolver_root" \
                        --prepare --noninteractive
                    if test -f "$out/inputs/resolver-answers"; then
                        set -- "$@" --answers "$out/inputs/resolver-answers"
                    fi
                    while read -r candidate_alias candidate_name; do
                        if test "$candidate_alias" != "$alias"; then
                            set -- "$@" --candidate "$candidate_alias:$candidate_name"
                        fi
                    done < "$work/requested-sources"
                    for accepted in $accepted_arch; do
                        set -- "$@" --accept-arch "$accepted"
                    done
                    "$@"
                ) > "$work/solve-$alias-$package_name.record" \
                    2> "$work/solve-$alias-$package_name.error"; then
                    break
                else
                    rc=$?
                fi
                if test "$rc" -ne 3; then
                    cat "$work/solve-$alias-$package_name.error" >&2
                    exit "$rc"
                fi
                awk '$1 == "holypkg:" && $2 == "decision-required" &&
                     $3 == "architecture" {
                         hash = ""; target = ""
                         for (i = 4; i <= NF; ++i) {
                             if ($i ~ /^artifact=/) hash = substr($i, 10)
                             if ($i ~ /^target=/) target = $i
                         }
                         if (target == "target=x86;") print hash
                     }' "$work/solve-$alias-$package_name.error" \
                    > "$work/arch-decisions"
                new_decision=0
                while IFS= read -r accepted; do
                    test "${#accepted}" -eq 64 || exit 6
                    case "$accepted" in *[!0-9a-f]*) exit 6 ;; esac
                    case " $accepted_arch " in *" $accepted "*) continue ;; esac
                    "$bin" info "local:$resolver_root/var/cache/holypkg/objects/sha256/$accepted.holy" \
                        > "$work/arch-info"
                    grep -qx 'arch x86' "$work/arch-info" || exit 4
                    accepted_arch="$accepted_arch $accepted"
                    new_decision=1
                    printf 'resolver-architecture image %s artifact %s accepted\n' \
                        "$arch" "$accepted" >> "$record"
                done < "$work/arch-decisions"
                if test "$new_decision" -eq 0; then
                    cat "$work/solve-$alias-$package_name.error" >&2
                    exit 3
                fi
            done
            if test "$kind" = --core; then
                root_digest=$(awk '$1 == "plan-set" && $4 == "root" {print $5}' \
                    "$work/solve-$alias-$package_name.record")
                test "${#root_digest}" -eq 64 || exit 6
                printf '%s %s %s\n' "$role" "$root_digest" "$source_id" >> "$work/core-roots"
            fi
            awk '$1 == "selected" {print $2}' \
                "$work/solve-$alias-$package_name.record" > "$work/selected"
            test -s "$work/selected" || exit 6
            while IFS= read -r digest; do
                test "${#digest}" -eq 64 || exit 6
                selected_source=$(awk -v hash="$digest" \
                    '$1 == "binding" && $2 == hash && $3 == "source" {print $4}' \
                    "$work/solve-$alias-$package_name.record")
                test "${#selected_source}" -eq 64 || exit 6
                existing=$(awk -v hash="$digest" '$1 == hash {print $2}' "$work/source-artifacts")
                if test -n "$existing"; then
                    test "$existing" = "$selected_source" || {
                        echo "artifact $digest selected from multiple sources" >&2
                        exit 4
                    }
                    continue
                fi
                printf '%s %s\n' "$digest" "$selected_source" >> "$work/source-artifacts"
            done < "$work/selected" ;;
        *) exit 2 ;;
    esac
done
while read -r digest selected_source; do
    selected_alias=$(awk -v id="$selected_source" \
        '$1 == "source" && $2 == id && $4 == "active" {gsub(/"/, "", $3); print $3}' \
        "$work/source-list")
    test -n "$selected_alias" || exit 6
    mkdir "$work/fetch-$digest"
    "$bin" repo fetch "$out/mirrors/$selected_alias" "$digest" \
        --output "$work/fetch-$digest" > "$work/fetch-$digest.record"
    input="$work/fetch-$digest/$digest.holy"
    test "$(cat "$work/fetch-$digest.record")" = "$input" && test -f "$input" || exit 6
    roles=$(awk -v hash="$digest" '$2 == hash {print $1}' "$work/core-roots")
    if test -n "$roles"; then
        test "$(printf '%s\n' "$roles" | wc -l)" -eq 1 || {
            echo "artifact $digest selected for multiple core roles" >&2
            exit 4
        }
        role=$roles
        root_source=$(awk -v hash="$digest" '$2 == hash {print $3}' "$work/core-roots")
        test "$root_source" = "$selected_source" || exit 4
        cp "$input" "$work/core-$role.holy"
        if test "$role" = kernel; then label=linux; else label=$role; fi
        printf '%s %s\n' "$label" "$selected_source" >> "$work/add-sources"
        printf 'core-input %s %s %s\n' "$role" "$digest" "$selected_source" >> "$record"
    else
        add_image_package "$input" "$selected_source"
    fi
done < "$work/source-artifacts"
printf '\n' >> "$work/additional-packages"