Skip to content

Commit a3c5248

Browse files
authored
Merge branch 'dev' into main (#32)
* update .gitignore * update dependencies on Linux * nuitka_build more fix and improvements * update nuitka_build.py * use more os build * Update README.md
1 parent 4e5e27b commit a3c5248

7 files changed

Lines changed: 223 additions & 60 deletions

File tree

.github/workflows/dev_package_and_upload.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,14 @@ jobs:
136136
# # 设置控制台编码为UTF-8
137137
# chcp.com 65001
138138

139-
- name: Install ccache on Linux
139+
- name: Install dependencies on Linux
140140
if: ${{ runner.os == 'Linux' }}
141141
run: |
142142
sudo apt-get update -y
143143
sudo apt-get install -y ccache
144+
echo 'export PATH="/usr/lib/ccache:$PATH"' >> ~/.bashrc
145+
source ~/.bashrc
146+
sudo apt-get install -y patchelf
144147
145148
- name: Cache Nuitka cache directory
146149
uses: actions/cache@v4

.github/workflows/nuitka_package_release.yml

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ on:
1010

1111
jobs:
1212
package-and-upload:
13-
runs-on: windows-latest
14-
# runs-on: ${{ matrix.os }}
15-
# strategy:
16-
# matrix:
17-
# os: [ubuntu-latest,ubuntu-24.04-arm,windows-latest] # windows-11-arm没有对应的 Python
13+
# runs-on: windows-latest
14+
runs-on: ${{ matrix.os }}
15+
strategy:
16+
matrix:
17+
os: [ubuntu-latest,ubuntu-24.04-arm,windows-latest] # windows-11-arm没有对应的 Python
1818
env:
1919
PYTHON_VERSION: '3.10'
2020
NUITKA_CACHE_DIR: ${{ github.workspace }}/nuitka-cache
@@ -145,11 +145,14 @@ jobs:
145145
# # 设置控制台编码为UTF-8
146146
# chcp.com 65001
147147

148-
- name: Install ccache on Linux
148+
- name: Install dependencies on Linux
149149
if: ${{ runner.os == 'Linux' }}
150150
run: |
151151
sudo apt-get update -y
152152
sudo apt-get install -y ccache
153+
echo 'export PATH="/usr/lib/ccache:$PATH"' >> ~/.bashrc
154+
source ~/.bashrc
155+
sudo apt-get install -y patchelf
153156
154157
- name: Cache Nuitka cache directory
155158
uses: actions/cache@v4

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,4 +199,7 @@ cython_debug/
199199
temp/
200200
.vscode/
201201
.idea/
202-
**/*.bak
202+
**/*.bak
203+
*.build/
204+
*.dist/
205+
*.onefile-build/

README.md

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,35 @@
1-
# python-code
2-
3-
我写的python小代码
4-
5-
**禁止任何人将代码用于违法行为**
6-
7-
[![Nuitka Package and Release](https://github.com/God-2077/python-code/actions/workflows/nuitka_package_release.yml/badge.svg)](https://github.com/God-2077/python-code/actions/workflows/nuitka_package_release.yml)
8-
[![Nuitka Package and Upload(dev)](https://github.com/God-2077/python-code/actions/workflows/dev_package_and_upload.yml/badge.svg)](https://github.com/God-2077/python-code/actions/workflows/dev_package_and_upload.yml)
1+
<div align="center">
2+
<img src="https://socialify.git.ci/God-2077/python-code/image?font=JetBrains+Mono&language=1&name=1&owner=1&pattern=Circuit+Board&theme=Auto" alt="python-code" width="640" height="320" />
3+
</div>
4+
<div align="center">
5+
<a href="https://github.com/God-2077/python-code/releases">
6+
<img src="https://img.shields.io/github/release/God-2077/python-code.svg?color=0366d6" alt="Latest Release">
7+
</a>
8+
<a href="https://github.com/God-2077/python-code/releases">
9+
<img src="https://img.shields.io/github/release-date/God-2077/python-code.svg?color=28a745" alt="Release Date">
10+
</a>
11+
<a href="https://github.com/God-2077/python-code/commits/main/">
12+
<img src="https://img.shields.io/github/commit-activity/t/God-2077/python-code?color=6f42c1" alt="GitHub commit activity">
13+
</a>
14+
<a href="https://github.com/God-2077/python-code#GPL-3.0-1-ov-file">
15+
<img src="https://img.shields.io/github/license/God-2077/python-code?color=ff5722" alt="GitHub License">
16+
</a>
17+
<a href="https://github.com/God-2077/python-code/actions">
18+
<img src="https://img.shields.io/github/actions/workflow/status/God-2077/python-code/nuitka_package_release.yml?style=flat&color=20c997" alt="GitHub Actions Workflow Status">
19+
</a>
20+
</div>
21+
<br />
22+
在我眼里,Python不只是一门编程语言,更像个万能工具🛠️——简单易懂,却能干成不少事。
23+
24+
这里分享了一些我写的实用代码,部分已编译成可直接使用的程序,大家可以去 [Releases](https://github.com/God-2077/python-code/releases) 下载。
25+
26+
我目前技术还在提升中,对Python开发和git操作不算精通,所以部分代码可能不够规范,git提交记录也有些乱~ 不过更新日志可以直接看README.md哦。
27+
28+
如果大家遇到BUG,非常欢迎提交issue,我有空一定会看的~ 另外我即将升入高三,可能回复会慢一些,但一定会留意的。
29+
30+
也欢迎大家在这里分享Python代码呀~
31+
32+
另外提醒一句:禁止任何人将这些代码用于违法行为。
933

1034
## [网易云音乐歌单批量下载歌曲][1]
1135

package/nuitka_build.py

Lines changed: 97 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,52 @@
88
import uuid
99
import shutil
1010

11+
# 自定义字典类,用于支持默认值为 None 的键
12+
class MyDict(dict):
13+
def get(self, key, default=None):
14+
# 如果键存在且值为 None,返回默认值
15+
if key in self and self[key] is None:
16+
return default
17+
# 其他情况调用原生 get 方法
18+
return super().get(key, default)
19+
1120
def normalize_path(path_str):
1221
"""将路径字符串中的反斜杠转换为当前系统的分隔符"""
1322
return Path(path_str.replace('\\', os.sep))
1423

24+
def get_dir_name(directory):
25+
"""获取目录名称"""
26+
# 处理根目录和路径结尾带分隔符的情况(如 "dist/")
27+
base = os.path.basename(directory)
28+
if not base: # 当路径以分隔符结尾时(如 "dist/")
29+
return os.path.basename(os.path.dirname(directory))
30+
return base
31+
1532
def delete_folders(directory):
16-
"""删除指定目录下的所有文件夹,但保留文件"""
17-
if os.path.basename(directory) == '' or os.path.basename(directory):
18-
dir_name = os.path.basename(os.path.dirname(directory))
19-
else:
20-
dir_name = os.path.basename(directory)
33+
"""directory is str,删除指定目录下的所有文件夹,但保留文件"""
34+
dir_name = get_dir_name(directory)
2135
print(f'清理文件夹({dir_name})下的文件夹')
2236
try:
2337
# 确保目录存在
2438
if not os.path.exists(directory):
2539
print(f"目录不存在: {directory}")
2640
return True
2741

42+
deleted_dirs = [] # 新增:用于记录删除的目录
2843
# 遍历目录中的所有项
2944
for item in os.listdir(directory):
3045
item_path = os.path.join(directory, item)
3146
# 如果是文件夹,则删除
3247
if os.path.isdir(item_path):
33-
# print(f"删除文件夹: {item_path}")
34-
rm_item_dir = ','.join(item_path)
48+
deleted_dirs.append(get_dir_name(item_path)) # 记录被删除的路径
3549
shutil.rmtree(item_path)
36-
# else:
37-
# print(f"保留文件: {item_path}")
38-
print(f'清理文件夹({dir_name})下的文件夹完成: {rm_item_dir}')
50+
51+
# 修改打印语句
52+
if deleted_dirs:
53+
# print(f'清理文件夹({dir_name})下的文件夹完成: {", ".join(deleted_dirs)}')
54+
print(f'清理文件夹({dir_name})下的文件夹完成: {deleted_dirs}')
55+
else:
56+
print(f'未发现需要清理的文件夹({dir_name})')
3957
print("操作完成")
4058
return True
4159
except Exception as e:
@@ -89,6 +107,7 @@ def main():
89107

90108
# 遍历所有打包任务
91109
for i, task in enumerate(config, start=1):
110+
task = MyDict(task)
92111
try:
93112
print(f"\n{'='*40}")
94113
print(f"开始打包任务: [{i}/{len(config)}] {task['name']}")
@@ -101,17 +120,29 @@ def main():
101120
enable_plugins = task.get('enable-plugins', [])
102121

103122
icon = task.get('icon')
104-
windows_disable_console = task.get('windows-disable-console', False)
105123
name = task.get('name')
106124
version = task.get('version')
107125
timeout = task.get('timeout', 60 * 45)
126+
127+
# c-compiler
128+
# c_compiler_clang = task.get('c-compiler', {}).get('clang', False)
129+
# c_compiler_mingw64 = task.get('c-compiler', {}).get('mingw64', False)
130+
c_compiler = MyDict(task.get('c-compiler', {}))
131+
c_compiler_lto = c_compiler.get('lto', 'auto')
132+
c_compiler_static_libpython = c_compiler.get('static-libpython', 'auto')
108133

134+
# windows-specific-controls
135+
windows_specific_controls = MyDict(task.get('windows-specific-controls', {}))
136+
windows_console_mode = windows_specific_controls.get('console-mode')
137+
windows_icon = windows_specific_controls.get('icon')
138+
windows_uac_admin = windows_specific_controls.get('uac-admin',False)
139+
109140
# 处理输出文件名模板
110141
output_name_template = task.get('output-name-template', '{{name}}_{{version}}_nuitka_{{os}}_{{arch}}{{exe_suffix}}')
111142

112143
# 处理架构名称统一
113144
normalized_arch = "x64" if arch == "AMD64" else arch
114-
exe_suffix = '.exe' if system_os == 'Windows' else ''
145+
exe_suffix = '.exe' if system_os == 'Windows' else '.bin'
115146

116147
output_name = output_name_template.replace('{{name}}', name) \
117148
.replace('{{version}}', version) \
@@ -122,14 +153,13 @@ def main():
122153
custom_command = task.get('custom-command')
123154
only_linux_command = task.get('only-linux-command')
124155
only_windows_command = task.get('only-windows-command')
156+
clean_cache = task.get('clean-cache')
125157

126158
# 检查Python文件是否存在
127159
if not python_file.exists():
128160
print(f"错误: Python文件不存在 {python_file}")
129161
continue
130162

131-
# 创建输出目录
132-
dist_path.mkdir(parents=True, exist_ok=True)
133163

134164
# 安装依赖
135165
if requirements:
@@ -139,8 +169,6 @@ def main():
139169
# 构建Nuitka命令
140170
cmd = [
141171
sys.executable, '-m', 'nuitka',
142-
f'--output-filename={output_name}',
143-
f'--output-dir={dist_path}', # 输出目录
144172
'--onefile', # 单文件
145173
'--standalone',
146174
f'--jobs={os.cpu_count()}', # 多线程
@@ -150,15 +178,16 @@ def main():
150178
# Windows特定参数
151179
if system_os == 'Windows':
152180
cmd.append('--mingw64')
153-
if windows_disable_console:
154-
cmd.append('--windows-disable-console')
155-
156-
if icon:
157-
icon_path = base_dir / normalize_path(icon)
181+
if windows_console_mode in ['force','disable','attach','hide']:
182+
cmd.append(f'--windows-console-mode={windows_console_mode}')
183+
if windows_icon:
184+
icon_path = base_dir / normalize_path(windows_icon)
158185
if icon_path.exists():
159186
cmd.append(f'--windows-icon-from-ico={icon_path}')
160187
else:
161188
print(f"警告: 图标文件不存在 {icon_path}")
189+
if windows_uac_admin:
190+
cmd.append('--windows-uac-admin')
162191
if only_windows_command:
163192
if isinstance(only_windows_command, str):
164193
cmd.extend(only_windows_command.split())
@@ -173,8 +202,26 @@ def main():
173202
cmd.append('--clang')
174203
else:
175204
# Linux/macOS 使用 clang
176-
cmd.append('--clang')
205+
pass
177206

207+
# c-compiler
208+
# if c_compiler_clang and c_compiler_mingw64:
209+
# print('不能同时选择 clang mingw64')
210+
# else:
211+
# if c_compiler_clang:
212+
# cmd.append('--clang')
213+
# if c_compiler_mingw64:
214+
# cmd.append('--mingw64')
215+
if c_compiler_lto in ['auto','yes','no']:
216+
cmd.append(f'--lto={c_compiler_lto}')
217+
else:
218+
print(f"警告: 无效的lto选项 '{c_compiler_lto}',将忽略")
219+
if c_compiler_static_libpython in ['auto','yes','no']:
220+
cmd.append(f'--static-libpython={c_compiler_static_libpython}')
221+
else:
222+
print(f"警告: 无效的static-libpython选项 '{c_compiler_static_libpython}',将忽略")
223+
224+
178225
# 启用插件
179226
if enable_plugins:
180227
plugin_list = ','.join(enable_plugins)
@@ -198,9 +245,28 @@ def main():
198245
elif isinstance(custom_command, list):
199246
cmd.extend(custom_command)
200247

248+
# 禁用缓存
249+
if clean_cache:
250+
if not clean_cache in ['all','bytecode','ccache','compression','dll-dependencies']:
251+
print(f"警告: 无效的clean-cache选项 '{clean_cache}',将忽略")
252+
else:
253+
cmd.append(f'--clean-cache={clean_cache}')
254+
201255
# 创建临时文件避免中文路径问题
202-
temp_file = base_dir / f"{uuid.uuid4().hex}.py"
256+
temp_uuid = uuid.uuid4().hex
257+
temp_file = base_dir / f"{temp_uuid}.py"
258+
temp_output_path = base_dir / temp_uuid
259+
203260
shutil.copy(python_file, temp_file)
261+
# 创建目录
262+
dist_path.mkdir(parents=True, exist_ok=True)
263+
temp_output_path.mkdir(parents=True, exist_ok=True)
264+
265+
cmd.append(f'--output-filename={output_name}')
266+
# 使用临时目录
267+
cmd.append(f'--output-dir={temp_output_path}')
268+
269+
# 添加py文件
204270
cmd.append(str(temp_file))
205271

206272
# 打印并执行命令
@@ -216,7 +282,8 @@ def main():
216282

217283
print(f"打包成功: {dist_path / output_name}")
218284
success_count += 1
219-
285+
# 移动打包结果到dist目录
286+
shutil.move(temp_output_path / output_name, dist_path / output_name)
220287
except subprocess.TimeoutExpired:
221288
print(f"任务[{i}/{len(config)} {task['name']}] 执行超时 {timeout} 秒")
222289
task_error_list.append(task['name'])
@@ -228,6 +295,8 @@ def main():
228295
# 确保临时文件被删除
229296
if temp_file.exists():
230297
temp_file.unlink()
298+
if temp_output_path.exists():
299+
shutil.rmtree(temp_output_path)
231300

232301
except Exception as e:
233302
print(f"任务[{i}/{len(config)} {task['name']}]失败: {str(e)}")
@@ -243,18 +312,18 @@ def main():
243312
files_list = []
244313

245314
# 遍历目录下的所有条目
246-
for entry in os.listdir(str(base_dir / 'dist')):
315+
for entry in os.listdir(str(dist_path)):
247316
# 拼接完整的文件路径
248-
full_path = os.path.join(str(base_dir / 'dist'), entry)
317+
full_path = os.path.join(str(dist_path), entry)
249318
# 检查该路径是否为文件
250319
if os.path.isfile(full_path):
251320
files_list.append(entry)
252321

253322
# 输出文件列表
254323
print(f'Dist: {str(files_list)}')
255324
# 清理文件夹
256-
if delete_folders(dist_path):
257-
print(f"已清理dist目录下文件夹: {dist_path}")
325+
# if delete_folders(dist_path):
326+
# print(f"已清理dist目录下文件夹: {dist_path}")
258327

259328
if task_error_list:
260329
print(f"失败的任务: {', '.join(task_error_list)}")

0 commit comments

Comments
 (0)