Files
AXP-Resurection/scripts/009-rebuild-from-los.sh
sunfish-adminandCursor 2d145c2878 009: Polish bacon fixes, OTA host scripts, and migration docs.
Restore disable_configstore, EuiccDisabler and thermal CDEV guards, branding
and rebuild/sync helpers; document device roles, laptop migration, and Gitea.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-16 21:06:45 +02:00

159 lines
5.6 KiB
Bash
Executable File

#!/bin/bash
# Rebuild AXP Resurection from a LineageOS 23.2 sunfish tree on rom-dev01.
#
# This is the OTA entry point. It always ships:
# - Magisk 30.7 preroot + release-keys (009 bacon)
# - wave 4 deblob (AXP_DEBLOB_WAVE4=1)
# - hardened_malloc 2 GiB (012), after a libc link check
# - AVB flags 0 (WITH_AVB=true)
#
# It does not download the signed nightly zip. The source is the repo tree
# at LINEAGE_TREE (default /srv/rom/src/lineage), branch lineage-23.2.
#
# Usage (host only, detached):
# LOS_SYNC=1 /srv/rom/artifacts/bin/rom-detach bacon009ota -- \
# bash /path/to/AXP_Resurection/scripts/009-rebuild-from-los.sh
#
# LOS_SYNC=1
# Clean project worktrees, repo sync -c -j8 --force-sync, then check out every project
# revision from LOS_MANIFEST. LOS_MANIFEST is mandatory in this mode.
# LOS_MANIFEST=/path/to/build-manifest.xml
# Exact official nightly build-manifest.xml. After pinning, write repo
# manifest -r and fail if any common project revision differs.
# LOS_DATE=YYYYMMDD
# Nightly date used as LINEAGE_BUILD_DATE, so the zip is named
# AXP-Resurection-Pro-23.2-<LOS_DATE>-sunfish.zip.
#
# Current tree (2026-10-10) was synced 2026-09-13 (vanilla bacon 2026-09-14),
# kernel reset each bacon to 28f9290ae067. That is NOT
# lineage-23.2-20261008-nightly-sunfish. Set LOS_SYNC=1 to move the tree
# forward, then compare manifests before trusting the zip.
set -euo pipefail
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
TREE=${LINEAGE_TREE:-/srv/rom/src/lineage}
ART=/srv/rom/artifacts/009-axp-los23-port
PROJECT_SOURCE=${AXP_PROJECT_SOURCE:-}
if [[ ! -d "$TREE/.repo" ]]; then
echo "FAIL: $TREE is not a repo checkout" >&2
exit 1
fi
cd "$TREE"
# rom-dev01: if bacon is started as root, git refuses android-build-owned trees.
export HOME="${HOME:-/home/android-build}"
mkdir -p "$ART"
STAMP=$(date -u +%Y%m%dT%H%M%SZ)
if [[ "${LOS_SYNC:-0}" == 1 ]]; then
if [[ -z "${LOS_MANIFEST:-}" || ! -f "$LOS_MANIFEST" ]]; then
echo "FAIL: LOS_SYNC=1 requires an existing LOS_MANIFEST" >&2
exit 1
fi
echo "=== clean existing project worktrees $(date -Is) ==="
repo forall -c 'git reset --hard -q HEAD; git clean -fdq'
echo "=== repo sync -c -j8 --force-sync $(date -Is) ==="
# force-sync is needed when upstream changed a project's object-store
# association. Project worktrees were reset above; our patch source is
# staged outside the repo tree.
repo sync -c -j8 --force-sync
echo "=== pin projects to $(basename "$LOS_MANIFEST") $(date -Is) ==="
python3 - "$LOS_MANIFEST" <<'PY'
import pathlib
import subprocess
import sys
import xml.etree.ElementTree as ET
root = ET.parse(sys.argv[1]).getroot()
missing = []
count = 0
for el in root.iter("project"):
path = pathlib.Path(el.get("path") or el.get("name") or "")
rev = el.get("revision")
if not path or not rev:
continue
if not (path / ".git").exists():
missing.append(str(path))
continue
probe = subprocess.run(
["git", "-C", str(path), "cat-file", "-e", f"{rev}^{{commit}}"],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
if probe.returncode:
sys.exit(f"FAIL: nightly revision unavailable in {path}: {rev}")
subprocess.run(
["git", "-C", str(path), "checkout", "--detach", "-q", rev],
check=True,
)
subprocess.run(["git", "-C", str(path), "clean", "-fdq"], check=True)
count += 1
print(f"OK: pinned {count} projects; {len(missing)} nightly-only paths absent locally")
for path in missing[:20]:
print(f"MISSING_LOCAL {path}")
if len(missing) > 20:
print(f"... {len(missing) - 20} more missing paths")
PY
fi
MANIFEST_OUT="$ART/manifest-${STAMP}.xml"
repo manifest -r -o "$MANIFEST_OUT"
echo "OK: wrote $MANIFEST_OUT"
if [[ -n "${LOS_MANIFEST:-}" ]]; then
if [[ ! -f "$LOS_MANIFEST" ]]; then
echo "FAIL: LOS_MANIFEST not a file: $LOS_MANIFEST" >&2
exit 1
fi
echo "=== manifest diff vs $LOS_MANIFEST ==="
python3 - "$MANIFEST_OUT" "$LOS_MANIFEST" <<'PY'
import sys
import xml.etree.ElementTree as ET
def revs(path):
root = ET.parse(path).getroot()
out = {}
for el in root.iter("project"):
name = el.get("name") or el.get("path")
rev = el.get("revision")
if name and rev:
out[name] = rev
return out
local, nightly = revs(sys.argv[1]), revs(sys.argv[2])
only_l = sorted(set(local) - set(nightly))
only_n = sorted(set(nightly) - set(local))
differ = sorted(n for n in local.keys() & nightly.keys() if local[n] != nightly[n])
print(f"projects local={len(local)} nightly={len(nightly)} differ={len(differ)} only_local={len(only_l)} only_nightly={len(only_n)}")
for n in differ[:40]:
print(f"DIFF {n}\n local {local[n]}\n nightly {nightly[n]}")
if len(differ) > 40:
print(f"... {len(differ) - 40} more diffs")
if differ:
sys.exit("FAIL: local source revisions do not match the pinned nightly")
PY
fi
if [[ -n "${LOS_DATE:-}" ]]; then
[[ "$LOS_DATE" =~ ^[0-9]{8}$ ]] || { echo "FAIL: LOS_DATE must be YYYYMMDD" >&2; exit 1; }
echo "$LOS_DATE" > "$TREE/.axp-los-date"
echo "OK: build name date = LOS nightly $LOS_DATE"
fi
if [[ -n "$PROJECT_SOURCE" ]]; then
if [[ ! -d "$PROJECT_SOURCE/vendor/sunfish-a16" ]]; then
echo "FAIL: AXP_PROJECT_SOURCE lacks vendor/sunfish-a16: $PROJECT_SOURCE" >&2
exit 1
fi
echo "=== install current AXP working tree into source tree ==="
rsync -a --delete --exclude .git \
"$PROJECT_SOURCE/vendor/sunfish-a16/" "$TREE/vendor/sunfish-a16/"
fi
echo "=== mandatory ship: wave4 + hardened_malloc + release-keys bacon ==="
export AXP_DEBLOB_WAVE4=1
export AXP_AVB_FLAGS=0
export WITH_AVB=true
exec bash "$SCRIPT_DIR/009-bacon-hardened-malloc.sh"