sealdice-core icon indicating copy to clipboard operation
sealdice-core copied to clipboard

一种关于插件依赖机制、包管理机制的参考方案

Open fy0 opened this issue 11 months ago • 6 comments

在提问之前...

  • [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。

一开始,所有扩展都在待加载列表中,我们对其应用这样一个函数:

  1. 对“待加载列表”的每一项,检查其依赖是否已存在于“已加载列表中”,如果全为是,或待加载列表为空,将其标记为可被加载。
  2. 加载所有可被加载的扩展
  3. 将本轮加载的扩展放入“已加载列表”,并踢出“待加载列表”

循环应用此函数,当一次循环时,待加载列表中项目的个数不再改变时中止。 此时如果里面还有项目,那么这些项目是缺少依赖,或者是循环引用的,可以汇报给用户。 如果没有项目了,那么所有加载成功完成。

依赖版本

我们允许有限的依赖版本声明,基本上参照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

fy0 avatar Feb 28 '24 09:02 fy0

一开始,所有扩展都在待加载列表中,我们对其应用这样一个函数:

这一段描述了一个拓扑排序的过程。拓扑排序有效率更高的 Kahn 算法,复杂度是 O(E + V), 具体实现时可以灵活处理。

Xiangze-Li avatar Feb 28 '24 09:02 Xiangze-Li

我们允许有限的依赖版本声明,基本上参照pip和npm的做法。

作为一个 无高亮、无补全、无静态检查、很少示例 的文件头,格式应该尽可能简单。

我的建议是只支持每行 1 个依赖,每个依赖只支持添加 1 个约束,并且只支持 不指定版本、特定版本、最低版本 三种约束,如下:

@depends A
@depends [email protected]
@depends C>=1.2.0

Xiangze-Li avatar Feb 28 '24 09:02 Xiangze-Li

作为一个 无高亮、无补全、无静态检查、很少示例 的文件头,格式应该尽可能简单。

我的建议是只支持每行 1 个依赖,每个依赖只支持添加 1 个约束,并且只支持 不指定版本、特定版本、最低版本 三种约束……

同意这一建议,应该仅支持每行一个依赖,同时版本约束也简化,降低犯错风险。

同时希望 @depends 应该包含作者名以区分不同作者的同名插件,格式类似:

// @depends JustAnotherID::A
// @depends JustAnotherID::[email protected]
// @depends JustAnotherID::C>=1.2.0

JustAnotherID avatar Feb 28 '24 10:02 JustAnotherID

我们允许有限的依赖版本声明,基本上参照pip和npm的做法。

作为一个 无高亮、无补全、无静态检查、很少示例 的文件头,格式应该尽可能简单。

我的建议是只支持每行 1 个依赖,每个依赖只支持添加 1 个约束,并且只支持 不指定版本、特定版本、最低版本 三种约束,如下:

@depends A
@depends [email protected]
@depends C>=1.2.0

还是应当有高版本约束吧?很难保证2.0会向下兼容1.0

fy0 avatar Feb 28 '24 15:02 fy0

我们允许有限的依赖版本声明,基本上参照pip和npm的做法。

作为一个 无高亮、无补全、无静态检查、很少示例 的文件头,格式应该尽可能简单。 我的建议是只支持每行 1 个依赖,每个依赖只支持添加 1 个约束,并且只支持 不指定版本、特定版本、最低版本 三种约束,如下:

@depends A
@depends [email protected]
@depends C>=1.2.0

还是应当有高版本约束吧?很难保证2.0会向下兼容1.0

我的想法是支持1.*.*这样的写法

Szzrain avatar Feb 28 '24 19:02 Szzrain

实现了依赖的原型版本(#614),支持了完整的 SemVer 规则,声明语法调整如下

// @depends JustAnotherID:A
// @depends JustAnotherID:B:1.2.3  // 指定特定版本
// @depends JustAnotherID:C:^1.2.0 // 详见 SemVer 规则

JustAnotherID avatar Mar 02 '24 11:03 JustAnotherID