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
140 changes: 124 additions & 16 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -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 提交时会自动执行同样检查)。
4 changes: 4 additions & 0 deletions doc/10-如何编写recipe.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@

`chsrc` 主程序不提供配置文件,不提供数据文件,干净无污染。那么在实现 `recipe` 的时候,除了备份文件外,也不要污染用户环境。

## 其它

如果你借助 AI 进行开发,让 AI 阅读 [copilot-instructions.md](../.github/copilot-instructions.md) 并将它作为项目规范,该文件明确了很多在 AI 辅助开发时需要注意的问题。

<br>

[rawstr4c]: https://github.com/RubyMetric/rawstr4c
Expand Down