chsrc Documentation

Chsrc 全平台通用换源工具与框架. Change Source everywhere for every software

6,901 stars C C 17 files · ~8,001 tokens #archlinux#brew#c11#cargo#composer#cpan#debian#fedora
RAW Doc

Technical Documentation: RubyMetric/chsrc

ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference

Overview (`README.md`)

全平台通用换源工具与框架 chsrc,目标支持 Linux, Windows (native, MSYS2, Cygwin), macOS, BSD, Android 等尽可能多的操作系统环境,龙芯、飞腾、RISC-V 等尽可能多的 CPU。我们使用 C11 来完成上述目标,以保证最大的可用性。本软件为自由软件,SDPX 软件许可证为 GPL-3.0-or-later and MIT

❤️ 致所有的朋友们

2025年8月11日,我因通宵重构本项目代码而被送去抢救(#252,突发!换源工具 chsrc 作者在重构过程中被送去 120 抢救)。大家给予的关心和帮助让我非常非常感动!在此,我衷心感谢每一位朋友!无论是开源还是闭源,无论是否为职业程序员,我们其实都是一群使用软件、热心互助、充满友爱的人,这是一个温暖的大家庭。

我为 chsrc 采用 GPL 协议,怀着殷切的期望:希望能够营造像 Richard Stallman 在创建 GNU 项目之前,在 MIT 那样的氛围——写自己用得上的软件,与大家一起开发、维护,简单纯粹,无关商业利益。就像小区、校园自发组建的足球篮球队,从一次偶然的加入,逐渐成长为互相支持的伙伴。

这次经历让我更加深刻地体会到:开源,是一种把大家联系在一起的方式,它让互助和协作成为可能。最后,希望大家能够时刻关注自己的身体,你可以随时 chsrc chown chgrp chmod 无限次,但是无法 chbody!

🤝 协作与贡献

[!TIP]
chsrc 不仅是一个命令行工具,同时也是一个体现了 Ruby on Rails 思想的 MVC 换源框架,它甚至使你能够在不了解C语言的情况下编写出新的换源方法 (recipe)。 配合使用 rawstr4c, 这将比写 shell 脚本更加轻松。 如何编写 recipe?


[!NOTE]
这也许是你可以参与的第一个现实世界中有用的C语言项目,用 VS Code 一分钟内上手编译、运行、测试 chsrc

欢迎对 GitHub、Gitee 协作不熟悉的人以此为契机学习参与贡献, 欢迎任何编程初学者。从开发到提交PR,我们覆盖全流程文档


[!IMPORTANT]
chsrc 可换源 65+ 菜品。每个人仅仅贡献和维护自己熟悉的部分,回报是得到其他所有领域专家的帮助。 欢迎成为 recipe 维护者

📌 示例

桌面端:

安卓:

🚀 安装

[!IMPORTANT]
若通过下述手动方式安装,则会下载到当前目录,可直接通过 ./chsrc 运行

Windows

bash
scoop install chsrc
bash
winget install RubyMetric.chsrc
  • 可通过 PowerShell 脚本一键下载最新版二进制文件,感谢 @wickdynex

    若下方链接无法访问,可使用 https://gitee.com/RubyMetric/chsrc/raw/main/tool/installer.ps1 替代

powershell
# 使用 -Version 指定版本 (不指定时默认为 pre)
#   1. 安装 pre 版本; 这比从包管理器安装的总是更新一些
#   2. 安装旧版本; 有时新版本可能引入某些 Bug,临时使用旧版本解决燃眉之急
"& { $(iwr -useb https://chsrc.run/windows) } -Version pre" | iex
  • 或手动下载二进制文件,这是最新版,往往比 scoop 提供的更新,适用于修复 Bug、添加新功能后及时使用,以及未安装 scoop 时
bash
# x64
curl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-x64-windows.exe -o chsrc.exe

# x86
curl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-x86-windows.exe -o chsrc.exe

# Arm64 (WoA, Windows on Arm)
curl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-arm64-windows.exe -o chsrc.exe

Linux

bash
# x64
$ curl -LO https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc_latest-1_amd64.deb

# 也可以使用 Wget
wget https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc_latest-1_amd64.deb

$ sudo apt install ./chsrc_latest-1_amd64.deb
# 或
$ sudo sudo dpkg -i chsrc_latest-1_amd64.deb
bash
# AUR
$ yay -S chsrc-bin # Binary from GitHub Release
$ yay -S chsrc-git # Build  from the latest main branch (stable)
$ yay -S chsrc     # Build  from GitHub Release
  • 可通过 shell 脚本一键安装最新版,感谢 @Efterklang 与 @wickdynex

    若下方链接无法访问,可使用 https://gitee.com/RubyMetric/chsrc/raw/main/tool/installer.sh 替代

bash
# 非root用户默认安装至 ~/.local/bin
$ curl https://chsrc.run/posix | bash

# 也可以使用 Wget
$ wget -O - https://chsrc.run/posix | bash

# root用户默认安装至 /usr/local/bin
$ curl https://chsrc.run/posix | sudo bash

# 使用 -d 指定目录安装
$ curl https://chsrc.run/posix | bash -s -- -d ./

# 使用 -v 指定版本 (不指定时默认为 pre)
#   1. 安装 pre 版本; 这比从包管理器安装的总是更新一些
#   2. 安装旧版本; 有时新版本可能引入某些 Bug,临时使用旧版本解决燃眉之急
$ curl https://chsrc.run/posix | bash -s -- -v 0.2.1

# 使用 -l en 输出英文
$ curl https://chsrc.run/posix | bash -s -- -l en
  • 可手动下载二进制文件安装
bash
# x64
curl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-x64-linux -o chsrc; chmod +x ./chsrc

# aarch64
curl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-aarch64-linux -o chsrc; chmod +x ./chsrc

# riscv64
curl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-riscv64-linux -o chsrc; chmod +x ./chsrc

# armv7
curl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-armv7-linux -o chsrc; chmod +x ./chsrc

如果你所在的处理器架构没有预编译版本,可以使用 chsrc-bootstrap

macOS

bash
brew install chsrc
  • 可通过 shell 脚本安装最新版,感谢 @Efterklang 与 @wickdynex

    若下方链接无法访问,可使用 https://gitee.com/RubyMetric/chsrc/raw/main/tool/installer.sh 替代

bash
# 非root用户默认安装至 ~/.local/bin
$ curl https://chsrc.run/posix | bash

# root用户默认安装至 /usr/local/bin
$ curl https://chsrc.run/posix | sudo bash

# 使用 -d 指定目录安装
$ curl https://chsrc.run/posix | bash -s -- -d ./

# 使用 -v 指定版本 (不指定时默认为 pre)
#   1. 安装 pre 版本; 这比从包管理器安装的总是更新一些
#   2. 安装旧版本; 有时新版本可能引入某些 Bug,临时使用旧版本解决燃眉之急
$ curl https://chsrc.run/posix | bash -s -- -v 0.2.1

# 使用 -l en 输出英文
$ curl https://chsrc.run/posix | bash -s -- -l en
  • 或手动下载二进制文件,这是最新版,往往比 homebrew 提供的更新,适用于修复 Bug、添加新功能后及时使用
bash
# arm64/aarch64
curl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-aarch64-macos -o chsrc; chmod +x ./chsrc

# x64
curl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-x64-macos -o chsrc; chmod +x ./chsrc

BSD

如果已安装好了编译 chsrc 所需要的依赖,可直接运行:

bash
git clone https://gitee.com/RubyMetric/chsrc.git; cd chsrc
clang -Iinclude -Ilib src/chsrc-main.c -o chsrc

如果还不存在这些依赖,你将会被死锁住: 我还没有换源,我该如何安装这些依赖呢?

这就是 chsrc-bootstrap 起作用的时刻,你可使用BSD系统的原生脚本语言编写 bootstrapper,并向我们提交

注: chsrc 实现的 FreeBSD recipe 长期存在问题,因此一个新的 bootstrapper 是相当必要的,请帮助你自己和大家!

Android/Termux

Termux 中默认无 Wget,我们都用 cURL 来下载安装

bash
# arm64/aarch64
curl -L https://gitee.com/RubyMetric/chsrc/releases/download/pre/chsrc-arm64-android -o chsrc; chmod +x ./chsrc

如果你所在的处理器架构没有预编译版本,可以使用 chsrc-bootstrap:

bash
curl -L https://gitee.com/RubyMetric/chsrc/raw/main/bootstrap/Termux.bash | bash

其他平台

若你所在的平台不存在预编译好的 chsrc,你需要手动编译。如果已安装好了编译 chsrc 所需要的依赖,可直接运行:

bash
git clone https://gitee.com/RubyMetric/chsrc.git; cd chsrc; make

如果还不存在这些依赖,你将会被死锁住: 我还没有换源,我该如何安装这些依赖呢?

这就是 chsrc-bootstrap 起作用的时刻,你可使用该平台原生脚本语言编写 bootstrapper,并向我们提交

💡 使用

bash
名称:
   chsrc - Change Source - (GPLv3+)

使用:
   chsrc <command> [options] [dish] [mirror]

命令:
   help,  h                 打印此帮助,或 -h, --help
   issue, i                 查看相关issue

   list, ls, l              列出可用镜像站和可换源菜品
   list  mirror|dish        列出支持的: 镜像站/换源菜品
   list  os|lang|ware       列出支持的: 操作系统/编程语言/软件
   list   <dish>            查看该菜品可用源与支持功能

   measure, m, cesu <dish>  对该菜品所有源测速

   get, g <dish>            查看该菜品当前源的使用情况

   set, s <dish>            换源,自动测速后挑选最快源
   set    <dish>  first     换源,使用维护团队测速第一的源
   set    <dish> <mirror>   换源,指定使用某镜像站 (通过list <dish>查看)
   set    <dish>  <URL>     换源,用户自定义源URL
   reset  <dish>            重置,使用上游默认使用的源

选项:
   -dry                       Dry Run,模拟换源过程,命令仅打印并不运行
   -scope=project|user|system 仅对本项目换源 / 用户级换源 / 系统级换源 (通过ls <dish>查看)
   -ipv6                      使用IPv6测速
   -en(glish)                 使用英文输出
   -no-color                  无颜色输出
bash
自动测速,寻找最快者,换源

    $ chsrc set ruby

不想自动测速的时候,可使用维护团队测试的最快镜像站

    $ chsrc set ruby first

先列出可用的镜像站,然后选择其一,如使用 RubyChina 作为镜像站

    $ chsrc ls  ruby
    $ chsrc set ruby rubychina

若有自己的镜像,可以使用自定义URL

    $ chsrc set ruby https://gems.ruby-china.com/

对支持 *项目级* 换源的菜品,可以避免全局(*系统级* 或 *用户级*)换源

    $ chsrc set -scope=project bundler
    $ chsrc set -scope project pdm

编程语言开发

bash
chsrc set ruby|rb|gem|bundler|rubygems

chsrc set python | py | pypi # 同时换 pip, poetry, pdm, uv 这4个包管理器,也可以4个独立换源
  chsrc set pip
  chsrc set poetry
  chsrc set pdm
  chsrc set uv

chsrc set rye

chsrc set node | nodejs # 同时换 npm, yarn 和 pnpm 这3个包管理器,也可以3个独立换源
  chsrc set npm
  chsrc set yarn
  chsrc set pnpm

chsrc set nvm
chsrc set bun

chsrc set perl | cpan
chsrc set php  | composer
chsrc set lua  | luarocks

chsrc set rust | cargo | crate
chsrc set rustup

chsrc set go
chsrc set java    | maven | mvn | maven-daemon | mvnd | gradle
chsrc set clojure | clojars
chsrc set dart    | pub
chsrc set flutter
chsrc set haskell | hackage | cabal | stack
chsrc set ocaml   | opam

# 同时会为 bioconductor 换源
chsrc set r | cran
chsrc set julia

操作系统

bash
sudo chsrc set ubuntu
sudo chsrc set zorinos
sudo chsrc set linuxmint
sudo chsrc set debian
sudo chsrc set fedora
# 同时支持 Leap 和 Tumbleweed
sudo chsrc set opensuse
sudo chsrc set kali
sudo chsrc set arch
sudo chsrc set archlinuxcn
sudo chsrc set manjaro
sudo chsrc set gentoo
sudo chsrc set rocky | rockylinux
sudo chsrc set alma  | almalinux
sudo chsrc set alpine
sudo chsrc set voidlinux
sudo chsrc set solus
sudo chsrc set ros   | ros2
sudo chsrc set trisquel
sudo chsrc set linuxlite
sudo chsrc set raspi | raspberrypi
sudo chsrc set armbian
sudo chsrc set openwrt

sudo chsrc set openeuler
sudo chsrc set openanolis | anolis
sudo chsrc set openkylin
sudo chsrc set deepin

chsrc set msys2 | msys

# Android
chsrc set termux

# BSD
sudo chsrc set freebsd
sudo chsrc set openbsd
sudo chsrc set netbsd

软件

bash
chsrc set winget
chsrc set brew      | homebrew
chsrc set cocoapods | cocoa | pod
chsrc set dockerhub | docker
chsrc set flathub   | flatpak
chsrc set nix
chsrc set guix
chsrc set emacs  | elpa
chsrc set tex    | ctan | latex | texlive | miktex
chsrc set conda  | anaconda

📝 许可证

  • chsrc 主程序采用 GPL-3.0-or-later 许可证,保证该软件的永久自由
  • xy.h 使用 MIT 许可证,保证该库可以在尽可能多的情况下复用

❤️ 致谢

感谢各个镜像站提供的优质免费镜像服务

  1. mirror.c 包含了通用的镜像站信息
  2. 各个recipe内部定义的专用镜像站

另外特别感谢以下组织或项目:

  1. 校园网联合镜像站(MirrorZ)
  2. 清华大学 Tuna
  3. 上海交通大学软件源镜像服务
  4. 中国科学技术大学 Linux 用户协会
  5. Thanks Mirror 项目 by @eryajf

🚀 赞赏支持

你是否因为 chsrc 而受到启发、节省了时间精力 or whatever?

爱发电主页: https://afdian.com/a/ccmywish


Overview (`.vscode/README.md`)

Dev in VS Code

首先需要安装好 just,而不再硬性需要 make

  1. Ctrl-Shift-B 直接构建
  2. F5 直接开始 Debug

Overview (`bootstrap/README.md`)

Bootstrap

ruby
begin
  download_prebuilt_chsrc_binary_for_my_platform
rescue NoReadyMadeBinary => e
  bootstrap! e.my_platform
end

预编译产生的死锁问题

我们支持预编译的操作系统目前只有 Windows, Linux, macOS,支持的架构请参考项目 README

某些操作系统如 BSD 家族,甚至是更小众的操作系统, 或者上述操作系统的某些架构,无法享受直接下载二进制立即使用的便利性,这导致用户需要自己编译 chsrc.

然而用户自己编译则面临着一个问题: 需要提前安装项目依赖

  1. 把代码 git clone 下来 或 下载 zip 包进行解压缩
  2. C语言编译器
  3. GNU make 或 just (这二者非强制,但是有了更好)

可是如果用户还没有换源,他/她又如何获得上述这些程序呢?这是一把死锁,导致用户最终回到手动换源的原始农耕时代。

`chsrc-bootstrap` to the Rescue

chsrc-bootstrap 是一组使用原生脚本语言的脚本,每个脚本称为 bootstrapper,用来完成两件事情:

  1. 帮助用户进行最基本的换源,让用户能够立即开始使用该系统安装其他软件

  2. 用户自行决定是否需要安装 chsrc

    • 若不需要: 流程直接结束,用户已可以完成基本日常工作

    • 若需要: 帮助用户安装好所需的最少依赖,并编译安装 chsrc

注意,最基本的换源,即不测速,由维护者暂时决定先切换到某一个具体的源,先让系统跑起来。

支持的语言

上述提到的原生脚本语言只能是这些:

  1. Windows: PowerShell, CMD

  2. Linux: Bash, sh

    备选: Perl

  3. macOS: Zsh, Bash, sh

    备选: Ruby, Perl

  4. BSD: sh

    备选: 待议

  5. 其他平台: 一切该平台支持的脚本语言,无需额外安装

`chsrc` 与 `chsrc-bootstrap`

chsrc 需要实现 chsrc-bootstrap 中支持的平台。这是因为,chsrc-bootstrap 只换到了某一个具体的源,只是临时性的,后续用户可能还想要换到其他源,此时 chsrc 就可以接管。

而事实上,chsrc-bootstrap 可以完成一些操作,使得系统已经满足一些前置条件,这样的话 chsrc 可以在这些前置条件存在时接着换源,从而大幅减轻 recipe 的实现难度。

帮助

  1. FreeBSD 的换源 从项目一开始就是我们的目标之一,然而由于其:

    • 换源所需的步骤太多
    • 面临着特有的鸡蛋困境
    • BSD 工具和 GNU 工具总是有不兼容之处
    • 在C语言中实现困难重重

    因此我们一直没有很好的办法去实现

  2. 任何你所在的平台,都可以添加到此


Overview (`doc/README.md`)

文档说明

E2E (End-to-End) 开发文档:

具体 recipe 相关:

用户手册:

  1. chsrc.1
  2. chsrc.texi

贡献指导

若有任何问题,可在 GitHub discussions 中询问和讨论


Overview (`pkg/README.md`)

Packages

分发情况

  • Homebrew
  • Scoop
  • WinGet
  • AUR
  • Flatpak
  • snap
  • ...
bash
$ brew install chsrc

$ scoop install chsrc

$ winget install RubyMetric.chsrc

yay -S chsrc-bin # Binary from GitHub Release
yay -S chsrc     # Build  from GitHub Release
yay -S chsrc-git # Build  from the latest main branch (stable)

打包情况

  • deb

Overview (`tool/README.md`)

工具说明

  1. installer.sh

    Bash 编写的一键安装工具

  2. installer.ps1

    PowerShell 编写的一键安装工具

  3. download-pre-on-GitHub.ps1

    从 GitHub pre release 上下载所有附件

  4. completion/ 目录

    Shell 自动补全文件

`rawstr4c`

C语言字符串生成工具,本身是为了本项目而开发,是放在本仓库下的一个完整子项目。但为了维护更方便,拆分到新的仓库: https://github.com/RubyMetric/rawstr4c


Overview (`pkg/AUR/README.md`)

AUR package

本文档说明了 chsrc 项目的 AUR 包的相关情况

相关文件

CI 维护者 @Jerry-Terrasse

分发

位于 https://aur.archlinux.org/packages

  • chsrc-bin: 从 GitHub Releases 直接下载的二进制文件

  • chsrc:从 GitHub Releases 的代码构建

  • chsrc-git:从最新源码构建的版本,偶尔可能不稳定


Overview (`pkg/deb/README.md`)

deb package

本文档说明了 chsrc 项目的 deb 包的相关情况

相关文件

  • .github/workflows/pkg-deb.yml - CI 配置文件
  • ./CI.md - CI 情况说明
  • ./debian/ - deb 包构建配置目录
  • ./BUILD.md - 如何手动构建
  • ./Makefile - deb 包构建 Makefile
  • ./deb-installation-test.sh - deb 包 已正确安装 测试脚本

安装

如果你是普通用户,你应该从 GitHub Releases 下载合适的 deb 包,然后运行以下命令安装:

bash
sudo dpkg -i chsrc_*.deb
sudo apt-get install -f  # Fix any dependency issues

如果你是高级用户,你可以自己阅读本目录下的 ./BUILD.md 来自己构建 deb 包并按照上述同样的方式安装。

`debian/` 目录结构

text
debian/
├── changelog      # 版本更新日志
├── compat         # debhelper 兼容性版本
├── control        # 包控制信息和依赖
├── copyright      # 版权信息
├── postinst       # 安装后脚本
├── prerm          # 卸载前脚本
└── rules          # 构建规则

其中,最后三个是 +x 的可执行文件。


Overview (`src/recipe/lang/Ruby/README.md`)

Ruby 换源问题

https://github.com/ustclug/discussions/issues/438


Overview (`src/recipe/ware/Docker/README.md`)

Docker

  • USTC 与 SJTUG 于 2024-06-06 停止支持 DockerHub
  • NJU 于 2024-06-07 停止支持 DockerHub

Overview (`src/recipe/lang/Python/uv/README.md`)

uv 换源实现说明

chsrc set uv 同时配置两类下载地址:

  1. Python 包索引,即 uv.toml 的 [[index]] 或 pyproject.toml 的 [[tool.uv.index]]
  2. uv 管理的 CPython 下载地址,即 python-install-mirror

配置文件选择

项目作用域只修改当前目录,不向父目录查找并修改配置:

  1. 当前目录存在 uv.toml 时修改 uv.toml
  2. 否则,当前目录存在 pyproject.toml 时修改其中的 [tool.uv]
  3. 两者都不存在时创建 uv.toml

这个顺序与 uv 的行为一致:同一目录同时存在 uv.toml 与 pyproject.toml 的 [tool.uv] 时,uv 优先使用 uv.toml 中的对应字段。

用户作用域使用 uv 的用户配置目录:Windows 为 %APPDATA%\uv\uv.toml,Linux 和 macOS 优先使用 $XDG_CONFIG_HOME/uv/uv.toml,未设置时使用 ~/.config/uv/uv.toml。

Python 包索引

索引 URL 必须指向兼容 Python Simple Repository API 的地址,通常以 /simple 结尾;uv 不要求 URL 必须以 / 结尾。

default = true 表示该 index 替代 uv 内置的 PyPI,并且始终具有最低 index 优先级。它不表示“文本中的第一个”或“最高优先级”。配置中存在多个 index 时,chsrc 优先更新 default = true 的 index;没有 default index 时才更新第一个 index。

默认的 first-index 策略会在第一个包含目标包的 index 停止搜索。私有源与公共镜像并存时,不应把它理解成跨所有 index 选择全局最新版本。

Python 下载镜像

python-install-mirror 是 https://github.com/astral-sh/python-build-standalone/releases/download 的替换前缀。配置值必须是镜像侧对应的 releases/download 基址,不能是仓库主页、某个具体构建日期或某个归档文件。uv 会在其后追加构建日期和
归档文件名。

官方示例使用不带尾部 / 的基址,chsrc 内置源也遵循该形式。

reset 与备份

chsrc set uv 修改已有配置前会创建 .bak 备份。

chsrc reset uv 把 chsrc 管理的 index 与 python-install-mirror 写回默认上游:index 恢复为 https://pypi.org/simple,
python-install-mirror 恢复为 https://github.com/astral-sh/python-build-standalone/releases/download。
其他用户配置原样保留,不依赖 .bak 恢复旧 URL。

指定镜像代码时,若该代码同时提供 PyPI 与 Python 下载镜像(例如 nju),两部分使用同一镜像代码;仅提供其中一类时,另一类自动测速。用户自定义 URL 只解释为 PyPI index URL,因为 Python 下载镜像要求完全不同的 releases 目录布局。

default = true 的 index(不存在时取第一个)被视为 PyPI 替代源,reset 只修改这一处;私有 index 不受影响。

实现边界

配置改写器只解析 chsrc 使用的 TOML 子集,但支持常见的行首缩进、CRLF、行尾注释、多个 index,以及位于 [tool.uv.sources] 等子表之后的 [[tool.uv.index]]。读取时换行统一为 LF 处理,写入时按系统平台输出行尾(Windows 为 CRLF,其余为 LF)。多行字符串和完整 TOML 转义语义不属于该轻量改写器的支持范围。

参考:


Doc 01 开发与构建 (`doc/01-开发与构建.md`)

开发 chsrc

依赖与开发环境

请安装好:

  1. GCC 或 Clang
  2. just 或 make
  3. curl
  4. rawstr4c (可选)

我推荐你使用 VS Code 开发,你可以在一分钟内成功编译、运行和 Debug chsrc

  1. Ctrl-Shift-B 直接构建
  2. F5 直接开始 Debug

获取代码

请务必使用 dev 分支开发

bash
git clone https://gitee.com/RubyMetric/chsrc.git -b dev

关于分支的说明,可参考 ./03-CONTRIBUTING.md

编译运行

共有四种构建模式:

  1. DEV mode
  2. DEBUG mode
  3. RELEASE mode
  4. CI-RELEASE mode

开发时只需要前两种模式;第四种模式只在 GitHub Actions 使用。

如果你使用 just,可以在 VS Code 中获得更好的体验,按 Ctrl-Shift-B 直接使用 DEV mode 构建

注意: DEBUG 模式下, 执行任意一个 recipe 的任意操作,会额外检查所有 _prepare() 是否能正常工作,如: ./chsrc-debug ls <recipe>

bash
just (b)      # 在Windows上默认使用 gcc 编译,在macOS上默认使用 clang 编译,在其他系统上默认使用 cc 编译
just CC=clang # 使用 clang 编译
just CC=gcc   # 使用 gcc   编译

# 编译出 debug 版本: chsrc-debug
just bd
# 编译出 release 版本: chsrc-release
just br

make 用户:

bash
make (b)      # 在Windows上默认使用 cc 编译,在macOS上默认使用 clang 编译,在其他系统上默认使用 cc 编译
make CC=clang # 使用 clang 编译
make CC=gcc   # 使用 gcc   编译

# 编译出 debug 版本: chsrc-debug
make bd
# 编译出 release 版本: chsrc-release
make br

Debug

如果你使用 just,可以在 VS Code 中获得更好的体验,按 F5 即可立即开始 Debug

bash
# 重新编译出 ./chsrc-debug,并启动 GDB 调试 (在macOS上启动 LLDB 调试)
$ just debug

# 重新编译出 ./chsrc-debug,并启动 LLDB 调试
$ just DEBUGGER=lldb debug

make 用户:

bash
# 重新编译出 ./chsrc-debug,并启动 GDB 调试 (在macOS上启动 LLDB 调试)
$ make debug

# 重新编译出 ./chsrc-debug,并启动 LLDB 调试
$ make debug DEBUGGER=lldb

测试

just 用户只需要替换下述 make 为 just

bash
make test-xy  # 测试 xy.h
make test-fw  # 测试 framework
make test     # 测试上述两个
make test-cli # 测试命令
make clean

提交 PR

关于分支的说明以及如何提交代码,请参考 ./03-CONTRIBUTING.md


Doc 02 提交与贡献 (`doc/02-提交与贡献.md`)

贡献说明

分支

  • gh-build:仅仅在发布版本时由 @ccmywish 推送,触发编译到 GitHub Releases 中
  • main: stable,代码一定是可以编译运行的,我们假设 end users 在其他条件都得不到二进制时,会自己编译这个分支来运行 chsrc
  • dev:开发分支,工作分支,在此分支上解决冲突

提交与审阅

当你提交 PR 的时候,一定要将 PR 指定 chsrc 原仓库的 dev 分支。

提交的代码分两种情况考虑。(1)recipe 相关的 (2)framework 相关的

(1)

需要先搜索你修改的部分涉及到的 recipe,然后提 issue @ 所有相关的 recipe chefs 来 review


(2)

如果涉及了所有 recipe,则需要 @ 项目创建者或者协作者,而无需把所有 recipe 的 chefs 都喊过来,但是如果觉得有必要,可以 @ 任意你觉得有能力 review 和能给出建议的人来 review


Doc 03 为什么拒绝使用代码格式化工具 (`doc/03-为什么拒绝使用代码格式化工具.md`)

chsrc 代码风格

Ruby 的语法优美性在编程行业中具有标杆地位。Matz(松本行弘)提出的 代码应该为人类而写,偶尔为机器执行 这一理念,已经成为现代编程语言设计的重要指导原则。chsrc 项目的第一作者深受 Ruby 语言哲学的影响。

本项目起源于 AI 编程尚未流行的时代,所有代码全部依赖人类的耐心来维护。现在,我们的代码以及这篇文章不仅会由人类阅读,也会由 AI 阅读。我们始终坚持:代码的可读性和维护性是项目长期发展的根本保障。

为什么我们坚持不使用代码格式化工具

代码格式化工具(code formatter)在多人协作的代码仓库中确实有其价值,参与的人越多,统一格式的需求越迫切。然而,chsrc 项目经过深思熟虑后,拒绝使用代码格式化工具。让我来说明这一决定背后的深层原因。

被强迫使用

像 Prettier 这样的工具表面上带来了统一性,但其代价是什么?它是极度专制的(opiniated),我们必须完全交出代码审美的自主权。今天我们大部分人使用 Prettier,并非出于真心的认同,而是因为整个前端生态圈的集体胁迫——不用就意味着被边缘化。

这种现象的本质令人深思:少数 Prettier 维护者的个人偏好,竟然决定了全球数百万开发者的代码美学标准。这显然是一种技术独裁,坚决拒绝向格式化工具的霸权低头。

一致性 ≠ 美观 ≠ 可读

格式化工具只保证了表面的一致性,就像一些校服,一致不一定代表美。同样,一致不一定代表代码就是最易读易懂的。

每一个有追求的程序员都应该保留对代码美学的最后决定权,格式化工具的便利性不应该以牺牲美观性和可维护性为代价。

满足不了我们的需求

C语言的格式化工具通常选择 clang-format,它的配置选项十分丰富,比 Prettier 要理性得多。然而,即便如此,其配置的复杂性和局限性仍然无法满足 chsrc 对代码格式的严苛要求。如果你是一位 clang-format 的配置专家,我们诚挚邀请您告诉我们如何优雅地处理以下代码场景,也许这能改变我的立场。

挑战案例

以下是我认为自动格式化工具很难完美处理的代码场景:

= 对齐:

c
char *name  = va_arg (args, char*);
char *email = va_arg (args, char*);

复杂逻辑的 = 对齐:

c
bool matched = iterate_menu (chsrc_pl_menu, input, &dish_tmp);
if (!matched) matched = iterate_menu (chsrc_os_menu, input, &dish_tmp);
if (!matched) matched = iterate_menu (chsrc_wr_menu, input, &dish_tmp);

预处理指令的层次缩进:

c
#ifdef _WIN32
  #define XY_Build_On_Windows 1
  #define xy_on_windows true
  #ifdef XY_DEBUG
    #define xy_debug_mode 1
  #endif
#endif

...... 等等

C语言代码风格

  • 整体上基于 GNU style,但我们坚持自己的美学原则,在细节上有所改进

  • 类型名: PascalCase_t,即 UpperCamelCase_t

  • 函数定义和调用时,函数名和()之间始终保持一个空格,如果是在宏中,可紧凑一些,无硬性规定

  • 函数和函数定义之间一般保持2个空行

    • 若函数之间有高度关联性,可用1个空行
    • 若一系列函数和一系列函数存在主题性区别,可用3个空行

Markdown 写作风格

维护者很多时候不是从渲染好的界面来看 Markdown 文件的,而是阅读 Markdown 源文件,所以 Markdown 在源文件层面也要易读。

我们保持每个主题之间 1个`` + 3个空行 的简单风格。

拒绝使用 VS Code 的 markdownlint 插件,因为它总是用它狭隘的标准给我们增加了巨多的黄色下划线。

其他语言代码风格

我们秉承 入乡随俗、尊重传统 的原则,尊重每种语言社区的既定传统。比如,YAML 使用2个空格,JSON使用4个空格,Perl 使用 Larry Wall 钟爱的4个空格。

我们使用 .editorconfig 来确保这些格式的应用。


Doc 10 如何编写Recipe (`doc/10-如何编写recipe.md`)

Write A Recipe Even If You Don't Know C

介绍

chsrc 不仅是一个命令行工具,同时也是一个体现了 Ruby on Rails 思想的 MVC 换源框架,它甚至使你能够在不了解C语言的情况下编写出新的换源方法(recipe)。

我鼓励你为新的软件添加换源支持,因为通过 chsrc 框架,这将比写 shell 脚本更加轻松,你的贡献也将非常有价值。理论上每一个 recipe 都需要有专人长时间维护 (招募)。

  • 本项目采用 GPLv3+ 协议,是真正的自由软件,而非仅仅是开源软件
  • 代码规范灵活遵循 GNU 标准(若标准干扰了可维护性,则并不采纳)
  • 高度模块化,目录结构清晰易懂
  • 极小依赖,极易构建,只需要 GCC 或 Clang 即可编译 (make 和 just可简化编译,但不是必需的)
  • 易于将 shell 脚本转换为等价的 recipe
  • 已有大量 recipe 可提供参考,并提供了 recipe template 供直接使用
  • 本仓库外的子项目 rawstr4c 帮助你在C语言中维护复杂的字符串
  • chsrc-bootstrap 帮助你在没有预编译 chsrc 的平台上 bootstrap 自己

成功案例:

基本概念

  • dish: 所要换源的菜品

  • combo dish: 一个 dish 包含了多个子 dish,比如 Python 包含了该语言的多个包管理器

  • category: 是 dish category 的简写,即 dish 所属的类别,可以是 编程语言,操作系统,软件 三类之一

    1. 在目录中,三者分别为 lang, os, ware
    2. 在代码中,三者前缀分别为 pl, os, wr
  • mirror: 是 mirror site 的简写,指镜像站,如清华大学开源软件镜像站

  • source: 该 dish 所能换的具体的源,由 mirror 提供服务,往往一个 mirror 会提供许多 source

  • recipe: 是为一个 dish 定义的具体换源方法,请参考 src 目录中的 recipe 目录

  • chef DSL:是 chef Domain Specific Language 的简写,这是一组以 chef_ 开头的函数,用来定义维护者信息、可用源等元信息

  • 换源链接: 指镜像站所提供的某一个具体的换源使用的URL

  • 测速链接: 用来测速的URL,与 "换源链接" 不同,可分为 精准测速 和 模糊测速

    1. 在代码中,测速链接一般使用 smURL (即 speed measure URL) 或 speed_measure_url 来指代

    2. 在代码中,换源链接一般使用 repoURL (即 repository URL) 或直接用 url 来指代

      • 为什么不用 regurl,因为使用术语 repository 的 dish 远多于使用术语 registry 的。
      • 为什么莫名其妙使用了大小写混合的API? 因为 smurl 和 repourl 的可读性太差
  • 镜像源: 为了方便,偶尔我们将直接称mirror和/或source为镜像源,这只是一种方便性的称呼,可以统称二者,也可以根据上下文指代二者之一

编写 `recipe` 步骤

  1. 确定你要编写的 dish 的标准名称,创建 Dish-Name.c 文件

    大小写需严格按官方,若名称包含空格,需使用 - 代替空格

  2. 根据类别将上述文件放在 recipe/ 目录的某个子目录中

  3. 复制 recipe template 的内容到上述文件中,并替换 <...> 占位符

  4. 参考现有 recipe 的写法

    1. 看一眼就能上手的参照物是 PHP recipe
    2. 最好的参照物是 Ruby recipe
    3. 组换源参照物是 JS combo recipe
  5. 在 Wiki 中记录的镜像站中寻找可用源;可以额外补充镜像站

  6. 使用 chef DSL 定义 _prepare() 函数

    该函数将填充 dish 所有的必要信息,包括维护信息、换源信息

  7. 设置/修改 "换源链接" 和 "测速链接" (how?)

  8. 按需实现 _setsrc() _getsrc() _resetsrc(), 可以使用这些函数:

    1. framework/*.c 中以 chsrc_, chef_, hp_ 开头的所有函数或宏
    2. xy.h 中以 xy_ 开头的所有函数或宏

    一个简单的方法是,在 VS Code 中按快捷键 Ctrl-T 搜索上述三种前缀

  9. 在 recipe/menu.c 中登记此 dish

  10. 编译、运行、测试 (how?),若无问题可提交 Pull Request

开发准则

  1. 代码高度可移植

  2. Convention over Configuration

  3. NO UFO 原则: 不要乱丢文件到$HOME等目录,尤其是使用各种隐晦的文件名

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

其它

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


Doc 11 如何设置换源链接与测速链接 (`doc/11-如何设置换源链接与测速链接.md`)

新增/修改 "换源链接"

在 _prepare() 函数中,在 def_sources_begin() 的位置的第二列,新增/修改你想要替换的链接。

注: 以下代码仅起解释作用,JavaScript换源的真正实现可能不同

c
def_sources_begin()
{&UpstreamProvider, "https://registry.npmjs.org/",                     FeedByPrepare},
{&NpmMirror,        "https://registry.npmmirror.com",                  FeedByPrepare},
{&Huawei,           "https://mirrors.huaweicloud.com/repository/npm/", FeedByPrepare},
{&Tencent,          "https://mirrors.cloud.tencent.com/npm/",          FeedByPrepare},
{&某新镜像站,       "某镜像站提供的换源链接",                         FeedByPrepare}
def_sources_end()

//

// 调整上述某一个镜像站的所提供源的 "换源链接"
chef_set_repoURL (this, &UpstreamProvider, "新的换源链接");

设置/修改 "测速链接"

在 _prepare() 函数中,在 def_sources_begin() 的位置的第三列,设置/修改你想要替换的链接。

  1. 在下面代码的第一行中,我们直接给了一个链接,这就是精准测速链接

  2. 在下面代码的第二行和第三行中,我们都设置了一个宏 DelegateToMirror,这意味着我们没有直接提供精准测速链接,而是让 chsrc 去测试其对应镜像站定义的测速链接

    • NpmMirror 是专用镜像站,所以其测速链接被设置为了 ACCURATE,即精准测速
    • Huawei 是通用镜像站,所以其测速链接被设置为了 ROUGH ,即模糊测速
  3. 在下面代码的第四行中,我们设置了一个宏 FeedByPrepare,这意味着我们将在 _prepare() 函数的后续动态计算 URL

注: 以下代码仅起解释作用,JavaScript换源的真正实现可能不同

c
def_sources_begin()
{&UpstreamProvider, "https://registry.npmjs.org/",                     "https://registry.npmjs.org/BigFile.tar.gz"},
{&NpmMirror,        "https://registry.npmmirror.com",                  DelegateToMirror},
{&Huawei,           "https://mirrors.huaweicloud.com/repository/npm/", DelegateToMirror},
{&Tencent,          "https://mirrors.cloud.tencent.com/npm/",          FeedByPrepare},
def_sources_end()

//

// 调整/设置上述某一个镜像站的所提供源的 "精准测速链接"
chef_set_smURL (this, &UpstreamProvider, "新的测速链接");
// 设置上述某一个镜像站的所提供源的 "精准测速链接" 设置为 "换源链接" + postfix
chef_set_smURL_with_postfix (this, &UpstreamProvider, "/dir/BigFile.tar.gz");
// 基于 "换源链接" 做更自定义的操作
chef_set_smURL_with_func (this, &UpstreamProvider, func, data);

// 把所有上述源中还未设置 "精准测速链接" 的源进行设置
chef_set_rest_smURL_with_postfix (this, "/dir/BigFile.tar.gz");
chef_set_rest_smURL_with_func (this, func, data);

// 调整某一个镜像站(Provider)的 "测速链接"
chef_set_provider_smURL (&Tencent, "https://mirrors.cloud.tencent.com/npm/BigFile.tar.gz");
// 调整某一个镜像站(Provider)的 "测速精度"
chef_set_provider_sm_accuracy (&UpstreamProvider, ROUGH);

Doc 50 协作者与维护者 (`doc/50-协作者与维护者.md`)

协作者与维护者

想要达到最理想的维护状态,每一个 recipe 都需要有专人长时间维护。我们的代码里使用了 recipe (某个菜的烹饪方法) 这个词,因而整个项目便和 "饮食" 有关,比如 menu: 汇集了所有的 dish 的菜单。因此,我们的维护者和贡献者身份依然使用了这个惯例:

  1. Chef

    主厨: 一个 recipe 的主要作者

  2. Saucier

    调味:一个 recipe 的次要贡献者

第一次贡献者

注册身份信息

在 src/chsrc-main.c 的 chsrc_register_contributors() 函数里,在最后(我们按参与本项目的时间顺序排列)添加一行:

c
chef_register_contributor ("@ID: 你的GitHub/Gitee用户名或任意不与其他贡献者冲突的名字",
  "你的真实姓名",
  "你的邮箱地址",
  "若 chsrc ls <recipe> 的时候不想使用真实姓名,可以用这个参数的字符串来代替");

更新 Recipe 信息

在你修改的 recipe 文件的 _prepare() 函数里,需要做以下更新:

  1. 更新 recipe 修改时间(每次修改 recipe 代码都要更新):

    c
    chef_set_recipe_last_updated (this, "YYYY-MM-DD");
  2. 更新镜像源信息时间(仅当你修改了镜像源列表时才更新):

    c
    chef_set_sources_last_updated (this, "YYYY-MM-DD");
  3. 将自己加入 sauciers(次要贡献者列表,将计数加一并添加自己的 @ID):

    c
    // 原来是 0 个 saucier:
    chef_set_sauciers (this, 0);
    // 改为添加你自己:
    chef_set_sauciers (this, 1, "@你刚注册的ID");
    
    // 原来已有 1 个 saucier:
    chef_set_sauciers (this, 1, "@Someone");
    // 改为添加你自己:
    chef_set_sauciers (this, 2, "@Someone", "@你刚注册的ID");
  4. 验证上述信息正确

    sh
    # 应当能看到你的信息
    ./chsrc ls <recipe>

--- METRICS ---