一条命令管本机的开发环境、常驻服务、工具和镜像源。
单个静态二进制,不依赖 Python、Node 或任何运行时,装上就能跑。支持 macOS 与 Linux 的 x86_64 / arm64。
curl -fsSL https://raw.githubusercontent.com/farfarfun/fundeploy/HEAD/install.sh | shcurl -fsSL https://raw.githubusercontent.com/farfarfun/fundeploy/HEAD/install.sh | sh默认装到 ~/.local/bin/fundeploy。脚本不会去动你的 shell 配置,该加的 PATH 那行它会打出来。
可选参数与环境变量:
| 变量 | 作用 | 默认 |
|---|---|---|
FUNDEPLOY_VERSION / --version |
装哪一版 | latest |
FUNDEPLOY_BIN_DIR / --bin-dir |
装到哪儿 | ~/.local/bin |
FUNDEPLOY_RELEASE_REPO |
从哪个仓库的 release 取 | farfarfun/fundeploy |
FUNDEPLOY_RELEASE_SOURCE |
从 github 还是 gitee 取 |
先 GitHub,不通换 Gitee |
FUNDEPLOY_GITHUB_HUB_PROXY_PREFIX |
GitHub 直连不通时的加速前缀 | 空 |
GitHub 连不上时脚本会自动改用 Gitee 上的镜像,不用额外设置。嫌那一次探测(8 秒) 慢就直接点名:
FUNDEPLOY_RELEASE_SOURCE=gitee \
curl -fsSL https://gitee.com/farfarfun/fundeploy/raw/master/install.sh | sh连 raw.githubusercontent.com 都拿不到脚本本身时,就用上面这个 Gitee 的地址
(Gitee 的 raw 路径要写分支名 master,没有 HEAD 这种写法)。
镜像由 CI 从 GitHub 整仓同步过去,release 附件一并搬,两边的包字节一致、校验和
是同一份。装完之后 fundeploy upgrade 认同一个变量,行为也一样。
brew tap farfarfun/packages https://github.com/farfarfun/packages
brew trust farfarfun/packages
brew install fundeploytap 那行要带 URL:brew tap a/b 默认去找 github.com/a/homebrew-b,而这个仓库还
兼着 apt 源。trust 那行也不能省:Homebrew 6.0 起第三方 tap 默认不可信,不信任的话
装会被拒。两步都只做一次。
GitHub 连不上就把 tap 的 URL 换成 https://gitee.com/farfarfun/packages,后面两行
照旧。下包那一步不用管:formula 里每个 url 都带了 Gitee mirror,brew 自己会回落。
curl -fsSL https://farfarfun.github.io/packages/farfarfun.gpg \
| sudo tee /usr/share/keyrings/farfarfun.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/farfarfun.gpg] https://farfarfun.github.io/packages/deb stable main" \
| sudo tee /etc/apt/sources.list.d/farfarfun.list
sudo apt update && sudo apt install fundeploy这是 farfarfun 所有项目共用的源,加一次以后别的包也直接 apt install,见
farfarfun/packages。
apt 这条路没有 Gitee 备份:deb 树是 Actions 部署到 GitHub Pages 的,不在 git 里,
镜像仓库带不走它。farfarfun.github.io 连不上就用上面的装机脚本。
Releases 里每个平台一个 fundeploy-<target>.tar.gz,
解开把 fundeploy 丢进 PATH 即可。同目录下的 SHA256SUMS 可以校验。
cargo install fundeploy要本地有 Rust 工具链,而且是从源码编,比上面几种慢得多。手上已经有工具链的话这条最省事, 否则不建议——用它装工具链反而要求你先有工具链,顺序是反的。
fundeploy upgrade # 升到最新版
fundeploy upgrade --check # 只看有没有新版本,什么都不动
fundeploy upgrade --version 0.2.0 # 装指定版本,比当前旧也照做(这是回退的用法)不管当初是怎么装的,升级都是这一条命令,它会先认出这份二进制归谁管,再走对应的路:
| 装法 | fundeploy upgrade 做什么 |
|---|---|
| 装机脚本 / 直接下二进制 | 从 Release 下对应平台的 tar.gz,原子替换掉自己 |
| Homebrew | 进 tap 仓库 git pull --ff-only,再 brew upgrade <tap>/fundeploy |
| APT | apt-get update 后 apt-get install fundeploy(按需加 sudo) |
| cargo | cargo install fundeploy --force --locked(从源码编,慢) |
自己管的那条路:换下来的新二进制会先跑一次 --version 确认能起来,再原子替换掉自己;
跑不起来就原样不动。
交给包管理器的那几条路,跑完会再问一次它那边现在装着哪一版再下结论——brew upgrade
和 apt install 在「没有更新可升」时也退出 0,光看退出码会把没升上去当成升成功了。
发版之后这几条渠道要等几分钟(apt 索引和 formula 等 farfarfun/packages 重建,cargo 等
crates.io 发布),所以刚看到 GitHub 上有新版时这边可能还是旧的,过一会儿再试。
--version 只有自己管的安装和 cargo 支持:brew 的 tap 里只有一个跟着最新版走的
formula,apt 源也只放最新一版,点了版本会直接报错并给出路,不会假装装上了。
卸载就是删掉那个文件。用 Homebrew / APT 装的交给对应包管理器:brew uninstall fundeploy、
sudo apt remove fundeploy。
fundeploy # 不带参数:打开菜单(可输入过滤)
fundeploy list # 列出所有能管的东西
fundeploy about # 这是什么、谁做的输出按「一张卡片说完一件事」排:框宽跟着终端走,窄终端下长路径中间省略而不是把框
撑破;NO_COLOR=1 或输出被重定向时自动退回无框的纯文本,不往日志里塞框线和色码。
等端口监听这种最长半分钟的干等会转一个 spinner(进度画在 stderr,不混进重定向的结果)。
fundeploy service # 列出所有服务
fundeploy service status # 所有服务的状态总览(在跑 / 没在跑 / 部分)
fundeploy service funread-web install
fundeploy service funread-web start
fundeploy service funread-web status每个服务都是这套动作:install、upgrade、rollback <版本>、start、run(前台)、
stop、restart、status、uninstall。
| 服务 | 说明 |
|---|---|
funfluid-web |
funfluid 前后端(18806 / 8806) |
funlesson-web |
funlesson 前后端(18812 / 8814) |
fungame-web |
fungame 后端 + 管理端 + 用户端(8809 / 8807 / 8808);后端包为 fungame-api,前端包为 @farfarfun/fungame-admin、@farfarfun/fungame-web |
funflix-web |
funflix 前后端(18810 / 8810) |
funread-web |
funread 前后端(18811 / 8811) |
funmill |
funmill 任务执行 API(8813 / 8812) |
new-api |
new-api 中转网关(8801) |
code-server |
浏览器里的 VS Code(8080) |
sub2api |
sub2api 订阅转 API(8802) |
airflow |
Apache Airflow standalone(8815) |
celery |
Celery worker / beat / flower(8816) |
paperclip |
Paperclip 本机服务(8804) |
服务默认只监听回环地址。要对外暴露就显式设对应的 *_HOST / *_ADDRESS 环境变量。
多进程的服务(前后端一体的那几个)只提供合并命令:一条 start 把该起的都起来,
一条 stop 全停掉。换包前会先停服、装完按原状态起回来——在跑着的进程底下换全局包,
Node 还开着那棵树里的文件。
stop 走完还有人占着端口时,会按端口反查出占用者,问一声再强停(SIGTERM,5 秒不走
上 SIGKILL)。端口不腾出来,紧接着的 start 会跳过那个组件,于是 stop 和 start
都报成功、跑的却还是旧进程——restart 卡住多半就是这么来的。
警告: new-api 的端口 8801 停完还占着,占用者是 PID 2593874(python3)
? 强制停掉它,腾出端口 8801 吗 (Y/n)
回车就是停。没有终端时(cron、CI、输出被重定向)不问直接停,restart 因此不会断在
半路;盯着终端但不想每次都按回车的,设 FUNDEPLOY_STOP_KILL_PORT_YES=1。
init 和 fundeploy 自己这两个 PID 永远不动。
paperclip 额外转发官方 CLI 的动作:install-canary、check、backup、channels、
doctor、health、onboard、logs、plugin、service-install。
fundeploy service paperclip install 和 fundeploy service paperclip install-canary 在
新安装时默认从 npm 镜像下载,安装到用户目录;
无需设置环境变量。upgrade 跟随安装时选择的通道和实际成功使用的源;镜像失败时会
自动改用官方 npm 源。已有 managed install 继续走原安装路径,避免暗中切换;该模式
可用 PAPERCLIP_HTTPS_PROXY=http://127.0.0.1:7890 加速官方源。npm 全局安装不保留
managed payload,因此不支持 rollback。
fundeploy dev # 列出全部的当前状态
fundeploy dev uv install
fundeploy dev go upgrade
fundeploy dev python status # Python 多版本虚拟环境覆盖 go、nodejs、pnpm、rust、uv,动作是 status、install、upgrade、
uninstall。status 会把「官方包装在哪儿」和「PATH 上实际用的是哪个」分开列——
这两者不一致是最常见的「我明明装了」。
fundeploy dev python 管的是 ~/opt 下按版本号分开的 Python 虚拟环境。
fundeploy source # 看全部工具当前配的是哪个源
fundeploy source pip test # 测所有源的延迟
fundeploy source pip use # 不给名字就自动选最快的
fundeploy source pip use tuna
fundeploy source pip reset # 恢复官方源
fundeploy source pip add 自己的源 https://...覆盖 pip(pip / uv / poetry / pdm 共用这份配置)、npm(pnpm / yarn / bun 共用)、
brew(配方 API、bottle 二进制、brew 仓库三处一起换)、cargo、go。
brew(Homebrew 本身)、cockpit-tools(AI IDE 账号管理桌面应用)、
open-pencil(CLI + MCP 服务器,额外有 install-desktop、mcp-config)。
fundeploy ai # 三样的当前状态
fundeploy ai claude install
fundeploy ai all upgrade覆盖 claude、codex、cursor。官方安装器优先,装不上再退到包管理器那条路。
fundeploy doctor github # 网页打得开、git clone 却卡住的那类问题
fundeploy doctor github --fix # 按诊断结果自动挑一条通道改过去
fundeploy doctor github --undo # 撤掉写进 git / ssh 配置里的东西fundeploy port-kill 8080 8081 # 查出谁占着端口,停掉它
fundeploy port-kill 8080 --list # 只看不动手
fundeploy skills sync # 同步 Gitee 上的 farfarfun-skills 仓库查版本、取安装包都要走 GitHub。相关的环境变量:
| 变量 | 作用 |
|---|---|
FUNDEPLOY_RELEASE_SOURCE |
github 或 gitee;只管 fundeploy 自己的升级 |
FUNDEPLOY_GITHUB_HUB_PROXY_PREFIX |
直连慢或不通时的加速前缀,必须 https:// |
GITHUB_TOKEN / GH_TOKEN |
调 GitHub API 时带上 |
匿名调 API 是每小时 60 次、按出口 IP 算,公司网和校园网很容易共用一个出口撞上限,
症状是「查不到最新版本」。gh auth login 过的机器通常已经有 GH_TOKEN 了。
token 只发往 api.github.com——配了加速前缀时不会跟着请求递给那个代理。
fundeploy upgrade 默认先试 GitHub,连不上再换 Gitee 镜像,换的时候会出声。
FUNDEPLOY_RELEASE_SOURCE 点了名就只用那一个,失败直接报错而不背着你换源。
它只对 fundeploy 自己生效:装别的工具时取的是上游仓库的 release,那些我们没有
镜像,一律直连 GitHub。加速前缀也只往 GitHub 的地址上套,不会拿去绕 Gitee。
cargo build
cargo test
cargo fmt --all --check
cargo clippy --all-targets -- -D warnings目录结构:
src/
common/ 外部命令、下载、解包、平台探测等公共件
service/ 服务域:spec 声明 + 三族通用生命周期
dev/ 开发工具链
tool/ 非常驻工具
source/ 换源
ai/ AI 命令行
doctor/ 诊断
cli.rs 命令行解析与分发
packaging/ .deb 打包脚本
install.sh 装机脚本
核心约定是差异是数据,不是逻辑:生命周期只写一遍,每个具体的服务/工具退化成一份
声明。加一个 PyPI + npm 的前后端服务通常只需要往 src/service/registry.rs 里加十几行。
装不进这套形状的(Paperclip 要直驱上游 CLI)才单独实现 trait。
发布:改 Cargo.toml 里的 version,提交,推同版本的 tag(v0.3.1)。CI 会核对 tag
与版本号、构建四个平台、生成校验和与安装包、发 Release,用装机脚本真装一遍验证,然后
发 crates.io 并通知 farfarfun/packages 重建
apt 索引和 Homebrew formula。
- packaging/README.md —— 打包与发布
- CHANGELOG.md
farfarfun 是一个专注于实用工具库的开源组织, 涵盖云存储、数据处理、AI、多媒体与开发工具链等方向。
- 🏠 组织主页:https://github.com/farfarfun
- 📧 联系:farfarfun@qq.com
本项目基于 MIT 协议开源。