Skip to content

铁铺 (TiePM) 设计笔记 ​

对标实现:铁铺 v0.2.1(tiepm/核心.xt 981 行 + tiepm/铁铺.xt 79 行) 本文同步日期:2026-10-05(逐函数对照 核心.xt / 铁铺.xt / xuantie_compiler/编译.xt / tiepm-site/main.go 核对) 注意:site/guide/ 下的同名文件由 site/scripts/sync-docs.mjs 从本目录生成,勿直接编辑 site 副本。


设计目标 ​

铁铺是玄铁语言的包管理器,核心目标:

  1. 安装:查远程索引 → 下载包 → SHA256 校验 → 解压落位
  2. 搜索:按关键词在索引里过滤包名
  3. 发布:本地打包、算哈希,并向索引登记
  4. 轻量:不依赖第三方包管理器运行时(Node.js/Python 等),客户端用玄铁自举实现

架构总览 ​

┌─────────────────┐     HTTP      ┌──────────────────┐
│   铁铺 CLI       │ ◄──────────► │  TiePM 官网       │
│  (铁铺.xt)       │   JSON API   │  (tiepm-site/)    │
│                  │              │  Go + 静态 HTML    │
├─────────────────┤              ├──────────────────┤
│ • 安装/搜索/发布 │              │  GET  /api/index   │
│ • SHA256 校验    │              │  POST /api/publish │
│ • TOML 清单解析  │              │  GET  /api/search  │
│ • 本地缓存管理   │              │  GET  /download/:名/:版本 │
└─────────────────┘              └────────┬─────────┘
                                          │ 读写
                                   ┌──────▼──────────┐
                                   │ data/index.json │
                                   └─────────────────┘

关键设计决策(与实现一致):

  • 索引与源码分离:官网只托管包索引 JSON;包文件由各项目的 GitHub/GitCode Releases 承载,官网不存包。
  • 无状态服务:Go 服务器以本地 data/index.json 持久化,无数据库;静态页面用 embed.FS 编进二进制,单文件部署。
  • 裸包名导入:编译器识别裸包名(引 "UI" 予 UI),自动解析到 ~/.tiepm/已安装/<包名>/,无需写路径。
  • 客户端只用两个端点:GET /api/index 与 POST /api/publish。官网另有 /api/search 与 /download/:名/:版本(302 到 {仓库}/archive/v{版本}.zip)、以及注册/登录/控制台——CLI 当前不调用这些,搜索是在本地对索引做包名过滤。

包索引格式 ​

索引是单个 JSON 对象(data/index.json):

json
{
  "数组工具": {
    "1.0.0": {
      "版本": "1.0.0",
      "哈希": "sha256 十六进制",
      "仓库": "https://github.com/用户名/仓库",
      "作者": "张三",
      "描述": "提供数组工具函数"
    }
  }
}

CLI 命令 ​

命令作用
铁铺 安装 <包名> [版本约束](az)解依赖并安装;失败以非零码退出
铁铺 列出(lc)列 ~/.tiepm/已安装 条目 + 编译器内置库表
铁铺 搜索 <关键词>(ss)拉索引后按包名过滤(不搜描述)
铁铺 发布(fb)打包 + 登记索引(见"发布流程")
铁铺 清理(ql)删除 ~/.tiepm/缓存 内容
无参数打印用法
未知命令打印"未知命令"+用法(不设非零退出码)

暂无 更新 / 卸载 命令。所有命令执行前都会先跑一次初始化(建目录)。

安装流程(实际路径) ​

  1. 拉索引:地址硬编码 https://tiepm.xt.markjy.com/api/index,可用环境变量 TIEPM_INDEX 覆盖(空值/含异常字符时回退默认)。
  2. 解版本约束:在索引里"查找最高满足版本"(逐键比较,非排序取首)。约束语法:*/空、>=x.y.z、^x.y.z(0.x 按 semver 锁次版本)、精确匹配;不支持 ~、<、> 与区间。版本号按纯数字三段比较。
  3. 拼下载地址:{仓库}/releases/download/v{版本}/{仓库末段}_v{版本}.zip;仓库不含 github.com / gitcode.com 时直接当 URL 用。下载用 curl -L -o,落在当前工作目录的 _tiepm_dl.zip。
  4. 哈希校验:三平台分派——Windows certutil -hashfile、macOS shasum -a 256、Linux sha256sum(POSIX 两支互备重试)。索引条目没有哈希字段则跳过校验;校验失败 → 安装失败退出。
  5. 解压落位:tar -xf 解到 CWD 的 _tiepm_unzip,再 xcopy/cp -R 搬到 ~/.tiepm/已安装/<包名>(不重命名)。zip 内不强制固定层级。
  6. 依赖递归:读被装包的 tiepm.toml,递归安装 [依赖];深度上限 10 层(超限报"可能存在循环依赖");另有显式循环检测、已装/已解析缓存去重、以及多约束冲突检测(同一包出现不一致约束则整单失败)。装完删掉 CWD 里的下载包。

本地目录结构 ​

~/.tiepm/
├── 已安装/<包名>/        # 解压落位处(编译器裸包名解析的目标)
├── 缓存/                 # 发布产物 zip、_publish.json(用后删)
└── 认证                  # 文件(非目录):发布用 Bearer 令牌

安装期的 _tiepm_dl.zip / _tiepm_unzip 在当前工作目录,成功路径会清理;清理 命令只清 ~/.tiepm/缓存,不递归、不清 CWD 残留。

编译期裸包名解析 ​

编译器对 引 "<包名>"(无路径前缀)的解析顺序:

  1. ~/.tiepm/已安装/<包名>/<包名>.xt;
  2. 兼容 GitHub archive 多包一层 <名>-<版本>/ 的目录(再探一层);
  3. 编译器自带副本:发行布局 <编译器同级>/lib/<包名>/<包名>.xt,开发布局上一级 lib/。
  • 安装副本优先于自带副本;两者版本不一致时打印明确告警("若报'未找到成员'请先核对此处")。
  • 安装根目录可用 TIEPM_HOME 覆盖。
  • 另有 [原生] 对象登记路径(本地 C 库/对象文件经此参与链接)。

使用者必读:玄铁的选项是字典,旧库对未知键不报错、静默忽略。给库加了新功能后,只有把新版装进铁铺(或走发布流程)才会在运行期生效——仓库里有新代码、本机装的还是旧版,会表现为"改了没反应"。

tiepm.toml 清单 ​

toml
[包]
名称 = "数组工具"
版本 = "1.0.0"            # 2~3 段点分,如 1.0 / 1.0.0
仓库 = "https://github.com/用户名/仓库"
作者 = "开发者名"          # 可选
描述 = "一句话"            # 可选

[依赖]                     # 可选:包名 = 版本约束
渲染 = "^1.2.3"
  • 必填:[包] 节及其 名称 / 版本 / 仓库。
  • 可选后备写法:顶层 [作者].姓名、[描述].简介。
  • 依赖约束支持"精确 / >= / *"(注释口径与实现一致,^ 亦支持)。
  • 包名合法性校验(防路径穿越)只在安装链路使用;发布 时不校验包名。

发布流程 ​

铁铺 发布 实际做四件事:

  1. 校验清单;打印包名/作者/描述/依赖。
  2. 打包:tar -czf(排除 .git、.tiepm),产物移到 ~/.tiepm/缓存/<仓库末段>_v<版本>.zip,并算 SHA256。
  3. 打印需要手动完成的两步:
    • git tag v<版本> && git push --tags;
    • 建 GitHub Release,把上一步缓存目录里的 zip 传上去。
  4. 自动登记索引:把 {名称, 版本, 哈希, 仓库[, 作者, 描述]} 写成 缓存/_publish.json,用 curl -X POST 发到 /api/publish(Authorization: Bearer <~/.tiepm/认证>)。

⚠️ 两个已知行为要记牢:

  • 无密钥时:提示后跳过注册,但整体仍返回成功——别把"发布完成"当成"索引已登记"。
  • 资产名是硬约定:安装端按 <仓库末段>_v<版本>.zip 拼下载 URL,Release 里传的文件名与仓库目录名对不上就装不上。

安全设计 ​

  • 完整性:安装强制比对 SHA256(索引无哈希则跳过);下载仅判 curl 退出码,无大小/文件名检查。
  • 路径安全:校验包名 拦截路径穿越(限于安装链路)。
  • 服务端:sync.RWMutex 保护索引读写(读并发、写独占);发布 API 校验必填字段,缺则 400;搜索大小写不敏感;哈希日志预览超 16 字符截断。
  • 认证:发布走 Bearer 令牌(官网有注册/登录/控制台)。

已知局限与后续 ​

局限说明
无 更新 / 卸载CLI 未实现
版本约束有限不支持 ~、<、>、区间
无纯玄铁 SHA256依赖外部命令(三平台分派)
无 lockfile按约束取最高满足版本(未找到锁文件机制)
搜索只匹配包名不含描述/关键词
缓存清理不彻底只清 ~/.tiepm/缓存,CWD 残留需手动
发布不校验包名校验只在安装链路
登记失败仍可能"成功"无密钥时跳过注册但返回成功

项目文件结构 ​

tiepm/
├── 铁铺.xt              # CLI 入口(命令分发)
├── 核心.xt              # 核心实现(索引/版本/下载/哈希/解压/依赖/发布)
├── 核心_test.xt         # 自检(内含旧索引地址,不参与主流程)
├── 示例tiepm.toml       # 清单示例(四节齐全)
└── tiepm.exe            # 构建产物(发行时同时产出到 build/env/tiepm.exe)
tiepm-site/              # 官网(Go + embed 静态 + data/index.json)

构建:xtc 铁 tiepm/铁铺.xt -sc tiepm/tiepm.exe(CI 与发行打包同款)。

平台支持 ​

v0.2.1 起 Windows / macOS / Linux 均可用:平台靠 uname -s 探测(失败回退 Windows),路径分隔符、目录操作、move/xcopy、certutil/shasum/sha256sum、缓存清理各自分派;若探测失败会按 Windows 分支执行("探测失败 ≠ 不可用")。

基于 VitePress 静态构建 · 文档内容与仓库 GUIDE/ 同源

玄铁玄铁 XUANTIE · 中文系统级编程语言MARK 玄·折 120×120 · STROKE 8 · NO CURVES