Add a new translation tool scripts/trslt.py For - translation file help tool - translation corresponding version control Signed-off-by: Wu XiangCheng <bobwxc@xxxxxxxx> --- scripts/trslt.py | 267 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100755 scripts/trslt.py diff --git a/scripts/trslt.py b/scripts/trslt.py new file mode 100755 index 000000000000..1acc6f2e69f3 --- /dev/null +++ b/scripts/trslt.py @@ -0,0 +1,267 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0+ +# +# Kernel Documentation Translation File tool +# Document see: Documentation/doc-guide/trslt.rst +# +# Wu XiangCheng <bobwxc@xxxxxxxx>, 2021. + +import os +import argparse +import subprocess + +# global verbose mode flag +VERBOSE_FLAG = False + +# change to source root dir +def cdpath(): + # at source ROOT + if os.path.isdir("Documentation/translations") and os.path.isfile("MAINTAINERS"): + return 0 + # at Documentation/ + elif os.path.isdir("translations") and os.path.isfile("../MAINTAINERS"): + os.chdir("../") + return 0 + # at Documentation/translation/ + elif os.path.isdir("zh_CN") and os.path.isfile("../../MAINTAINERS"): + os.chdir("../../") + return 0 + # at Documentation/translations/ll_NN/ + elif os.path.isdir("translations") == False and os.path.isdir("../../translations") and os.path.isfile("../../../MAINTAINERS"): + os.chdir("../../../") + return 0 + # anywhere else + else: + print("ERROR: Please run this script under linux kernel source ROOT dir") + return -1 + +# argv +def arg(): + parser = argparse.ArgumentParser( + description='Linux Kernel Documentation Translation File Tool') + # file path + parser.add_argument('file', help="specific file path") + # verbose mode + parser.add_argument('-v', '--verbose', + help="enable verbose mode", + action='store_true') + # language choose + parser.add_argument('-l', '--language', + help="choose translation language, default: zh_CN", + type=str, + choices=["it_IT", "ja_JP", "ko_KR", "zh_CN"], + default="zh_CN") + # required action group + ch = parser.add_mutually_exclusive_group(required=True) + # \_ copy + ch.add_argument('-c', '--copy', + help="copy a origin file to translation directory", + action='store_true') + # \_ update + ch.add_argument('-u', '--update', + help="get a translation file's update information", + action='store_true') + + argv_ = parser.parse_args() + + # modify global VERBOSE_FLAG + if argv_.verbose: + global VERBOSE_FLAG + VERBOSE_FLAG = True + print(argv_) + + return argv_ + +# get newest commit id of a origin doc file +def get_newest_commit(fp): + cmd = "git log --format=oneline --no-merges "+fp + p = subprocess.Popen(cmd, + shell=True, + stdout=subprocess.PIPE, + errors="replace") + log = p.stdout.readline() + commit_id = log[:log.find(' ')] + return commit_id + +# add language special header +def la_head(fp, la): + if la == "zh_CN": + cfp = fp[0:14]+"translations/"+la+'/'+fp[14:] + r = ".. include:: " + \ + os.path.relpath( + "Documentation/translations/zh_CN/disclaimer-zh_CN.rst", + cfp[0:cfp.rfind('/')]) + "\n\n" + r += ":Original: "+fp+"\n\n" + r += ".. translation_origin_commit: "+get_newest_commit(fp)+"\n\n" + r += ":译者: 姓名 EnglishName <email@xxxxxxxxxxx>\n\n" + else: + r = ":Original: "+fp+"\n\n" + r += ".. translation_origin_commit: "+get_newest_commit(fp)+"\n\n" + r += ":Translator: Name <email@xxxxxxxxxxx>\n\n" + + return r + +# copy mode +def copy(fp, la): + if os.path.isfile(fp) == False: + return -2 + + if fp.find("/translations/") != fp.rfind("/translations/"): + print("WARNING: seems you are copying a file only exist in translations/ dir") + return -3 + + f = open(fp, 'r') + try: + first = f.read(2048) + except: + print("ERROR: can not read file", fp) + return -2 + + spdx_id = first.find(".. SPDX-License-Identifier: ") + if spdx_id != -1: + insert_id = first.find('\n', spdx_id)+1 + first = first[:insert_id]+'\n'+la_head(fp, la)+first[insert_id:] + else: + first = la_head(fp, la)+first + + if fp[0:14] == "Documentation/": + cfp = fp[0:14]+"translations/"+la+'/'+fp[14:] + + if cfp[cfp.rfind('.'):] != ".rst": + print("WARNING: this is not a rst file, may cause problems.", + "copy will continue, but please \033[31mcheck it!\033[0m") + + cfp_dir = cfp[0:cfp.rfind('/')] + + if not os.path.exists(cfp_dir): + os.makedirs(cfp_dir) + + if os.path.isfile(cfp): + print("WARNING:\033[31m", cfp, + "\033[0mis existing, can not use copy, please try -u/--update!") + return -3 + + cf = open(cfp, 'w') + cf.write(first) + + while True: + a = f.read(2048) + if a != '': + cf.write(a) + else: + break + + cf.close() + print("INFO: \033[32m" + cfp + + "\033[0m has been created, please remember to edit it.") + else: + return -2 + + return 0 + +# generete origin text diff file for update +def gen_diff(ofp, old_id): + new_id = get_newest_commit(ofp) + if old_id == new_id: + return 1 + + cmd = "git show "+old_id+".."+new_id+" "+ofp + p = subprocess.Popen(cmd, + shell=True, + stdout=subprocess.PIPE, + errors="replace") + log = p.stdout.read() + log = cmd+"\n\n"+log + return log + +# update mode +def update(fp, la): + if os.path.isfile(fp) == False: + return -2 + if fp.find("Documentation/translations/"+la) == -1: + print("ERROR:", fp, "does not belong to", la, "translation!") + return -3 + + # origin file path + ofp = fp[:fp.find("translations/"+la)] + \ + fp[fp.find("translations/"+la)+14+len(la):] + + if not os.path.isfile(ofp): + print("ERROR: origin file",ofp,"does not exist or not a file") + return -2 + + f = open(fp, 'r') + try: + first = f.read(3072) + except: + print("ERROR: can not read file", fp) + return -2 + + commit_id = first.find("\n.. translation_origin_commit: ") + if commit_id == -1: + print("WARNING:", fp, "\033[31mdoes not have a translation_origin_commit tag,", + "can not generate a diff file\033[0m, please add a tag if you want to update it.") + print("\n\033[33m.. translation_origin_commit: " + + get_newest_commit(ofp) + "\033[0m") + return -4 + else: + commit_id = commit_id+1 # '\n' + commit_id = first[commit_id:first.find('\n', commit_id)] + commit_id = commit_id[commit_id.find(' ')+1:] + commit_id = commit_id[commit_id.find(' ')+1:] + + diff = gen_diff(ofp, commit_id) + if diff == 1: + print("INFO:", ofp, "does not have any change since", commit_id) + else: + with open(fp+".diff", 'w') as d: + d.write(diff) + print("INFO: \033[32m"+fp+".diff\033[0m file has generated",) + print("INFO: if you want to update " + fp + + ", please \033[31mDo Not Forget\033[0m to update the translation_origin_commit tag.", + "\n\n\033[33m.. translation_origin_commit: " + + get_newest_commit(ofp) + "\033[0m") + + return 0 + +# main entry +def main(): + argv_ = arg() + + # get file's abspath before cdpath + file_path = os.path.abspath(argv_.file) + if VERBOSE_FLAG: + print(file_path) + + if cdpath() != 0: + return -1 + + # if file_path valid + if file_path.find("Documentation") == -1: + print("ERROR: file does not in Linux Kernel source Documentation") + return -2 + elif os.path.isfile(file_path[file_path.find("Documentation"):]) == False: + print("ERROR: file does not exist or not a file") + return -2 + else: + file_path = file_path[file_path.find("Documentation"):] + + if VERBOSE_FLAG: + print(file_path) + + if argv_.copy: + return copy(file_path, argv_.language) + elif argv_.update: + return update(file_path, argv_.language) + + return 0 + + +if __name__ == "__main__": + exit_code = main() + if VERBOSE_FLAG: + if exit_code == 0: + print("exit with code:\033[32m", exit_code, "\033[0m") + else: + print("exit with code:\033[31m", exit_code, "\033[0m") + exit(exit_code) -- 2.20.1