1010
1111The usage is as follows:
1212- ./scripts/checktransupdate.py -l zh_CN
13- This will print all the files that need to be updated in the zh_CN locale.
13+ This will print all the files that need to be updated or translated in the zh_CN locale.
1414- ./scripts/checktransupdate.py Documentation/translations/zh_CN/dev-tools/testing-overview.rst
1515This will only print the status of the specified file.
1616
1717The output is something like:
18- Documentation/translations/zh_CN/dev-tools/testing-overview.rst (1 commits)
18+ Documentation/dev-tools/kfence.rst
19+ No translation in the locale of zh_CN
20+
21+ Documentation/translations/zh_CN/dev-tools/testing-overview.rst
1922commit 42fb9cfd5b18 ("Documentation: dev-tools: Add link to RV docs")
23+ 1 commits needs resolving in total
2024"""
2125
2226import os
23- from argparse import ArgumentParser , BooleanOptionalAction
27+ import time
28+ import logging
29+ from argparse import ArgumentParser , ArgumentTypeError , BooleanOptionalAction
2430from datetime import datetime
2531
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-
3632
3733def get_origin_path (file_path ):
34+ """Get the origin path from the translation path"""
3835 paths = file_path .split ("/" )
3936 tidx = paths .index ("translations" )
4037 opaths = paths [:tidx ]
@@ -43,17 +40,16 @@ def get_origin_path(file_path):
4340
4441
4542def 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 )
43+ """Get the latest commit from the specified commit for the specified file"""
44+ command = f"git log --pretty=format:%H%n%aD%n%cD%n%n%B { commit } -1 -- { file_path } "
45+ logging .debug (command )
5046 pipe = os .popen (command )
5147 result = pipe .read ()
5248 result = result .split ("\n " )
5349 if len (result ) <= 1 :
5450 return None
5551
56- dprint ("Result: {}" . format ( result [0 ]) )
52+ logging . debug ("Result: %s" , result [0 ])
5753
5854 return {
5955 "hash" : result [0 ],
@@ -64,17 +60,19 @@ def get_latest_commit_from(file_path, commit):
6460
6561
6662def get_origin_from_trans (origin_path , t_from_head ):
63+ """Get the latest origin commit from the translation commit"""
6764 o_from_t = get_latest_commit_from (origin_path , t_from_head ["hash" ])
6865 while o_from_t is not None and o_from_t ["author_date" ] > t_from_head ["author_date" ]:
6966 o_from_t = get_latest_commit_from (origin_path , o_from_t ["hash" ] + "^" )
7067 if o_from_t is not None :
71- dprint ("tracked origin commit id: {}" . format ( o_from_t ["hash" ]) )
68+ logging . debug ("tracked origin commit id: %s" , o_from_t ["hash" ])
7269 return o_from_t
7370
7471
7572def get_commits_count_between (opath , commit1 , commit2 ):
76- command = "git log --pretty=format:%H {}...{} -- {}" .format (commit1 , commit2 , opath )
77- dprint (command )
73+ """Get the commits count between two commits for the specified file"""
74+ command = f"git log --pretty=format:%H { commit1 } ...{ commit2 } -- { opath } "
75+ logging .debug (command )
7876 pipe = os .popen (command )
7977 result = pipe .read ().split ("\n " )
8078 # filter out empty lines
@@ -83,113 +81,183 @@ def get_commits_count_between(opath, commit1, commit2):
8381
8482
8583def pretty_output (commit ):
86- command = "git log --pretty='format:%h (\" %s\" )' -1 {}" .format (commit )
87- dprint (command )
84+ """Pretty print the commit message"""
85+ command = f"git log --pretty='format:%h (\" %s\" )' -1 { commit } "
86+ logging .debug (command )
8887 pipe = os .popen (command )
8988 return pipe .read ()
9089
9190
91+ def valid_commit (commit ):
92+ """Check if the commit is valid or not"""
93+ msg = pretty_output (commit )
94+ return "Merge tag" not in msg
95+
9296def check_per_file (file_path ):
97+ """Check the translation status for the specified file"""
9398 opath = get_origin_path (file_path )
9499
95100 if not os .path .isfile (opath ):
96- dprint ( "Error: Cannot find the origin path for {}" . format ( file_path ) )
101+ logging . error ( " Cannot find the origin path for {file_path}" )
97102 return
98103
99104 o_from_head = get_latest_commit_from (opath , "HEAD" )
100105 t_from_head = get_latest_commit_from (file_path , "HEAD" )
101106
102107 if o_from_head is None or t_from_head is None :
103- print ( "Error: Cannot find the latest commit for {}" . format ( file_path ) )
108+ logging . error ( " Cannot find the latest commit for %s" , file_path )
104109 return
105110
106111 o_from_t = get_origin_from_trans (opath , t_from_head )
107112
108113 if o_from_t is None :
109- print ("Error: Cannot find the latest origin commit for {}" . format ( file_path ) )
114+ logging . error ("Error: Cannot find the latest origin commit for %s" , file_path )
110115 return
111116
112117 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
118+ logging .debug ("No update needed for %s" , file_path )
116119 else :
117- print ( "{}" . format (file_path ), end = " \t " )
120+ logging . info (file_path )
118121 commits = get_commits_count_between (
119122 opath , o_from_t ["hash" ], o_from_head ["hash" ]
120123 )
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 )
124+ count = 0
125+ for commit in commits :
126+ if valid_commit (commit ):
127+ logging .info ("commit %s" , pretty_output (commit ))
128+ count += 1
129+ logging .info ("%d commits needs resolving in total\n " , count )
130+
131+
132+ def valid_locales (locale ):
133+ """Check if the locale is valid or not"""
134+ script_path = os .path .dirname (os .path .abspath (__file__ ))
135+ linux_path = os .path .join (script_path , ".." )
136+ if not os .path .isdir (f"{ linux_path } /Documentation/translations/{ locale } " ):
137+ raise ArgumentTypeError ("Invalid locale: {locale}" )
138+ return locale
139+
140+
141+ def list_files_with_excluding_folders (folder , exclude_folders , include_suffix ):
142+ """List all files with the specified suffix in the folder and its subfolders"""
143+ files = []
144+ stack = [folder ]
145+
146+ while stack :
147+ pwd = stack .pop ()
148+ # filter out the exclude folders
149+ if os .path .basename (pwd ) in exclude_folders :
150+ continue
151+ # list all files and folders
152+ for item in os .listdir (pwd ):
153+ ab_item = os .path .join (pwd , item )
154+ if os .path .isdir (ab_item ):
155+ stack .append (ab_item )
156+ else :
157+ if ab_item .endswith (include_suffix ):
158+ files .append (ab_item )
159+
160+ return files
161+
162+
163+ class DmesgFormatter (logging .Formatter ):
164+ """Custom dmesg logging formatter"""
165+ def format (self , record ):
166+ timestamp = time .time ()
167+ formatted_time = f"[{ timestamp :>10.6f} ]"
168+ log_message = f"{ formatted_time } { record .getMessage ()} "
169+ return log_message
170+
171+
172+ def config_logging (log_level , log_file = "checktransupdate.log" ):
173+ """configure logging based on the log level"""
174+ # set up the root logger
175+ logger = logging .getLogger ()
176+ logger .setLevel (log_level )
177+
178+ # Create console handler
179+ console_handler = logging .StreamHandler ()
180+ console_handler .setLevel (log_level )
181+
182+ # Create file handler
183+ file_handler = logging .FileHandler (log_file )
184+ file_handler .setLevel (log_level )
185+
186+ # Create formatter and add it to the handlers
187+ formatter = DmesgFormatter ()
188+ console_handler .setFormatter (formatter )
189+ file_handler .setFormatter (formatter )
190+
191+ # Add the handler to the logger
192+ logger .addHandler (console_handler )
193+ logger .addHandler (file_handler )
127194
128195
129196def main ():
197+ """Main function of the script"""
130198 script_path = os .path .dirname (os .path .abspath (__file__ ))
131199 linux_path = os .path .join (script_path , ".." )
132200
133201 parser = ArgumentParser (description = "Check the translation update" )
134202 parser .add_argument (
135203 "-l" ,
136204 "--locale" ,
205+ default = "zh_CN" ,
206+ type = valid_locales ,
137207 help = "Locale to check when files are not specified" ,
138208 )
209+
139210 parser .add_argument (
140- "--print-commits " ,
211+ "--print-missing-translations " ,
141212 action = BooleanOptionalAction ,
142213 default = True ,
143- help = "Print commits between the origin and the translation " ,
214+ help = "Print files that do not have translations " ,
144215 )
145216
146217 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- )
218+ '--log' ,
219+ default = 'INFO' ,
220+ choices = ['DEBUG' , 'INFO' , 'WARNING' , 'ERROR' , 'CRITICAL' ],
221+ help = 'Set the logging level' )
152222
153223 parser .add_argument (
154- "--debug" ,
155- action = BooleanOptionalAction ,
156- help = "Print debug information" ,
157- default = False ,
158- )
224+ '--logfile' ,
225+ default = 'checktransupdate.log' ,
226+ help = 'Set the logging file (default: checktransupdate.log)' )
159227
160228 parser .add_argument (
161229 "files" , nargs = "*" , help = "Files to check, if not specified, check all files"
162230 )
163231 args = parser .parse_args ()
164232
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
233+ # Configure logging based on the --log argument
234+ log_level = getattr (logging , args .log .upper (), logging .INFO )
235+ config_logging (log_level )
169236
170- # get files related to linux path
237+ # Get files related to linux path
171238 files = args .files
172239 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 ))
240+ offical_files = list_files_with_excluding_folders (
241+ os .path .join (linux_path , "Documentation" ), ["translations" , "output" ], "rst"
242+ )
243+
244+ for file in offical_files :
245+ # split the path into parts
246+ path_parts = file .split (os .sep )
247+ # find the index of the "Documentation" directory
248+ kindex = path_parts .index ("Documentation" )
249+ # insert the translations and locale after the Documentation directory
250+ new_path_parts = path_parts [:kindex + 1 ] + ["translations" , args .locale ] \
251+ + path_parts [kindex + 1 :]
252+ # join the path parts back together
253+ new_file = os .sep .join (new_path_parts )
254+ if os .path .isfile (new_file ):
255+ files .append (new_file )
256+ else :
257+ if args .print_missing_translations :
258+ logging .info (os .path .relpath (os .path .abspath (file ), linux_path ))
259+ logging .info ("No translation in the locale of %s\n " , args .locale )
260+
193261 files = list (map (lambda x : os .path .relpath (os .path .abspath (x ), linux_path ), files ))
194262
195263 # cd to linux root directory
0 commit comments