Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/dev_package_and_upload.yml
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,14 @@ jobs:
# # 设置控制台编码为UTF-8
# chcp.com 65001

- name: Install ccache on Linux
- name: Install dependencies on Linux
if: ${{ runner.os == 'Linux' }}
run: |
sudo apt-get update -y
sudo apt-get install -y ccache
echo 'export PATH="/usr/lib/ccache:$PATH"' >> ~/.bashrc
source ~/.bashrc
sudo apt-get install -y patchelf

- name: Cache Nuitka cache directory
uses: actions/cache@v4
Expand Down
15 changes: 9 additions & 6 deletions .github/workflows/nuitka_package_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ on:

jobs:
package-and-upload:
runs-on: windows-latest
# runs-on: ${{ matrix.os }}
# strategy:
# matrix:
# os: [ubuntu-latest,ubuntu-24.04-arm,windows-latest] # windows-11-arm没有对应的 Python
# runs-on: windows-latest
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest,ubuntu-24.04-arm,windows-latest] # windows-11-arm没有对应的 Python
env:
PYTHON_VERSION: '3.10'
NUITKA_CACHE_DIR: ${{ github.workspace }}/nuitka-cache
Expand Down Expand Up @@ -145,11 +145,14 @@ jobs:
# # 设置控制台编码为UTF-8
# chcp.com 65001

- name: Install ccache on Linux
- name: Install dependencies on Linux
if: ${{ runner.os == 'Linux' }}
run: |
sudo apt-get update -y
sudo apt-get install -y ccache
echo 'export PATH="/usr/lib/ccache:$PATH"' >> ~/.bashrc
source ~/.bashrc
sudo apt-get install -y patchelf

- name: Cache Nuitka cache directory
uses: actions/cache@v4
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -199,4 +199,7 @@ cython_debug/
temp/
.vscode/
.idea/
**/*.bak
**/*.bak
*.build/
*.dist/
*.onefile-build/
40 changes: 32 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,35 @@
# python-code

我写的python小代码

**禁止任何人将代码用于违法行为**

[![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)
[![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)
<div align="center">
<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" />
</div>
<div align="center">
<a href="https://github.com/God-2077/python-code/releases">
<img src="https://img.shields.io/github/release/God-2077/python-code.svg?color=0366d6" alt="Latest Release">
</a>
<a href="https://github.com/God-2077/python-code/releases">
<img src="https://img.shields.io/github/release-date/God-2077/python-code.svg?color=28a745" alt="Release Date">
</a>
<a href="https://github.com/God-2077/python-code/commits/main/">
<img src="https://img.shields.io/github/commit-activity/t/God-2077/python-code?color=6f42c1" alt="GitHub commit activity">
</a>
<a href="https://github.com/God-2077/python-code#GPL-3.0-1-ov-file">
<img src="https://img.shields.io/github/license/God-2077/python-code?color=ff5722" alt="GitHub License">
</a>
<a href="https://github.com/God-2077/python-code/actions">
<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">
</a>
</div>
<br />
在我眼里,Python不只是一门编程语言,更像个万能工具🛠️——简单易懂,却能干成不少事。

这里分享了一些我写的实用代码,部分已编译成可直接使用的程序,大家可以去 [Releases](https://github.com/God-2077/python-code/releases) 下载。

我目前技术还在提升中,对Python开发和git操作不算精通,所以部分代码可能不够规范,git提交记录也有些乱~ 不过更新日志可以直接看README.md哦。

如果大家遇到BUG,非常欢迎提交issue,我有空一定会看的~ 另外我即将升入高三,可能回复会慢一些,但一定会留意的。

也欢迎大家在这里分享Python代码呀~

另外提醒一句:禁止任何人将这些代码用于违法行为。

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

Expand Down
125 changes: 97 additions & 28 deletions package/nuitka_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,52 @@
import uuid
import shutil

# 自定义字典类,用于支持默认值为 None 的键
class MyDict(dict):
def get(self, key, default=None):
# 如果键存在且值为 None,返回默认值
if key in self and self[key] is None:
return default
# 其他情况调用原生 get 方法
return super().get(key, default)

def normalize_path(path_str):
"""将路径字符串中的反斜杠转换为当前系统的分隔符"""
return Path(path_str.replace('\\', os.sep))

def get_dir_name(directory):
"""获取目录名称"""
# 处理根目录和路径结尾带分隔符的情况(如 "dist/")
base = os.path.basename(directory)
if not base: # 当路径以分隔符结尾时(如 "dist/")
return os.path.basename(os.path.dirname(directory))
return base

def delete_folders(directory):
"""删除指定目录下的所有文件夹,但保留文件"""
if os.path.basename(directory) == '' or os.path.basename(directory):
dir_name = os.path.basename(os.path.dirname(directory))
else:
dir_name = os.path.basename(directory)
"""directory is str,删除指定目录下的所有文件夹,但保留文件"""
dir_name = get_dir_name(directory)
print(f'清理文件夹({dir_name})下的文件夹')
try:
# 确保目录存在
if not os.path.exists(directory):
print(f"目录不存在: {directory}")
return True

deleted_dirs = [] # 新增:用于记录删除的目录
# 遍历目录中的所有项
for item in os.listdir(directory):
item_path = os.path.join(directory, item)
# 如果是文件夹,则删除
if os.path.isdir(item_path):
# print(f"删除文件夹: {item_path}")
rm_item_dir = ','.join(item_path)
deleted_dirs.append(get_dir_name(item_path)) # 记录被删除的路径
shutil.rmtree(item_path)
# else:
# print(f"保留文件: {item_path}")
print(f'清理文件夹({dir_name})下的文件夹完成: {rm_item_dir}')

# 修改打印语句
if deleted_dirs:
# print(f'清理文件夹({dir_name})下的文件夹完成: {", ".join(deleted_dirs)}')
print(f'清理文件夹({dir_name})下的文件夹完成: {deleted_dirs}')
else:
print(f'未发现需要清理的文件夹({dir_name})')
print("操作完成")
return True
except Exception as e:
Expand Down Expand Up @@ -89,6 +107,7 @@ def main():

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

icon = task.get('icon')
windows_disable_console = task.get('windows-disable-console', False)
name = task.get('name')
version = task.get('version')
timeout = task.get('timeout', 60 * 45)

# c-compiler
# c_compiler_clang = task.get('c-compiler', {}).get('clang', False)
# c_compiler_mingw64 = task.get('c-compiler', {}).get('mingw64', False)
c_compiler = MyDict(task.get('c-compiler', {}))
c_compiler_lto = c_compiler.get('lto', 'auto')
c_compiler_static_libpython = c_compiler.get('static-libpython', 'auto')

# windows-specific-controls
windows_specific_controls = MyDict(task.get('windows-specific-controls', {}))
windows_console_mode = windows_specific_controls.get('console-mode')
windows_icon = windows_specific_controls.get('icon')
windows_uac_admin = windows_specific_controls.get('uac-admin',False)

# 处理输出文件名模板
output_name_template = task.get('output-name-template', '{{name}}_{{version}}_nuitka_{{os}}_{{arch}}{{exe_suffix}}')

# 处理架构名称统一
normalized_arch = "x64" if arch == "AMD64" else arch
exe_suffix = '.exe' if system_os == 'Windows' else ''
exe_suffix = '.exe' if system_os == 'Windows' else '.bin'

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

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

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

# 安装依赖
if requirements:
Expand All @@ -139,8 +169,6 @@ def main():
# 构建Nuitka命令
cmd = [
sys.executable, '-m', 'nuitka',
f'--output-filename={output_name}',
f'--output-dir={dist_path}', # 输出目录
'--onefile', # 单文件
'--standalone',
f'--jobs={os.cpu_count()}', # 多线程
Expand All @@ -150,15 +178,16 @@ def main():
# Windows特定参数
if system_os == 'Windows':
cmd.append('--mingw64')
if windows_disable_console:
cmd.append('--windows-disable-console')

if icon:
icon_path = base_dir / normalize_path(icon)
if windows_console_mode in ['force','disable','attach','hide']:
cmd.append(f'--windows-console-mode={windows_console_mode}')
if windows_icon:
icon_path = base_dir / normalize_path(windows_icon)
if icon_path.exists():
cmd.append(f'--windows-icon-from-ico={icon_path}')
else:
print(f"警告: 图标文件不存在 {icon_path}")
if windows_uac_admin:
cmd.append('--windows-uac-admin')
if only_windows_command:
if isinstance(only_windows_command, str):
cmd.extend(only_windows_command.split())
Expand All @@ -173,8 +202,26 @@ def main():
cmd.append('--clang')
else:
# Linux/macOS 使用 clang
cmd.append('--clang')
pass

# c-compiler
# if c_compiler_clang and c_compiler_mingw64:
# print('不能同时选择 clang mingw64')
# else:
# if c_compiler_clang:
# cmd.append('--clang')
# if c_compiler_mingw64:
# cmd.append('--mingw64')
if c_compiler_lto in ['auto','yes','no']:
cmd.append(f'--lto={c_compiler_lto}')
else:
print(f"警告: 无效的lto选项 '{c_compiler_lto}',将忽略")
if c_compiler_static_libpython in ['auto','yes','no']:
cmd.append(f'--static-libpython={c_compiler_static_libpython}')
else:
print(f"警告: 无效的static-libpython选项 '{c_compiler_static_libpython}',将忽略")


# 启用插件
if enable_plugins:
plugin_list = ','.join(enable_plugins)
Expand All @@ -198,9 +245,28 @@ def main():
elif isinstance(custom_command, list):
cmd.extend(custom_command)

# 禁用缓存
if clean_cache:
if not clean_cache in ['all','bytecode','ccache','compression','dll-dependencies']:
print(f"警告: 无效的clean-cache选项 '{clean_cache}',将忽略")
else:
cmd.append(f'--clean-cache={clean_cache}')

# 创建临时文件避免中文路径问题
temp_file = base_dir / f"{uuid.uuid4().hex}.py"
temp_uuid = uuid.uuid4().hex
temp_file = base_dir / f"{temp_uuid}.py"
temp_output_path = base_dir / temp_uuid

shutil.copy(python_file, temp_file)
# 创建目录
dist_path.mkdir(parents=True, exist_ok=True)
temp_output_path.mkdir(parents=True, exist_ok=True)

cmd.append(f'--output-filename={output_name}')
# 使用临时目录
cmd.append(f'--output-dir={temp_output_path}')

# 添加py文件
cmd.append(str(temp_file))

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

print(f"打包成功: {dist_path / output_name}")
success_count += 1

# 移动打包结果到dist目录
shutil.move(temp_output_path / output_name, dist_path / output_name)
except subprocess.TimeoutExpired:
print(f"任务[{i}/{len(config)} {task['name']}] 执行超时 {timeout} 秒")
task_error_list.append(task['name'])
Expand All @@ -228,6 +295,8 @@ def main():
# 确保临时文件被删除
if temp_file.exists():
temp_file.unlink()
if temp_output_path.exists():
shutil.rmtree(temp_output_path)

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

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

# 输出文件列表
print(f'Dist: {str(files_list)}')
# 清理文件夹
if delete_folders(dist_path):
print(f"已清理dist目录下文件夹: {dist_path}")
# if delete_folders(dist_path):
# print(f"已清理dist目录下文件夹: {dist_path}")

if task_error_list:
print(f"失败的任务: {', '.join(task_error_list)}")
Expand Down
Loading
Loading