cjreg:用仓颉写一个私有中心仓,Web 界面不用写一行 JS

💡 原文中文,约6300字,阅读约需15分钟。
📝

内容提要

cjreg 是用仓颉编写的可自部署私有包仓库,与官方中心仓协议互通,cjpm 客户端只需修改配置地址即可使用。它支持多仓优先级查找、按拓扑顺序发布、团队权限管理和三级删除审计;Web 界面基于 cjxt 服务端渲染,无需编写 JS。发布链路全程流式处理,内存占用与包体大小解耦。项目包含 1002 个测试用例,行覆盖率达 91.3%,并依赖作者自研的七个仓颉库。

🔎

延伸解读

私有仓的定位:补位而非替代

cjreg 明确不替代官方中心仓,而是解决内网离线、发布不可逆、团队预演位三类官方仓不覆盖的问题。它与官方协议互通,cjpm 客户端只需改配置地址,因此适合在保留官方仓的同时,为内部包和灰度版本提供可控的落点。这种边界划分让读者能判断它是否匹配自身场景,而非把它当作官方仓的替代品。

流式发布解决的是内存上限,不是吞吐

文章指出整包驻留内存时峰值约为包体 2–3 倍,默认 256 MB 堆下发 100 MB 包就会失败。cjreg 将发布链路改为边读边算 sha256、临时文件校验后原子落盘,使 2 MiB、32 MiB、200 MiB 三档发布的 VmHWM 都稳定在 291 MiB。这意味着内存占用与包体大小解耦,但吞吐数据来自单机 loopback 冒烟基准,作者也说明它不是容量规划数字。

权限模型把覆盖权收归团队

cjreg 按团队而非个人授权,有效权限取个人路径与团队路径中较高者。值得注意的设计是:同版本不同 sha 的覆盖需要团队 overwrite 权限,首发者本人也没有。文章解释这是有意的,因为覆盖会影响所有使用该版本的人。此外,组织匹配不做模糊,未登记组织关联 ID 为 -1,避免“关联无组织”的团队越权到任意未登记组织。

自研库堆叠带来的部署简化与测试成本

cjreg 的 Web 界面基于 cjxt 服务端渲染,整个控制台与服务端打成一个静态二进制,运维无需 Node、npm 或前端构建链。代价是项目依赖作者自研的七个仓颉库,合计六万多行,cjreg 本身只有 31 个生产文件。文章也提到 bstorm 在测试中预分配大量对象,默认堆下会随机失败,最终通过调大测试进程堆解决,说明这种库层下推并非没有维护成本。

❓

Q&A

cjreg 是什么?它和官方仓颉中心仓是什么关系?

cjreg 是一个用仓颉编写的可自部署私有包仓库,与官方中心仓协议互通,cjpm 客户端只需修改 cangjie-repo.toml 中的地址即可使用。它不替代官方中心仓,而是补位,解决内网离线、发布不可逆、团队私有仓等官方仓不覆盖的场景。

cjreg 的 Web 管理界面是怎么做到不用写 JS 的?

Web 界面基于 cjxt 框架实现服务端渲染,服务端直接产出 HTML 和增量 patch,浏览器只运行框架自带的约 100 KB 运行时(cangjie-ui.js 加浮层定位库)来应用 patch。因此写页面时无需编写任何 JS,也没有 Node、npm 或前端构建链,整个 Web 控制台跟服务端一起打成一个静态二进制。

cjreg 的多仓查找机制是怎样的?

一个 cjreg 实例可以同时挂载多个上游仓(官方仓、内部仓、镜像仓等),查包时按上游的 priority 字段从小到大依次查索引,第一个命中的即返回;都没命中则返回 404。内部包可以覆盖同名官方包,而 cjpm 客户端无需改动。切仓只需改 cangjie-repo.toml 地址并刷新缓存。

cjreg 的发布计划如何保证跨团队按依赖顺序发布?

发布计划先用 analyze 将待发包分为待发、可选、已存在、冲突四类,execute 再按依赖拓扑顺序推送到目标上游(复用 cjdep 的拓扑排序)。每个计划项经历六态状态机:pending → running → waiting_index → completed/failed/skipped,其中 waiting_index 要求版本出现且 sha256 一致才算完成,避免索引先到的假完成。进度通过 SSE 实时推送,中断后计划保持 pending。

cjreg 的团队权限模型是怎样的?覆盖权为什么在团队手里?

cjreg 以团队为权限单元,团队关联若干组织或包,成员继承团队权限。权限分三档:read(读取)、write(发布新版本)、overwrite(覆盖同版本不同 sha)。有效权限取个人路径和团队路径中较高者。覆盖权在团队手里而非发布者个人,因为覆盖会影响所有使用该版本的人,首发者自己也没有覆盖权,需团队 overwrite 权限。

cjreg 如何解决发布大包时的内存问题?

cjreg 将发布链路全程改为流式处理:按段解析头获取长度与校验,边读边算 sha256 不缓存整包,写临时文件后校验再 rename 原子落盘;下载和回源同样流式。这样内存与包体大小解耦,实测 2 MiB、32 MiB、200 MiB 三档发布进程 VmHWM 均恒定在 291 MiB。

cjreg 的质量和性能数据如何?

cjreg 有 1002 个单元测试用例全部通过,行覆盖率 91.3%(11241/12312 行,90 个源文件),另有双仓 e2e 9 步和 CI 六步。性能方面:索引回源到本地命中 p50 从 16.16 ms 降至 2.74 ms(5.9 倍);发布吞吐 2 MiB 为 74 MiB/s、32 MiB 为 278 MiB/s、200 MiB 为 324 MiB/s;发布内存三档恒定 291 MiB;启动到可服务 0.27 秒,SIGTERM 关闭 0.03 秒。

cjreg 明确不做什么?

cjreg 不替代官方中心仓(定位补位,两者并存),不做公网 SaaS 托管(私有仓价值在私有),不做包的签名与验签(不越权官方信任链),不做依赖漏洞扫描(属于另一类工具)。完整未实现清单在仓库 docs/finals-submission.md §4.5。

🏷️

标签

➡️

继续阅读