1 #!/usr/bin/env python3 2 # SPDX-License-Identifier: GPL-2.0 3 4 """ 5 This script helps track the translation status of the documentation 6 in different locales, e.g., zh_CN. More specially, it uses `git log` 7 commit to find the latest english commit from the translation commit 8 (order by author date) and the latest english commits from HEAD. If 9 differences occur, report the file and commits that need to be updated. 10 11 The usage is as follows: 12 - ./scripts/checktransupdate.py -l zh_CN 13 This will print all the files that need to be updated in the zh_CN locale. 14 - ./scripts/checktransupdate.py Documentation/translations/zh_CN/dev-tools/testing-overview.rst 15 This will only print the status of the specified file. 16 17 The output is something like: 18 Documentation/translations/zh_CN/dev-tools/testing-overview.rst (1 commits) 19 commit 42fb9cfd5b18 ("Documentation: dev-tools: Add link to RV docs") 20 """ 21 22 import os 23 from argparse import ArgumentParser, BooleanOptionalAction 24 from datetime import datetime 25 26 flag_p_c = False 27 flag_p_uf = False 28 flag_debug = False 29 30 31 def dprint(*args, **kwargs): 32 if flag_debug: 33 print("[DEBUG] ", end="") 34 print(*args, **kwargs) 35 36 37 def get_origin_path(file_path): 38 paths = file_path.split("/") 39 tidx = paths.index("translations") 40 opaths = paths[:tidx] 41 opaths += paths[tidx + 2 :] 42 return "/".join(opaths) 43 44 45 def get_latest_commit_from(file_path, commit): 46 command = "git log --pretty=format:%H%n%aD%n%cD%n%n%B {} -1 -- {}".format( 47 commit, file_path 48 ) 49 dprint(command) 50 pipe = os.popen(command) 51 result = pipe.read() 52 result = result.split("\n") 53 if len(result) <= 1: 54 return None 55 56 dprint("Result: {}".format(result[0])) 57 58 return { 59 "hash": result[0], 60 "author_date": datetime.strptime(result[1], "%a, %d %b %Y %H:%M:%S %z"), 61 "commit_date": datetime.strptime(result[2], "%a, %d %b %Y %H:%M:%S %z"), 62 "message": result[4:], 63 } 64 65 66 def get_origin_from_trans(origin_path, t_from_head): 67 o_from_t = get_latest_commit_from(origin_path, t_from_head["hash"]) 68 while o_from_t is not None and o_from_t["author_date"] > t_from_head["author_date"]: 69 o_from_t = get_latest_commit_from(origin_path, o_from_t["hash"] + "^") 70 if o_from_t is not None: 71 dprint("tracked origin commit id: {}".format(o_from_t["hash"])) 72 return o_from_t 73 74 75 def get_commits_count_between(opath, commit1, commit2): 76 command = "git log --pretty=format:%H {}...{} -- {}".format(commit1, commit2, opath) 77 dprint(command) 78 pipe = os.popen(command) 79 result = pipe.read().split("\n") 80 # filter out empty lines 81 result = list(filter(lambda x: x != "", result)) 82 return result 83 84 85 def pretty_output(commit): 86 command = "git log --pretty='format:%h (\"%s\")' -1 {}".format(commit) 87 dprint(command) 88 pipe = os.popen(command) 89 return pipe.read() 90 91 92 def check_per_file(file_path): 93 opath = get_origin_path(file_path) 94 95 if not os.path.isfile(opath): 96 dprint("Error: Cannot find the origin path for {}".format(file_path)) 97 return 98 99 o_from_head = get_latest_commit_from(opath, "HEAD") 100 t_from_head = get_latest_commit_from(file_path, "HEAD") 101 102 if o_from_head is None or t_from_head is None: 103 print("Error: Cannot find the latest commit for {}".format(file_path)) 104 return 105 106 o_from_t = get_origin_from_trans(opath, t_from_head) 107 108 if o_from_t is None: 109 print("Error: Cannot find the latest origin commit for {}".format(file_path)) 110 return 111 112 if o_from_head["hash"] == o_from_t["hash"]: 113 if flag_p_uf: 114 print("No update needed for {}".format(file_path)) 115 return 116 else: 117 print("{}".format(file_path), end="\t") 118 commits = get_commits_count_between( 119 opath, o_from_t["hash"], o_from_head["hash"] 120 ) 121 print("({} commits)".format(len(commits))) 122 if flag_p_c: 123 for commit in commits: 124 msg = pretty_output(commit) 125 if "Merge tag" not in msg: 126 print("commit", msg) 127 128 129 def main(): 130 script_path = os.path.dirname(os.path.abspath(__file__)) 131 linux_path = os.path.join(script_path, "..") 132 133 parser = ArgumentParser(description="Check the translation update") 134 parser.add_argument( 135 "-l", 136 "--locale", 137 help="Locale to check when files are not specified", 138 ) 139 parser.add_argument( 140 "--print-commits", 141 action=BooleanOptionalAction, 142 default=True, 143 help="Print commits between the origin and the translation", 144 ) 145 146 parser.add_argument( 147 "--print-updated-files", 148 action=BooleanOptionalAction, 149 default=False, 150 help="Print files that do no need to be updated", 151 ) 152 153 parser.add_argument( 154 "--debug", 155 action=BooleanOptionalAction, 156 help="Print debug information", 157 default=False, 158 ) 159 160 parser.add_argument( 161 "files", nargs="*", help="Files to check, if not specified, check all files" 162 ) 163 args = parser.parse_args() 164 165 global flag_p_c, flag_p_uf, flag_debug 166 flag_p_c = args.print_commits 167 flag_p_uf = args.print_updated_files 168 flag_debug = args.debug 169 170 # get files related to linux path 171 files = args.files 172 if len(files) == 0: 173 if args.locale is not None: 174 files = ( 175 os.popen( 176 "find {}/Documentation/translations/{} -type f".format( 177 linux_path, args.locale 178 ) 179 ) 180 .read() 181 .split("\n") 182 ) 183 else: 184 files = ( 185 os.popen( 186 "find {}/Documentation/translations -type f".format(linux_path) 187 ) 188 .read() 189 .split("\n") 190 ) 191 192 files = list(filter(lambda x: x != "", files)) 193 files = list(map(lambda x: os.path.relpath(os.path.abspath(x), linux_path), files)) 194 195 # cd to linux root directory 196 os.chdir(linux_path) 197 198 for file in files: 199 check_per_file(file) 200 201 202 if __name__ == "__main__": 203 main()
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.