From 870066f092ed1e2e415fbb583d019b79c05da90f Mon Sep 17 00:00:00 2001 From: Luis-ADFA Date: Wed, 2 Sep 2026 15:48:03 -0600 Subject: [PATCH 1/2] K2GO-377 chore(rootfs): name the built artifacts k2go_, and sweep the old ones once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rootfs images carried the iiab-oa_ prefix from the upstream project. They are the product's own artifacts, so they take its name; the stable pointers keep theirs, since latest__.meta4/.installed never carried a product prefix. The app is unaffected: it asks for the pointer and takes the file name and URL from inside the metalink, so it never builds the artifact name itself. The publish loop and the retention prune move to k2go_ together — a prune left filtering the old prefix would let the new artifacts pile up at ~1.7 GB each while still eating the old ones. A transitional sweep clears the pre-rename artifacts in full instead of ageing them out seven deep, and is marked for removal before merge: run the workflow from this branch to migrate the bucket, confirm no iiab-oa_ keys remain, then delete the block so it does not outlive its purpose. ROOTFS_PUBLIC_BASE comes along from K2GO-90: on main it still defaults to a path-based route that was never created, so a migration build run without it would republish metalinks pointing at 404. --- .github/workflows/bake-rootfs.yml | 38 +++++++++++++++++++---- tools/rootfs-builder/build-iiab-rootfs.sh | 8 +++-- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/.github/workflows/bake-rootfs.yml b/.github/workflows/bake-rootfs.yml index 3082fa8a6..ec314b086 100644 --- a/.github/workflows/bake-rootfs.yml +++ b/.github/workflows/bake-rootfs.yml @@ -26,9 +26,13 @@ on: env: BUCKET_NAME: k2go-rootfs R2_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }} - # Public base that goes into the .meta4 . Path-based route - # k2go-download.appdevforall.org/rootfs/* -> k2go-rootfs. - ROOTFS_PUBLIC_BASE: ${{ vars.ROOTFS_PUBLIC_BASE || 'https://k2go-download.appdevforall.org/rootfs' }} + # Public base that goes into the .meta4 — where the APK actually downloads the + # rootfs FROM, so it has to name the bucket that holds it. The two buckets are separate + # and so are their names: k2go-download.appdevforall.org serves the APK repo only. + # K2GO-90: this defaulted to k2go-download.appdevforall.org/rootfs, a path-based route that + # was never created. The metalinks published with it resolved to 404 — and since + # --reset-mirrors leaves a single source, there was nothing to fall back to. + ROOTFS_PUBLIC_BASE: ${{ vars.ROOTFS_PUBLIC_BASE || 'https://pub-d64c885cef6c42db8c7925144d73d0ee.r2.dev' }} # Key prefix inside the bucket. Empty when the route strips /rootfs/ (keys at root); # set to 'rootfs/' if the route keeps the prefix. R2_KEY_PREFIX: ${{ vars.ROOTFS_KEY_PREFIX }} @@ -133,7 +137,7 @@ jobs: # 1) Big artifacts FIRST (data before any pointer that resolves to them). shopt -s nullglob - for f in iiab-oa_*.tar.gz; do + for f in k2go_*.tar.gz; do echo ">> upload artifact $f" aws s3 cp "$f" "s3://${BUCKET_NAME}/${PFX}${f}" --endpoint-url "$ENDPOINT" done @@ -157,12 +161,12 @@ jobs: # 4) Prune: keep only the newest $KEEP batches per (tier,arch); delete older + sidecars. # Only the heavy dated tarballs accumulate (they carry _); logs and the - # TSV overwrite in place, so they never pile up. The prefix filter matches iiab-oa_* + # TSV overwrite in place, so they never pile up. The prefix filter matches k2go_* # only, so proot-distro-v*/ is never touched. for meta in latest_*_"${ARCH}".meta4; do base="${meta%.meta4}"; te="${base#latest_}"; tier="${te%_${ARCH}}" mapfile -t keys < <(aws s3api list-objects-v2 --bucket "$BUCKET_NAME" \ - --prefix "${PFX}iiab-oa_" --endpoint-url "$ENDPOINT" \ + --prefix "${PFX}k2go_" --endpoint-url "$ENDPOINT" \ --query "sort_by(Contents,&LastModified)[?contains(Key,'_${tier}_') && ends_with(Key,'_${ARCH}.tar.gz')].Key" \ --output text | tr '\t' '\n' | sed '/^$/d') n=${#keys[@]} @@ -174,4 +178,26 @@ jobs: done done fi + + # K2GO-377 (TRANSITIONAL — remove before merging). The retention above keeps the + # newest $KEEP k2go_ batches; the pre-rename iiab-oa_ artifacts have no pointer left + # once this tier republished, so they go in full rather than ageing out $KEEP deep at + # ~1.7 GB each. It sits INSIDE this loop on purpose: it only ever touches the tier and + # arch this job just republished, so a tier that failed to build keeps the artifact its + # metalink still names. + # + # Removal is gated on evidence, not on this run finishing. Delete the block only when + # aws s3api list-objects-v2 --bucket "$BUCKET_NAME" --prefix "iiab-oa_" \ + # --endpoint-url "$ENDPOINT" --query "length(Contents)" --output text + # reports None/0 — otherwise the leftovers outlive the only code that would clear them. + mapfile -t legacy < <(aws s3api list-objects-v2 --bucket "$BUCKET_NAME" \ + --prefix "${PFX}iiab-oa_" --endpoint-url "$ENDPOINT" \ + --query "Contents[?contains(Key,'_${tier}_') && ends_with(Key,'_${ARCH}.tar.gz')].Key" \ + --output text | tr '\t' '\n' | sed '/^$/d') + for key in "${legacy[@]}"; do + echo ">> sweep legacy $key (+ sidecars)" + for ext in '' .meta4 .sha256 .installed .torrent; do + aws s3 rm "s3://${BUCKET_NAME}/${key}${ext}" --endpoint-url "$ENDPOINT" || true + done + done done diff --git a/tools/rootfs-builder/build-iiab-rootfs.sh b/tools/rootfs-builder/build-iiab-rootfs.sh index c3c80ccc7..8ae14d752 100755 --- a/tools/rootfs-builder/build-iiab-rootfs.sh +++ b/tools/rootfs-builder/build-iiab-rootfs.sh @@ -22,8 +22,8 @@ # branch (git ls-remote, then the REST API). --iiab-commit overrides everything. # # Output: -# - iiab-oa____.tar.gz (top-level = installed-rootfs/iiab/) -# - iiab-oa_<...>.tar.gz.meta4 / .torrent (per-artifact, mkmetalink) +# - k2go____.tar.gz (top-level = installed-rootfs/iiab/) +# - k2go_<...>.tar.gz.meta4 / .torrent (per-artifact, mkmetalink) # - latest__.meta4 (STABLE pointer the APK requests; a copy of the # per-artifact .meta4. Inside it, mirrors point at the full-named tarball, # so this stable name always resolves to the newest build.) @@ -744,7 +744,9 @@ fi [[ -n "$IIAB_SHA" ]] || die "Could not determine the iiab/iiab commit id. Pass --iiab-commit ." log "iiab/iiab id: ${IIAB_SHA} [source: ${IIAB_SRC}]" -ARTIFACT="iiab-oa_${STAMP}_${TIER_NAME}_${IIAB_SHA}_${ARCH}.tar.gz" +# K2GO-377: the artifacts carry the product name. The stable pointers do not change — +# latest__.meta4/.installed never carried a product prefix. +ARTIFACT="k2go_${STAMP}_${TIER_NAME}_${IIAB_SHA}_${ARCH}.tar.gz" META4="latest_${TIER_NAME}_${ARCH}.meta4" INSTALLED="latest_${TIER_NAME}_${ARCH}.installed" # ADFA-5110: stable uncompressed-size sidecar From 7ac1fe228abb29f2af62751647d8a668edea32f5 Mon Sep 17 00:00:00 2001 From: Luis-ADFA Date: Wed, 2 Sep 2026 15:58:19 -0600 Subject: [PATCH 2/2] K2GO-377 chore(backup): the user's backup file takes the product name too The suggested filename kept the iiab-oa_ prefix the built artifacts just left behind, so the app would have written backups under one name while the bucket held another. It is only ever a suggestion for the SAF picker: nothing reads it back, and a restore identifies an archive by the manifest inside it, so backups already written under the old name keep restoring unchanged. --- .../iiab/controller/backup/domain/BackupEngine.java | 10 ++++++++-- .../controller/deploy/domain/ExtractProgressTest.java | 4 ++-- .../controller/download/domain/MetalinkFileTest.java | 8 ++++---- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/controller/app/src/main/java/org/iiab/controller/backup/domain/BackupEngine.java b/controller/app/src/main/java/org/iiab/controller/backup/domain/BackupEngine.java index 772a150f5..e246d66d0 100644 --- a/controller/app/src/main/java/org/iiab/controller/backup/domain/BackupEngine.java +++ b/controller/app/src/main/java/org/iiab/controller/backup/domain/BackupEngine.java @@ -29,14 +29,20 @@ public final class BackupEngine { private BackupEngine() {} - /** Suggested external filename: {@code iiab-oa_YYYY.DDD__.tar.gz}. */ + /** + * Suggested external filename: {@code k2go_YYYY.DDD__.tar.gz}. + * + *

K2GO-377: the prefix follows the built rootfs artifacts onto the product's own name. It is + * only ever a suggestion for the SAF picker — nothing reads it back, and a restore identifies an + * archive by the manifest inside it, so backups written under the old name keep working. + */ public static String suggestedFileName(Context ctx) { java.util.Calendar c = java.util.Calendar.getInstance(); int year = c.get(java.util.Calendar.YEAR); int day = c.get(java.util.Calendar.DAY_OF_YEAR); String abi = org.iiab.controller.deploy.data.RootfsManifest.appAbiId(); String arch = abi != null && abi.contains("64") ? "aarch64" : "armhf"; - return String.format(java.util.Locale.US, "iiab-oa_%04d.%03d_%d_%s.tar.gz", + return String.format(java.util.Locale.US, "k2go_%04d.%03d_%d_%s.tar.gz", year, day, System.currentTimeMillis() / 1000L, arch); } diff --git a/controller/app/src/test/java/org/iiab/controller/deploy/domain/ExtractProgressTest.java b/controller/app/src/test/java/org/iiab/controller/deploy/domain/ExtractProgressTest.java index fc533cf57..5cc6a6315 100644 --- a/controller/app/src/test/java/org/iiab/controller/deploy/domain/ExtractProgressTest.java +++ b/controller/app/src/test/java/org/iiab/controller/deploy/domain/ExtractProgressTest.java @@ -32,8 +32,8 @@ public void ordinaryNamesAreStillShown() { public void shortHexLikeWordsAreNotMistakenForDigests() { assertEquals("deadbeef.conf", ExtractProgress.fileLabel("etc/deadbeef.conf")); assertEquals("facade.png", ExtractProgress.fileLabel("share/facade.png")); - assertEquals("iiab-oa_2026.224_standard.tar.gz", - ExtractProgress.fileLabel("downloads/iiab-oa_2026.224_standard.tar.gz")); + assertEquals("k2go_2026.224_standard.tar.gz", + ExtractProgress.fileLabel("downloads/k2go_2026.224_standard.tar.gz")); } /** Fails open: a name we cannot classify is shown, never hidden on a guess. */ diff --git a/controller/app/src/test/java/org/iiab/controller/download/domain/MetalinkFileTest.java b/controller/app/src/test/java/org/iiab/controller/download/domain/MetalinkFileTest.java index feb7af3b4..e094d481f 100644 --- a/controller/app/src/test/java/org/iiab/controller/download/domain/MetalinkFileTest.java +++ b/controller/app/src/test/java/org/iiab/controller/download/domain/MetalinkFileTest.java @@ -21,15 +21,15 @@ public class MetalinkFileTest { private static final String META4 = "\n" + "\n" - + " \n" + + " \n" + " 1453144579\n" + " " + FILE_HASH + "\n" + " \n" + " " + FIRST_PIECE_HASH + "\n" + " 67c19c9e0509ff1aaeb104fce7498f53f02052acb18a241409b6d58c9c114142\n" + " \n" - + " https://iiab.switnet.org/android/rootfs/iiab-oa_2026.192_standard_17dd521_arm64-v8a.tar.gz\n" - + " https://mirror2.example.org/iiab-oa_2026.192_standard_17dd521_arm64-v8a.tar.gz\n" + + " https://pub-d64c885cef6c42db8c7925144d73d0ee.r2.dev/k2go_2026.192_standard_17dd521_arm64-v8a.tar.gz\n" + + " https://mirror2.example.org/k2go_2026.192_standard_17dd521_arm64-v8a.tar.gz\n" + " \n" + "\n"; @@ -40,7 +40,7 @@ private MetalinkFile parse() throws Exception { } @Test public void parsesFileName() throws Exception { - assertEquals("iiab-oa_2026.192_standard_17dd521_arm64-v8a.tar.gz", parse().fileName()); + assertEquals("k2go_2026.192_standard_17dd521_arm64-v8a.tar.gz", parse().fileName()); } @Test public void parsesSize() throws Exception {