veroeffentliche_04.py: leserliche Ausgabe, 404-Probe entfernt

Der erste Alltagseinsatz zeigte drei Schoenheitsfehler, alle in der Ausgabe.

Der Bericht stand verkehrt herum: Die rsync-Zeilen erschienen VOR "Ziel:" und
"Vorpruefung bestanden". Python puffert seine Ausgabe blockweise, sobald sie
nicht an ein Terminal geht, waehrend der Unterprozess unmittelbar schreibt.
sys.stdout.reconfigure(line_buffering=True) stellt die Reihenfolge her.

150 Zeilen fuer eine uebertragene Datei: --itemize-changes lief auch im echten
Durchgang mit, obwohl der Probelauf schon berichtet hatte, was passieren wird.
149 der 150 Zeilen besagten nur ".f..t......" - Inhalt gleich, nur Zeitstempel
nachgezogen, die erwartbare Folge von --checksum. Die Auflistung bleibt jetzt
dem Probelauf vorbehalten.

Der Ersatz war zuerst schlimmer als das Problem: --info=progress2 zeigt am
Terminal eine sich selbst ueberschreibende Zeile, in einer Pipe dagegen jeden
Zwischenstand einzeln - gemessen 213 Zeilen fuer 213 Dateien. Die Anzeige
haengt jetzt an sys.stdout.isatty().

Ausserdem: Die 404-Probe auf anhang-glossar-literatur.html ist entfernt. Die
Datei ist geloescht - im Arbeitsbaum, in Git und auf dem Server -, und die
Probe koennte einen Rueckschritt gar nicht mehr entdecken: Sie bliebe auch
dann gruen, wenn jemand --delete aus dem rsync-Aufruf naehme. Was sie belegt
hat, steht in PROGRESS.md. Von vierzehn Adressen bleiben dreizehn.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
dschlueter 2026-09-08 20:04:53 +02:00
commit 7757e33a97
6 changed files with 61 additions and 10 deletions

View file

@ -70,7 +70,7 @@ python3 Operations_Research_mit_Python_Version_04/veroeffentliche_04.py
**nicht** per `scp`, denn das überschreibt nur und löscht nie; eine aus dem Buch entfernte **nicht** per `scp`, denn das überschreibt nur und löscht nie; eine aus dem Buch entfernte
Seite bliebe sonst dauerhaft online. Vorher prüft es, ob eine Quelldatei neuer ist als die Seite bliebe sonst dauerhaft online. Vorher prüft es, ob eine Quelldatei neuer ist als die
gebaute Website (die Website hing einmal wochenlang einen Bau zurück, ohne dass es auffiel), gebaute Website (die Website hing einmal wochenlang einen Bau zurück, ohne dass es auffiel),
hinterher ruft es vierzehn Adressen per HTTP ab. Bei mehr als 30 Löschungen bricht es ab — hinterher ruft es dreizehn Adressen per HTTP ab. Bei mehr als 30 Löschungen bricht es ab —
die Liste ist dann anzusehen, bevor `--loeschgrenze N` sie freigibt. Ziel in `.env` die Liste ist dann anzusehen, bevor `--loeschgrenze N` sie freigibt. Ziel in `.env`
(nicht im Repository, Vorlage `.env.beispiel`); Anmeldung per SSH-Schlüssel, kein Passwort. (nicht im Repository, Vorlage `.env.beispiel`); Anmeldung per SSH-Schlüssel, kein Passwort.

View file

@ -56,9 +56,15 @@ QUELLEN = [
os.path.join(BASIS, WEB_NAME), os.path.join(BASIS, WEB_NAME),
] ]
# Was nach dem Hochladen erreichbar sein MUSS bzw. NICHT MEHR erreichbar sein # Was nach dem Hochladen erreichbar sein muss.
# darf. Die 404-Zeile ist die eigentliche Probe darauf, dass --delete gewirkt #
# hat: Sie war der Anlass fuer dieses Skript. # Hier stand bis zur ersten Veroeffentlichung eine 404-Zeile fuer
# 'anhang-glossar-literatur.html' - die Seite, die nach dem Teilen von Anhang
# E/F verwaist auf dem Server zurueckblieb und der Anlass fuer dieses Skript
# war. Sie hat ihren Zweck erfuellt und ist wieder entfernt: Die Datei ist
# geloescht, und die Probe koennte einen Rueckschritt gar nicht mehr
# entdecken - sie bliebe auch dann 404, wenn jemand --delete aus dem
# rsync-Aufruf naehme. Was sie belegt hat, steht in PROGRESS.md.
NACHPRUEFUNG = [ NACHPRUEFUNG = [
("", 200), ("", 200),
("index.html", 200), ("index.html", 200),
@ -73,7 +79,6 @@ NACHPRUEFUNG = [
("assets/site.css", 200), ("assets/site.css", 200),
("katex/katex.min.js", 200), ("katex/katex.min.js", 200),
(PDF_DATEINAME, 200), (PDF_DATEINAME, 200),
("anhang-glossar-literatur.html", 404),
] ]
LOESCHGRENZE = 30 LOESCHGRENZE = 30
@ -200,10 +205,25 @@ def rsync_befehl(env: dict[str, str], probelauf: bool) -> list[str]:
# auf beiden Seiten faellt dagegen nicht ins Gewicht. # auf beiden Seiten faellt dagegen nicht ins Gewicht.
befehl = ["rsync", "-rltz", "--checksum", "--delete", "--chmod=D755,F644", befehl = ["rsync", "-rltz", "--checksum", "--delete", "--chmod=D755,F644",
"--skip-compress=pdf/zip/woff2/png/jpg/svg", "--skip-compress=pdf/zip/woff2/png/jpg/svg",
"--itemize-changes",
"-e", ssh_optionen(env)] "-e", ssh_optionen(env)]
if probelauf: if probelauf:
befehl.append("--dry-run") # Nur der Probelauf listet auf - seine Ausgabe wird gelesen und
# ausgewertet. Der echte Lauf wiederholte diese Liste sonst auf dem
# Bildschirm, obwohl schon berichtet wurde, was passieren wird: beim
# ersten Einsatz waren das 150 Zeilen, von denen 149 nur besagten,
# dass rsync einen Zeitstempel nachgezogen hat.
befehl += ["--dry-run", "--itemize-changes"]
elif sys.stdout.isatty():
# Eine einzige, sich selbst ueberschreibende Fortschrittszeile - bei
# 23 MB ueber eine Hausleitung ist die Frage "laeuft es noch?"
# berechtigt.
#
# Nur am Terminal: progress2 ueberschreibt seine Zeile mit
# Wagenruecklauf. Laeuft die Ausgabe in eine Pipe oder Protokolldatei,
# bleibt jeder Zwischenstand als eigene Zeile stehen - gemessen
# 213 Zeilen fuer 213 Dateien, also genau das Rauschen, das hier
# abgestellt werden soll.
befehl.append("--info=progress2")
ziel = env["OR_ZIEL"] ziel = env["OR_ZIEL"]
befehl += [HTML_VERZ + os.sep, befehl += [HTML_VERZ + os.sep,
f'{env["OR_BENUTZER"]}@{env["OR_HOST"]}:{ziel}'] f'{env["OR_BENUTZER"]}@{env["OR_HOST"]}:{ziel}']
@ -306,6 +326,13 @@ def main() -> int:
help="Schritt 4 ueberspringen (kein Netz zum Server)") help="Schritt 4 ueberspringen (kein Netz zum Server)")
argumente = zerleger.parse_args() argumente = zerleger.parse_args()
# Sonst puffert Python seine Ausgabe blockweise, sobald sie nicht an ein
# Terminal geht (Pipe, Protokolldatei, Aufruf aus einer anderen Oberflaeche
# heraus). Die Meldungen dieses Skripts erschienen dann NACH der Ausgabe
# des rsync-Unterprozesses, der unmittelbar schreibt - der Bericht stand
# also verkehrt herum auf dem Bildschirm.
sys.stdout.reconfigure(line_buffering=True)
env = lies_env() env = lies_env()
ziel = f'{env["OR_BENUTZER"]}@{env["OR_HOST"]}:{env["OR_ZIEL"]}' ziel = f'{env["OR_BENUTZER"]}@{env["OR_HOST"]}:{env["OR_ZIEL"]}'
print(f"Ziel: {ziel}") print(f"Ziel: {ziel}")

View file

@ -2233,6 +2233,31 @@ folgt jetzt der Quelle.
Damit ist jede der vier Stellen abgesichert: eine ist die Quelle, zwei werden daraus erzeugt, Damit ist jede der vier Stellen abgesichert: eine ist die Quelle, zwei werden daraus erzeugt,
eine wird geprüft. eine wird geprüft.
### ✅ Der Upload berichtet jetzt leserlich
Der erste Alltagseinsatz des Skripts zeigte drei Schönheitsfehler, alle in der Ausgabe.
**Der Bericht stand verkehrt herum.** Die `rsync`-Zeilen erschienen *vor* „Ziel:" und
„Vorprüfung bestanden". Ursache: Python puffert seine Ausgabe blockweise, sobald sie nicht
an ein Terminal geht, während der Unterprozess unmittelbar schreibt. Ein
`sys.stdout.reconfigure(line_buffering=True)` in `main()` stellt die Reihenfolge her.
**150 Zeilen für eine übertragene Datei.** `--itemize-changes` lief auch im echten Durchgang
mit, obwohl der Probelauf längst berichtet hatte, was passieren wird. Von den 150 Zeilen
besagten 149 nur `.f..t......` — „Inhalt gleich, nur Zeitstempel nachgezogen", die
erwartbare Folge von `--checksum`. Die Auflistung bleibt jetzt dem Probelauf vorbehalten.
**Und der Ersatz war zuerst schlimmer als das Problem.** Statt der Liste sollte
`--info=progress2` eine einzige, sich selbst überschreibende Fortschrittszeile zeigen. Am
Terminal tut es das; in einer Pipe bleibt jeder Zwischenstand als eigene Zeile stehen —
gemessen **213 Zeilen für 213 Dateien**. Die Anzeige hängt deshalb an
`sys.stdout.isatty()`.
**Nebenbei aufgeräumt:** Die 404-Probe auf `anhang-glossar-literatur.html` ist entfernt. Sie
hat ihren Zweck erfüllt — aber einen Rückschritt könnte sie gar nicht mehr entdecken: Die
Datei ist gelöscht, die Probe bliebe auch dann grün, wenn jemand `--delete` aus dem
`rsync`-Aufruf nähme. Von den ursprünglich vierzehn Adressen bleiben dreizehn.
--- ---
## 8. Commit-Historie des V04-Strangs ## 8. Commit-Historie des V04-Strangs

View file

@ -210,9 +210,8 @@ Vier Schritte, jeder mit einer eigenen Aufgabe:
ist der Lauf verdächtig (falscher Zielpfad, halb gebautes Verzeichnis) und bricht ab; ist der Lauf verdächtig (falscher Zielpfad, halb gebautes Verzeichnis) und bricht ab;
`--loeschgrenze N` hebt die Grenze an. `--loeschgrenze N` hebt die Grenze an.
3. **Übertragung.** 3. **Übertragung.**
4. **Nachprüfung per HTTP.** Vierzehn Adressen werden abgerufen und ihr Statuscode mit der 4. **Nachprüfung per HTTP.** Dreizehn Adressen werden abgerufen und ihr Statuscode mit der
Erwartung verglichen — einschließlich der Probe, dass eine entfernte Seite wirklich 404 Erwartung verglichen.
liefert.
`--probelauf` führt nur die Schritte 1 und 2 aus. In der `.env` steht **kein Geheimnis**: `--probelauf` führt nur die Schritte 1 und 2 aus. In der `.env` steht **kein Geheimnis**:
`rsync` und `scp` haben keine Passwort-Option, die Anmeldung läuft über den SSH-Schlüssel. `rsync` und `scp` haben keine Passwort-Option, die Anmeldung läuft über den SSH-Schlüssel.