Skip to content

Commit dc734a9

Browse files
committed
Move merge to its own script.
It's probably longer, but it handles upstream file deletion.
1 parent cbfb182 commit dc734a9

2 files changed

Lines changed: 146 additions & 25 deletions

File tree

Makefile

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
# - make spell # To check for spelling
1010
# - make clean # To remove build artifacts
1111
# - make fuzzy # To find fuzzy strings
12-
# - make merge # To merge pot from upstream
1312
#
1413
# Modes are: autobuild-stable, autobuild-dev, and autobuild-html,
1514
# documented in gen/src/3.6/Doc/Makefile as we're only delegating the
@@ -121,30 +120,6 @@ fuzzy: ensure_prerequisites
121120
.PHONY: verifs
122121
verifs: wrap spell
123122

124-
.PHONY: merge
125-
merge: ensure_prerequisites
126-
@echo "Merge from $(UPSTREAM)"
127-
git -C venv/cpython/ checkout $(BRANCH)
128-
git -C venv/cpython/ pull --ff-only
129-
(cd venv/cpython/Doc; sphinx-build -Q -b gettext -D gettext_compact=0 . ../pot)
130-
find venv/cpython/pot/ -name '*.pot' |\
131-
while read -r POT; \
132-
do \
133-
PO="./$$(echo "$$POT" | sed "s#venv/cpython/pot/##; s#\.pot\$$#.po#")"; \
134-
mkdir -p "$$(dirname "$$PO")"; \
135-
if [ -f "$$PO" ]; \
136-
then \
137-
msgmerge --backup=off --force-po -U "$$PO" "$$POT"; \
138-
else \
139-
msgcat -o "$$PO" "$$POT"; \
140-
fi \
141-
done
142-
rm -fr venv/cpython/pot/
143-
sed -i 's|^#: .*Doc/|#: |' *.po */*.po
144-
powrap -m
145-
@printf "\n%s %s\n" "Replace CPYTHON_CURRENT_COMMIT in Makefile by: " $(shell git -C venv/cpython/ rev-parse HEAD)
146-
@printf 'To add, you can use:\n git status -s | grep "^ M .*\.po" | cut -d" " -f3 | while read -r file; do if [ $$(git diff "$$file" | wc -l) -gt 13 ]; then git add "$$file"; fi ; done\n'
147-
148123
.PHONY: clean
149124
clean:
150125
@echo "Cleaning *.mo and $(POSPELL_TMP_DIR)"

merge.py

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
"""Tool to merge cpython pot files to python-docs-fr po files for a
2+
given branch.
3+
"""
4+
5+
import re
6+
import shutil
7+
from pathlib import Path
8+
import argparse
9+
from subprocess import run, PIPE
10+
from tqdm import tqdm
11+
12+
13+
def parse_args():
14+
parser = argparse.ArgumentParser(description=__doc__)
15+
parser.add_argument(
16+
"--cpython_repo",
17+
default=Path("venv/cpython"),
18+
type=Path,
19+
help="Use this given cpython clone.",
20+
)
21+
parser.add_argument("branch", help="Merge from this branch")
22+
return parser.parse_args()
23+
24+
25+
def setup_repo(repo_path: Path, branch: str):
26+
"""Ensure we're up-to-date."""
27+
run(["git", "-C", repo_path, "checkout", branch])
28+
run(["git", "-C", repo_path, "pull", "--ff-only"])
29+
30+
31+
def copy_new_files(new_files: set[Path], pot_path: Path) -> None:
32+
"""Just copy new po files to our hierarchy."""
33+
print(f"{len(new_files)} new files.")
34+
for file in new_files:
35+
file.parent.mkdir(parents=True, exist_ok=True)
36+
src = (pot_path / file).with_suffix(".pot")
37+
run(["msgcat", "-o", file, src])
38+
39+
40+
def update_known_files(known_files: set[Path], pot_path: Path) -> None:
41+
"""msgmerge updated pot files in our po files."""
42+
print(f"{len(known_files)} files to update.")
43+
for file in tqdm(known_files, desc="merging pot files"):
44+
src = (pot_path / file).with_suffix(".pot")
45+
run(
46+
["msgmerge", "--backup=off", "--force-po", "-U", file, src],
47+
stdout=PIPE,
48+
stderr=PIPE,
49+
)
50+
51+
52+
def remove_old_files(old_files: set[Path]) -> None:
53+
"""Remove files removed upstream."""
54+
print(f"{len(old_files)} removed files.")
55+
56+
for file in old_files:
57+
run(["git", "rm", file])
58+
59+
60+
def clean_paths(files: set[Path]) -> None:
61+
"""Ensure the path present in po files are always relative.
62+
63+
This avoid having diffs on those paths when we change something in
64+
a script.
65+
"""
66+
for file in tqdm(files, desc="Cleaning rst path in pot files"):
67+
contents = file.read_text(encoding="UTF-8")
68+
contents = re.sub("^#: .*Doc/", "#: ", contents, flags=re.M)
69+
file.write_text(contents, encoding="UTF-8")
70+
71+
72+
def update_makefile(cpython_repo: Path) -> None:
73+
"""Update CPYTHON_CURRENT_COMMIT in the Makefile.
74+
75+
So that when we run `make` it use the same commit than the one
76+
used to generate the `po` files.
77+
"""
78+
makefile = Path("Makefile").read_text(encoding="UTF-8")
79+
head = run(
80+
["git", "-C", cpython_repo, "rev-parse", "HEAD"],
81+
stdout=PIPE,
82+
encoding="UTF-8",
83+
).stdout
84+
makefile = re.sub(
85+
"^CPYTHON_CURRENT_COMMIT :=.*$",
86+
f"CPYTHON_CURRENT_COMMIT := {head}",
87+
makefile,
88+
flags=re.M,
89+
)
90+
Path("Makefile").write_text(makefile, encoding="UTF-8")
91+
run(["git", "add", "Makefile"])
92+
93+
94+
def git_add_relevant_files():
95+
"""Add only files with relevant modifications.
96+
97+
This only add files with actual modifications, not just metadata
98+
modifications, to avoid noise in history.
99+
"""
100+
git_status = run(
101+
["git", "status", "--short"], stdout=PIPE, encoding="UTF-8"
102+
).stdout.split("\n")
103+
to_add = [
104+
line.split()[-1]
105+
for line in git_status
106+
if line.startswith(" M") and ".po" in line
107+
]
108+
for file in to_add:
109+
diff = run(["git", "diff", file], encoding="UTF-8", stdout=PIPE).stdout
110+
if len(diff.split("\n")) > 13:
111+
run(["git", "add", file])
112+
else:
113+
run(["git", "checkout", "--", file])
114+
run(["git", "rm", "-f", "whatsnew/changelog.po"])
115+
116+
117+
def main():
118+
args = parse_args()
119+
setup_repo(args.cpython_repo, args.branch)
120+
run(
121+
["sphinx-build", "-jauto", "-QDgettext_compact=0", "-bgettext", ".", "../pot"],
122+
cwd=args.cpython_repo / "Doc",
123+
)
124+
pot_path = args.cpython_repo / "pot"
125+
upstream = {
126+
file.relative_to(pot_path).with_suffix(".po")
127+
for file in pot_path.glob("**/*.pot")
128+
}
129+
downstream = {
130+
po
131+
for po in Path(".").glob("**/*.po")
132+
if not (po.is_relative_to(Path("locales")) or po.is_relative_to(Path(".git")))
133+
}
134+
copy_new_files(upstream - downstream, pot_path=pot_path)
135+
update_known_files(upstream & downstream, pot_path=pot_path)
136+
remove_old_files(downstream - upstream)
137+
clean_paths((upstream - downstream) | (upstream & downstream))
138+
shutil.rmtree(pot_path)
139+
run(["powrap", "-m"])
140+
update_makefile(args.cpython_repo)
141+
git_add_relevant_files()
142+
run(["git", "commit", "-m", "Make merge"])
143+
144+
145+
if __name__ == "__main__":
146+
main()

0 commit comments

Comments
 (0)