fspack 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. fspack-0.1.0/.copier-answers.yml +21 -0
  2. fspack-0.1.0/.github/workflows/ci.yml +63 -0
  3. fspack-0.1.0/.github/workflows/release.yml +44 -0
  4. fspack-0.1.0/.gitignore +35 -0
  5. fspack-0.1.0/.pre-commit-config.yaml +21 -0
  6. fspack-0.1.0/.python-version +1 -0
  7. fspack-0.1.0/.readthedocs.yaml +23 -0
  8. fspack-0.1.0/.trae/.ignore +15 -0
  9. fspack-0.1.0/.trae/docs/iter-01-cli-loader.md +103 -0
  10. fspack-0.1.0/.trae/docs/iter-02-nsis-installer.md +67 -0
  11. fspack-0.1.0/.trae/docs/iter-03-linux-standalone.md +72 -0
  12. fspack-0.1.0/.trae/docs/iter-04-code-quality.md +51 -0
  13. fspack-0.1.0/.trae/req/req-01-fspack-p1.md +48 -0
  14. fspack-0.1.0/.trae/req/req-02-fspack-p2.md +31 -0
  15. fspack-0.1.0/.trae/req/req-03-fspack-p3.md +33 -0
  16. fspack-0.1.0/.trae/req/req-04-fspack-p4.md +27 -0
  17. fspack-0.1.0/.trae/rules/rule-01-/345/274/200/345/217/221/346/265/201/347/250/213.md +19 -0
  18. fspack-0.1.0/.trae/rules/rule-02-/350/207/252/351/251/261/345/274/200/345/217/221/345/216/237/345/210/231.md +57 -0
  19. fspack-0.1.0/.trae/rules/rule-09-git/346/217/220/344/272/244/350/247/204/345/210/231.md +7 -0
  20. fspack-0.1.0/.trae/rules/rule-11-python-standards.md +108 -0
  21. fspack-0.1.0/.vscode/settings.json +35 -0
  22. fspack-0.1.0/LICENSE +21 -0
  23. fspack-0.1.0/Makefile +55 -0
  24. fspack-0.1.0/PKG-INFO +136 -0
  25. fspack-0.1.0/README.md +92 -0
  26. fspack-0.1.0/docs/_static/.gitkeep +0 -0
  27. fspack-0.1.0/docs/api.rst +7 -0
  28. fspack-0.1.0/docs/changelog.rst +7 -0
  29. fspack-0.1.0/docs/conf.py +69 -0
  30. fspack-0.1.0/docs/index.rst +58 -0
  31. fspack-0.1.0/pyproject.toml +145 -0
  32. fspack-0.1.0/src/fspack/__init__.py +7 -0
  33. fspack-0.1.0/src/fspack/analyzer.py +296 -0
  34. fspack-0.1.0/src/fspack/builder.py +156 -0
  35. fspack-0.1.0/src/fspack/cli.py +87 -0
  36. fspack-0.1.0/src/fspack/commands/__init__.py +1 -0
  37. fspack-0.1.0/src/fspack/commands/build.py +25 -0
  38. fspack-0.1.0/src/fspack/commands/clean.py +21 -0
  39. fspack-0.1.0/src/fspack/commands/package.py +26 -0
  40. fspack-0.1.0/src/fspack/commands/run.py +36 -0
  41. fspack-0.1.0/src/fspack/config.py +92 -0
  42. fspack-0.1.0/src/fspack/embed.py +102 -0
  43. fspack-0.1.0/src/fspack/exceptions.py +36 -0
  44. fspack-0.1.0/src/fspack/installer.py +128 -0
  45. fspack-0.1.0/src/fspack/loader.py +207 -0
  46. fspack-0.1.0/src/fspack/mirror.py +35 -0
  47. fspack-0.1.0/src/fspack/platform.py +36 -0
  48. fspack-0.1.0/src/fspack/project.py +125 -0
  49. fspack-0.1.0/src/fspack/py.typed +0 -0
  50. fspack-0.1.0/src/fspack/standalone.py +82 -0
  51. fspack-0.1.0/tests/__init__.py +0 -0
  52. fspack-0.1.0/tests/examples/helloworld/helloworld.py +10 -0
  53. fspack-0.1.0/tests/examples/helloworld/pyproject.toml +3 -0
  54. fspack-0.1.0/tests/test_analyzer.py +60 -0
  55. fspack-0.1.0/tests/test_builder.py +230 -0
  56. fspack-0.1.0/tests/test_cli.py +137 -0
  57. fspack-0.1.0/tests/test_commands.py +159 -0
  58. fspack-0.1.0/tests/test_config.py +83 -0
  59. fspack-0.1.0/tests/test_e2e_slow.py +42 -0
  60. fspack-0.1.0/tests/test_embed.py +125 -0
  61. fspack-0.1.0/tests/test_fspack.py +17 -0
  62. fspack-0.1.0/tests/test_installer.py +164 -0
  63. fspack-0.1.0/tests/test_loader.py +140 -0
  64. fspack-0.1.0/tests/test_mirror.py +35 -0
  65. fspack-0.1.0/tests/test_platform.py +43 -0
  66. fspack-0.1.0/tests/test_project.py +124 -0
  67. fspack-0.1.0/tests/test_standalone.py +122 -0
  68. fspack-0.1.0/tox.ini +21 -0
  69. fspack-0.1.0/uv.lock +2529 -0
@@ -0,0 +1,21 @@
1
+ # Changes here will be overwritten by Copier
2
+ _commit: v0.4.6
3
+ _src_path: https://github.com/gookeryoung/coopie
4
+ author_email: gooker_young@qq.com
5
+ author_name: gooker_young
6
+ coverage_fail_under: 95
7
+ description: 极速 Python 项目打包器。
8
+ initial_version: 0.1.0
9
+ license: MIT
10
+ max_python_version: '3.14'
11
+ min_python_version: '3.8'
12
+ package_name: fspack
13
+ project_name: fspack
14
+ project_type: cli
15
+ use_cicd: true
16
+ use_cli: true
17
+ use_docker: false
18
+ use_docs: true
19
+ use_domestic_mirrors: true
20
+ use_tox: true
21
+
@@ -0,0 +1,63 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, develop]
6
+ pull_request:
7
+ branches: [main, develop]
8
+
9
+ concurrency:
10
+ group: ${{ github.workflow }}-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ jobs:
14
+ lint:
15
+ name: Lint & Typecheck
16
+ runs-on: ubuntu-latest
17
+ timeout-minutes: 10
18
+ steps:
19
+ - uses: actions/checkout@v5
20
+
21
+ - name: Install uv
22
+ uses: astral-sh/setup-uv@v8.3.2
23
+ with:
24
+ enable-cache: true
25
+ cache-dependency-glob: "uv.lock"
26
+
27
+ - name: Sync dependencies
28
+ run: uv sync --frozen --extra lint
29
+
30
+ - name: Ruff check
31
+ run: uv run ruff check src tests
32
+
33
+ - name: Ruff format check
34
+ run: uv run ruff format --check src tests
35
+
36
+ - name: Pyrefly check
37
+ run: uv run pyrefly check
38
+
39
+ test:
40
+ name: Test (Python 3.8 & 3.14)
41
+ runs-on: ubuntu-latest
42
+ timeout-minutes: 15
43
+ strategy:
44
+ fail-fast: false
45
+ matrix:
46
+ python-version: ["3.8", "3.14"]
47
+ steps:
48
+ - uses: actions/checkout@v5
49
+
50
+ - name: Install uv
51
+ uses: astral-sh/setup-uv@v8.3.2
52
+ with:
53
+ enable-cache: true
54
+ cache-dependency-glob: "uv.lock"
55
+
56
+ - name: Set up Python ${{ matrix.python-version }}
57
+ run: uv python install ${{ matrix.python-version }}
58
+
59
+ - name: Sync dependencies
60
+ run: uv sync --frozen --extra test --python ${{ matrix.python-version }}
61
+
62
+ - name: Run tests
63
+ run: uv run pytest -m "not slow" --cov=fspack --cov-fail-under=95 --cov-report=term-missing
@@ -0,0 +1,44 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags: ['v*.*.*']
6
+
7
+ permissions:
8
+ contents: write
9
+ id-token: write
10
+
11
+ concurrency:
12
+ group: release-${{ github.ref }}
13
+ cancel-in-progress: false
14
+
15
+ jobs:
16
+ release:
17
+ name: Build & Publish
18
+ runs-on: ubuntu-latest
19
+ environment: pypi
20
+ timeout-minutes: 10
21
+ steps:
22
+ - uses: actions/checkout@v5
23
+
24
+ - name: Install uv
25
+ uses: astral-sh/setup-uv@v8.3.2
26
+ with:
27
+ enable-cache: true
28
+ cache-dependency-glob: "uv.lock"
29
+
30
+ - name: Build distributions
31
+ run: uv build
32
+
33
+ - name: Publish to PyPI (OIDC)
34
+ run: uv publish
35
+
36
+ - name: Create GitHub Release
37
+ env:
38
+ GH_TOKEN: ${{ github.token }}
39
+ TAG_NAME: ${{ github.ref_name }}
40
+ run: |
41
+ gh release create "$TAG_NAME" \
42
+ --title "Release $TAG_NAME" \
43
+ --generate-notes \
44
+ dist/*
@@ -0,0 +1,35 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # 测试与覆盖率
13
+ .coverage
14
+ .coverage.*
15
+ htmlcov/
16
+ coverage.xml
17
+ .tox/
18
+
19
+ # 工具缓存
20
+ .ruff_cache/
21
+ .pyrefly_cache/
22
+ .mypy_cache/
23
+ .uv-cache/
24
+
25
+ # IDE
26
+ .idea/
27
+ *_profile.html
28
+
29
+ # 环境变量与凭证(勿提交)
30
+ .env
31
+ .env.*
32
+
33
+ # Sphinx 文档构建输出
34
+ docs/_build/
35
+ .trae/refs
@@ -0,0 +1,21 @@
1
+ # prek / pre-commit 配置
2
+ # See https://pre-commit.com for more information
3
+ repos:
4
+ - repo: https://github.com/astral-sh/ruff-pre-commit
5
+ # Ruff 版本 - 与 pyproject.toml 保持同步
6
+ rev: v0.15.8
7
+ hooks:
8
+ # 运行 linter
9
+ - id: ruff
10
+ args: [--fix, --exit-non-zero-on-fix]
11
+ # 运行格式化
12
+ - id: ruff-format
13
+ - repo: https://github.com/pre-commit/pre-commit-hooks
14
+ rev: v5.0.0
15
+ hooks:
16
+ - id: check-merge-conflict
17
+ - id: debug-statements
18
+ - id: fix-byte-order-marker
19
+ - id: trailing-whitespace
20
+ args: [--markdown-linebreak-ext=md]
21
+ - id: end-of-file-fixer
@@ -0,0 +1 @@
1
+ 3.8
@@ -0,0 +1,23 @@
1
+ # ReadTheDocs 配置
2
+ # https://docs.readthedocs.io/en/stable/config-file/v2.html
3
+ version: 2
4
+
5
+ # 构建配置
6
+ build:
7
+ os: ubuntu-24.04
8
+ tools:
9
+ python: "3.8"
10
+
11
+ # Python 依赖与构建命令
12
+ python:
13
+ install:
14
+ - method: pip
15
+ path: .
16
+ extra_requirements:
17
+ - docs
18
+
19
+ # Sphinx 构建
20
+ sphinx:
21
+ configuration: docs/conf.py
22
+ builder: html
23
+ fail_on_warning: false
@@ -0,0 +1,15 @@
1
+ # PYTHON
2
+ .coverage
3
+ .pytest_cache/
4
+ .ruff_cache/
5
+ .tox/
6
+ .venv/
7
+ __pycache__/
8
+
9
+ # NODEJS
10
+ node_modules/
11
+
12
+ # IDE
13
+ .idea
14
+ .trae
15
+ .vscode
@@ -0,0 +1,103 @@
1
+ # iter-01 CLI 与 C Loader 垂直切片
2
+
3
+ ## 迭代目标
4
+
5
+ 交付 P1:从 pyproject.toml 解析到 `fsp b` 产出可被 `fsp r` 运行的 hello world .exe,全程在 Linux 用 mingw 交叉编译 + wine 运行验证。
6
+
7
+ ## 关键决策与依据
8
+
9
+ ### 模块结构
10
+ ```
11
+ src/fspack/
12
+ __init__.py # 版本号
13
+ cli.py # fsp b/c/r 子命令分发(argparse)
14
+ commands/
15
+ __init__.py
16
+ build.py # fsp b → builder.build()
17
+ clean.py # fsp c → 清理 dist/
18
+ run.py # fsp r → wine 运行 dist .exe
19
+ project.py # pyproject.toml → ProjectInfo
20
+ analyzer.py # AST import 扫描 → DependencyReport
21
+ mirror.py # MirrorConfig 国内镜像
22
+ embed.py # embed python 下载/解压/_pth
23
+ loader.py # C loader 源码生成 + mingw 交叉编译
24
+ builder.py # 流水线编排
25
+ config.py # dataclass(ProjectInfo/AppType/MirrorConfig 等)
26
+ exceptions.py # FspackError 层级
27
+ ```
28
+
29
+ ### 镜像选型
30
+ - 华为云(已验证 HTTP 200):`https://mirrors.huaweicloud.com/python/{ver}/python-{ver}-embed-amd64.zip`,pip 索引 `https://mirrors.huaweicloud.com/pypi/simple/`。
31
+ - 备选阿里云、清华;默认华为云,`--mirror` 可切换。
32
+
33
+ ### embed python _pth
34
+ ```
35
+ python3X.zip
36
+ .
37
+ Lib
38
+ Lib\site-packages
39
+ import site
40
+ ```
41
+
42
+ ### C loader 设计
43
+ - 不依赖 Python.h(embed 包不含开发头文件),改用动态加载 `python3X.dll`,解析 `Py_Main(argc, argv)` 符号调用。
44
+ - 配置在生成时以 `#define` 烧入:`ENTRY_FILE`、`PYTHON_HOME`(相对 exe 的 runtime 子目录)、`PYTHON_DLL`(如 `python311.dll`)。
45
+ - 设置环境变量 PYTHONHOME/PYTHONPATH 后 `Py_Main(["loader.exe", exe_dir\ENTRY_FILE, ...用户参数])`。
46
+ - GUI 子系统:mingw `-mwindows`;CLI:默认 console。
47
+ - 版本无关:优先加载 `python3.dll`(稳定 ABI),回退 `python3X.dll`。
48
+
49
+ ### 依赖下载策略(Linux dev 拉 Windows wheel)
50
+ - embed python.exe 是 Windows 程序,Linux dev 无法直接跑它的 pip。
51
+ - 方案:dev python 执行 `pip download -d wheelhouse --platform win_amd64 --python-version <ver> --only-binary=:all: -i <镜像> <deps>`,再用 `zipfile` 把每个 .whl 解包到 `dist/Lib/site-packages/`。
52
+ - 无依赖项目(hello world)跳过此步。
53
+
54
+ ### Python 3.8 兼容
55
+ - `.python-version=3.8`,uv 已装 3.8.20。
56
+ - toml:`sys.version_info>=(3,11)` 用 `tomllib`,否则 `tomli`(条件依赖 `tomli; python_version<'3.11'`)。
57
+ - 标准库模块名:`sys.stdlib_module_names`(3.10+)不可用,3.8/3.9 用 curated frozenset 回退。
58
+ - 注解用 `from __future__ import annotations`,可用 `list[str]` 等。
59
+
60
+ ### 测试策略
61
+ - 公共 API 单测:解析、AST、镜像 URL、_pth 内容、loader C 源码字符串、wheel 解包。mock 网络(urllib)与子进程(pip/mingw)。
62
+ - `@pytest.mark.slow`:真实 embed 下载、mingw 编译、wine 运行、端到端 hello world。
63
+ - 门禁:`ruff check`/`ruff format --check`/`pyrefly check`/`pytest -m 'not slow' --cov≥95%`。
64
+
65
+ ## 改动文件清单
66
+
67
+ 新增:
68
+ - src/fspack/{config,exceptions,project,analyzer,mirror,embed,loader,builder,cli}.py
69
+ - src/fspack/commands/{__init__,build,clean,run}.py
70
+ - tests/test_{config,project,analyzer,mirror,embed,loader,builder,cli}.py
71
+ - tests/examples/helloworld/ 示例项目
72
+ - .trae/req/req-01-fspack-p1.md、.trae/docs/iter-01-cli-loader.md
73
+
74
+ 修改:
75
+ - src/fspack/__init__.py(保持版本)
76
+ - src/fspack/cli.py(重写为子命令分发)
77
+ - pyproject.toml(加 tomli 条件依赖)
78
+ - README.md(更新快速上手)
79
+
80
+ ## 验证结果
81
+
82
+ 非 slow 门禁全过(2026-07-12):
83
+
84
+ - `uv run ruff check src tests`:All checks passed!
85
+ - `uv run ruff format --check src tests`:27 files already formatted
86
+ - `uv run pyrefly check`:0 errors(1 suppressed)
87
+ - `uv run pytest -m "not slow" --cov=fspack --cov-fail-under=95`:83 passed, 1 deselected, 覆盖率 99.45%
88
+
89
+ 修复要点:
90
+ - `DependencyReport.missing` 用 `re.split(r"[<>=!~;\[]", d, maxsplit=1)` 剥离版本号,修正 "numpy>=1.0" 误判 missing。
91
+ - 移除 `test_analyze_dependencies_classification` 中错误的 `assert 'main' in r.ast_local`(项目名未被 import 不在 ast_local)。
92
+ - 移除 `test_write_pth_content` 中 site-packages 目录断言(该目录由 `ensure_embed` 创建,`write_pth` 只写文件)。
93
+ - 移除 `_infer_app_type` 死代码 try/except(`_has_entry` 已验证解析成功)。
94
+ - 新增 `tests/test_commands.py` 直测 build/clean/run 子命令与 `_build_cmd` Linux(wine 有/无)/非 Linux 分支。
95
+ - 补 project.py 分支测试:[project] 非 dict、_has_entry SyntaxError 跳过、多依赖非 GUI 推断 CLI。
96
+
97
+ 唯一未覆盖行:`project.py:83`(`detect_entry` 中 `mod in seen` 防御性 continue,正常流程无法触发,保留作防御)。
98
+
99
+ ## 遗留事项
100
+
101
+ - mingw-w64 + wine 需用户 sudo 安装;安装前 slow 测试(真实 embed 下载 + mingw 编译 + wine 运行 + hello world 端到端)无法运行。
102
+ - 需求 #10 端到端验证待 mingw+wine 就绪后跑 `pytest -m slow`。
103
+ - P2:NSIS 安装包;P3:Linux 支持。
@@ -0,0 +1,67 @@
1
+ # iter-02 NSIS 安装包生成
2
+
3
+ ## 迭代目标
4
+
5
+ 在 P1 dist 产出基础上,生成 NSIS 安装脚本并调用 makensis 编译为单个 `<name>-setup.exe` 安装包,通过 `fsp p`(package)子命令触发。
6
+
7
+ ## 关键决策
8
+
9
+ ### 模块结构
10
+ ```
11
+ src/fspack/
12
+ installer.py # NSIS 脚本生成 + makensis 编译
13
+ commands/package.py # fsp p → 编排 build + installer
14
+ cli.py # 加 package/p 子命令
15
+ ```
16
+
17
+ ### NSIS 脚本设计
18
+ - 用 MUI2 宏实现现代化安装向导(Welcome/Directory/InstFiles/Finish)。
19
+ - 安装目录 `$PROGRAMFILES64\<name>`,`RequestExecutionLevel admin`。
20
+ - `Section "Main"`:`SetOutPath $INSTDIR` + `File /r "dist\*.*"` 递归复制 dist 全量 + `WriteUninstaller`。
21
+ - GUI 项目额外创建开始菜单与桌面快捷方式(`CreateShortCut`)。
22
+ - `Section "Uninstall"`:`RMDir /r $INSTDIR` + 清理快捷方式。
23
+ - 中英文双语(SimpChinese + English)。
24
+
25
+ ### makensis 调用
26
+ - `subprocess.run(["makensis", str(nsi_path)], check=True, capture_output=True)`。
27
+ - 缺失 makensis 抛 `InstallerError`(提示安装 NSIS)。
28
+ - 编译产出 `<name>-setup.exe` 放 `dist/release/`。
29
+ - 真实编译标 `@pytest.mark.slow`。
30
+
31
+ ### fsp p 命令
32
+ - `fsp p [project] [--no-build] [--mirror X] [--py-version X]`。
33
+ - 默认先 `build` 再生成安装包;`--no-build` 跳过重建直接用已有 dist。
34
+ - dist 不存在或缺 exe 时抛 `FspackError` 提示先 `fsp b`。
35
+
36
+ ## 改动文件清单
37
+
38
+ 新增:
39
+ - src/fspack/installer.py
40
+ - src/fspack/commands/package.py
41
+ - tests/test_installer.py
42
+
43
+ 修改:
44
+ - src/fspack/cli.py(加 package/p 子命令)
45
+ - src/fspack/exceptions.py(加 InstallerError)
46
+ - tests/test_commands.py(补 package.run)
47
+ - tests/test_cli.py(补 fsp p 分发)
48
+
49
+ ## 验证结果
50
+
51
+ 非 slow 门禁全过(2026-07-12):
52
+
53
+ - `uv run ruff check src tests`:All checks passed!
54
+ - `uv run ruff format --check src tests`:30 files already formatted
55
+ - `uv run pyrefly check`:0 errors(1 suppressed)
56
+ - `uv run pytest -m "not slow" --cov=fspack --cov-fail-under=95`:96 passed, 1 deselected, 覆盖率 99.53%
57
+
58
+ 模块覆盖:
59
+ - `installer.py` 100%(generate_nsis_script CLI/GUI 内容断言、compile_installer missing/error/no-output/success、build_installer no_build 三分支 + with_build)
60
+ - `commands/package.py` 100%(默认参数 + 显式选项)
61
+ - `cli.py` 98%(`fsp p` 分发已覆盖)
62
+
63
+ ## 遗留事项
64
+
65
+ - makensis 需用户安装(`sudo apt install -y nsis`);安装前 slow 编译测试与端到端安装包产出验证无法运行。
66
+ - 需求 #5 端到端验证待 makensis 就绪后跑 `pytest -m slow`。
67
+ - P3:Linux 支持。
@@ -0,0 +1,72 @@
1
+ # iter-03 Linux 平台支持(python-build-standalone)
2
+
3
+ ## 迭代目标
4
+
5
+ P3 增加 Linux 打包:用 indygreg python-build-standalone 作为便携式 CPython 运行时,C loader 加载 libpython 调用 Py_Main,思路与 Windows embed 一致。复用 P1/P2 的解析/AST/依赖下载/流水线框架,加平台抽象层。
6
+
7
+ ## 关键决策
8
+
9
+ ### 平台抽象
10
+ - 新增 `platform.py`:`Platform` 枚举(WINDOWS/LINUX)、`detect_platform()` 按 `sys.platform` 识别、平台常量(wheel platform tag、编译器、libpython 后缀)。
11
+ - `BuildConfig` 加 `target: Platform` 字段,流水线按 target 分发。
12
+
13
+ ### python-build-standalone 下载(standalone.py)
14
+ - URL:`https://github.com/indygreg/python-build-standalone/releases/download/{release_tag}/cpython-{ver}+{release_tag}-x86_64-unknown-linux-gnu-install_only.tar.gz`。
15
+ - 缓存到 `~/.fspack/cache/standalone/`,命中跳过下载。
16
+ - 解压到 `dist/runtime/`,解压后顶层 `python/` 目录为 Python 根(含 bin/python3.X、lib/libpython3.X.so、lib/python3.X/)。
17
+ - `ensure_standalone` 幂等:`runtime/python/bin/python3` 存在则跳过。
18
+
19
+ ### Linux C loader
20
+ - 模板用 `dlopen(libpython.so, RTLD_NOW|RTLD_GLOBAL)` + `dlsym("Py_Main")` + `setenv("PYTHONHOME", "runtime/python")`。
21
+ - 入口路径烧入:`ENTRY_FILE`(如 `src/helloworld.py`)、`LIBPYTHON`(如 `runtime/python/lib/libpython3.11.so`)、`PYTHONHOME`(`runtime/python`)。
22
+ - `exe_dir` 用 `readlink("/proc/self/exe")` 获取 loader 所在目录。
23
+ - gcc 编译:`gcc -O2 -o <exe> <c> -ldl`(Linux 无 GUI 子系统,AppType.GUI 仅影响快捷方式/安装包,loader 不区分)。
24
+
25
+ ### 流水线分支
26
+ - `builder.build(target=...)`:
27
+ - WINDOWS:ensure_embed + write_pth + mingw loader + wheel `win_amd64`
28
+ - LINUX:ensure_standalone(不写 _pth,用 PYTHONHOME)+ gcc loader + wheel `manylinux2014_x86_64`
29
+ - Linux 不写 _pth(PYTHONHOME 已定位标准库,site-packages 在 `runtime/python/lib/python3.X/site-packages`)。
30
+
31
+ ### CLI
32
+ - `fsp b --target linux|windows`(默认当前平台)。
33
+ - `fsp p --target` 同理。
34
+
35
+ ## 改动文件清单
36
+
37
+ 新增:
38
+ - src/fspack/platform.py
39
+ - src/fspack/standalone.py
40
+ - tests/test_standalone.py
41
+ - tests/test_platform.py
42
+
43
+ 修改:
44
+ - src/fspack/config.py(BuildConfig 加 target)
45
+ - src/fspack/loader.py(generate_loader_source/compile_loader 加 platform 分支 + Linux 模板)
46
+ - src/fspack/builder.py(build 加 target 参数,按平台分支)
47
+ - src/fspack/commands/build.py、package.py(透传 target)
48
+ - src/fspack/cli.py(--target 选项)
49
+
50
+ ## 验证结果
51
+
52
+ 四项门禁全过(2026-07-12):
53
+
54
+ - `ruff check src tests`:All checks passed
55
+ - `ruff format --check src tests`:34 files already formatted
56
+ - `pyrefly check`:0 errors(2 suppressed)
57
+ - `pytest -m "not slow" --cov=fspack`:118 passed, 1 deselected, cov 99.08%
58
+
59
+ 修复要点:
60
+ - `loader.generate_loader_source` Linux 分支 libpython 路径漏 "python" 前缀(`lib3.11.so` → `libpython3.11.so`),与 `platform.libpython_so` 对齐。
61
+ - `test_loader.py` 缺 `Platform`/`gcc_available` 导入。
62
+ - `test_builder.py` Windows 测试的 `fake_compile` 缺 `platform` 参数、`download_wheels` lambda 缺 `platform_tag` 关键字参数(builder.build 现按 target 透传)。
63
+
64
+ 未覆盖行(非新增):
65
+ - `platform.py:21`(detect_platform 的 Windows 分支,Linux dev 不可达)
66
+ - `project.py:83`(防御性 `mod in seen` continue)
67
+ - `cli.py:66->exit`/`82`(argparse 错误分支)
68
+
69
+ ## 遗留事项
70
+
71
+ - python-build-standalone 真实下载/gcc 编译标 slow,待环境验证。
72
+ - P4:macOS 支持;Linux 安装包(.deb/.rpm/AppImage)。
@@ -0,0 +1,51 @@
1
+ # iter-04 代码质量改进与覆盖率提升
2
+
3
+ ## 迭代目标
4
+
5
+ P1/P2/P3 三阶段交付后,清理冗余字段并补齐未覆盖分支,提升覆盖率与代码质量。
6
+
7
+ ## 关键决策
8
+
9
+ ### BuildConfig.arch 移除
10
+ - `arch: str = "win_amd64"` 字段未被任何业务代码使用(builder.py 用 `wheel_platform_tag(target)` 派生),且默认值对 Linux target 不正确。
11
+ - 移除字段,test_config.py 断言改为 `cfg.target == Platform.WINDOWS`(真正表达平台语义)。
12
+
13
+ ### detect_platform Windows 分支
14
+ - `platform.py:21` 的 Windows 分支在 Linux dev 下不可达。用 monkeypatch `_platform.system` 返回 "Windows"/"Linux" 分别测试两个分支。
15
+
16
+ ### detect_entry 去重分支(核心发现)
17
+ - `project.py` 的 `if mod in seen or not path.is_file(): continue` 长期显示 line 83 (continue) missing。
18
+ - 根因:Python sys.settrace 对 `if: continue` 的 JUMP_ABSOLUTE 指令不触发 continue 行的 line event,导致 coverage 误报。用 sys.settrace 追踪 locals 确认 `mod in seen` 确实为 True 但 continue 行未被记录。
19
+ - 修复:改写为正向条件 `if mod not in seen and path.is_file():`,消除 continue 语句。De Morgan 等价,语义不变,coverage 正确记录。
20
+
21
+ ### _parse_target windows 分支
22
+ - `cli.py:82` 的 `return Platform.WINDOWS` 未覆盖(之前只测 --target linux)。加 `test_build_target_windows_dispatch`。
23
+
24
+ ## 改动文件清单
25
+
26
+ 修改:
27
+ - src/fspack/config.py(移除 BuildConfig.arch)
28
+ - src/fspack/project.py(detect_entry 改写正向条件)
29
+ - tests/test_config.py(断言 arch → target)
30
+ - tests/test_platform.py(+2 detect_platform Windows/Linux 分支测试)
31
+ - tests/test_project.py(+1 dedup 同名无 entry 测试)
32
+ - tests/test_cli.py(+1 --target windows 分发测试)
33
+
34
+ ## 验证结果
35
+
36
+ 四项门禁全过(2026-07-12):
37
+
38
+ - `ruff check src tests`:All checks passed
39
+ - `ruff format --check src tests`:34 files already formatted
40
+ - `pyrefly check`:0 errors(2 suppressed)
41
+ - `pytest -m "not slow" --cov=fspack`:122 passed, 1 deselected, cov 99.87%
42
+
43
+ 覆盖率演进:
44
+ - P3:118 passed, cov 99.08%(未覆盖:platform.py:21、project.py:83、cli.py:82)
45
+ - P4:122 passed, cov 99.87%(project.py 达 100%,platform.py 100%,cli.py 99%)
46
+ - 仅剩 cli.py `66->exit`(argparse choices 限制,command 非 build/run/clean/package 的分支不可达)
47
+
48
+ ## 遗留事项
49
+
50
+ - cli.py `66->exit` 为 argparse 结构性不可达分支,接受现状(99.87% 已远超 95% 门槛)。
51
+ - slow 端到端验证仍待外部环境(mingw/wine/makensis/python-build-standalone 真实下载)。
@@ -0,0 +1,48 @@
1
+ # fspack P1 需求清单
2
+
3
+ 参考本人 fspacker(PyPI)设计的新一代 Python 打包 CLI 工具 `fspack`。
4
+
5
+ ## 总体目标
6
+
7
+ 构建一个类似 cargo 的简洁 Python 打包工具,使用 embed python 调用用户脚本,通过 C loader 配置运行环境,最终用 NSIS 打包为 Windows 安装包分发。本文件记录第一阶段(P1)需求。
8
+
9
+ ## 平台与范围(用户确认)
10
+
11
+ - 目标平台:Windows 优先,Linux 后续阶段。
12
+ - Loader 实现:C + Python 引导(C 设置环境加载 embed python,重逻辑放 Python)。
13
+ - 安装包工具:NSIS(后续阶段,P1 不含)。
14
+ - 开发环境:Linux 交叉编译(mingw-w64 + wine)。
15
+
16
+ ## P1 范围(垂直切片:能运行 hello world)
17
+
18
+ [x] 1. CLI 骨架:`fsp b`(build) / `fsp c`(clean) / `fsp r`(run) / `fsp -V`(version),cargo 风格短命令,argparse 子命令分发。
19
+ [x] 2. 项目元数据解析:解析 pyproject.toml(name/version/dependencies),识别入口(`def main()` 或 `if __name__=='__main__'`),判定 CLI/GUI 类型。
20
+ [x] 3. AST 依赖分析:扫描源码 import,提取顶层模块,与标准库/本地包/第三方分类,补全未声明依赖。
21
+ [x] 4. embed python 下载:国内镜像源(华为云优先,阿里云/清华备选)下载 `python-X.Y.Z-embed-amd64.zip`,缓存到 `~/.fspack/cache/embed/`,解压到 `dist/runtime/`。
22
+ [x] 5. _pth 配置:生成 `python3X._pth` 启用 site-packages,创建 `Lib/site-packages` 目录。
23
+ [x] 6. 依赖下载:用 dev python 的 `pip download --platform win_amd64 --only-binary=:all:` 拉取 Windows wheel 到 wheelhouse,解包到 `dist/runtime/Lib/site-packages/`。
24
+ [x] 7. C loader 生成与编译:生成 C 源码(动态加载 python3X.dll,调用 `Py_Main` 运行入口脚本),支持 CLI(console)/GUI(windows) 子系统,用 `x86_64-w64-mingw32-gcc` 交叉编译为 .exe(编译命令已实现并单测 mock,真实编译待 mingw)。
25
+ [x] 8. 构建流水线编排:parse → download embed → download deps → copy src → gen loader → compile → assemble dist/。
26
+ [x] 9. run/clean 命令:`fsp r` 用 wine 运行 dist 下的 .exe;`fsp c` 清理 dist/。
27
+ [] 10. hello world 端到端验证:一个无依赖的示例项目能 `fsp b` 后 `fsp r` 输出 "hello, world"(待 mingw-w64 + wine 安装后跑 slow 测试验证)。
28
+
29
+ ## 不在 P1 范围
30
+
31
+ - NSIS 安装包生成(P2)。
32
+ - Linux 平台支持(P3+)。
33
+ - 源码加密(pyarmor)、nuitka 编译优化。
34
+ - 多项目批量打包。
35
+
36
+ ## 验收标准
37
+
38
+ - `fsp b` 对无依赖项目产出 `dist/<name>.exe` + `dist/runtime/` + `dist/src/` + `dist/runtime/Lib/site-packages/`。
39
+ - `fsp r` 通过 wine 运行 .exe 输出预期内容。
40
+ - `fsp c` 清空 dist/。
41
+ - 全套门禁通过:`ruff check`、`ruff format --check`、`pyrefly check`、`pytest --cov≥95%`(mingw/wine/网络相关标 slow)。
42
+ - Python 3.8 兼容。
43
+
44
+ ## 约束
45
+
46
+ - 国内镜像优先;网络/编译/运行类测试标 `slow`。
47
+ - 不引入 requests 等重依赖,下载用 urllib + tomli(仅 py<3.11)。
48
+ - 遵循 rule-11 Python 规范与既有工具链配置。
@@ -0,0 +1,31 @@
1
+ # fspack P2 需求清单
2
+
3
+ P1 已交付 CLI + 解析 + 下载 + loader 垂直切片(非 slow 门禁全过)。P2 在此基础上增加 NSIS 安装包生成,使用户能产出可分发的 Windows 安装程序。
4
+
5
+ ## P2 范围
6
+
7
+ [x] 1. NSIS 脚本生成器:根据 ProjectInfo 与 dist 目录内容生成 `.nsi` 脚本,含 Name/OutFile/InstallDir/Section(File /r)/UninstallSection/CreateShortCut(GUI 时)。
8
+ [x] 2. makensis 编译调用:调用 `makensis` 将 .nsi 编译为单个 `<name>-setup.exe` 安装包,输出到 `dist/release/`(编译命令已实现并单测 mock,真实编译待 makensis)。
9
+ [x] 3. `fsp p`(package) 子命令:在 `fsp b` 产出 dist 基础上生成安装包;支持 `--no-build` 跳过重建直接打包已有 dist。
10
+ [x] 4. 单测:NSIS 脚本内容断言(Name/OutFile/File/Shortcut/Uninstall)、makensis 调用 mock、`fsp p` 命令分发。
11
+ [] 5. 端到端验证(slow):真实 makensis 编译安装包,断言 .exe 产出(待 makensis 安装)。
12
+
13
+ ## 不在 P2 范围
14
+
15
+ - 数字签名(signtool)。
16
+ - 自动更新(在线升级机制)。
17
+ - 多语言安装界面(仅中文 + 英文默认)。
18
+ - Linux 平台支持(P3)。
19
+
20
+ ## 验收标准
21
+
22
+ - `fsp p` 对已构建项目产出 `dist/release/<name>-setup.exe`。
23
+ - NSIS 脚本含完整安装/卸载逻辑,GUI 项目额外创建开始菜单与桌面快捷方式。
24
+ - 全套门禁通过:`ruff check`、`ruff format --check`、`pyrefly check`、`pytest --cov≥95%`(makensis 相关标 slow)。
25
+ - Python 3.8 兼容。
26
+
27
+ ## 约束
28
+
29
+ - 不引入新依赖,NSIS 脚本用字符串模板生成。
30
+ - makensis 调用用 subprocess,标 slow。
31
+ - 遵循 rule-11 Python 规范。
@@ -0,0 +1,33 @@
1
+ # fspack P3 需求清单
2
+
3
+ P1/P2 已交付 Windows 优先的完整链路(CLI + 解析 + embed + loader + NSIS)。P3 增加 Linux 平台支持,运行时用 indygreg 的 python-build-standalone 便携式 CPython,C loader 加载 libpython 调用 Py_Main,思路与 Windows embed 一致。
4
+
5
+ ## P3 范围
6
+
7
+ [x] 1. 平台抽象:新增 `Platform` 枚举(WINDOWS/LINUX),`BuildConfig` 带 target 字段,`detect_platform()` 识别当前系统。
8
+ [x] 2. python-build-standalone 下载与解压:新增 `standalone.py`,从 GitHub releases 下载 `cpython-{ver}+{date}-x86_64-unknown-linux-gnu-install_only.tar.gz`,缓存到 `~/.fspack/cache/standalone/`,解压到 `dist/runtime/python/`。
9
+ [x] 3. Linux C loader:扩展 `loader.py` 生成 Linux C 源码(dlopen libpython.so + dlsym Py_Main + setenv PYTHONHOME),用 gcc 编译为 ELF 可执行文件(`-ldl`)。
10
+ [x] 4. Linux 依赖下载:扩展 `builder.download_wheels` 支持 `--platform manylinux2014_x86_64` 拉 Linux wheel。
11
+ [x] 5. 流水线平台分支:`builder.build` 加 `target` 参数,按平台调 standalone/embed + 对应 loader + 对应 wheel 平台。
12
+ [x] 6. CLI `--target`:`fsp b`/`fsp p` 加 `--target windows|linux`,默认当前平台。
13
+ [x] 7. 单测:standalone 下载/解压 mock、Linux loader 源码内容断言、gcc 编译 mock、build target 分支、CLI --target 分发。
14
+ [] 8. 端到端验证(slow):真实下载 python-build-standalone + gcc 编译 + 运行 hello world。
15
+
16
+ ## 不在 P3 范围
17
+
18
+ - macOS 支持(P4+)。
19
+ - Linux 安装包(.deb/.rpm/AppImage),P3 仅产出可运行目录。
20
+ - Linux GUI(无 windows 子系统概念,Tk/Qt 直接运行)。
21
+
22
+ ## 验收标准
23
+
24
+ - `fsp b --target linux` 在 Linux 上产出 `dist/<name>`(ELF 可执行文件)+ `dist/runtime/python/` + `dist/src/` + `dist/runtime/python/lib/python3.X/site-packages/`。
25
+ - `dist/<name>` 直接运行输出预期内容(无需 wine)。
26
+ - 全套门禁通过:`ruff check`、`ruff format --check`、`pyrefly check`、`pytest --cov≥95%`(standalone 下载/gcc 编译标 slow)。
27
+ - Python 3.8 兼容(dev 环境)。
28
+
29
+ ## 约束
30
+
31
+ - python-build-standalone 从 GitHub 下载(无稳定国内镜像),标 slow;单测 mock urllib。
32
+ - Linux loader 用 gcc(系统自带),不需 mingw。
33
+ - 遵循 rule-11 Python 规范,平台分支用枚举分发,避免字符串判断。
@@ -0,0 +1,27 @@
1
+ # fspack P4 需求清单
2
+
3
+ P1/P2/P3 已交付三阶段完整链路。P4 聚焦代码质量改进与覆盖率提升,消除冗余字段并补齐未覆盖分支。
4
+
5
+ ## P4 范围
6
+
7
+ [x] 1. 移除 `BuildConfig.arch` 冗余字段:实际平台标签由 `wheel_platform_tag(target)` 派生,arch 字段未被使用且默认值 "win_amd64" 对 Linux 不正确。同步清理 test_config.py 对应断言。
8
+ [x] 2. 补 `detect_platform` Windows 分支测试:monkeypatch `platform.system` 返回 "Windows",覆盖 platform.py:21。
9
+ [x] 3. 补 `detect_entry` 重复候选测试:构造项目名与 .py 同名且该文件无 entry、另一文件有 entry 的场景,触发 `mod in seen` continue 分支(project.py:83)。
10
+ [x] 4. 补 `_parse_target` windows 分支测试:`fsp b --target windows` 分发,覆盖 cli.py:82 的 `return Platform.WINDOWS`。
11
+ [x] 5. 全套门禁通过:ruff check / ruff format --check / pyrefly check / pytest --cov≥95%(覆盖率不得低于 99.08%)。
12
+
13
+ ## 不在 P4 范围
14
+
15
+ - macOS 支持、Linux 安装包(P5+ 候选)。
16
+ - slow 端到端验证(依赖外部环境安装)。
17
+
18
+ ## 验收标准
19
+
20
+ - `BuildConfig` 无 arch 字段,所有引用清理干净。
21
+ - 四项门禁全过,覆盖率不低于 99.08%。
22
+ - 未覆盖分支数减少。
23
+
24
+ ## 约束
25
+
26
+ - 遵循 rule-11 Python 规范。
27
+ - 测试用 monkeypatch,禁用 @patch 装饰器。