-
-
Notifications
You must be signed in to change notification settings - Fork 41
/
merge.py
145 lines (115 loc) · 4.65 KB
/
merge.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
"""Tool to merge cpython pot files to python-docs-tr po files for a
given branch.
A CPython clone present in the venv/ directory is required if the --cpython_repo is not specified.
This script is run automatically by the GitHub Actions workflow every first day of the month.
"""
import argparse
import re
import shutil
import subprocess
from pathlib import Path
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")
head = run(
"git", "-C", cpython_repo, "rev-parse", "HEAD", stdout=PIPE
).stdout.strip()
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 = {
Path(po)
for po in run("git", "ls-files", "*.po", stdout=PIPE).stdout.splitlines()
}
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()
if __name__ == "__main__":
main()