summaryrefslogtreecommitdiffstats
path: root/image-builder/lib.sh
blob: dfb076bf94124e8acab97139fdca2df21ad05421 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#
# Copyright (C) 2026 Danilo M. <danix@danix.xyz>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# Shared helpers for the image builder. Source, do not execute.
# Sourcing must have no side effects beyond defining functions.

_log()  { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [${LOG_TAG:-image-builder}] $*"; }
_warn() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [${LOG_TAG:-image-builder}] WARNING: $*" >&2; }
_err()  { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [${LOG_TAG:-image-builder}] ERROR: $*" >&2; exit 1; }

# mirror_path MIRROR RELPATH
# Join a MIRROR (file:///... or http(s)://...) with a relative path.
mirror_path() {
    local mirror="$1" rel="$2"
    printf '%s/%s' "${mirror%/}" "${rel#/}"
}

# is_local_mirror MIRROR -> 0 if file:// or bare absolute path, else 1
is_local_mirror() {
    case "$1" in
        file://*) return 0 ;;
        http://*|https://*) return 1 ;;
        /*) return 0 ;;
        *) return 1 ;;
    esac
}

# strip_scheme URL -> filesystem path for a file:// or bare-local URL
strip_scheme() {
    local u="$1"
    case "$u" in
        file://*) printf '%s' "${u#file://}" ;;
        *) printf '%s' "$u" ;;
    esac
}

# fetch SRC DEST
# Copy SRC (a full mirror URL) to DEST. Local mirror -> cp, http -> curl.
# Returns non-zero on failure; caller decides whether that is fatal.
fetch() {
    local src="$1" dest="$2"
    if is_local_mirror "$src"; then
        local path; path="$(strip_scheme "$src")"
        [[ -f "$path" ]] || return 1
        cp "$path" "$dest"
    else
        curl -sSfL --connect-timeout 60 "$src" -o "$dest"
    fi
}

# txz_hash DIR
# Stable hash of the set of Slackware package files (*.t?z) in DIR (names +
# contents), order
# independent. Empty/absent dir -> empty string.
txz_hash() {
    local dir="$1"
    [[ -d "$dir" ]] || { printf ''; return 0; }
    local files; files=$(find "$dir" -maxdepth 1 -name '*.t?z' -type f | sort)
    [[ -n "$files" ]] || { printf ''; return 0; }
    # Hash sorted "name  sha256" lines so reordering does not change output.
    while IFS= read -r f; do
        printf '%s  %s\n' "$(basename "$f")" "$(sha256sum "$f" | cut -d' ' -f1)"
    done <<< "$files" | sha256sum | cut -d' ' -f1
}

# require_mount VERSION
# Assert the NAS tree for VERSION is mounted (file:// mirror only).
# x86_64 tree dir is slackware64-${VERSION}.
require_mount() {
    local version="$1"
    is_local_mirror "$MIRROR" || return 0   # http mirror: nothing to check
    local base; base="$(strip_scheme "$MIRROR")"
    local dir="${base}/slackware64-${version}"
    [[ -d "$dir" ]] || _err "NAS tree not mounted: ${dir}"
}