# Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License. # See LICENSE.md for license information. # SPDX-License-Identifier: MIT # # Private files: the ones in files.sha1, which are never fetched from a # public source. They arrive from the owner's bundle (JOEY_BUNDLE_URL) or # from `install.sh import`. Sourced after lib/common.sh. JOEY_FILES_TABLE="$JOEY_INSTALLER/files.sha1" JOEY_BUNDLE_CONF="$JOEY_INSTALLER/bundle.conf" # privateTable -- print "sha1 destination" for every private file. privateTable() { awk '!/^#/ && NF >= 2 { print $1, $2 }' "$JOEY_FILES_TABLE" } # privateSha1For DEST -- the checksum files.sha1 expects at DEST. privateSha1For() { awk -v d="$1" '!/^#/ && $2 == d { print $1 }' "$JOEY_FILES_TABLE" } # privatePresent DEST -- true when DEST holds the expected file. privatePresent() { local want want="$(privateSha1For "$1")" [ -n "$want" ] || die "no files.sha1 entry for $1" [ -f "$JOEY_REPO/$1" ] && [ "$(sha1sum "$JOEY_REPO/$1" | cut -d' ' -f1)" = "$want" ] } # importOneFile FILE -- install FILE if its checksum is a private file's. # Prints the destination it was installed to. importOneFile() { local sum local dest sum="$(sha1sum "$1" | cut -d' ' -f1)" dest="$(privateTable | awk -v s="$sum" '$1 == s { print $2 }')" [ -n "$dest" ] || return 0 # Importing a file that is already in place is a no-op, not an error. if [ "$(realpath "$1")" != "$(realpath -m "$JOEY_REPO/$dest")" ]; then install -D -m 644 "$1" "$JOEY_REPO/$dest" fi printf '%s\n' "$dest" } # importPaths PATH... -- scan files, directories, .zip and .7z archives and # Amiga .adf disk images and install every private file found. Prints what # was installed. (Workbench's own disk is how most people own AmigaOS files # such as Devs/serial.device; a .7z is opened with 7z, when installed.) importPaths() { local path local file local tmp tmp="$(mktemp -d)" for path in "$@"; do [ -e "$path" ] || die "no such file or directory: $path" while IFS= read -r -d '' file; do case "$file" in *.zip|*.ZIP) rm -rf "$tmp/zip" mkdir -p "$tmp/zip" if unzip -qq -o "$file" -d "$tmp/zip" 2>/dev/null; then find "$tmp/zip" -type f -print0 | while IFS= read -r -d '' inner; do importOneFile "$inner" done fi ;; *.7z|*.7Z) if ! command -v 7z > /dev/null 2>&1; then warn "skipping $file: opening a .7z needs 7z (Debian/Ubuntu: p7zip-full, Fedora: p7zip-plugins)" continue fi rm -rf "$tmp/7z" mkdir -p "$tmp/7z" if 7z x -y -o"$tmp/7z" "$file" > /dev/null 2>&1; then find "$tmp/7z" -type f -print0 | while IFS= read -r -d '' inner; do importOneFile "$inner" done fi rm -rf "$tmp/7z" ;; *.adf|*.ADF) rm -rf "$tmp/adf" mkdir -p "$tmp/adf" if python3 "$JOEY_REPO/tools/adfTool.py" extractall "$file" "$tmp/adf" 2>/dev/null; then find "$tmp/adf" -type f -print0 | while IFS= read -r -d '' inner; do importOneFile "$inner" done fi ;; *) importOneFile "$file" ;; esac done < <(find "$path" -type f -print0) done rm -rf "$tmp" } # bundleUrl -- the configured bundle URL, or nothing. bundleUrl() { if [ -n "${JOEY_BUNDLE_URL:-}" ]; then printf '%s\n' "$JOEY_BUNDLE_URL" elif [ -f "$JOEY_BUNDLE_CONF" ]; then (. "$JOEY_BUNDLE_CONF" && printf '%s\n' "${JOEY_BUNDLE_URL:-}") fi } # bundleFetch -- download the owner's bundle (if one is configured) and # import what it contains. Its checksum is not pinned -- the owner updates # it -- but every file taken from it is checked against files.sha1. bundleFetch() { local url local tmp url="$(bundleUrl)" [ -n "$url" ] || return 1 tmp="$(mktemp -d)" info "fetching the private bundle" curl -fL --retry 3 --connect-timeout 30 --progress-bar -o "$tmp/bundle.tar.gz" "$url" || { rm -rf "$tmp"; die "could not download the private bundle from $url"; } mkdir -p "$tmp/x" tar -xzf "$tmp/bundle.tar.gz" -C "$tmp/x" || { rm -rf "$tmp"; die "the private bundle is not a .tar.gz"; } importPaths "$tmp/x" >/dev/null rm -rf "$tmp" } # privateEnsure DEST -- make DEST present, from the bundle if configured, # or stop and explain how to supply it. privateEnsure() { local what privatePresent "$1" && return 0 bundleFetch || true privatePresent "$1" && return 0 what="$(awk -v d="$1" '!/^#/ && $2 == d { $1 = ""; $2 = ""; sub(/^ +/, ""); print }' "$JOEY_FILES_TABLE")" die "$1 is missing: $what (sha1 $(privateSha1For "$1")). This file is not downloaded from public sources. Supply your copy with ./install.sh import PATH (files, folders or .zip archives) or set JOEY_BUNDLE_URL in installer/bundle.conf to your private bundle." } # bundleCreate OUTFILE -- pack every private file present into OUTFILE # (a .tar.gz) for the owner to host. bundleCreate() { local out="$1" local dest local sum local tmp local count=0 tmp="$(mktemp -d)" while read -r sum dest; do if privatePresent "$dest"; then install -D -m 644 "$JOEY_REPO/$dest" "$tmp/$dest" count=$((count + 1)) else warn "not bundled (not present here): $dest" fi done < <(privateTable) [ "$count" -gt 0 ] || { rm -rf "$tmp"; die "none of the private files are present to bundle"; } tar -czf "$out" -C "$tmp" . rm -rf "$tmp" ok "bundled $count private files into $out" }