2021-10-22 12:56:00 +00:00
|
|
|
"""Tool to merge cpython pot files to python-docs-fr po files for a
|
|
|
|
given branch.
|
|
|
|
"""
|
|
|
|
|
|
|
|
import re
|
|
|
|
import shutil
|
|
|
|
from pathlib import Path
|
|
|
|
import argparse
|
|
|
|
import subprocess
|
|
|
|
from subprocess import PIPE
|
|
|
|
from tqdm import tqdm
|
|
|
|
|
|
|
|
|
|
|
|
def run(*args: str | Path, **kwargs) -> subprocess.CompletedProcess:
|
|
|
|
"""Run a shell command with subprocess.run() with check=True and
|
|
|
|
encoding="UTF-8".
|
|
|
|
"""
|
|
|
|
return subprocess.run(list(args), encoding="UTF-8", check=True, **kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
def parse_args():
|
|
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
|
|
parser.add_argument(
|
|
|
|
"--cpython_repo",
|
|
|
|
default=Path("venv/cpython"),
|
|
|
|
type=Path,
|
|
|
|
help="Use this given cpython clone.",
|
|
|
|
)
|
|
|
|
parser.add_argument("branch", help="Merge from this branch")
|
|
|
|
return parser.parse_args()
|
|
|
|
|
|
|
|
|
|
|
|
def setup_repo(repo_path: Path, branch: str):
|
|
|
|
"""Ensure we're up-to-date."""
|
|
|
|
run("git", "-C", repo_path, "checkout", branch)
|
|
|
|
run("git", "-C", repo_path, "pull", "--ff-only")
|
|
|
|
|
|
|
|
|
|
|
|
def copy_new_files(new_files: set[Path], pot_path: Path) -> None:
|
|
|
|
"""Just copy new po files to our hierarchy."""
|
|
|
|
print(f"{len(new_files)} new files.")
|
|
|
|
for file in new_files:
|
|
|
|
file.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
src = (pot_path / file).with_suffix(".pot")
|
|
|
|
run("msgcat", "-o", file, src)
|
|
|
|
|
|
|
|
|
|
|
|
def update_known_files(known_files: set[Path], pot_path: Path) -> None:
|
|
|
|
"""msgmerge updated pot files in our po files."""
|
|
|
|
print(f"{len(known_files)} files to update.")
|
|
|
|
for file in tqdm(known_files, desc="merging pot files"):
|
|
|
|
src = (pot_path / file).with_suffix(".pot")
|
|
|
|
run("msgmerge", "-q", "--backup=off", "--force-po", "-U", file, src)
|
|
|
|
|
|
|
|
|
|
|
|
def remove_old_files(old_files: set[Path]) -> None:
|
|
|
|
"""Remove files removed upstream."""
|
|
|
|
print(f"{len(old_files)} removed files.")
|
|
|
|
|
|
|
|
for file in old_files:
|
|
|
|
run("git", "rm", file)
|
|
|
|
|
|
|
|
|
|
|
|
def clean_paths(files: set[Path]) -> None:
|
|
|
|
"""Ensure the path present in po files are always relative.
|
|
|
|
|
|
|
|
This avoid having diffs on those paths when we change something in
|
|
|
|
a script.
|
|
|
|
"""
|
|
|
|
for file in tqdm(files, desc="Cleaning rst path in pot files"):
|
|
|
|
contents = file.read_text(encoding="UTF-8")
|
|
|
|
contents = re.sub("^#: .*Doc/", "#: ", contents, flags=re.M)
|
|
|
|
file.write_text(contents, encoding="UTF-8")
|
|
|
|
|
|
|
|
|
|
|
|
def update_makefile(cpython_repo: Path) -> None:
|
|
|
|
"""Update CPYTHON_CURRENT_COMMIT in the Makefile.
|
|
|
|
|
|
|
|
So that when we run `make` it use the same commit than the one
|
|
|
|
used to generate the `po` files.
|
|
|
|
"""
|
|
|
|
makefile = Path("Makefile").read_text(encoding="UTF-8")
|
2021-11-05 22:32:47 +00:00
|
|
|
head = run(
|
|
|
|
"git", "-C", cpython_repo, "rev-parse", "HEAD", stdout=PIPE
|
|
|
|
).stdout.strip()
|
2021-10-22 12:56:00 +00:00
|
|
|
makefile = re.sub(
|
|
|
|
"^CPYTHON_CURRENT_COMMIT :=.*$",
|
|
|
|
f"CPYTHON_CURRENT_COMMIT := {head}",
|
|
|
|
makefile,
|
|
|
|
flags=re.M,
|
|
|
|
)
|
|
|
|
Path("Makefile").write_text(makefile, encoding="UTF-8")
|
|
|
|
run("git", "add", "Makefile")
|
|
|
|
|
|
|
|
|
|
|
|
def git_add_relevant_files():
|
|
|
|
"""Add only files with relevant modifications.
|
|
|
|
|
|
|
|
This only add files with actual modifications, not just metadata
|
|
|
|
modifications, to avoid noise in history.
|
|
|
|
"""
|
|
|
|
modified_files = run("git", "ls-files", "-m", stdout=PIPE).stdout.split("\n")
|
|
|
|
modified_po_files = [line for line in modified_files if line.endswith(".po")]
|
|
|
|
for file in modified_po_files:
|
|
|
|
diff = run("git", "diff", "-U0", file, stdout=PIPE).stdout
|
|
|
|
if len(diff.split("\n")) > 8:
|
|
|
|
run("git", "add", file)
|
|
|
|
else:
|
|
|
|
run("git", "checkout", "--", file)
|
|
|
|
run("rm", "-f", "whatsnew/changelog.po") # We don't translate this file.
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
args = parse_args()
|
|
|
|
setup_repo(args.cpython_repo, args.branch)
|
|
|
|
run(
|
|
|
|
*["sphinx-build", "-jauto", "-QDgettext_compact=0", "-bgettext", ".", "../pot"],
|
|
|
|
cwd=args.cpython_repo / "Doc",
|
|
|
|
)
|
|
|
|
pot_path = args.cpython_repo / "pot"
|
|
|
|
upstream = {
|
|
|
|
file.relative_to(pot_path).with_suffix(".po")
|
|
|
|
for file in pot_path.glob("**/*.pot")
|
|
|
|
}
|
|
|
|
downstream = {
|
2022-05-22 17:58:14 +00:00
|
|
|
Path(po)
|
|
|
|
for po in run("git", "ls-files", "*.po", stdout=PIPE).stdout.splitlines()
|
2021-10-22 12:56:00 +00:00
|
|
|
}
|
|
|
|
copy_new_files(upstream - downstream, pot_path=pot_path)
|
|
|
|
update_known_files(upstream & downstream, pot_path=pot_path)
|
|
|
|
remove_old_files(downstream - upstream)
|
|
|
|
clean_paths((upstream - downstream) | (upstream & downstream))
|
|
|
|
shutil.rmtree(pot_path)
|
|
|
|
run("powrap", "-m")
|
|
|
|
update_makefile(args.cpython_repo)
|
|
|
|
git_add_relevant_files()
|
|
|
|
run("git", "commit", "-m", "Make merge")
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|