☰
alist 开发贡献指南:环境搭建、本地预览与新增存储驱动的完整流程
2026/9/30 11:15:44 网站建设 项目流程
  • 后端
  • 文件存储

【免费下载链接】alist

🗂️A file list/WebDAV program that supports multiple storages, powered by Gin and Solidjs. / 一个支持多存储的文件列表/WebDAV程序,使用 Gin 和 Solidjs。

项目地址:https://gitcode.com/GitHub_Trending/al/alist
点击查看免费下载

导读:alist 是一个基于 Go 与前端框架构建的多存储文件列表/WebDAV 程序(仓库根目录命令描述见 cmd/root.go)。本文以仓库根目录的 CONTRIBUTING.md 为主线,完整梳理从开发环境搭建、克隆源码、本地前后端预览,到基于drivers/template模板新增一个存储驱动、编写符合规范的提交信息并提交 Pull Request 的端到端流程。读完本文,你将掌握 alist 开发者视角的完整工作流,并理解驱动注册与加载的底层机制,能够独立为该项目贡献新存储后端。


一、环境准备:搭建 alist 开发机

1.1 前置依赖

alist 由 Go 编写后端、前端框架编写 Web 界面(CONTRIBUTING.md 原文表述为 React,仓库命令描述则写作 Go/Solid.js,见 cmd/root.go)。按照 CONTRIBUTING.md 的要求,开发机器需要安装以下工具:

依赖用途说明
git版本控制克隆源码、管理分支与提交
Go 1.20+后端编译运行文档要求 1.20+;当前仓库 go.mod 中声明的版本为go 1.25.0,实际编译时建议使用较新的 Go 工具链
gcc编译 CGO 依赖部分第三方库(如本地缩略图、加密相关依赖)依赖 CGO
nodejs前端开发配合 pnpm 运行前端开发服务器

1.2 克隆源码

按文档要求,将后端仓库alist与前端仓库alist-web克隆到任意位置:

$ git clone https://github.com/alist-org/alist.git $ git clone --recurse-submodules https://github.com/alist-org/alist-web.git

其中前端仓库必须使用--recurse-submodules以同时拉取子模块。开发时应切换到main分支,与上游主线保持一致。

克隆得到的alist后端仓库核心目录结构如下(以当前仓库实际内容为准):

  • main.go:程序入口,仅调用cmd.Execute()
  • cmd/:基于 Cobra 的命令行实现(root.go、server.go、storage.go、user.go等)
  • drivers/:全部存储驱动,每个子目录是一个独立驱动,另含template模板与 all.go 注册聚合文件
  • internal/:核心业务逻辑,其中 internal/driver 定义了驱动接口
  • server/:HTTP/FTP/SFTP/WebDAV 等服务端路由
  • pkg/:通用工具库

二、预览你的改动:前后端开发服务器

2.1 后端:go run main.go

在alist仓库根目录直接运行:

$ go run main.go

该命令会编译并启动开发服务器。从源码看,main.go 只做一件事:调用cmd.Execute(),进而执行 cmd/root.go 中的 Cobra 命令分发。真正拉起服务的是 cmd/server.go 中的ServerCmd:它会依次完成配置初始化、加载存储(bootstrap.LoadStorages())、初始化任务管理器与 FRP 内网穿透,然后启动 HTTP/HTTPS/Unix Socket、S3、FTP、SFTP 与 MCP 等监听服务。

因此,go run main.go默认行为等同于执行alist server,监听地址等由配置文件决定(相关实现见 cmd/server.go)。

2.2 前端:pnpm dev

进入alist-web目录运行:

$ pnpm dev

即可启动前端开发服务器。前后端联调时,前端开发服务器通常需要配置代理指向本机后端端口;开发期间修改 Go 代码后重启go run main.go,修改前端代码则由 Vite 热更新自动生效。


三、新增一个存储驱动(Driver)

这是 alist 贡献中最核心的扩展点。CONTRIBUTING.md 给出的方法极为简洁——复制drivers/template文件夹并重命名,然后按照其中的注释实现。下面结合源码把这条指引展开成可操作的完整步骤。

3.1 模板文件夹结构

drivers/template共包含 4 个文件(见 drivers/template):

文件职责
meta.go定义驱动注册信息config、用户可配置字段Addition,并在init()中调用op.RegisterDriver完成注册
driver.go定义驱动主体结构Template并实现全部接口方法(大部分为 TODO 占位)
types.go类型定义占位文件
util.go工具函数占位文件,注释提示“可在此实现 Driver 接口之外的其他逻辑”

3.2 注册信息与配置字段(meta.go)

drivers/template/meta.go 揭示了每个驱动的两个核心组成部分:

Addition结构体:通过 struct tag 声明用户在前端页面填写的配置项。模板默认嵌入driver.RootPath或driver.RootID二者之一(通常按驱动是按路径还是按 ID 标识文件来选择),并示范了一个自定义字段:

type Addition struct { // Usually one of two driver.RootPath driver.RootID // define other Field string `json:"field" type:"select" required:"true" options:"a,b,c" default:"a"` }

这里的 tag 约定(json、type、required、options、default、help)会被管理界面自动解析为表单控件。以本地驱动 drivers/local/meta.go 为真实范例,可以看到更丰富的字段,例如thumbnail(是否启用缩略图)、use_ffmpeg(是否用 ffmpeg 生成视频缩略图)、thumb_pixel(缩略图目标宽度像素)、video_thumb_pos(视频缩略图时间点,支持秒数或百分比)、mkdir_perm(新建目录权限)、recycle_bin_path(回收站路径)等,每个字段都带有help说明,非常值得模仿。

config变量:类型为driver.Config,用于描述驱动的能力与行为:

var config = driver.Config{ Name: "Template", LocalSort: false, OnlyLocal: false, OnlyProxy: false, NoCache: false, NoUpload: false, NeedMs: false, DefaultRoot: "root, / or other", CheckStatus: false, Alert: "", NoOverwriteUpload: false, }

字段含义可从命名推断:OnlyLocal表示仅限本机文件系统(本地驱动 drivers/local/meta.go 将其置为true并开启LocalSort、NoCache);NoUpload表示不支持上传;DefaultRoot是默认根路径提示;Alert可在界面上展示注意事项。

注册:文件末尾的init()调用op.RegisterDriver:

func init() { op.RegisterDriver(func() driver.Driver { return &Template{} }) }

所有驱动正是通过各包的init()副作用完成注册,而 drivers/all.go 以空导入方式统一聚合了全部驱动(注释写明“All do nothing, just for import”)。

3.3 驱动主体与接口方法(driver.go)

drivers/template/driver.go 定义的驱动结构体嵌入model.Storage与自定义Addition,从而自动获得存储基础属性与配置字段:

type Template struct { model.Storage Addition }

必实现方法(标注required):

方法签名职责
ConfigConfig() driver.Config返回驱动能力配置
GetAdditionGetAddition() driver.Additional返回配置字段指针,供 JSON 反序列化使用(见 internal/driver/driver.go 中Meta接口注释)
InitInit(ctx) error初始化,如登录/刷新 Token;注释提示可调用op.MustSaveDriverStorage(d)保存存储
DropDrop(ctx) error销毁时清理资源
ListList(ctx, dir, args) ([]model.Obj, error)列出目录文件,必实现
LinkLink(ctx, file, args) (*model.Link, error)返回文件下载链接/本地路径/读取流,必实现

可选方法(标注optional):MakeDir(建目录)、Move(移动)、Rename(重命名)、Copy(复制)、Remove(删除)、Put(上传)、GetArchiveMeta/ListArchive/Extract/ArchiveDecompress(压缩包相关能力)。未实现的可选方法统一返回errs.NotImplement,框架会自动降级为内置工具处理或提示不支持。

3.4 接口层:驱动的契约由谁定义

模板中每个方法签名都来自 internal/driver/driver.go 定义的Driver接口体系:

type Driver interface { Meta Reader }
  • Meta:Config、GetStorage/SetStorage、GetAddition、Init/Drop(internal/driver/driver.go)
  • Reader:List与Link两个只读核心方法(internal/driver/driver.go),这就是“必实现”的来源
  • 写操作通过Mkdir、Move、Rename、Copy、Remove、Put等可选接口以能力组合方式扩展(internal/driver/driver.go);Put接口的注释还给出了上传取消、进度上报、限速的最佳实践

模板末尾有一行编译期断言var _ driver.Driver = (*Template)(nil)(drivers/template/driver.go),确保实现始终满足接口契约。

3.5 参考真实实现

drivers/local是最适合对照学习的完整示例:其 driver.go 中List通过readDir读取真实目录并过滤隐藏文件;Link支持普通文件与缩略图两种请求(drivers/local/driver.go);Put用utils.CopyWithCtx实现可取消、带进度上报的写入(drivers/local/driver.go)。新增驱动时,若目标存储 API 与某个已有驱动相近,直接在 drivers/ 下寻找同名实现做参照会事半功倍。


四、创建符合规范的提交(Commit Message)

CONTRIBUTING.md 要求提交信息必须格式化、标准化,采用业界常见的 Conventional Commits 风格。

4.1 总体格式

<type>(<scope>): <subject> <BLANK LINE> <body> <BLANK LINE> <footer>
  • header必填,其中scope可选
  • 任何一行不得超过 100 个字符,以便在 GitHub 与各类 git 工具中清晰阅读

4.2 Type:提交类型

必须为下表之一(原文定义见 CONTRIBUTING.md):

Type含义
feat新功能
fix修复缺陷
docs仅文档变更
style不影响代码语义的格式调整(空白、缺失分号等)
refactor既不修复缺陷也不增加功能的代码重构
perf性能改进
test补充缺失或修正已有测试
build影响构建或依赖变更
revert还原某次提交
ci持续集成相关文件修改
chore构建流程、辅助工具与库的变更(如文档生成)
release发布新版本

4.3 Scope:作用域

scope指明变更所在位置,例如$location、$browser、$compile、$rootScope、ngHref、ngClick、ngView等。结合 alist 的实际目录结构,实践中可自然使用如drivers/local、server/webdav、cmd等作为作用域;当变更影响多个作用域时使用*。

4.4 Subject:主题行

主题行是对变更的简洁描述,必须遵守三条规则:

  • 使用祈使句、一般现在时:写change,不写changed或changes
  • 首字母不大写
  • 末尾不加句号(.)

4.5 Body:正文

与 Subject 相同,正文同样使用祈使句、一般现在时。正文应包含变更动机,并与变更前的行为形成对比,让审阅者理解“为什么要改、怎么改的”。

4.6 Footer:页脚

页脚承载两类信息:

  • 破坏性变更:必须以BREAKING CHANGE:开头,后跟一个空格或两个换行,其余部分作为详细说明
  • 关闭 Issue 的引用:可在此引用本次提交所关闭的 GitHub Issue

4.7 Revert:还原提交

若提交用于还原之前的某次提交,必须以revert:开头并紧跟被还原提交的 header;正文中需写明This reverts commit <hash>.,其中<hash>为被还原提交的 SHA。

一个符合规范的提交示例(综合上述规则):

feat(drivers/local): support recycle bin path for remove move deleted files into configured recycle bin instead of permanently deleting them, so users can recover accidental removals. BREAKING CHANGE: `remove` behavior changes when recycle_bin_path is configured. This reverts nothing.

五、提交 Pull Request

完成开发与本地验证后,按以下流程提交贡献(CONTRIBUTING.md):

  1. 将本地分支推送到你的alistfork 仓库
  2. 在 GitHub 上向上游alist仓库的main分支发起 Pull Request
  3. 在 PR 描述中说明变更动机、实现方式与验证结果,配合符合上一节规范的提交信息,便于维护者高效审阅

建议在提交 PR 前先在本地完整跑通一次后端go run main.go与前端pnpm dev,确认新驱动能正常列出、预览与操作文件,再进入提交流程。


小结

本文围绕 CONTRIBUTING.md 展开,从环境搭建、源码克隆、前后端预览,到基于 drivers/template 新增存储驱动、编写规范提交信息、提交 PR,给出了 alist 贡献者的完整工作流。其中“新增驱动”是 alist 扩展能力的核心路径:理解 internal/driver/driver.go 的接口契约、参考 drivers/local 的真实实现,再配合 drivers/all.go 的注册机制,你就能把任意一个云存储/网盘后端接入 alist。更多细节可继续阅读仓库内各驱动的实现与测试文件。

  • 后端
  • 文件存储

【免费下载链接】alist

🗂️A file list/WebDAV program that supports multiple storages, powered by Gin and Solidjs. / 一个支持多存储的文件列表/WebDAV程序,使用 Gin 和 Solidjs。

项目地址:https://gitcode.com/GitHub_Trending/al/alist
点击查看免费下载

相关推荐

上一篇:Dagger TypeScript SDK 深度指南:ContainerWithMountedCacheOpts 缓存卷挂载选项全解析
下一篇:OpenMed Agent Skills 捆绑包导出与安装:离线、确定性与可审计的 Skill 分发实战

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询