sealdice-core
sealdice-core copied to clipboard
一种关于插件依赖机制、包管理机制的参考方案
在提问之前...
- [X] 我填写了简短且清晰明确的标题,以便开发者在翻阅 issue 列表时能快速确定大致问题。而不是“一个建议”、“卡住了”等
- [X] 我基本确定这是一个新功能/建议,而不是遇到了 bug(不确定的话请附上日志)
说说你遇到的问题?
只有在插件 A 已经加载的情况下,插件 B 才能正常运作,目前只能采取轮询等待的方式,而没有一个通用的机制
有什么好的想法?
应当通过某一个机制,实现对插件加载的排序,例如b依赖a,那么应当能保证a先加载,再加载b
如何实现依赖机制
可以通过插件头的 UserScript 字段来定义一些信息,声明其包名和依赖名(参考自油猴)
例如:
// ==UserScript==
// @name B
// @key B
// @author 木落
// @version 1.0.0
// @depends A
// ==/UserScript==
这里读取 @key 为包名,如果没有key,自动使用 @name 为替代(或者命名为@extname等) 在程序实现中,我们会维护两个列表:待加载列表,已加载列表
首先我们读取插件信息,获得了每一个插件的 key 和依赖列表(depends)。 这个过程通过简单的文本解析就能完成,不需要执行js。
一开始,所有扩展都在待加载列表中,我们对其应用这样一个函数:
- 对“待加载列表”的每一项,检查其依赖是否已存在于“已加载列表中”,如果全为是,或待加载列表为空,将其标记为可被加载。
- 加载所有可被加载的扩展
- 将本轮加载的扩展放入“已加载列表”,并踢出“待加载列表”
循环应用此函数,当一次循环时,待加载列表中项目的个数不再改变时中止。 此时如果里面还有项目,那么这些项目是缺少依赖,或者是循环引用的,可以汇报给用户。 如果没有项目了,那么所有加载成功完成。
依赖版本
我们允许有限的依赖版本声明,基本上参照pip和npm的做法。
来看一些情况,首先是同时依赖多项,有两种写法,第一种是空格间隔:
// @depends A C D
第二种是多行:
// @depends A
// @depends C
// @depends D
版本要求:
// @depends A@1
// @depends [email protected].*
// @depends D@>=1.0.2,<2.0
注意,由于项目的体量较小,对于分别依赖某个插件的不同版本的情况,我们直接放弃。 也就是对于固定名字的插件,用户只能同时安装其一个版本。 这样也同时避免了 node_modules 黑洞的问题。
包管理机制
为javascript仓库增设一个action,进行如下操作:
扫描所有插件的静态信息,如名字、描述、作者、协议、依赖等,汇总为一个 json 文件,可以叫做packages.json、libraries.json等
注意,对于key冲突的扩展,我们只会允许更早的那个通过pr,除非经过很长时间,原始扩展失去维护,而且社区一致认为应当将其移除。
这样一来,本地的海豹直接下载这个仓库json文件,就可以得知当前线上可用的所有插件了,同时可以实现从仓库安装,和安装依赖两个需求。
值得一提的点为:插件的历史版本以什么形式存在?,还有待讨论。
另外,对javascript仓库进行的操作,不应当加重插件提交者的负担。 如果提交者需要下载好多数据才能进行提交,那我们应该提供一些简单的方式。
优缺点
优点:
- 实现简单,机制可靠
- 完全兼容所有旧的插件,且不会增加js和go的耦合
- 全静态分析,避免奇怪问题
- 一定程度上可以防呆,不好好写插件的作者会自食其果(我们可以修改日期较新的js插件先被加载,如果他没有写依赖就一定会崩溃)
- 此模式完全是 pip / npm 的缩水翻版,经过充分验证
缺点:
- 如果开发者在一个插件中,实际注册了与key不同名的插件,或多个插件,这个机制是检测不出的
- 对于重名插件,是否限制过于严格?是否要支持一下不同作者的同名插件?(就行npm那样)
- 待补充
P.S. 为缺点1稍作辩护:首先插件pr要批准才会进源,其次这种现象其实是存在于pip中的(是的,pip允许包名和import的名字不同,甚至会有install之后长出多个包),但是pip多年来没有出太大乱子,所以我姑且认为可靠。
其他内容
No response
一开始,所有扩展都在待加载列表中,我们对其应用这样一个函数:
这一段描述了一个拓扑排序的过程。拓扑排序有效率更高的 Kahn 算法,复杂度是 O(E + V), 具体实现时可以灵活处理。
我们允许有限的依赖版本声明,基本上参照pip和npm的做法。
作为一个 无高亮、无补全、无静态检查、很少示例 的文件头,格式应该尽可能简单。
我的建议是只支持每行 1 个依赖,每个依赖只支持添加 1 个约束,并且只支持 不指定版本、特定版本、最低版本 三种约束,如下:
@depends A
@depends [email protected]
@depends C>=1.2.0
作为一个 无高亮、无补全、无静态检查、很少示例 的文件头,格式应该尽可能简单。
我的建议是只支持每行 1 个依赖,每个依赖只支持添加 1 个约束,并且只支持 不指定版本、特定版本、最低版本 三种约束……
同意这一建议,应该仅支持每行一个依赖,同时版本约束也简化,降低犯错风险。
同时希望 @depends
应该包含作者名以区分不同作者的同名插件,格式类似:
// @depends JustAnotherID::A
// @depends JustAnotherID::[email protected]
// @depends JustAnotherID::C>=1.2.0
我们允许有限的依赖版本声明,基本上参照pip和npm的做法。
作为一个 无高亮、无补全、无静态检查、很少示例 的文件头,格式应该尽可能简单。
我的建议是只支持每行 1 个依赖,每个依赖只支持添加 1 个约束,并且只支持 不指定版本、特定版本、最低版本 三种约束,如下:
@depends A @depends [email protected] @depends C>=1.2.0
还是应当有高版本约束吧?很难保证2.0会向下兼容1.0
我们允许有限的依赖版本声明,基本上参照pip和npm的做法。
作为一个 无高亮、无补全、无静态检查、很少示例 的文件头,格式应该尽可能简单。 我的建议是只支持每行 1 个依赖,每个依赖只支持添加 1 个约束,并且只支持 不指定版本、特定版本、最低版本 三种约束,如下:
@depends A @depends [email protected] @depends C>=1.2.0
还是应当有高版本约束吧?很难保证2.0会向下兼容1.0
我的想法是支持1.*.*这样的写法
实现了依赖的原型版本(#614),支持了完整的 SemVer 规则,声明语法调整如下
// @depends JustAnotherID:A
// @depends JustAnotherID:B:1.2.3 // 指定特定版本
// @depends JustAnotherID:C:^1.2.0 // 详见 SemVer 规则