Monday, March 22, 2010

where conary is different from slackware

[This is a reply to Grissiom post about slackware's package-management]

Foresight LinuxSlackware Linux 的根本不同在于两者的定位不同,Foresight 的目标是一个简单易用的桌面系统,而 Slackware 应该是给 geek 用的。所以,好多争论其实是没有意义的。

而 conary 跟 slackware 的包管理,也有着完全不同的目标。conary 的重点在于自动化(automatic),跟 slackware 是背道而驰。所以对两者的比较只能是技术上的讨论,无法说谁优谁劣。

下边是具体内容。

管理文件就不用说了,每一个包管理都有这个功能 (否则可以称之为 Windows)。

依赖处理
======
Slackware 是不处理依赖的,而 conary 就强在处理依赖上。conary 把整个系统都归在自己的管理下,不仅能处理单个包的依赖,还能保证整个系统都处于 consistent 的状态。

能做到这一点,是因为 conary 里面 group 的概念。一个 group 本质上只是包含一堆包的一个包。注意,对 conary 来说,group 也是一个软件包。能对普通包进行的操作,也能在 group 上进行。而基于 conary 的发行版,其整个系统是由一个 group 定义的,通常叫做 group-什么什么-dist,比如 group-gnome-dist (定义 GNOME 版 Foresight 的 group)、group-xfce-dist (定义 XFCE 版 Foresight 的 group)。正因为此,conary 能够管理整个系统,使得系统范围内的依赖关系都是良好的。

另外一点,conary 是在文件级别处理依赖的 (跟 slackware 是两个极端)。上篇文章提过了,这里不再赘述。

自动还是不自动?
============
可以看出,slackware 进行各种操作主要是靠用户运行各种(自创或者外来的)脚本。毫无疑问,这样非常"爽",符合 hacker 精神 (我也喜欢 :-)。

不过这种方式对于系统管理员 (要维护大量的机器) 来说,无疑是个噩梦,会"极大的束缚生产力"。作为一个 SA,他必须为自己的各种任务创造各种各样的脚本,或者从别的 SA 那借鉴一些轮子 (因为大家的许多任务还是差不多的嘛)。这些脚本或者命令都是人工管理的,维护成本会很高。如果 SA 跳槽了,新来的 SA 八成是个杯具...

与此相反,conary 的设计哲学是,common 的情景都由它来做,然后 SA 把需要特殊注意的事情说明白,就行了。所以在 conary 系统上,会看到各种操作都是能简单就简单,能用模板就用模板。

举例来说
======

比如打包的时候,许多软件都是同样的 configure; make; make install,所以 conary 提供了一个 recipe template,叫 AutoPackageRecipe,表示用 autotools 来打包的软件就可以用这个模板。只需要给 conary 一个 tarball,它会自动调用模板里定义的 Configure/Make/MakeInstall 函数来打包。请参考 Foresight Linux 的 automake 包。注意它根本没有指明如何 make、如何 install。

再举一个极端的例子。用于指定 tarball 位置的 URL,原则也是能简则简:

* 添加一个tarball,用 addArchive 函数。'正常'的写法是:
addArchive('ftp://ftp.gnu.org/gnu/automake/automake-1.11.tar.bz2')

* 如果遵循好的编程习惯,最好写成:
addArchive('ftp://ftp.gnu.org/gnu/automake/automake-%(version)s.tar.bz2')

* 但是,其实只需要一个目录,conary 会自动去找压缩包:
addArchive('ftp://ftp.gnu.org/gnu/automake/')

* 其实... conary 能识别一系列的 mirror (/etc/conary/mirros/),所以只需要这样就行了:
addArchive('mirror://gnu/automake/')
或者 addArchive('mirror://gnu/%(name)s/')

这只是一个细节问题,但它反映了 conary 行事的惯例。上边的例子同样可以参考 automake 包

常用操作
=====
可以看到,slackware 中许多操作都是'简单'的 grep/find 等命令的组合,而 conary 系统中,则是用 conary 提供的一系列命令。conary 提供了命令行的接口,以方便 scripting;而且也提供 API 接口,可以在代码中调用,比如 PackageKit 的 conary 后端,注意这一行
from conary import dbstore, queryrep, versions, updatecmd

在命令行下:
* 查询一个 package 包含了哪些文件
conary query gedit --ls

* 查询某个文件是由哪个包提供的
conary query --path /usr/bin/gedit

* 查询一个包有哪些依赖,提供了哪些依赖
conary query --deps gedit

* 检查一个包是不是完好无损
conary verify gedit

* 查询源里边包的信息
conary repquery gedit

等等...

关于回滚
=====
回滚只是 conary 细粒度依赖处理的一个表现而已。conary 能保证系统处在一个已知的、确定的状态中 (consistent),回滚无非是在当前状态跟上一个状态的转变。

比如安装了一个包(volti),它同时带来了好多依赖(pyalsaaudio, python-xlib)。稍后的回滚能撤销整个操作,也就是不仅会删除 volti,随它而来的 pyalsaaudio 和 python-xlib 也会被同时删除。再比如系统范围的 updateall,被回滚的话,会被整个撤销。在其他的包管理下,就只能来个 for 循环,统统 downgrade 回旧版本了。

conary 提供了 sync 命令,能把一个包同步到某个版本去。注意 group 也是一个包,所以如果 sync 的对象是 group-x-dist 的话,能保证整个系统都处于指定版本上。软件包的任何损坏 (比如不同版本的库被错误安到了一块),都可以侦探出来 (上边提到的 conary verify),都可以修复。这个特点是简单粗暴的卸载重装无法比拟的。

"Each one uses different package formats that cannot understand each other"
=======
conary 能够理解 rpm 和 deb 格式,能够把这些格式的包转换成 conary 系统可用的包。比如这个 linuxqq 的包,是直接用了腾讯发布的 rpm 包 (没有经过再次编译)。比如这个 picasa 包,是用了 deb 包,也没有再次编译。比如这个 libgnome 包,用了 src.rpm,利用 rpm 的 spec,重新编译形成 conary 包。

Sunday, March 7, 2010

what's good about conary

试图总结一下 conary 到底有什么独特之处... 不过我对其他的包管理不是很熟悉,所以不太好总结。

这样,以下内容基本上是这篇文章的意译。

包管理,也就是管理系统上所有其他软件的一个软件。但 conary 不只是一个包管理软件,更是一个强大的对软件系统的版本管理系统。

===========
第一个问题,如何组织软件源(repository)

在 deb/rpm 系统上,一个 repository 无非是某个服务器上的一个目录,其中存放着软件包(一些文件)。文件的命名无非就是"软件名",加上"软件版本"(当然一般还有其他部分,稍后再提)。

问题来自于文件的命名是任意的,手动的。比如有两个软件源,都提供了firefox-3.0 这个包,那么包管理就会搜索到两个"相同"的包,可能产生冲突。

而 conary 不这样处理软件源,conary 的 repository 并不是一个静态的目录,而是一个有版本的动态的分支。整个软件源都是处在版本控制下的,随着其中软件的更新,不断的向前发展,而不是像磁盘文件系统上的一个目录,新版本的文件会覆盖旧文件。

当然,conary 里面的包名字也必须有好几个部分,比如名字加版本。但这些都是由 conary 自动管理,没有手动的过程,conary 能保证两个不同的包,用户能识别出它们确实是不一样的。比如有两个 deb 的源,apt.joeschmoe.com 和 apt.joesmith.com,它们有同一个版本的 liferea,那包名可能是一样的,就会有问题,而 conary 不会遇到这个矛盾,因为,软件源的域名其实也是包名字的一部分。

如果 deb 要以域名来辨别不同的包,那只能把域名写到文件名里面,结果必然是,软件包的名字变得特别长。正因为 conary 下的“包”并不是以文件形式存在的,才能做到上边这一点。

而问题没有到此为止,一般发行版会支持多个硬件平台 (至少有 32 位或 64 位之分吧)。deb/rpm 的做法是什么?只能把 arch 写进文件名里面。结果就是这样的,liferea-1.2.2-2.el5.rf.x86_64.rpm。能看出跟 liferea-1.2.2-2.el5.rf.x86-64.rpm 的区别吗?

conary 也需要支持不用的 arch,包名字也会包含 x86, x86_64 等等。但由于 conary 的“自动管理”,默认情况下这些额外信息是被隐藏的。有时候一个简单的"liferea"就能识别一个包,有时候需要 "liferea=1.0"才能识别, 有时候需要 "liferea=foresight.rpath.org@fl:2-devel" (以区别 "liferea=foresight.rpath.org@fl:2-qa", 或者 "liferea=jesse.rpath.org@fl:2-devel"),有时候甚至需要"liferea=foresight.rpath.org@fl:2-devel/1.7.3-0.1-2",而这就是 conary 里面包的 full-name 的样子。

===========
正由于以上这些,conary 不需要复杂的 sources.list。如果你想从我的个人软件源安装 liferea,在 deb 世界里需要把我的源添加到 sources.list 里边,这样 apt 才能自动从那里查找更新。

而对于 conay, 只需要安装 liferea=jesse.rpath.org@fl:2-devel,conary 会记住这个源,以后只会从这里查找更新,即使 foresight 的官方源里面有更新的版本,也不会影响你的系统。

===========
细粒度的依赖关系

解决依赖是包管理的另一个基本作用,对于 deb/rpm 来说,依赖是定义在包的层面的,带来的一个问题是,有时候要安装某个包,需要先安装一系列的依赖,它们的体积加起来可能很大。另一个问题是,更新的时候,整个包都要重新下载,而好多时候这是不需要的,比如 man page 和一些图片,可能并没有任何变化。

conary 是在文件层次上解决依赖的,所以,一个包并不依赖于另"一个包",而是依赖某个文件的存在。conary 把包划分成几个部分,比如 :runtime, :doc, 或者 :devel,安装依赖包、更新包都是基于这个子部分的,用不到或没有变化的部分就不用下载。好处是可以节省带宽,节省硬盘空间,节省电力,节省能源...

而且这带来了另一个可能:系统可以定制得很小,能够把不需要的都删掉。比如最近我们在裁减 GNOME Developer Kit 的大小,在脚本里有这一句:

        r.removeComponents(['doc', 'supdoc', 'build-tree', 'devellib', 'devel'],
            'group-gnome-dist')

这样就把所有的文档、开发相关的文件移除了。

当然,deb 和 rpm 也能把一个包划分开 (也就是那些 -devel 包的由来)。问题是,手动。打包的开发者必须在 spec 文件里手动指明哪些文件是 liferea-doc 的,哪些是 liferea-devel 包的。但 conary 能自动完成这些,安装到 /etc 的,一般就是 :config 部分的;在 /user/share/man/ 下的,应该就是 :doc。conary 能识别出 general case 来,开发者只需要做剩下的那一点。

===========
回滚。由于整个系统都是在 conary 的版本管理之下,所以 conary 支持包管理操作的回滚。这个特性是最容易记住的,所以不细说了。

===========
给 conary 打包非常容易,所有的打包过程,都由简短的 python 脚本定义。在我看来,比 rpm 的 spec 文件清晰的多。而且像前面提到的,一般来说,开发者只处理特殊情况就行了,负担会大大减小。

===========
所以,无论对用户还是对开发者,conary 都是个不错的选择。

现在对用户存在的一个大问题呢,就是 conary 还缺少一个足够简单、但又能发挥其威力的前端,PackageKit 是当前的选择,但是还有很多的工作要做。

想进一步了解的话,请登陆 #foresight (freenode)。

一个冷笑话

第n题
请描述 /proc 的作用:

答:proc 文件夹 blah blah blah