[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/python/python-docs-de/3.14/tools/tx_push.py [Back]  [Original]

#!/usr/bin/env python3
"""Interaktiver Transifex-Push: fragt, welche Dateien hochgeladen werden.

Das Skript liest .tx/config des aktuellen Branches, ordnet jeder .po-Datei
ihren Transifex-Resource-Namen zu und stellt sie zur Auswahl. Gepusht wird
mit der forcierten Kombination, die wir beim Abgleich benutzen:

    tx push -t -l de -f --skip --replace-edited-strings  ...

      -t                        nur Uebersetzungen (die Quelltexte kommen
                                aus CPython, nicht von uns)
      -l de                      nur die deutsche Sprache
      -f                        Zeitstempel-Sperre aus ("remote is newer")
      --replace-edited-strings   ueberschreibt auch in Transifex bearbeitete
                                Strings -- GitHub ist die Quelle der Wahrheit
      --skip                     bricht nicht ab, wenn eine Ressource zickt

Aufruf:
    python tools/tx_push.py                  # geaenderte Dateien vorschlagen
    python tools/tx_push.py --alle           # alle Dateien aus .tx/config
    python tools/tx_push.py howto            # nach Pfad filtern
    python tools/tx_push.py library/csv.po
    python tools/tx_push.py --dry-run howto  # nur zeigen, nicht pushen
"""

import argparse
import configparser
import re
import subprocess
import sys
from pathlib import Path

try:
    import polib
except ImportError:
    polib = None  # Fortschrittsanzeige ist dann eben leer


def git(*args: str) -> str:
    e = subprocess.run(["git", *args], capture_output=True, text=True)
    return e.stdout if e.returncode == 0 else ""


def repo_wurzel() -> Path:
    aus = git("rev-parse", "--show-toplevel").strip()
    if not aus:
        sys.exit("Kein Git-Repository -- bitte im python-docs-de-Verzeichnis starten.")
    return Path(aus)


def ressourcen(wurzel: Path) -> dict:
    """{po-Pfad: (projekt, resource)} aus .tx/config."""
    pfad = wurzel / ".tx" / "config"
    if not pfad.is_file():
        sys.exit(f"{pfad} nicht gefunden.")

    cfg = configparser.ConfigParser()
    cfg.read(pfad, encoding="utf-8")

    aus = {}
    for name in cfg.sections():
        # [o:python-doc:p:python-314:r:howto--index]
        m = re.match(r"o:([^:]+):p:([^:]+):r:(.+)", name)
        if not m:
            continue
        _org, projekt, resource = m.groups()
        abschnitt = cfg[name]
        datei = abschnitt.get("trans.de") or abschnitt.get("file_filter", "")
        datei = datei.replace("", "de").strip()
        if datei:
            aus[datei] = (projekt, resource)
    if not aus:
        sys.exit("In .tx/config wurden keine Ressourcen gefunden.")
    return aus


def geaenderte_dateien(wurzel: Path) -> set:
    """.po-Dateien, die sich gegenueber origin/ oder im Baum geaendert haben."""
    branch = git("branch", "--show-current").strip()
    kandidaten = set()
    for befehl in (
        ["diff", "--name-only"],                       # unversionierte Aenderungen
        ["diff", "--name-only", "--cached"],           # gestaged
        ["diff", "--name-only", f"origin/{branch}...HEAD"],  # noch nicht gepusht
    ):
        for zeile in git(*befehl).splitlines():
            if zeile.endswith(".po"):
                kandidaten.add(zeile)
    return kandidaten


def stand(wurzel: Path, datei: str) -> str:
    """'123/456 (27 %)' -- oder leer, wenn polib fehlt."""
    if polib is None:
        return ""
    p = wurzel / datei
    if not p.is_file():
        return "fehlt lokal"
    try:
        po = polib.pofile(str(p))
    except Exception:
        return "nicht lesbar"
    gesamt = len([e for e in po if not e.obsolete])
    fertig = len([e for e in po if not e.obsolete and e.translated()])
    prozent = 100 * fertig // gesamt if gesamt else 0
    return f"{fertig}/{gesamt} ({prozent} %)"


def auswahl_lesen(anzahl: int) -> list:
    """'1,3-5' oder 'a' einlesen und in Indizes uebersetzen."""
    while True:
        roh = input("\nNummern (z. B. 1,3-5), a = alle, q = Abbruch: ").strip().lower()
        if roh in ("q", ""):
            sys.exit("Abgebrochen.")
        if roh == "a":
            return list(range(anzahl))
        indizes = set()
        try:
            for teil in roh.replace(" ", "").split(","):
                if "-" in teil:
                    von, bis = teil.split("-", 1)
                    indizes.update(range(int(von) - 1, int(bis)))
                else:
                    indizes.add(int(teil) - 1)
        except ValueError:
            print("Das habe ich nicht verstanden.")
            continue
        if any(i < 0 or i >= anzahl for i in indizes):
            print(f"Nur 1 bis {anzahl} sind gueltig.")
            continue
        return sorted(indizes)


def main() -> None:
    p = argparse.ArgumentParser(
        description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
    )
    p.add_argument("muster", nargs="*", help="Pfadteile zum Filtern, z. B. howto")
    p.add_argument("--alle", action="store_true",
                   help="alle Dateien aus .tx/config zur Auswahl stellen")
    p.add_argument("--dry-run", action="store_true",
                   help="Befehl nur anzeigen, nicht ausfuehren")
    args = p.parse_args()

    wurzel = repo_wurzel()
    branch = git("branch", "--show-current").strip()
    karte = ressourcen(wurzel)
    projekt = next(iter(karte.values()))[0]

    dateien = sorted(karte)
    herkunft = "alle Ressourcen aus .tx/config"

    if args.muster:
        dateien = [d for d in dateien if any(m in d for m in args.muster)]
        herkunft = "Treffer fuer " + ", ".join(args.muster)
    elif not args.alle:
        geaendert = geaenderte_dateien(wurzel) & set(karte)
        if geaendert:
            dateien = sorted(geaendert)
            herkunft = "geaenderte Dateien"
        else:
            print("Keine geaenderten .po-Dateien gefunden -- zeige alle.\n")

    if not dateien:
        sys.exit("Keine passende Datei gefunden.")

    print(f"Branch {branch}  ->  Transifex-Projekt {projekt}   ({herkunft})\n")
    breite = max(len(d) for d in dateien)
    for i, d in enumerate(dateien, 1):
        print(f"  {i:>3}  {d:

Web Proxy Viewer  |  New URL  |  Original Page