nav-map

raku-pm 上手与排障地图(贡献者速查)

目标:让你改代码或排查问题时,第一眼就知道该打开哪个文件。 配套详细设计见 docs/architecture.md(更密,适合通读);本文件是「速查表」。

0. 一句话心智模型

把 raku-pm 想成 一辆自行车 + 一堆可拆的摩托车附件:

  • 自行车本体(核心链路,每次必走):bin 薄壳 → CLI 派发 → Resolver 解析 → Repository 取包 → Store 缓存 → Installer 装进 site/ → Ledger/Lock 记账。约 7 个模块,是「装个包」真正需要的全部。

  • 摩托车附件(重型子系统):事务/世代回滚、跨进程文件锁、单后端 HTTP(curl)、测试超时+失败复验、verify/doctor 诊断、自我升级、作者侧发布、本地库探测。

你「觉得复杂、不敢动」的根因:附件太多,且最大的那个模块以前叫 Reporter 却装着写命令(名字骗人)。

1. 改动 X / 出了问题 → 去哪个文件

你想改 / 症状文件行数(约)
命令列表、别名、help 文案lib/RakuPM/CliSpec.rakumod + lib/RakuPM/Help.rakumod + lib/RakuPM/CLI.rakumod(派发)297 / 718 / 970
解析 / 依赖 / 版本约束(Foo:ver<1.0+>)lib/RakuPM/Resolver.rakumod + Version + Spec + Repository/Matching586 / 225 / 130 / 65
仓库接入 / 索引 / 下载 / 代理 / 某索引拉不动Repository/Ecosystem + HTTP(+HTTP/Tinyish) + Repositories595 / 294 / 285
安装落盘 / 多版本共存 / 与 zef 共存 / bin wrapperInstaller + Installer/ShellTemplates + Distribution1248 / 162 / 828
事务 / 世代回滚 / 账本Installer::Generations + Ledger141 / 152
provides / 模块 ↔ 磁盘(幽灵安装)Distribution:@MODULE-EXTS(扩展名唯一口径)→ scan-provides / provides-with-paths / provides-from-disk;护栏在 Store.put;历史条目由 verify/doctor 第 ⑥ 段查—
路径拼装 / 内容寻址 store / 路径安全Fs(唯一净化入口 path-component:穿越类 die / Windows 保留类 百分号编码;assert-under 第二道防线)+ Store224 / 596
测试执行(串行)/ 超时 / 进度 / 失败复验Client/Tester511
写操作(安装 / 升级 / 重装 / 测试 / 构建 / 卸载 / 回滚 / 回收)lib/RakuPM/Client.rakumod1415
只读查询 / 诊断(list / which / why / depends / rdepends / locate / browse / info / store / doctor / verify / search / list-available / env / lock / generations)+ native 库检查lib/RakuPM/Client/Query.rakumod1600
清理 / 全清Cleaner + Client/Flusher381 / 203
锁 / 并发写入 / 子进程令牌FileLock231
发布 / 打包 / bump / 登录Author1236
native 库检测NativeLib503
自我升级Client/SelfManager426
平台差异(路径/进程/后缀/强杀)Platform(唯一出处,别处不准写)390
启动入口 / 早期旗标bin/raku-pm.raku + CLI.run-cli13
门禁 / 测试纪律tools/run-suite.raku + t/ xt/—

命名约定(0.79.4 起):原 Client::Reporter 改名 Client::Query。 它只装只读查询 + 诊断 + native 检查;uninstall / rollback / autoremove 三个写命令已挪回 Client(编排器)。所以「改查询去 Query,改写操作去 Client」。

路径安全不变式(0.87.0 起,别拆):发行版 name / version 是包自己声明的 (发布者可控),任何把它们拼进路径的地方都必须先过 RakuPM::Fs.path-component —— 唯一净化入口,非法即 die。当前 7 处:① Store.path-for;② Client/Tester 日志目录; ③ Repository/Ecosystem 下载缓存;④ Installer 临时文件名;⑤ Author 归档名 / 发布落点; ⑥ Client/Git.!fetch-source 的 fetch --to 输出目录;⑦ Client/Git.!git-cache-key 的 git 缓存目录名(0.88.6 补;地址可来自恶意发行版的 git-deps)。(另有 Author.new 一处冗余防御——那里的名字已被正则校验,留着是防日后放宽正则。) ★ assert-under 对 .. 天然无效(字面前缀比对 + Raku 不折叠 ..)⇒ 净化只能 在生成路径时做,别指望事后断言。

模块源扩展名只有一份清单(0.87.1 起,别内联):.rakumod / .pm6 / .pm 定义在 RakuPM::Distribution 的 @MODULE-EXTS,跨模块经 module-extensions 取。 这份清单原先写了两遍(provides-with-paths、!walk-source-files)且都漏了 .pm —— 于是整个 .pm 时代的包全部幽灵安装。t/ghost-provides.t 有一条静态守卫盯着 「别处不许再出现 '.pm6' 字面量」。 落盘前再用 assert-under 断言"在根之内"。加一处新路径 = 加一处净化; 回归守卫在 t/path-safety.t(含"旧实现的逃逸落点必须不存在"的端到端断言)。

2. 端到端:raku-pm install Foo 走了什么

你敲命令
  → bin/raku-pm.raku(13 行薄壳,只解析 --target/--offline 早期旗标)
  → RakuPM::CLI.run-cli 派发到 install
  → Client 抢跨进程文件锁(FileLock,防并发写坏 store)
  → 解析仓库配置 + 目标前缀(Repositories / Prefix)
  → Resolver:找能提供 Foo 的发行版,按约束挑最高版,递归展开依赖 → 拓扑排序
  → 对每个发行版串行执行:
       fetch    (Repository 下载 tar → cache/dist)
       build    (Builder 跑 Build.pm,native 包在此编 .so/.dll)
       store    (Store 算 MD5 指纹,存进 store/)
       test     (Tester 串行跑 t/*.t;失败则整树回滚)
       install  (Installer 交给 CUR::Installation 装进 site/,写 bin wrapper)
  → 整段包在事务里:成功落一个「世代」,失败回滚到执行前
  → Ledger 写 installed.json + Lock 写 raku-pm.lock
  → Query 负责把「计划 / 结果」打印出来(show-* 系列)

一句话:核心链路是「解析 → 取 → 存 → 装 → 记」五步;灰色附件全是「让这五步更稳/更快/更可诊断」才套上去的。

3. 模块分层与「哪些可砍」

类别模块对「自行车」是否必要
核心链路 5 模块Resolver / Repository / Store / Installer / Ledger✅ 必留(本体)
多版本共存(CUR)+ 与 zef 共存Installer 内✅ 必留,Raku 包管理命脉
平台抽象Platform✅ 必留且已是最佳实践(唯一出处)
事务 / 世代回滚Installer::Generations + Ledger⚠️ 高级但值——半装态是真痛点
verify / doctor在 Query✅ 值得留,就是「坏了能查」的工具
文件锁FileLock⚠️ 防御性,去掉会真损坏 store
HTTP 层HTTP + Repository✅ 已简化(0.82.0):单后端 curl,可插拔注册表/回退已删
测试执行Client/Tester✅ 已简化(0.80.0):并发机制 + 预热已删,只留串行 + 失败复验
作者侧Author(1228 行)✅ 不必动(0.84.0 判定):模块面本就独立(独立文件 + 独立命名空间 + CLI 懒加载),只剩命令面;命令面保留,只补了 help <组名> 导航
native 库检测NativeLib(503 行)✅ 不必动(0.84.1 修订):不只是 native 查询命令的后端 —— 安装链每次都调它查 :from<native> / :from<bin> 依赖(见 Client/Git 的 !check-native-libs)。实测加载成本 ≈ 加载任意模块(~276ms vs ~275ms,而空 raku 仅 ~4ms),故「改按需 require」收益≈0
self-upgrade 路径Client/SelfManager✅ 已简化(0.83.0):三路径→两路(删「就地 pull 工作树」,收尾消息去重)

4. 命令分类(41 个命令里,大多数很便宜)

  • 查询 / 诊断(都在 Query):list which why depends rdepends locate browse info store doctor verify search list-available env lock generations。

  • 写操作(都在 Client):install upgrade reinstall test build uninstall rollback autoremove self-upgrade publish(publish 在 Author)。

5. 本地怎么验证改动没搞坏

raku tools/run-suite.raku --docs-only     # 秒级:版本号/provides/个人痕迹
raku tools/run-suite.raku --no-xt         # 跑 t/ 全量(不跑 xt/)
raku tools/run-suite.raku                 # 全量(含 xt/,较慢)
raku tools/run-suite.raku --no-timings    # 同上,但不打印每用例耗时与最慢排行

门禁默认给出耗时小结(每用例墙钟 + 最慢 15 + 实际墙钟 + 并行加速比 + raku 启动基线 占比):判断"慢在进程数还是慢在某个测试"用它,别靠感觉。

提交前务必跑 --no-xt(与预提交钩子同一口径)。套件默认并行(按 CPU 核数、上限 8), 且 t/ 与 xt/ 合成一个池、按历史耗时降序调度(LPT):长任务先起、短任务填空槽, 专治"批尾只剩一两个长任务在跑"的空转;任务分到 $jobs 条道上各跑各的(不设层屏障, 谁先空谁接下一个)。跑前只预热一次 precomp,跑完对失败用例串行复验。 别加 --jobs=1(那是把多核当单核用)。历史耗时缓存在 ~/.raku-pm/suite-timings.json, 只是排序提示(删掉不影响判定,RAKUPM_SUITE_TIMINGS 可改路径)。

门禁纪律见 docs/architecture.md 与 tools/run-suite.raku 顶部注释。

RakuPM v1.0.3

一个教学用的 Raku 包管理器:多索引仓库、依赖解析、跨系统本地库(:from<native>)探测、内容寻址存储、锁文件、单版本激活、单后端 HTTP 客户端(curl)、索引 TTL 与网络重试

Authors

  • skyter10086

License

Apache-2.0

Dependencies

Test Dependencies

Provides

  • RakuPM::Author
  • RakuPM::Builder
  • RakuPM::CLI
  • RakuPM::Cleaner
  • RakuPM::CliCheck
  • RakuPM::CliSpec
  • RakuPM::Client
  • RakuPM::Client::Flusher
  • RakuPM::Client::Git
  • RakuPM::Client::Query
  • RakuPM::Client::SelfManager
  • RakuPM::Client::Tester
  • RakuPM::Distribution
  • RakuPM::FileLock
  • RakuPM::Fs
  • RakuPM::HTTP
  • RakuPM::HTTP::Backend
  • RakuPM::HTTP::Tinyish
  • RakuPM::Help
  • RakuPM::InstallOptions
  • RakuPM::Installer
  • RakuPM::Installer::Generations
  • RakuPM::Installer::ShellTemplates
  • RakuPM::Ledger
  • RakuPM::Lock
  • RakuPM::MD5
  • RakuPM::Message
  • RakuPM::NativeLib
  • RakuPM::Net
  • RakuPM::Platform
  • RakuPM::Prefix
  • RakuPM::Repositories
  • RakuPM::Repository
  • RakuPM::Repository::Ecosystem
  • RakuPM::Repository::Local
  • RakuPM::Repository::Matching
  • RakuPM::Resolver
  • RakuPM::Spec
  • RakuPM::Store
  • RakuPM::UI
  • RakuPM::Version

The Camelia image is copyright 2009 by Larry Wall. "Raku" is a trademark of the Yet Another Society. All rights reserved.

Built with Podlite — the markup and publishing tools behind this site.