11#!/usr/bin/env python3
2- """
3- 自动将所有 try-except python2/3 兼容导入替换为 python3 only 导入,并显示处理日志
4- """
2+
53import os
64import re
5+ import time
6+
7+ ROOT = "."
8+ init_py_path = os .path .join (ROOT , "ddns" , "__init__.py" )
79
8- ROOT = '.'
910# 匹配 try-except 块,去除导入前缩进,保证import顶格,删除的行用空行代替
1011PATTERN = re .compile (
11- r' ^[ \t]*try:[^\n]*python 3[^\n]*\n' # try: # python 3
12- r' ((?:[ \t]+[^\n]*\n)+?)' # python3 导入内容
13- r' ^[ \t]*except ImportError:[^\n]*\n' # except ImportError: # python 2
14- r' ((?:[ \t]+from[^\n]*\n|[ \t]+import[^\n]*\n)*)' , # except块内容
15- re .MULTILINE
12+ r" ^[ \t]*try:[^\n]*python 3[^\n]*\n" # try: # python 3
13+ r" ((?:[ \t]+[^\n]*\n)+?)" # python3 导入内容
14+ r" ^[ \t]*except ImportError:[^\n]*\n" # except ImportError: # python 2
15+ r" ((?:[ \t]+from[^\n]*\n|[ \t]+import[^\n]*\n)*)" , # except块内容
16+ re .MULTILINE ,
1617)
1718
1819
1920def dedent_imports_with_blank (import_block , try_block , except_block ):
2021 """
2122 保留python3导入并去除缩进,try/except及except内容用空行代替
2223 """
23- try_lines = try_block .count ('\n ' )
24- except_lines = except_block .count ('\n ' )
25- imports = '' .join (line .lstrip ()
26- for line in import_block .splitlines (keepends = True ))
27- return ('\n ' * try_lines ) + imports + ('\n ' * except_lines )
24+ try_lines = try_block .count ("\n " )
25+ except_lines = except_block .count ("\n " )
26+ imports = "" .join (line .lstrip () for line in import_block .splitlines (keepends = True ))
27+ return ("\n " * try_lines ) + imports + ("\n " * except_lines )
2828
2929
3030def extract_pure_version (version_str ):
3131 """
3232 提取前4组数字并用点拼接,如 v1.2.3.beta4.5 -> 1.2.3.4
3333 """
34- import re
35- nums = re .findall (r'\d+' , version_str )
36- return '.' .join (nums [:4 ]) if nums else "0.0.0"
34+ nums = re .findall (r"\d+" , version_str )
35+ return "." .join (nums [:4 ]) if nums else "0.0.0"
3736
3837
39- def update_nuitka_version (pyfile ):
38+ def update_nuitka_version (pyfile , version = None ):
4039 """
4140 读取 __version__ 并替换 nuitka-project 版本号
4241 """
43- with open (pyfile , 'r' , encoding = 'utf-8' ) as f :
44- content = f .read ()
45-
46- # 提取 __version__ 变量
47- version_match = re .search (
48- r'__version__\s*=\s*[\'"]([^\'"]+)[\'"]' , content )
49- if not version_match :
50- print (f'No __version__ found in { pyfile } ' )
51- return False
52-
53- version_str = version_match .group (1 )
54- pure_version = extract_pure_version (version_str )
42+ pure_version = extract_pure_version (version )
5543
44+ with open (pyfile , "r" , encoding = "utf-8" ) as f :
45+ content = f .read ()
5646 # 替换 nuitka-project 行
5747 new_content , n = re .subn (
58- r'(# nuitka-project: --product-version=)[^\n]*' ,
59- r'\g<1>' + pure_version ,
60- content
48+ r"(# nuitka-project: --product-version=)[^\n]*" , r"\g<1>" + pure_version , content
6149 )
6250 if n > 0 :
63- with open (pyfile , 'w' , encoding = ' utf-8' ) as f :
51+ with open (pyfile , "w" , encoding = " utf-8" ) as f :
6452 f .write (new_content )
65- print (f' update nuitka-project version: { pure_version } in { pyfile } ' )
53+ print (f" update nuitka-project version: { pure_version } in { pyfile } " )
6654 return True
6755 return False
6856
@@ -71,63 +59,56 @@ def add_nuitka_file_description(pyfile):
7159 """
7260 添加 --file-description 配置,使用 __description__ 变量的值
7361 """
74- with open (pyfile , 'r' , encoding = ' utf-8' ) as f :
62+ with open (init_py_path , "r" , encoding = " utf-8" ) as f :
7563 content = f .read ()
7664
7765 # 提取 __description__ 变量的值
78- desc_match = re .search (
79- r'__description__\s*=\s*[\'"]([^\'"]+)[\'"]' , content )
66+ desc_match = re .search (r'__description__\s*=\s*[\'"]([^\'"]+)[\'"]' , content )
8067 if not desc_match :
81- print (f' No __description__ found in { pyfile } ' )
68+ print (f" No __description__ found in { init_py_path } " )
8269 return False
83-
8470 description = desc_match .group (1 )
85- if not content .endswith ('\n ' ):
86- content += '\n '
87- description_line = f'# nuitka-project: --file-description="{ description } "\n '
88- if description_line not in content :
89- content += description_line
90-
91- with open (pyfile , 'w' , encoding = 'utf-8' ) as f :
92- f .write (content )
93- print (f'Added file-description to { pyfile } ' )
71+ description_line = f'\n # nuitka-project: --file-description="{ description } "\n '
72+ with open (pyfile , "a" , encoding = "utf-8" ) as f :
73+ f .write (description_line )
9474 return True
9575
9676
9777def add_nuitka_include_modules (pyfile ):
9878 """
9979 读取 dns 目录下的所有 Python 模块,并添加到 run.py 末尾
10080 """
101- dns_dir = os .path .join (ROOT , 'dns' )
81+ dns_dir = os .path .join (ROOT , "ddns/provider" )
10282 if not os .path .exists (dns_dir ):
103- print (f' DNS directory not found: { dns_dir } ' )
83+ print (f" DNS directory not found: { dns_dir } " )
10484 return False
10585
10686 # 获取所有 Python 模块文件
10787 modules = []
10888 for filename in os .listdir (dns_dir ):
109- if filename .endswith (' .py' ) and filename != ' __init__.py' :
89+ if filename .endswith (" .py" ) and filename != " __init__.py" :
11090 module_name = filename [:- 3 ] # 去掉 .py 扩展名
111- modules .append (f'dns. { module_name } ' )
91+ modules .append (f"ddns.provider. { module_name } " )
11292
11393 if not modules :
114- print (' No DNS modules found' )
94+ print (" No DNS modules found" )
11595 return False
11696
11797 # 直接在文件末尾追加配置行
118- with open (pyfile , 'a' , encoding = ' utf-8' ) as f :
98+ with open (pyfile , "a" , encoding = " utf-8" ) as f :
11999 for module in sorted (modules ):
120- f .write (f' # nuitka-project: --include-module={ module } \n ' )
100+ f .write (f" # nuitka-project: --include-module={ module } \n " )
121101
122102 print (f'Added { len (modules )} DNS modules to { pyfile } : { ", " .join (modules )} ' )
123103 return True
124104
125105
126106def remove_python2_compatibility (pyfile ):
127107 """
108+ 自动将所有 try-except python2/3 兼容导入替换为 python3 only 导入,并显示处理日志
128109 删除指定文件中的 python2 兼容代码,逐行处理
129110 """
130- with open (pyfile , 'r' , encoding = ' utf-8' ) as f :
111+ with open (pyfile , "r" , encoding = " utf-8" ) as f :
131112 lines = f .readlines ()
132113
133114 new_lines = []
@@ -136,28 +117,27 @@ def remove_python2_compatibility(pyfile):
136117 while i < len (lines ):
137118 line = lines [i ]
138119 # 匹配 "try: # python3" 或 "try: # python 3"
139- if re .match (r' ^[ \t]*try:[^\n]*python ?3' , line ):
120+ if re .match (r" ^[ \t]*try:[^\n]*python ?3" , line ):
140121 try_block = []
141122 except_block = []
142123 i += 1
143124 # 收集try块内容
144- while i < len (lines ) and lines [i ].startswith ((' ' , ' \t ' )):
125+ while i < len (lines ) and lines [i ].startswith ((" " , " \t " )):
145126 try_block .append (lines [i ].lstrip ())
146127 i += 1
147128 # 跳过空行
148- while i < len (lines ) and lines [i ].strip () == '' :
129+ while i < len (lines ) and lines [i ].strip () == "" :
149130 i += 1
150131 # 检查是否存在except块 (不检查具体错误类型,但必须包含python2或python 2)
151- if i < len (lines ) and re .match (r' ^[ \t]*except[^\n]*python ?2' , lines [i ]):
132+ if i < len (lines ) and re .match (r" ^[ \t]*except[^\n]*python ?2" , lines [i ]):
152133 i += 1
153134 # 收集except块内容
154135 except_block = []
155- while i < len (lines ) and lines [i ].startswith ((' ' , ' \t ' )):
136+ while i < len (lines ) and lines [i ].startswith ((" " , " \t " )):
156137 except_block .append (lines [i ])
157138 i += 1
158139 # 添加try块内容,except块用空行替代
159- new_lines .extend (['\n ' ] + try_block + ['\n ' ]
160- * (len (except_block ) + 1 ))
140+ new_lines .extend (["\n " ] + try_block + ["\n " ] * (len (except_block ) + 1 ))
161141 changed = True
162142 else :
163143 # 没有except块,原样保留
@@ -168,30 +148,63 @@ def remove_python2_compatibility(pyfile):
168148 i += 1
169149
170150 if changed :
171- with open (pyfile , 'w' , encoding = ' utf-8' ) as f :
151+ with open (pyfile , "w" , encoding = " utf-8" ) as f :
172152 f .writelines (new_lines )
173- print (f'Removed python2 compatibility from { pyfile } ' )
153+ print (f"Removed python2 compatibility from { pyfile } " )
154+
155+
156+ def extract_version_from_env ():
157+ """
158+ 从环境变量中提取版本号
159+ """
160+ ref = os .environ .get ("GITHUB_REF_NAME" )
161+ if not ref :
162+ return time .strftime ("0.0.%m%d.%H%M" ) # 默认版本号
163+ if ref and ref .startswith ("v" ):
164+ return ref [1 :] # 去掉前缀 'v'
165+ return ref # 返回原始版本号
174166
175167
176168def main ():
177169 """
178170 遍历所有py文件并替换兼容导入,同时更新nuitka版本号
179171 """
180172 run_py_path = os .path .join (ROOT , "run.py" )
181- update_nuitka_version (run_py_path )
173+ version = extract_version_from_env ()
174+ update_nuitka_version (run_py_path , version )
182175 add_nuitka_file_description (run_py_path )
183176 add_nuitka_include_modules (run_py_path )
184177
178+ # 修改__init__.py 中的 __version__
179+
180+ replace_version_in_init (version , init_py_path )
181+
185182 changed_files = 0
186183 for dirpath , _ , filenames in os .walk (ROOT ):
187184 for fname in filenames :
188- if fname .endswith (' .py' ):
185+ if fname .endswith (" .py" ):
189186 fpath = os .path .join (dirpath , fname )
190187 remove_python2_compatibility (fpath )
191188 changed_files += 1
192- print ('done' )
193- print (f'Total processed files: { changed_files } ' )
189+ print ("done" )
190+ print (f"Total processed files: { changed_files } " )
191+
192+
193+ def replace_version_in_init (version , init_py_path ):
194+ """
195+ 替换 ddns/__init__.py 中的 __version__ 变量
196+ """
197+ version_str = f'v{ version } @{ time .strftime ("%Y-%m-%dT%H:%M:%S" )} '
198+ with open (init_py_path , "r" , encoding = "utf-8" ) as f :
199+ content = f .read ()
200+ new_content = re .sub (
201+ r'__version__\s*=\s*[\'"]([^\'"]+)[\'"]' , f'__version__ = "{ version_str } "' , content
202+ )
203+ if new_content != content :
204+ with open (init_py_path , "w" , encoding = "utf-8" ) as f :
205+ f .write (new_content )
206+ print (f"Updated __version__ in { init_py_path } to { version_str } " )
194207
195208
196- if __name__ == ' __main__' :
209+ if __name__ == " __main__" :
197210 main ()
0 commit comments