# 包 Deft 包是带有 `package.dft` 清单的模块目录。包是分发单位:通过 `pkg/install` 安装,以 `owner/name` 引用,可从任意模块导入。 ## 包标识 每个包都有一个规范 `owner/name` 标识(例如 `deft/editor`)。所有者名称在注册表上全局唯一;`deft` 保留给官方包。该标识以单个字符串传递给每个注册表操作:
[pkg/install "deft/editor"]
[pkg/info    "deft/editor"]
[pkg/uninstall "deft/editor"]
## 导入包模块 `owner/name` 标识同时也是导入路径前缀。位于 `:pkgs` 搜索根下的包(或由 `pkg/install` 安装的包)会自动挂载为 `owner/name`,因此模块无需任何配置即可导入:
import "deft/ui/components/button" as button
在名称后用 `@version` 固定精确版本:
import "deft/ui@0.1.0/components/button" as button
- 未固定的 `owner/name/...` 按所列顺序通过 `:pkgs` 根解析——第一个提供该包的根优先。对于已安装的包,版本来自 `pkg/install` 写入的 `latest` 指针,否则取已安装的最高 semver 版本。 - `owner/name@latest/...` 是未固定形式的显式别名。 - 与开发检出清单版本匹配的固定版本会解析到开发树(同样遵循根顺序规则);否则匹配已安装的版本目录。 - 固定版本缺失时会报错并列出可用版本;裸包前缀(例如 `ui/...`)会报错并给出 `did you mean "owner/name/..."?` 提示。 开发检出、已安装树以及旧式带版本的布局都受支持——“开发包”与“使用包”的区别只在于由哪个根提供它,而不在于导入语法。 ## 清单(`package.dft`) 清单声明包的标识、版本、依赖与入口点:
def manifest %Package{
    :owner       "alice"
    :name        "math-lib"
    :version     "1.0.0"
    :description "Personal math helpers"
    :entry       "src/main.dft"
    :deps @{
        %Dep{ :owner "deft" :name "stdext" :version "0.2.0" }
    |
    }
    :capabilities %PackageCapabilities{
        :ffi false
        :tui false
    |
    }
}
`[pkg/read-manifest "path/to/dir"]` 读取并校验清单,返回 `%Package{ ... }` 或 `%Err{ ... }`。 ## `pkg/*` 标准库函数 | 函数 | 返回 | 用途 | |---|---|---| | `[pkg/set-registry $url]` | nil | 设置注册表 URL(nil 重置为本地) | | `[pkg/get-registry]` | url 或 nil | 当前注册表 | | `[pkg/install "owner/name" ?version]` | 摘要映射或 `%Err` | 安装 | | `[pkg/install-bytes "owner/name" $ver $bytes]` | 摘要映射 | 安装预取的 tarball | | `[pkg/uninstall "owner/name"]` | bool 或 `%Err` | 卸载 | | `[pkg/list]` | 列表 | 所有搜索根中的包 | | `[pkg/list-paths]` | 字符串列表 | 搜索根 | | `[pkg/available]` | 列表 | 当前注册表中的包 | | `[pkg/info "owner/name" ?version]` | 映射 | 包详情 | | `[pkg/fetch "owner/name" ?version]` | bytes 或 Future | 下载 tarball | | `[pkg/read-manifest $dir]` | `%Package` 或 `%Err` | 读取清单 | | `[pkg/mount $export-path $dir]` | nil | 注册导入挂载 | ## 安装位置 安装始终以第一个搜索根为目标(规范位置:`.deft/packages/`),生成按所有者划分的带版本布局: ``` .deft/packages/<owner>/<name>/<version>/package.dft .deft/packages/<owner>/<name>/<version>/src/... ```` `pkg/install` 还会在版本目录旁写入 `latest` 文本指针(`.deft/packages/<owner>/<name>/latest`),使未固定的 `owner/name` 导入有明确的目标。 ## 搜索路径 启动时会扫描每个 `:pkgs` 根,找到的每个包都会自动挂载为 `owner/name`(以及 `owner/name@version` 固定版本和 `@latest` 别名)。根按所列顺序扫描——第一个提供某包的根优先,因此列在 `.deft/packages/` 之前的开发树会遮蔽已安装副本。预置文件中显式的 `:mounts` 条目始终优先于自动扫描。 使用 `[pkg/list-paths]` 查看当前的搜索根:
[pkg/list-paths]
# => @{ ".deft/packages" }
所有磁盘布局都受支持: - 扁平(开发):`<root>/<name>/package.dft` - 旧式带版本:`<root>/<name>/<version>/package.dft` - 按所有者划分的开发:`<root>/<owner>/<name>/package.dft` - 按所有者划分的已安装:`<root>/<owner>/<name>/<version>/package.dft` ## 注册表 两种注册表传输方式: - `dir://`(默认)——tarball 位于 `virt-pkg/packages/<owner>/<name>/<version>.tar.gz` 下。会识别 `latest` 符号链接或文本文件。适用于本地开发与离线环境。 - `http(s)://`——tarball 从 `<url>/packages/<owner>/<name>/<version>.tar.gz` 获取。用 `[pkg/set-registry $url]` 或 CLI 标志 `--url` 设置 URL。会识别 `latest` 文件。
pkg/set-registry "https://packages.example.com"
echo [pkg/get-registry]
# => https://packages.example.com

pkg/set-registry nil                           # reset to local virt-pkg
当前注册表 URL 会持久化到 `prelude.dft` 的 `:registry` 字段中,因此后续的 `deft` 调用会自动采用。 ## 安装包
def result [pkg/install "deft/editor"]
# => %{ :owner "deft" :name "editor" :version "1.5.0" :path ".deft/packages/deft/editor/1.5.0" }

def specific [pkg/install "deft/editor" "1.4.0"]
`pkg/install` 是同步的——它会阻塞直到获取与解压完成。失败时返回 `%Err{ :message ... }`。 ### 手动获取 + 安装 如果你已自行获取了 tarball 字节(例如通过代理),请使用 `pkg/install-bytes`:
set bytes [my-fetch "https://.../editor-1.5.0.tar.gz"]
pkg/install-bytes "deft/editor" "1.5.0" $bytes
## 手动挂载包 包自动发现覆盖 `:pkgs` 根下的所有内容。`[pkg/mount $name $dir]` 是用于根之外目录(或将名称指向特定检出)的应急手段:
pkg/mount "alice/mylib" "/home/alice/dev/mylib"
import "alice/mylib/helpers" as helpers
挂载名称可以是多段的(`alice/mylib`)——导入会优先解析最长匹配的挂载前缀。 ## 创建包 1. 布置目录结构: ``` my-package/ ├── package.dft └── src/ ├── main.dft └── helpers.dft ```` 2. 编写清单(`package.dft`):
def manifest %Package{
    :owner       "alice"
    :name        "my-package"
    :version     "0.1.0"
    :description "An example package."
    :entry       "src/main.dft"
    :deps @{}
|
}
3. (可选)通过将父目录加入搜索路径并导入来在本地测试:
pkg/mount "alice/my-package" "/path/to/my-package"
import "alice/my-package/src/main" as mp
4. 发布到你的注册表(将该目录打包为 tarball;上传到你的 HTTP 注册表或放到 `virt-pkg/packages/<owner>/<name>/` 下)。 ## 能力 包可以在清单中声明它需要的能力(FFI、TUI 等):
:capabilities %PackageCapabilities{
    :ffi true
    :tui false
|
}
当包被加载到缺少所需能力的运行时时,运行时会利用这些声明给出兼容性警告。 ## 应用帮助(`help/`) 应用包可以通过添加 `help/` 目录来附带自己的帮助: ``` my-app/ ├── package.dft ├── help/ │ ├── help.md # main page │ └── shortcuts.md # extra docs └── src/ ```` `help/help.md` 是主页面(目录中任何其他 `.md` 文件都会成为附加文档)。帮助应用的 Apps 标签页会扫描每个已配置的包根中的 `help/` 目录并列出找到的应用;面板名称命令面板的 Help 操作会在那里打开某个应用的帮助。网站会在 `/platform/apps/<name>` 下索引相同的目录,全文 Search/Apropos 会将它们作为 `app` 语料库纳入。 ## 快速参考 | 形式 | 用途 | |---|---| | `[pkg/install "owner/name" ?ver]` | 安装 | | `[pkg/uninstall "owner/name"]` | 卸载 | | `[pkg/list]` | 列出已安装 | | `[pkg/available]` | 列出注册表中的包 | | `[pkg/info "owner/name" ?ver]` | 显示详情 | | `[pkg/set-registry $url]` | 切换注册表 | | `[pkg/fetch "owner/name" ?ver]` | 下载 tarball | | `[pkg/mount $export-path $dir]` | 注册挂载 | | `[pkg/read-manifest $dir]` | 读取 `package.dft` |