diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 2c099bbfe..1fe84c915 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,32 +1,140 @@ -# chsrc Project Rules for AI Assistants +# chsrc — Change Source Everywhere -## 项目概述 +跨平台换源 CLI 工具与框架。使用 **C11**(推荐 C17 或更高版本)编写,从 `src/chsrc-main.c` 单文件编译。支持 Linux、Windows(原生/MSYS2/Cygwin)、macOS、BSD、Android。主程序采用 GPL-3.0-or-later 许可,`lib/xy.h` 采用 MIT 许可。 -这是 chsrc 项目,一个用 C 语言编写的跨平台命令行换源工具,帮助用户在不同的镜像之间切换,适用于编程语言、操作系统、其他软件。它的最强大之处在于它是一个框架,能够帮助用户轻松地为不同的目标换源。 +## 构建与测试 +单一入口:`src/chsrc-main.c` 通过 `#include` 引入所有框架和 recipe 文件。无需构建编排工具。 + +``` +# 构建 (just — 推荐用于原生 Windows) +just build # DEV 模式 → chsrc.exe +just bd # DEBUG 模式 (-DXY_DEBUG) → chsrc-debug.exe +just br # RELEASE 模式 (-O2) → chsrc-release.exe + +# 构建 (make — Linux/macOS/MSYS2) +make build / bd / br +make STATIC=1 br # 静态链接 + +# 调试 / 清理 +just debug # 构建 DEBUG 版并启动调试器 (gdb/lldb) +just clean # 清理构建产物 + +# 测试 +just test # xy.h + framework 单元测试 +just test-cli # CLI 集成测试 (Perl) +just fastcheck # CLI 快速检查 (test/cli.pl fastcheck) +``` + +DEBUG 模式(`-DXY_DEBUG`)会启用诊断功能:输出 `chsrc_debug*` 日志和 `chef_debug_target()` 调试信息,并在每次 Get/Set/Reset 操作后重跑所有 `_prelude()` 以验证其可重复执行且不会崩溃(见 `src/chsrc-main.c` 中的 `chsrc_perform_all_prelude()`)。 + +原生 Windows 上 `just br` 会先用 `windres` 编译 `src/resource/chsrc.rc` 生成 `chsrc.res` 再链接。开发与 PR 请使用 `dev` 分支(CI 仅在 PR 目标为 `dev` 时运行测试,见 `doc/01-开发与构建.md`)。 ## 架构 -- **Framework**: 在目录 `src/framework/` 中,包含了核心实现,支持 recipe +### 单文件编译 + +所有代码通过 `#include` 汇聚到 `src/chsrc-main.c`。整个编译过程不产生中间目标文件,也无额外链接步骤。 + +### 目录结构 + +| 路径 | 职责 | +| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | +| `src/chsrc-main.c` | 入口点:`main()`、CLI 解析、输出显示 | +| `src/framework/` | 核心:全局状态、Chef DSL、类型定义、镜像站注册、辅助工具 | +| `src/framework/struct.h` | `Target_t`、`Source_t`、`MirrorSite_t`、Chef DSL 宏 — **chsrc 的骨架** | +| `src/framework/core.c` | 框架核心:全局状态、C11 版本检查、速度测量(curl)、CLI 辅助 | +| `src/framework/chef.c` | Chef DSL 实现,供 recipe 作者使用 | +| `src/framework/helper.c` | `hp_*` 通用辅助函数(URL 判断、字符串处理等),供 recipe 与 framework 使用 | +| `src/framework/mirror.c` | 通用镜像站定义与测速链接(TUNA、BFSU 等教育网镜像) | +| `src/framework/version.h` | 版本宏(`Chsrc_Version` 等),发布新版本前修改 | +| `src/recipe/lang/` | 编程语言 recipe:按语言分子目录(`Ruby/`、`Python/`、`JavaScript/`、`Rust/`、`Dart/`)加平铺文件(Go、Java、Perl、PHP 等) | +| `src/recipe/os/` | 操作系统 recipe:按发行版分子目录(`APT/`、`BSD/`、`pacman/`、`YUM/`)加平铺文件(AlmaLinux、Alpine、Fedora 等) | +| `src/recipe/ware/` | 软件 recipe:按工具分子目录(`Anaconda/`、`Docker/`、`Homebrew/`)加平铺文件(CocoaPods、Flatpak、Nix 等) | +| `src/recipe/*/rawstr4c.h` | 各 recipe 子目录内使用的原始字符串资源(如 `src/recipe/lang/rawstr4c.h` 供 lang/ 下的 recipe 共享);文档见 `src/rawstr4c.md` | +| `src/recipe/*/common.h` | 同一 recipe 子目录内共享的公共头文件(如 `lang/Python/common.h`、`os/APT/common.h`) | +| `src/recipe/menu.c` | 注册表,将所有 recipe 接入三个分类列表(`pl`、`os`、`wr`) | +| `src/recipe/recipe-template.c` | 新 recipe 作者的模板 | +| `lib/xy.h` | 独立的 C11 工具库(MIT):字符串、操作系统检测、日志、数据结构、文件 I/O | +| `src/resource/` | Windows 资源文件(`chsrc.rc`、`logo.ico`),RELEASE 构建时由 `windres` 编译 | +| `include/` | 空占位目录(仅 `.keep`),配合构建参数 `-Iinclude -Ilib` | +| `test/` | `xy.c`(xy.h 测试)、`fw.c`(framework 测试)、`cli.pl`(CLI 集成测试,Perl) | +| `doc/` | 开发者和用户文档(中文) | + +### 核心抽象 + +- **`Target_t`** — 换源目标。字段:别名(`aliases`)、函数指针(`getfn`/`setfn`/`resetfn`/`preludefn`)、`inited` 标志、源列表(`sources`/`sources_n`)、特性(`can_english`、`can_user_define`)、作用域(`scope_caps[]`、`default_scope`)、`note`、维护信息(`created_on`/`last_updated`)、贡献者列表(`chefs`/`sauciers`)。 +- **`Scope_t`** — 作用域:`ProjectScope`/`UserScope`/`SystemScope`,外加特殊的 `ImplementationDefinedScope`(由 recipe 按实际情况决定;多数 recipe 的 `default_scope` 设为它)。 +- **`SourceProvider_t` / `MirrorSite_t`** — 镜像站或上游源提供者。类型:`IS_GeneralMirrorSite`(通用镜像站)、`IS_DedicatedMirrorSite`(专用镜像站)、`IS_UpstreamProvider`(上游默认源)、`IS_UserDefinedProvider`(用户自定义源)。 +- **Chef DSL** — 宏与函数的混合 API,供 recipe 作者使用: + - 宏:`def_target()`、`chef_prep_this()`、`chef_allow_gsr()/s()/sr()/gs()/NOOP()`、`def_sources_begin()/end()`、`chsrc_use_this_source()`。 + - 函数:贡献者 `chef_set_chefs()`/`chef_set_sauciers()`;作用域 `chef_set_scope_cap()`/`chef_set_default_scope()`;换源与测速链接 `chef_set_repoURL()`、`chef_set_smURL()`、`chef_set_smURL_with_postfix()`、`chef_set_smURL_with_func()`、`chef_set_provider_smURL()`;特性 `chef_allow_english()`/`chef_deny_english()`、`chef_allow_user_define()`/`chef_deny_user_define()`;其他 `chef_set_note()`、`chef_use_other_target_sources()`、`chef_verify_contributor()`。 +- **xy.h** — 跨平台运行时:`xy_on_windows`、字符串操作(`xy_str_gsub`、`xy_2strcat`)、`XySeq_t`(链表)、`XyMap_t`(哈希表)、命令执行、文件 I/O。内存约定:`return caller-free` 表示调用方必须释放返回值。 + +### 执行流程 + +1. `main()` → `chsrc_init_framework()` → `chsrc_init_menu()`(填充 target 列表),并调用 `chsrc_register_contributors()` 把所有贡献者登记到代码中 +2. 解析 CLI → 在 `pl`/`os`/`wr` 三个菜单中搜索匹配的 target → 调用 `preludefn()` → 按 `TargetOp`(Get/Set/Reset/Measure/List_Config)分派到 `getfn`/`setfn`/`resetfn` 等 +3. 执行 `set` 时:通过系统 `curl` 自动测量镜像站速度(精准/粗略测速,见 `doc/11-如何设置换源链接与测速链接.md`),选择最快的,recipe 的 `_setsrc()` 执行换源 + +### Recipe 模式 + +每个 target 由 `.c` 文件实现(一个文件可包含多个 target),包含: + +- `_prelude()` — **必需。** 通过 Chef DSL 初始化元数据和源列表。 +- `_setsrc()` — **必需。** 执行换源操作。必须调用 `chsrc_use_this_source (target)` 注入选中的源。 +- `_getsrc()` / `_resetsrc()` — 可选。 + +新 recipe 还必须在 `src/recipe/menu.c` 中注册(`#include` 该文件,然后用 `add()` 将其加入对应的 `pl`/`os`/`wr` 列表);未注册的 recipe 文件不会出现在任何菜单中。 + +参考:`src/recipe/recipe-template.c`、`doc/10-如何编写recipe.md`、`doc/11-如何设置换源链接与测速链接.md`。 + +### 开发辅助与质量保障 + +- **Lefthook git hooks**(`lefthook.yml`)— 提交前自动验证: + - 修改 `*.{c,h}`(不含 `test/`):`just build-in-debug-mode` + `./chsrc-debug get pip`(触发所有 `_prelude()` 检查) + - 修改 `lib/xy.h` 或 `test/xy.c`:`just test-xy` + - 修改 `src/framework/*`、`src/chsrc-main.c` 或 `test/fw.c`:`just test-fw` +- **CI**(`.github/workflows/`)— 多平台构建:Linux(x64/AArch64/ARMv7/riscv64)、macOS、Windows(x64/Arm64);PR 时 Ubuntu 运行 `make` + `make test`、Windows 运行 `just` + `just test`(`PR-test.yml`,仅 PR 目标分支为 `dev` 时触发) +- **参考文档**:`doc/README.md`、`doc/01-开发与构建.md`、`doc/02-提交与贡献.md`、`doc/50-协作者与维护者.md` - - `struct.h` 里定义了各种数据结构和宏,这是整个 chsrc 的核心,也是 chef DSL 的核心 - - `chef.c` 里实现了 chef DSL,你可以使用它来确定正确的使用方法 +### 命名约定 -- **Recipes**: 在目录 `src/recipe/` 中,包含了针对不同目标的具体实现 +- `pl*` = programming **l**anguage(编程语言)→ `src/recipe/lang/` +- `os*` = **o**perating **s**ystem(操作系统)→ `src/recipe/os/` +- `wr*` = soft**w**a**r**e(软件)→ `src/recipe/ware/` +- 类型名:`PascalCase_t` +- 函数名与 `()` 之间必须有空格 — 代码应写 `foo ()` 而非 `foo()`。(本文档中的 API 提及如 `_prelude()` 仅为简写。) - - `lang/` - 编程语言 (Ruby, JavaScript 等等) - - `os/` - 操作系统 (Ubuntu, Arch Linux 等等) - - `ware/` - 软件工具和应用 (Docker, Homebrew 等等) +## 代码风格 +- 基于 GNU 风格并做了项目特化调整(见 `doc/03-为什么拒绝使用代码格式化工具.md`)。 +- **不使用代码格式化工具。** 采用刻意的手动排版(对齐、预处理器缩进等)。 +- **保留已有注释** — 它们记录了重要的维护元数据。 +- 约定优于配置。NO UFO 原则:工具不会在用户目录下产生任何配置/数据文件。 +- 贡献者通过 `src/chsrc-main.c` 中的 `chef_register_contributor()` 注册到代码中,而非仅记录在 git 历史里。 -## Coding Guidelines +## 内存管理规则 -### C Coding Style: +**Recipe 层(`src/recipe/**`):** +除非不得不,否则不要调用 `free()`。单次调用的 CLI 模型意味着操作系统在退出时回收内存,释放短生命周期的临时对象收益过低,且易导致二次释放等额外问题。仅当指针由 xy.h 的 caller-free 函数堆分配、且生命周期止于 recipe 函数内部时才 `free()`(如 `Cargo.c`释放`cargo_config_file` 路径)。避免改动已有 recipe —— 保持工作代码不变。 -请阅读 `doc/03-为什么拒绝使用代码格式化工具.md` +**Framework 层(`lib/xy.h`、`src/framework/**`):** +严格检查所有内存分配是否泄漏。xy.h 中标记为 `return caller-free` 的函数要求调用方释放返回值。`xy_malloc0`、`xy_strdup`、`xy_str_gsub`、`xy_strcat`、`xy_2strcat`、`xy_file_read` 的每个返回结果都必须被释放或移交所有权。 -### Important Project Concepts: +## 代码审查清单 -请阅读 `doc/10-如何编写recipe.md` +进行代码审查时,检查以下各项: -## Important: 一定要保持注释,因为它记录了重要的维护信息 +1. **指针、边界与内存** — NULL 解引用、缓冲区溢出、use-after-free。 +2. **逻辑缺陷与结构设计** — 错误假设、脆弱的耦合、缺失的边界情况。 +3. **竞态条件** — 工具为单线程;标记任何引入的并发。 +4. **死锁** — 同上,标记任何引入的锁。 +5. **权限问题** — 文件/目录访问权限、特权要求。 +6. **标准合规** — 目标标准为 C11(推荐 C17 或更高版本,见开头说明)。POSIX 专有 API 必须有 `#ifdef` 守卫。 +7. **注释与代码不匹配** — 注释必须准确描述其所文档化的代码。 +8. **冗余代码** — 死代码、不可达分支、重复逻辑。 +9. **不充分的错误处理** — 静默失败、对可能失败的操作缺少 NULL 检查。 +10. **未定义行为** — 整数溢出、越界访问、使用未初始化内存、严格别名违反。 +11. **兼容性** — 必须能在 Linux(GCC/Clang)、macOS(Clang)、Windows(MinGW)上编译。不得使用 C11 不兼容的构造。 +12. **构建与测试验证** — 改动后至少本地运行 `just test`(或 `make test`)与 `just test-cli`(或 `make test-cli`);修改 `*.{c,h}` 后运行 `just bd && ./chsrc-debug get <受影响target>` 确认不崩溃(lefthook 提交时会自动执行同样检查)。 diff --git "a/doc/10-\345\246\202\344\275\225\347\274\226\345\206\231recipe.md" "b/doc/10-\345\246\202\344\275\225\347\274\226\345\206\231recipe.md" index c35aec10d..a6633d819 100644 --- "a/doc/10-\345\246\202\344\275\225\347\274\226\345\206\231recipe.md" +++ "b/doc/10-\345\246\202\344\275\225\347\274\226\345\206\231recipe.md" @@ -116,6 +116,10 @@ `chsrc` 主程序不提供配置文件,不提供数据文件,干净无污染。那么在实现 `recipe` 的时候,除了备份文件外,也不要污染用户环境。 +## 其它 + +如果你借助 AI 进行开发,让 AI 阅读 [copilot-instructions.md](../.github/copilot-instructions.md) 并将它作为项目规范,该文件明确了很多在 AI 辅助开发时需要注意的问题。 +
[rawstr4c]: https://github.com/RubyMetric/rawstr4c