Skip to content

Commit b94f49c

Browse files
committed
Add armbian-images.json generator and workflow
1 parent eb3cbd0 commit b94f49c

File tree

2 files changed

+310
-0
lines changed

2 files changed

+310
-0
lines changed
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
name: Update download JSON index
2+
3+
on:
4+
push:
5+
repository_dispatch:
6+
types: ["Webindex update"]
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: write
11+
12+
concurrency:
13+
group: redirector
14+
cancel-in-progress: false
15+
16+
env:
17+
SOURCE_OF_TRUTH: "rsync://fi.mirror.armbian.de"
18+
19+
jobs:
20+
Webindex:
21+
name: "Generate JSON Index"
22+
runs-on: ubuntu-24.04
23+
24+
env:
25+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
26+
27+
steps:
28+
- name: Checkout build framework repository
29+
uses: actions/checkout@v6
30+
with:
31+
repository: armbian/build
32+
fetch-depth: 1
33+
clean: false
34+
path: build
35+
36+
- name: Checkout OS repository
37+
uses: actions/checkout@v6
38+
with:
39+
repository: armbian/os
40+
fetch-depth: 1
41+
clean: false
42+
path: os
43+
44+
- name: Checkout armbian.github.io repository
45+
uses: actions/checkout@v6
46+
with:
47+
repository: armbian/armbian.github.io
48+
fetch-depth: 0
49+
clean: false
50+
path: armbian.github.io
51+
52+
- name: Checkout this repo (script)
53+
uses: actions/checkout@v6
54+
with:
55+
fetch-depth: 1
56+
clean: false
57+
path: runner
58+
59+
- name: Install dependencies
60+
run: |
61+
sudo apt-get update
62+
sudo apt-get install -y jq jc rsync
63+
64+
- name: Generate armbian-images.json
65+
working-directory: runner
66+
run: |
67+
set -euo pipefail
68+
OUT="armbian-images.json" \
69+
OS_DIR="${GITHUB_WORKSPACE}/os" \
70+
BOARD_DIR="${GITHUB_WORKSPACE}/build/config/boards" \
71+
SOURCE_OF_TRUTH="${SOURCE_OF_TRUTH}" \
72+
./scripts/generate-armbian-images-json.sh
73+
74+
# Copy into workspace root so later steps can reference easily
75+
cp armbian-images.json "${GITHUB_WORKSPACE}/armbian-images.json"
76+
77+
- name: Commit changes if any
78+
run: |
79+
80+
set -euo pipefail
81+
cd armbian.github.io
82+
83+
git config user.name "github-actions"
84+
git config user.email "github-actions@github.com"
85+
86+
git fetch origin data
87+
git checkout data
88+
git pull --rebase origin data
89+
90+
mkdir -p data
91+
cp "${GITHUB_WORKSPACE}/armbian-images.json" data/
92+
93+
git add data/armbian-images.json
94+
if ! git diff --cached --quiet; then
95+
git commit -m "Update armbian-images.json"
96+
# rebase once more right before push to reduce race window
97+
git pull --rebase origin data
98+
git push origin data
99+
fi
100+
101+
- name: Run Jira update action
102+
uses: peter-evans/repository-dispatch@v4
103+
with:
104+
token: ${{ secrets.GITHUB_TOKEN }}
105+
event-type: "Jira update"
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
IFS=$'\n\t'
4+
5+
# -----------------------------------------------------------------------------
6+
# Configuration
7+
# -----------------------------------------------------------------------------
8+
SOURCE_OF_TRUTH="${SOURCE_OF_TRUTH:-rsync://fi.mirror.armbian.de}"
9+
OS_DIR="${OS_DIR:-./os}"
10+
BOARD_DIR="${BOARD_DIR:-./build/config/boards}"
11+
OUT="${OUT:-armbian-images.json}"
12+
13+
# -----------------------------------------------------------------------------
14+
# Requirements
15+
# -----------------------------------------------------------------------------
16+
need() { command -v "$1" >/dev/null || { echo "ERROR: missing '$1'" >&2; exit 1; }; }
17+
need rsync gh jq jc find grep sed cut awk
18+
19+
[[ -f "${OS_DIR}/exposed.map" ]] || { echo "ERROR: ${OS_DIR}/exposed.map not found" >&2; exit 1; }
20+
[[ -d "${BOARD_DIR}" ]] || { echo "ERROR: board directory not found: ${BOARD_DIR}" >&2; exit 1; }
21+
22+
# -----------------------------------------------------------------------------
23+
# Extract variable from board config
24+
# -----------------------------------------------------------------------------
25+
extract_cfg_var() {
26+
local file="$1" var="$2"
27+
awk -v var="$var" '
28+
{
29+
line=$0
30+
sub(/[ \t]*#.*/, "", line)
31+
if (line ~ var"[ \t]*=") {
32+
sub(/^.*=/,"",line)
33+
gsub(/^["'\'']|["'\'']$/,"",line)
34+
print line; exit
35+
}
36+
}' "$file" 2>/dev/null || true
37+
}
38+
39+
# -----------------------------------------------------------------------------
40+
# Load board metadata
41+
# -----------------------------------------------------------------------------
42+
declare -A BOARD_NAME_MAP BOARD_VENDOR_MAP
43+
while IFS= read -r cfg; do
44+
slug="$(basename "${cfg%.*}")"
45+
slug="${slug,,}"
46+
name="$(extract_cfg_var "$cfg" BOARD_NAME)"
47+
vendor="$(extract_cfg_var "$cfg" BOARD_VENDOR)"
48+
[[ -n "$name" ]] && BOARD_NAME_MAP["$slug"]="$name"
49+
[[ -n "$vendor" ]] && BOARD_VENDOR_MAP["$slug"]="$vendor"
50+
done < <(find "$BOARD_DIR" -maxdepth 1 -type f)
51+
52+
# -----------------------------------------------------------------------------
53+
# Helpers
54+
# -----------------------------------------------------------------------------
55+
is_version_token() { [[ "$1" =~ ^[0-9]{2}\.[0-9] ]]; }
56+
57+
is_preinstalled_app() {
58+
case "$1" in
59+
kali|homeassistant|openhab|omv) return 0 ;;
60+
*) return 1 ;;
61+
esac
62+
}
63+
64+
strip_img_ext() {
65+
sed -E 's/(\.img(\.(xz|zst|gz))?)$//' <<<"$1"
66+
}
67+
68+
extract_file_extension() {
69+
local n="$1"
70+
[[ "$n" == *.img.xz ]] && echo "img.xz" && return
71+
[[ "$n" == *.img.zst ]] && echo "img.zst" && return
72+
[[ "$n" == *.img.gz ]] && echo "img.gz" && return
73+
[[ "$n" == *.img ]] && echo "img" && return
74+
echo "${n##*.}"
75+
}
76+
77+
get_download_repository() {
78+
local url="$1"
79+
if [[ "$url" == https://github.com/armbian/* ]]; then
80+
awk -F/ '{print $5}' <<<"$url"
81+
elif [[ "$url" == https://dl.armbian.com/* ]]; then
82+
awk -F/ '{print $5}' <<<"$url"
83+
else
84+
echo ""
85+
fi
86+
}
87+
88+
# -----------------------------------------------------------------------------
89+
# Parse image filename
90+
# -----------------------------------------------------------------------------
91+
parse_image_name() {
92+
local name="$1"
93+
IFS="_" read -r -a p <<<"$name"
94+
95+
local ver="" board="" distro="" branch="" kernel="" tail=""
96+
local variant="server" app="" storage=""
97+
98+
if is_version_token "${p[1]:-}"; then
99+
ver="${p[1]}"; board="${p[2]}"; distro="${p[3]}"; branch="${p[4]}"; kernel="${p[5]}"; tail="${p[6]:-}"
100+
else
101+
ver="${p[2]}"; board="${p[3]}"; distro="${p[4]}"; branch="${p[5]}"; kernel="${p[6]}"; tail="${p[7]:-}"
102+
fi
103+
104+
# kernel token may contain "-suffix"
105+
if [[ "$kernel" == *-* ]]; then
106+
suffix="$(strip_img_ext "${kernel#*-}")"
107+
if is_preinstalled_app "$suffix"; then
108+
app="$suffix"
109+
else
110+
[[ "${suffix##*-}" == "ufs" ]] && storage="ufs"
111+
fi
112+
fi
113+
114+
[[ "$tail" == minimal* ]] && variant="minimal"
115+
[[ "$name" == *_desktop.img.* ]] && variant="$tail"
116+
117+
printf '%s\n' "$ver" "$board" "$distro" "$branch" "$variant" "$app" "$storage"
118+
}
119+
120+
# -----------------------------------------------------------------------------
121+
# Build feeds (NO .txt files)
122+
# -----------------------------------------------------------------------------
123+
tmpdir="$(mktemp -d)"
124+
trap 'rm -rf "$tmpdir"' EXIT
125+
feed="$tmpdir/feed.txt"
126+
127+
echo "▶ Building feeds…" >&2
128+
129+
# Mirror feed
130+
rsync --recursive --list-only "${SOURCE_OF_TRUTH}/dl/" |
131+
awk '
132+
{
133+
size=$2; gsub(/[.,]/,"",size)
134+
url="https://dl.armbian.com/" $5
135+
if (url ~ /\/[^\/]+\/archive\/Armbian/ &&
136+
url !~ /\.txt$/ &&
137+
url !~ /\.(asc|sha|torrent)$/ &&
138+
url !~ /(homeassistant|openhab|kali|omv)/) {
139+
dt=$3 "T" $4 "Z"; gsub("/", "-", dt)
140+
print size "|" url "|" dt
141+
}
142+
}' >"$tmpdir/a.txt"
143+
144+
# GitHub feed
145+
: >"$tmpdir/bcd.txt"
146+
for repo in community os distribution; do
147+
gh release view --json assets --repo "github.com/armbian/$repo" |
148+
jq -r '.assets[]
149+
| select(.url | test("\\.txt($|\\?)") | not)
150+
| select(.url | test("\\.(asc|sha|torrent)($|\\?)") | not)
151+
| "\(.size)|\(.url)|\(.createdAt)"' >>"$tmpdir/bcd.txt"
152+
done
153+
154+
cat "$tmpdir/a.txt" "$tmpdir/bcd.txt" >"$feed"
155+
156+
# -----------------------------------------------------------------------------
157+
# JSON generation
158+
# -----------------------------------------------------------------------------
159+
{
160+
echo '"board_slug"|"board_name"|"board_vendor"|"armbian_version"|"file_url"|"file_url_asc"|"file_url_sha"|"file_url_torrent"|"redi_url"|"redi_url_asc"|"redi_url_sha"|"redi_url_torrent"|"file_updated"|"file_size"|"distro_release"|"kernel_branch"|"image_variant"|"preinstalled_application"|"promoted"|"download_repository"|"file_extension"'
161+
162+
while IFS="|" read -r SIZE URL DATE; do
163+
IMAGE_SIZE="${SIZE//[.,]/}"
164+
IMAGE_NAME="${URL##*/}"
165+
166+
mapfile -t p < <(parse_image_name "$IMAGE_NAME")
167+
VER="${p[0]}"; BOARD="${p[1]}"; DISTRO="${p[2]}"; BRANCH="${p[3]}"
168+
VARIANT="${p[4]}"; APP="${p[5]}"; STORAGE="${p[6]}"
169+
170+
[[ -z "$BOARD" ]] && continue
171+
BOARD_SLUG="${BOARD,,}"
172+
173+
REPO="$(get_download_repository "$URL")"
174+
[[ -z "$REPO" ]] && continue
175+
176+
PREFIX=""; [[ "$REPO" == "os" ]] && PREFIX="nightly/"
177+
178+
# -------- file_extension (FINAL RULES) --------
179+
BASE_EXT="$(extract_file_extension "$IMAGE_NAME")"
180+
if [[ "$IMAGE_NAME" == *.oowow.img.xz ]]; then
181+
FILE_EXTENSION="oowow.img.xz"
182+
elif [[ -n "$STORAGE" ]]; then
183+
FILE_EXTENSION="${STORAGE}.${BASE_EXT}"
184+
else
185+
FILE_EXTENSION="$BASE_EXT"
186+
fi
187+
# ---------------------------------------------
188+
189+
APP_SUFFIX=""; [[ -n "$APP" ]] && APP_SUFFIX="-${APP}"
190+
REDI_URL="https://dl.armbian.com/${PREFIX}${BOARD_SLUG}/${DISTRO^}_${BRANCH}_${VARIANT}${APP_SUFFIX}"
191+
192+
if [[ "$URL" == https://github.com/armbian/* ]]; then
193+
CACHE="https://cache.armbian.com/artifacts/${BOARD_SLUG}/archive/${IMAGE_NAME}"
194+
ASC="$CACHE.asc"; SHA="$CACHE.sha"; TOR="$CACHE.torrent"
195+
else
196+
ASC="$URL.asc"; SHA="$URL.sha"; TOR="$URL.torrent"
197+
fi
198+
199+
echo "${BOARD_SLUG}|${BOARD_NAME_MAP[$BOARD_SLUG]:-}|${BOARD_VENDOR_MAP[$BOARD_SLUG]:-}|${VER}|${URL}|${ASC}|${SHA}|${TOR}|${REDI_URL}|${REDI_URL}.asc|${REDI_URL}.sha|${REDI_URL}.torrent|${DATE}|${IMAGE_SIZE}|${DISTRO}|${BRANCH}|${VARIANT}|${APP}|false|${REPO}|${FILE_EXTENSION}"
200+
done <"$feed"
201+
202+
} | jc --csv | jq '{assets:.}' >"$OUT"
203+
204+
echo "✔ Generated $OUT"
205+
echo "✔ Assets: $(jq '.assets | length' "$OUT")"

0 commit comments

Comments
 (0)