Auf dem Gerät scheiterte das Upgrade an libmagic: trying to overwrite '.../include/magic.h', which is also in package file 5.47 Termux hat libmagic aus dem Paket file herausgelöst. Beide bringen dieselbe Datei mit, und dpkg verweigert grundsätzlich, wenn zwei Pakete um eine Datei streiten. Das ist kein Defekt, sondern der normale Zwischenzustand einer Paketaufteilung — und er blockiert danach jede weitere Installation. Beide Skripte erkennen den Konflikt jetzt an der Meldung und wiederholen mit --force-overwrite. Bewusst erst dann und nicht von vornherein: pauschal mitgegeben würde die Option jede künftige Dateikollision stillschweigend übergehen, auch eine, die auf ein echtes Problem hinweist. Die betroffene Zeile wird vorher angezeigt, damit nachvollziehbar bleibt, was übergangen wird. Gegen die tatsächliche Ausgabe vom Gerät geprüft: Konflikt wird erkannt, und nach dem Rauschfilter bleiben genau die zwei Zeilen übrig, auf die es ankommt. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
226 lines
9.9 KiB
Bash
Executable File
226 lines
9.9 KiB
Bash
Executable File
#!/data/data/com.termux/files/usr/bin/bash
|
|
# HPOS — Startpunkt auf dem Telefon.
|
|
#
|
|
# Dieses Skript ist absichtlich das EINZIGE, was per adb aufs Telefon kommt.
|
|
# Alles Weitere holt es sich per git. Der Grund: danach ist das Repo auf dem
|
|
# Telefon eine Arbeitskopie, keine Kopie. Aktualisieren heißt dann schlicht
|
|
#
|
|
# cd ~/hpos && git pull
|
|
#
|
|
# statt jedes Mal wieder den PC anzuwerfen und Dateien zu schieben.
|
|
#
|
|
# Aufruf in Termux:
|
|
# bash /sdcard/hpos-init.sh
|
|
# bash /sdcard/hpos-init.sh https://beispiel/anderes-repo.git
|
|
set -uo pipefail
|
|
|
|
REPO="${1:-${HPOS_REPO:-@@REPO_URL@@}}"
|
|
ZIEL="$HOME/hpos"
|
|
|
|
if [ -t 1 ]; then
|
|
C_OK=$'\033[32m'; C_WARN=$'\033[33m'; C_ERR=$'\033[31m'
|
|
C_HEAD=$'\033[1;36m'; C_DIM=$'\033[2m'; C_OFF=$'\033[0m'
|
|
else
|
|
C_OK=""; C_WARN=""; C_ERR=""; C_HEAD=""; C_DIM=""; C_OFF=""
|
|
fi
|
|
kopf() { printf '\n%s══ %s ══%s\n' "$C_HEAD" "$*" "$C_OFF"; }
|
|
ok() { printf '%s ✓%s %s\n' "$C_OK" "$C_OFF" "$*"; }
|
|
warn() { printf '%s !%s %s\n' "$C_WARN" "$C_OFF" "$*"; }
|
|
fehl() { printf '%s ✗%s %s\n' "$C_ERR" "$C_OFF" "$*"; }
|
|
hinweis() { printf '%s %s%s\n' "$C_DIM" "$*" "$C_OFF"; }
|
|
|
|
case "$REPO" in
|
|
@@*) fehl "Keine Repo-Adresse hinterlegt."
|
|
hinweis "Aufruf mit Adresse: bash /sdcard/hpos-init.sh <url>"
|
|
exit 1 ;;
|
|
esac
|
|
|
|
# Benutzernamen aus der Adresse entfernen. Lesen geht anonym; steht ein Name in
|
|
# der URL, fragt git trotzdem nach einem Passwort — auf einer Bildschirmtastatur
|
|
# eine unnötige Quälerei. Zum Schreiben braucht man ihn ohnehin nur auf dem PC.
|
|
REPO_ROH="$REPO"
|
|
REPO=$(printf '%s' "$REPO" | sed -E 's#^(https?://)[^/@]+@#\1#')
|
|
[ "$REPO" != "$REPO_ROH" ] && ANONYM=1 || ANONYM=0
|
|
|
|
kopf "HPOS — Ersteinrichtung auf dem Telefon"
|
|
hinweis "Repo: $REPO"
|
|
[ "$ANONYM" = 1 ] && hinweis "(Benutzername entfernt — gelesen wird anonym)"
|
|
|
|
# ── Vollupgrade ──────────────────────────────────────────────────────────────
|
|
# Muss VOR jedem anderen Paket laufen. Termux verträgt keine Teilupgrades: die
|
|
# Pakete werden gegeneinander gebaut, und ein einzeln nachinstalliertes trifft
|
|
# sonst auf veraltete Abhängigkeiten. Genau daran ist proot-distro gescheitert —
|
|
# es trug die Shebang-Zeile python3.13, während eine andere Fassung installiert war.
|
|
#
|
|
# Überspringbar mit HPOS_OHNE_UPGRADE=1, etwa bei knappem Datenvolumen.
|
|
kopf "Termux auf einen Stand bringen"
|
|
if [ "${HPOS_OHNE_UPGRADE:-0}" = 1 ]; then
|
|
warn "Übersprungen (HPOS_OHNE_UPGRADE=1)"
|
|
hinweis "Bei Problemen mit proot-distro ist das die erste Stelle zum Nachsehen."
|
|
else
|
|
hinweis "Das dauert und lädt einiges. Es erspart aber genau die Fehler,"
|
|
hinweis "die sonst erst Stunden später als kaputtes proot-distro auffallen."
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
|
|
# Beim Wechsel der Python-Version wirft dpkg dutzende Zeilen
|
|
# "unable to delete old directory ... Directory not empty". Das sind
|
|
# Warnungen, keine Fehler: in site-packages liegen noch .pyc-Dateien oder
|
|
# selbst installierte Module. Sie herauszufiltern ist kein Verstecken —
|
|
# sie verdecken sonst die eine Zeile, auf die es ankommt.
|
|
rauschfilter() { grep -viE 'unable to delete old directory|^(Unpacking|Preparing|Selecting) '; }
|
|
|
|
# --force-confold: vorhandene Konfiguration behalten, statt mitten im Lauf
|
|
# eine Rückfrage zu stellen, die niemand beantwortet.
|
|
AUSGABE=$(mktemp)
|
|
pkg update -y >"$AUSGABE" 2>&1; rauschfilter <"$AUSGABE"
|
|
|
|
upgrade_lauf() {
|
|
pkg upgrade -y -o Dpkg::Options::=--force-confold "$@" >"$AUSGABE" 2>&1
|
|
local rc=$?
|
|
rauschfilter <"$AUSGABE"
|
|
return $rc
|
|
}
|
|
|
|
if upgrade_lauf; then
|
|
ok "Termux ist aktuell"
|
|
else
|
|
# Dateikonflikt gezielt behandeln. Er entsteht, wenn ein Paket aufgeteilt
|
|
# wurde und beide Teile kurzzeitig dieselbe Datei mitbringen — bei Termux
|
|
# etwa libmagic, herausgelöst aus file. dpkg verweigert dann grundsätzlich.
|
|
#
|
|
# --force-overwrite wird bewusst NUR hier gesetzt, nachdem der Konflikt in
|
|
# der Ausgabe nachgewiesen ist. Pauschal mitzugeben hieße, jede künftige
|
|
# Dateikollision stillschweigend zu übergehen.
|
|
if grep -q 'which is also in package' "$AUSGABE"; then
|
|
warn "Dateikonflikt zwischen zwei Paketen — typisch bei einer Paketaufteilung."
|
|
grep 'trying to overwrite' "$AUSGABE" | head -3 | sed 's/^/ /'
|
|
hinweis "Wiederhole gezielt mit --force-overwrite."
|
|
if upgrade_lauf -o Dpkg::Options::=--force-overwrite; then
|
|
ok "Konflikt aufgelöst, Upgrade durchgelaufen"
|
|
rm -f "$AUSGABE"
|
|
AUSGABE=""
|
|
fi
|
|
fi
|
|
|
|
if [ -n "$AUSGABE" ] && ! upgrade_lauf; then
|
|
warn "Upgrade weiterhin unvollständig — versuche dpkg zu entwirren."
|
|
# Nach einem Abbruch steckt dpkg halb fertig fest und blockiert alles.
|
|
dpkg --configure -a >>"$AUSGABE" 2>&1
|
|
apt-get -f install -y >>"$AUSGABE" 2>&1
|
|
if upgrade_lauf -o Dpkg::Options::=--force-overwrite; then
|
|
ok "Nach der Reparatur durchgelaufen"
|
|
else
|
|
warn "Bleibt unvollständig."
|
|
hinweis "Speicherplatz prüfen: df -h \$PREFIX (nicht / — das ist die Systempartition)"
|
|
hinweis "Fehler ohne Rauschen: pkg upgrade -y 2>&1 | grep -viE 'unable to delete' | tail -20"
|
|
hinweis "Weiter geht es trotzdem — aber hier ansetzen, falls später etwas klemmt."
|
|
fi
|
|
fi
|
|
fi
|
|
rm -f "$AUSGABE" 2>/dev/null || true
|
|
fi
|
|
|
|
# ── git ──────────────────────────────────────────────────────────────────────
|
|
kopf "git"
|
|
if command -v git >/dev/null 2>&1; then
|
|
ok "bereits vorhanden ($(git --version))"
|
|
else
|
|
if pkg install -y git; then ok "installiert"
|
|
else fehl "Installation von git fehlgeschlagen"; exit 1; fi
|
|
fi
|
|
|
|
# Das Telefon liest nur. Es soll nie versehentlich versuchen zurückzuschreiben —
|
|
# ein Push von hier wäre weder gewollt noch möglich.
|
|
git config --global credential.helper "" 2>/dev/null || true
|
|
|
|
# ── Rückfallebene: Archiv statt Klon ─────────────────────────────────────────
|
|
# Gitea, Forgejo und GitHub bieten den Baum zusätzlich als Tarball an. Der Weg
|
|
# dorthin geht nicht über upload-pack und funktioniert deshalb auch dann noch,
|
|
# wenn der Klon am Server scheitert. Das Ergebnis ist aber nur ein Abzug: kein
|
|
# .git, kein 'git pull'. Es ist eine Notlösung, keine Alternative.
|
|
archiv_holen() {
|
|
local basis zweig="${HPOS_ZWEIG:-main}" url tmp
|
|
basis="${REPO%.git}"
|
|
|
|
command -v curl >/dev/null 2>&1 || pkg install -y curl >/dev/null 2>&1
|
|
command -v tar >/dev/null 2>&1 || pkg install -y tar >/dev/null 2>&1
|
|
|
|
tmp=$(mktemp -d)
|
|
for url in "$basis/archive/$zweig.tar.gz" \
|
|
"$basis/archive/refs/heads/$zweig.tar.gz"; do
|
|
hinweis "Versuche Archiv: $url"
|
|
if curl -sfL -o "$tmp/a.tar.gz" "$url" && tar tzf "$tmp/a.tar.gz" >/dev/null 2>&1; then
|
|
mkdir -p "$ZIEL"
|
|
# --strip-components=1: die Archive enthalten alles unter einem
|
|
# Wurzelverzeichnis, das wir nicht mit übernehmen wollen.
|
|
if tar xzf "$tmp/a.tar.gz" -C "$ZIEL" --strip-components=1; then
|
|
rm -rf "$tmp"
|
|
ok "Archiv entpackt nach $ZIEL"
|
|
return 0
|
|
fi
|
|
fi
|
|
done
|
|
rm -rf "$tmp"
|
|
return 1
|
|
}
|
|
|
|
# ── Holen oder aktualisieren ─────────────────────────────────────────────────
|
|
kopf "Repo"
|
|
if [ -d "$ZIEL/.git" ]; then
|
|
ok "Arbeitskopie vorhanden — aktualisiere"
|
|
if git -C "$ZIEL" pull --ff-only; then
|
|
ok "aktuell"
|
|
else
|
|
warn "git pull fehlgeschlagen."
|
|
hinweis "Lokale Änderungen? Dann: cd ~/hpos && git stash && git pull"
|
|
exit 1
|
|
fi
|
|
else
|
|
# --depth reicht nicht: für 'git pull' später brauchen wir eine vollwertige
|
|
# Arbeitskopie, kein abgeschnittenes Archiv.
|
|
if git clone "$REPO" "$ZIEL"; then
|
|
ok "geklont nach $ZIEL"
|
|
else
|
|
fehl "git clone fehlgeschlagen."
|
|
hinweis "Adresse war: $REPO"
|
|
echo
|
|
# Ein scheiternder Klon bei erreichbarem Repo hat fast immer eine
|
|
# serverseitige Ursache: upload-pack stirbt beim Schnüren des Pakets,
|
|
# während die Objekte selbst heil sind. Erkennbar daran, dass sich ein
|
|
# Archiv weiterhin erzeugen lässt — und genau das ist die Rückfallebene.
|
|
if archiv_holen; then
|
|
warn "Über ein Archiv geholt, NICHT als Arbeitskopie."
|
|
hinweis "'git pull' funktioniert damit nicht. Sobald der Server wieder"
|
|
hinweis "Pakete ausliefert: rm -rf ~/hpos && bash /sdcard/hpos-init.sh"
|
|
else
|
|
fehl "Auch die Rückfallebene über das Archiv hat nicht geklappt."
|
|
hinweis "Ist das Repo öffentlich lesbar? Ohne das braucht es Zugangsdaten,"
|
|
hinweis "und die gehören nicht aufs Telefon."
|
|
exit 1
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
chmod +x "$ZIEL"/spike/*.sh "$ZIEL"/spike/inner/*.sh 2>/dev/null || true
|
|
|
|
# ── Weiter ───────────────────────────────────────────────────────────────────
|
|
kopf "Fertig"
|
|
cat <<TEXT
|
|
Das Repo liegt jetzt unter ~/hpos und ist eine Arbeitskopie.
|
|
Aktualisieren später:
|
|
|
|
cd ~/hpos && git pull
|
|
|
|
Nächster Schritt:
|
|
|
|
cd ~/hpos
|
|
bash spike/00-bootstrap-termux.sh
|
|
|
|
Danach die Beweise der Reihe nach — S1 zuerst, weil er der wackligste ist:
|
|
|
|
bash spike/01-s1-plasma-mobile.sh
|
|
bash spike/02-s2-mikrofon.sh
|
|
bash spike/03-s3-pipewire-kamera.sh
|
|
bash spike/04-s4-intent-handoff.sh
|
|
TEXT
|