[Topic DIscussion] 使用go语言重新实现一款软件包管理器
Tofloor
poster avatar
Maicss
deepin
2022-04-02 01:02
Author

一直有个设想,能否把传统包管理器分来,另传统包管理器(apt、yum)只负责系统层面的安装和更新,应用的安装和更新交给另外的包管理器做,针对这个设想,我总结了下面这些理由:

该包管理器为了解决传统现有的包管理器的以下问题:

  • 通常情况下,在传统包管理器(apt、yum、pacman)中,系统和应用无法分开管理,这可能导致应用安装出现故障时会影响到系统的正常安装和更新,这是很多普通用户无法面对的。
  • 在传统包管理器中,我们只能以root权限安装应用,这导致任何软件包都有机会获得root权限,通常来说这是不安全的(一定程度上),我们需要完全信任软件包的维护者。
  • 在传统包管理器中,我们不能以普通用户身份为自己单独安装一款应用,因为通常我们需要root权限,而且只要安装就是为所有用户安装。
  • 在传统包管理器中,应用的大部分文件都不是放在home目录下,而是根目录的某个其他目录中,这可能导致根分区资源紧张。

现有的其他方案存在的问题:

  • AppImage方案中,重复的依赖存储导致应用包将占用过多磁盘空间,例如应用A和应用B都依赖python3(举例),那么python3这个依赖将被他们两个自带,这时同一份依赖就存储了两份,毫无疑问这是空间上的浪费,虽然硬盘资源目前并不紧缺,但是该问题仍然需要解决。
  • AppImage方案中,没有良好的中心化的管理机制,倘若你需要更新某个应用,你可能需要去官网下载最新的包,然后替换,如果之前配置了desktop文件,又要去做对应的修改,这很明显不方便。
  • flatpak方案中,可以说是我心目中最接近完美的方案,但是他也有相应的缺点。首先是容器机制带来的问题,例如IDE程序可能需要读取系统中的第三方库,例如需要对程序的某些部分进行修改,这些问题并不容易解决。
  • flatpak方案中,其这种机制也带来了一些性能问题。
  • flatpak的打包也比较困难,门槛略高
  • ...

我们都能很好解决吗?

不能。

其实我们的目标并非完全解决这些问题,就比如flatpak的方案,我们不能既要容器机制带来的安全性,又摒弃它所带来的弊端,我们只能寻求一个平衡的方案。我们希望提供当前状况下的最优解,而非真正意义上的最优解。

定位

首先确定一下这款新的包管理器的定位,目前来说,我们要解决的问题只是关于普通应用程序的问题,因此该包管理器仅用于管理普通应用,类似AppStore,他并不会涉及到系统包管理器(例如apt、yum这些)。

计划

作为一个现代的包管理器,我认为他应当至少具有一下特性:

  • 多依赖并存:系统中允许存在多个版本的同一个依赖,程序按照需要去调用(例如第三方库,或者runtime等)
  • 多用户支持:普通用户安装应用不应当需要系统的root权限,其有权只为自己安装,root用户可为所有用户安装。
  • 打包低门槛:减轻打包者的学习成本,用很简单方式去便可以构建一个软件包。
  • 代码易维护:作为开源项目,代码的可读性非常重要,现有的很多包管理器由于长时间的发展,代码过于复杂,外部参与者很难参与贡献。
  • 图形界面支持:图形界面暂时并不在开发计划中,但是要具有简单的接口,让任何人经过简单的学习便可开发图形界面管理程序。
  • 中心化管理:具有中心化的管理平台,开发者或者打包者可以在平台中投递和更新应用。
  • 应用认领:考虑到打包者与开发者并非同一人,且打包者可能没有精力对单个包长期维护,因此需要具有认领机制,可将维护不活跃的软件包重新分发维护权。
  • 自动化更新机制...

目前我已经开始尝试开发了一部分,简单描述一下已经实现部分的细节:

已经落实部分

打包

最基础的就是软件的打包,这部分使用tar进行打包,使用gzip进行压缩,并且支持软链接的打包和压缩,并且可以在不解压的情况下计算解压后所占空间。

包的结构大致如下:

  • 包根目录
    • files:文件夹,用于存放应用程序的主要文件
      • bin:文件夹:用于存放应用程序的可执行文件(必须,若软件本身并不是按照这个规则,那也可以是相对当前目录的软链接)
    • data:数据文件夹,内的所有文件将软链接到 工作目录/data下,也就是说,这个是可以用来安装主题,字体等内容的。
      • applications
      • icons
      • ...
    • runtime:文件夹,用于存储软件需要的依赖
      • lib:文件夹,用于存放动态链接库
      • exe:用于存放可执行文件,例如java程序可能需要jvm。
    • info:包的描述文件,类似control文件,可写入包名、版本号、作者、依赖等信息。
    • icon.png/icon.svg:图标文件,用于供图形界面程序读取包的图标。

解包

打包的反向操作。

安装

安装机制需要特殊说明,这里我需要定义两个目录:

/usr/share/finc
~/.local/share/finc

这两个目录的作用相同,区别就是一个针对全部用户,一个针对当前用户(管理器将根据当前运行的用户身份确定使用哪个)。这两个目录将称为工作目录。

工作目录的子目录data将在用户登录时加入XDG_DATA_DIRS环境变量中,也就是说:

/usr/share/finc/data和~/.local/share/finc/data

这两个目录将等同于我们通常使用的 /usr/share目录。

另外还有一个子目录exe,这个子目录将被加入到PATH环境变量中,也就是说:

/usr/share/finc/exe和~/.local/share/finc/exe

这两个目录将等同于我们通常使用的/usr/bin目录。

这么做的好处就是将包管理器本身所管理的内容于系统中现有内容隔离,提高可靠性,降低故障率。

另外工作目录还有一个子目录apps,这个目录将用于存放软件的主要文件。

安装过程

安装过程就是按照现有的规范将软件包中相应的文件该解压的解压,该链接的链接。

  1. 首先将软件包解压到 工作目录/apps/包名对应文件夹下。
  2. 将包中data目录下的内容链接到 工作目录/data目录下。
  3. 为包中files/bin目录下的内容编写脚本,并部署到 工作目录/exe中,内容大致如下(以motrix举例):
#!/bin/bash
export XDG_DATA_DIRS=/home/maicss/.local/share/finc/apps/app.motrix.dl/runtime/lib:$XDG_DATA_DIRS
export PATH=/home/maicss/.local/share/finc/apps/app.motrix.dl/runtime/exec:$PATH
/home/maicss/.local/share/finc/apps/app.motrix.dl/files/bin/motrix $*
  1. 将生成的链接和脚本记录到一个文件中,当卸载时根据这个文件删除这些内容。
  2. 将应用需要的依赖(库和可执行程序)链接到 工作目录/apps/包名/runtime中的对应目录下。(暂时未做,因为依赖的部分逻辑暂时还没实现)

至此,便基本上实现了大致的流程。

假设问答

  • 怎么划分哪些是应用程序哪些是系统程序?

    • 应用程序的存在与否不影响系统环境的正常运行。
  • 像虚拟机程序这种,在安装过程中必须用到root权限的怎么办?

    • 计划将安装后的部署工作从安装过程的末尾移动到程序第一次运行,但是这部分怎么实现比较好还没想好。

  • 只支持软件吗?

    • 不是,从上述原理中可以看出,也可以安装诸如字体、主题、图标等内容。

最后

上边是对于这个东西的初步想法和实现的尝试,肯定有诸多不完善,希望大家能尽情的提出建议,由于现在只是初步,所以大家的建议将影响这个东西怎么做,做成什么样,甚至是要不要继续做。

欢迎一起讨论!!!!!!!!!!!!

proud proudproudproudproudproud

Reply Favorite View the author
All Replies
liwl
deepin
2022-04-02 01:15
#1

帮顶!

不要停留在构想,任何计算机问题,都可以通过中间层来解决,加油搞搞

Reply View the author
beavailable
deepin
2022-04-02 01:30
#2

不要继续做了,真的。

现有的包管理器比如 apt已经能很好地工作了,用户并不需要另一个包管理器(诸如仅用户安装等功能虽然确实有用,但没有也不是大问题)。

appimageflatpaksnap基本上都是试图解决跨发行版打包麻烦以及依赖的问题,虽然这三者都有缺点,但你要开发的这个包管理器也不能解决这个问题呀。

对于你说的把系统和应用软件包分开处理,尽管有些道理,但这不是必须开发一个新的包管理器的理由,linux众多发行版这么多年一直都是统一处理的,发展到今天也没有遇到什么问题,如果你开发了一个新的包管理器,然后告诉大家能把系统和应用软件包分开处理,你觉得用户会因此而使用这个新的包管理器吗?我觉得不会。

Reply View the author
Comments
kentrl
2022-04-02 18:10
你都没理解楼主说的什么意思,你这理解能力堪忧。
深圳市耀影科技有限公司
deepin
2022-04-02 01:51
#3
  • 如果能够识别依赖的 版本号,追加版本号进行区别它,应该使用哪个依赖文件,我觉得可以实现版本共存,如果不满足,则提示需要哪个版本号

LINUX的依赖版本不同,名称却一样,导致只能在环境变量中只有一个依赖,除非手动编译指定它,我们是否可以自动识别版本号,来自动识别应该使用哪个版本的依赖文件及位置呢

Reply View the author
SamLukeYes
deepin
2022-04-02 02:04
#4

听起来有点像 homebrewtail

Reply View the author
SamLukeYes
deepin
2022-04-02 02:05
#5
深圳市耀影科技有限公司
  • 如果能够识别依赖的 版本号,追加版本号进行区别它,应该使用哪个依赖文件,我觉得可以实现版本共存,如果不满足,则提示需要哪个版本号

LINUX的依赖版本不同,名称却一样,导致只能在环境变量中只有一个依赖,除非手动编译指定它,我们是否可以自动识别版本号,来自动识别应该使用哪个版本的依赖文件及位置呢

这就是 Nix 在做的事情

Reply View the author
kentrl
deepin
2022-04-02 02:09
#6
It has been deleted!
Maicss
deepin
2022-04-02 02:20
#7
beavailable

不要继续做了,真的。

现有的包管理器比如 apt已经能很好地工作了,用户并不需要另一个包管理器(诸如仅用户安装等功能虽然确实有用,但没有也不是大问题)。

appimageflatpaksnap基本上都是试图解决跨发行版打包麻烦以及依赖的问题,虽然这三者都有缺点,但你要开发的这个包管理器也不能解决这个问题呀。

对于你说的把系统和应用软件包分开处理,尽管有些道理,但这不是必须开发一个新的包管理器的理由,linux众多发行版这么多年一直都是统一处理的,发展到今天也没有遇到什么问题,如果你开发了一个新的包管理器,然后告诉大家能把系统和应用软件包分开处理,你觉得用户会因此而使用这个新的包管理器吗?我觉得不会。

是的,但是Linux发展了这么多年,出现的flatpak,snap,appimage确实是对于这些问题的解决方案。

而且可以确定的是,有些问题不可能完美的解决。他们各自有各自的问题。

但是统一管理的方式我认为已经过时了,倒不是说在整个linux生态发展里过时了,而是在linux桌面环境的发展过程中过时了,当linux不再专一的执行指定任务时,统一的包管理器就展现出了它的弊端。

现在flatpak和snap的方案,确实对用户来说很好,但是对于开发者和打包者的压力稍大。而且容器这中方案也会带来一些麻烦。

appimage解决了大部分问题,我认为最大的缺点就是不方便管理。

Reply View the author
Maicss
deepin
2022-04-02 02:21
#8
深圳市耀影科技有限公司
  • 如果能够识别依赖的 版本号,追加版本号进行区别它,应该使用哪个依赖文件,我觉得可以实现版本共存,如果不满足,则提示需要哪个版本号

LINUX的依赖版本不同,名称却一样,导致只能在环境变量中只有一个依赖,除非手动编译指定它,我们是否可以自动识别版本号,来自动识别应该使用哪个版本的依赖文件及位置呢

自动识别依赖应该可以实现,但是识别出需要的版本恐怕困难

Reply View the author
andktan
deepin
2022-04-02 02:27
#9

虽然不太懂,点赞是必须的kissing_heart

Reply View the author
SamLukeYes
deepin
2022-04-02 02:31
#10
Maicss

是的,但是Linux发展了这么多年,出现的flatpak,snap,appimage确实是对于这些问题的解决方案。

而且可以确定的是,有些问题不可能完美的解决。他们各自有各自的问题。

但是统一管理的方式我认为已经过时了,倒不是说在整个linux生态发展里过时了,而是在linux桌面环境的发展过程中过时了,当linux不再专一的执行指定任务时,统一的包管理器就展现出了它的弊端。

现在flatpak和snap的方案,确实对用户来说很好,但是对于开发者和打包者的压力稍大。而且容器这中方案也会带来一些麻烦。

appimage解决了大部分问题,我认为最大的缺点就是不方便管理。

传统的包管理器确实显得有些过时了,但并非所有系统和应用全都管的包管理器都过时了。Nix 管得甚至比传统包管理器更宽,但它是新式的解决方案之一。个人觉得给 nix-env 做一个类似应用商店的前端,或者将其与 packagekit 结合(EDIT: 似乎已经有轮子了),都比重新造个轮子更现实tail

Reply View the author
Maicss
deepin
2022-04-02 02:51
#11
SamLukeYes

传统的包管理器确实显得有些过时了,但并非所有系统和应用全都管的包管理器都过时了。Nix 管得甚至比传统包管理器更宽,但它是新式的解决方案之一。个人觉得给 nix-env 做一个类似应用商店的前端,或者将其与 packagekit 结合(EDIT: 似乎已经有轮子了),都比重新造个轮子更现实tail

nix这个之前还真没了解过,刚大概看了一下确实很不错,再去详细了解试用一下

Reply View the author
神末shenmo
deepin
Spark-App
2022-04-02 04:57
#12
Reply View the author
深圳市耀影科技有限公司
deepin
2022-04-02 05:23
#13
Maicss

自动识别依赖应该可以实现,但是识别出需要的版本恐怕困难

这也是中间件要做的,

绝大多数可以使用 -V 输出它的版本号,如果没有使用APT,DEB,而是使用MAKE源码构建安装,我觉得依赖,就是一个编译好的文件,需要什么版本,我们去告诉它路径即可,也就是文件名+版本号,

比如 A 1.1 依赖B2.3 系统中只有B2.1

那我们装一个B2.3即可,2.1不动它

当然我们可以轻松管理每一个依赖,是否被引用所需,或者没有被引用,重而进行缩小系统

这个是一个中间层,也就是 让大多软件依赖库多版本共存, 需要什么版本,告诉它 在哪里,PYENV解决啦PY的版本路径问题,只是一个思路,但是可行不可行不知道

  • appimage解决了大部分问题,我认为最大的缺点就是不方便管理。
  • 但是appimage 会严重损耗磁盘,可重复使用的依赖也被打包进入一个文件中,而且无法管理
  • 软链接我们可以放到HOME,或者用户文件,可以引用MAKE的这个--prefix=/opt/apps/apr 参数,绝大多数的MAKE源码都支持,且其目录相当的统一 /BIN /LIB /等等。
  • 中间件负责指向具体所需要的依赖的版本,软连即可
  • 环境变量可以加入自定义的目录,而不是一定非要放在系统环境变量的目录混合一起,
Reply View the author
Maicss
deepin
2022-04-02 16:51
#14

依赖有很多种的,比如库依赖、可执行文件的依赖、插件依赖、资源依赖,并非所有的软件包都是标准二进制程序。

如果是普通程序

库依赖好说,使用ldd命令即可获得其依赖库的列表,但是其还可能用到了其他命令,比如wget,比如apt,这些,如果程序中使用了这些命令,我们肯定无法在程序运行前的阶段发现,这时就只能由开发者说明了,这是个例子,说明自动获取需要哪些依赖不是完全可行的。

另外就是依赖版本

还是拿普通程序举例,如果是库依赖,要获取版本,只要在可以运行的环境下,检测当前环境库的版本,记录即可,这样做的缺点是记录的库版本并不一定是最低需求版本。如果是可执行程序依赖,确实很多程序-v可以得到版本号,但是这并不是强制标准,其输出的格式也不一样,因此不能用这个方法。

所以,依赖的标注以能依靠开发者或者打包者去提前编写。

我们要解决的问题是,就像你说的,要安装多个版本的依赖,这个暂时还没有实现。

Reply View the author
深圳市耀影科技有限公司
deepin
2022-04-02 17:35
#15
Maicss

依赖有很多种的,比如库依赖、可执行文件的依赖、插件依赖、资源依赖,并非所有的软件包都是标准二进制程序。

如果是普通程序

库依赖好说,使用ldd命令即可获得其依赖库的列表,但是其还可能用到了其他命令,比如wget,比如apt,这些,如果程序中使用了这些命令,我们肯定无法在程序运行前的阶段发现,这时就只能由开发者说明了,这是个例子,说明自动获取需要哪些依赖不是完全可行的。

另外就是依赖版本

还是拿普通程序举例,如果是库依赖,要获取版本,只要在可以运行的环境下,检测当前环境库的版本,记录即可,这样做的缺点是记录的库版本并不一定是最低需求版本。如果是可执行程序依赖,确实很多程序-v可以得到版本号,但是这并不是强制标准,其输出的格式也不一样,因此不能用这个方法。

所以,依赖的标注以能依靠开发者或者打包者去提前编写。

我们要解决的问题是,就像你说的,要安装多个版本的依赖,这个暂时还没有实现。

这个中间层就是要做这个,能够解决这个问题,

我们可以自我一种 原则标准,可以让用户添加,

例如:我们给出 版本号的标准,用户可以自己填上所需版本号,和路径,然后跳入

这个可能是一个长效机制,需要大量的日积月累,这个配置文件可以共享,

社区可以把源码和二进制按规定放到对应版本路径及信息里面,或者其他形式

也不知道可以实现不,我现在所有的软件 就是 编译后路径加版本号, 但是其他一些不同的软件或者依赖形式,也需要慢慢解决,

APT不就是日记月累

Reply View the author
柚子
deepin
2022-04-02 17:58
#16
Maicss

是的,但是Linux发展了这么多年,出现的flatpak,snap,appimage确实是对于这些问题的解决方案。

而且可以确定的是,有些问题不可能完美的解决。他们各自有各自的问题。

但是统一管理的方式我认为已经过时了,倒不是说在整个linux生态发展里过时了,而是在linux桌面环境的发展过程中过时了,当linux不再专一的执行指定任务时,统一的包管理器就展现出了它的弊端。

现在flatpak和snap的方案,确实对用户来说很好,但是对于开发者和打包者的压力稍大。而且容器这中方案也会带来一些麻烦。

appimage解决了大部分问题,我认为最大的缺点就是不方便管理。

appimage是支持增量更新的

https://docs.appimage.org/packaging-guide/optional/updates.html

原理是基于zsync实现的

Reply View the author
深圳市耀影科技有限公司
deepin
2022-04-07 04:55
#17
  • 其实很多软件 提供源码和编译
  • 我们提供一个源,
  • 里面放上各个编译成功的二进制和源码
  • 下载下来环境变量就行啦
  • 我就是在​HOME/opt/src下,所有的源码放这里啦,HOME/opt/bin,然后环境变量软链接这里,
  • 我自己常用的软件我都编译好后放到自己的源里啦,然后需要哪个下载解压就行啦,
  • 这个源是针对DEEPIN系统的
  • 其实我们也可以用压缩包方式,管理各个版本软连等自动引用源二进制版本
Reply View the author
HualetWang
deepin
2022-05-24 01:37
#18

大佬啥时候毕业,来deepin么?

Reply View the author
Maicss
deepin
2022-05-27 04:47
#19
HualetWang

大佬啥时候毕业,来deepin么?

抱歉这几天忙,今天才看到,我还有一年毕业,能去deepin那肯定非常乐意啊blush

Reply View the author
HualetWang
deepin
2022-06-01 19:02
#20
Maicss

抱歉这几天忙,今天才看到,我还有一年毕业,能去deepin那肯定非常乐意啊blush

kissing_heart

Reply View the author