专业 rpm 包制作神器 multipkg 介绍

简介: 前言      rpm 包是linux 上比较常见的软件包组织格式;其安装,升级,卸载过程都比较简易,容易上手。但是,由于rpm的灵魂-spec 文件,其格式,语法不太容易理解,或者有些复杂,导致不少 SA, Pe 或者 开发人员,对于“晦涩”的 SPEC 文件编写却敬而远之,结果不少人就放弃了通

前言



     rpm 包是linux 上比较常见的软件包组织格式;其安装,升级,卸载过程都比较简易,容易上手。
但是,由于rpm的灵魂-spec 文件,其格式,语法不太容易理解,或者有些复杂,导致不少 SA, Pe 或者 开发人员,对于“晦涩”的 SPEC 文件编写却敬而远之,结果不少人就放弃了通过 rpm 去管理软件包。转而投靠 scp/rsync 文件复制, tgz压缩包,git,或者一股脑打包进docker 镜像的方式来管理软件。不管长江后浪如何来势汹汹,经典的 rpm 格式软件包依然是如今系统管理的主流软件管理方式,今天仍然值得技术人员去研习,掌握。

multipkg 的出现


  虽然鄙人曾编撰过一本《Linux 软件管理平台设计与实现》的技术书籍,其中以庖丁解牛的方式,大谈特谈了 rpm 是怎么组成的,从协议组成,字段,源码等等,把 rpm 大卸八块,然后又把spec文件,yum的原理等XX了一遍又一遍,觉得 rpm 和 yum 在我面前,基本已经体无完肤,摇摇欲坠,一览无余。 但是,时至今日,当有人来找我问我:我想搞个RPM,你帮我看下spec 怎么写?我依然会果断的回复:“我不会,自己搞去”。
     确实是的,你不可能天天都记得 spec 怎么写,除非你是SCM同学,于是乎,我们开始寻找一种不需要spec 文件的 rpm 制作方式(可能吗?),或者有无能避开spec编写的rpm制作工具? 答案不用猜,肯定是有的,那就是 multipkg(雅虎系有很多好用而朴实的工具):
https://github.com/ytoolshed/multipkg

multipkg 的安装

直接参考官方文档(注意,确保你的机器能连接到公网):
以下部署过程,在centos5,6,7 上都得到验证。


git clone https://github.com/ytoolshed/multipkg.git

cd multipkg

yum install perl-YAML-Syck perl-ExtUtils-MakeMaker

PREFIX=./root PKGVERID=0 INSTALLDIR=source scripts/transform
perl -I ./source/lib root/usr/bin/multipkg -t .

sudo yum -y install multipkg-*rpm

rm multipkg*rpm

git-multipkg -b https://github.com/ytoolshed/ multipkg

sudo yum upgrade ./multipkg*rpm



注意:对于6u的系统,subversion-perl-1.6.11 这个依赖包不好找,需要关注下。

我们都知道,rpm 包从生成过程来比较,分为两类:一类是需要源码编译生成二进制文件的格式,另外一种是不需要源码编译(直接压缩源码)形成的软件包;前者包括 c, java等语言开发的程序,而后者则是一些直接解释,不需要编译成中间代码的语言编写的程序,比如shell,python或者ruby等
语言写的程序。因此,本文,在讲述multipkg的用法时,会介绍到这两种不同生成过程的 rpm 包的构建方法。

multipkg 的工作原理


 multipkg 并没有按照 rpm 的格式去写一个rpm文件(《linux软件管理平台设计与实现》第一章中讲到的协议),因为那样做确实太复杂了,像其他工具一样, multipkg在制作rpm格式的软件包时,是基于rpmbuild命令来实现的。也就是说,准备好源码,spec文件,然后放到合适的目录中,调用rpmbuild命令,就编译生成 了rpm文件。只不过multipkg把rpmbuild+spec文件这种做包方式用的更优雅些,因为你不需要去关注spec文件,也不需要去关注编译rpm文件的目录,而只需要关注你的源码和编译时hook脚本即可。
     multipkg工作的大致原理是:通过 index.yaml 文件来提供SPEC文件中的所有tag,比如name,version,require,config等信息, 然后通过scripts/目录下的post.sh,pre.sh,postun.sh,preun.sh这四个脚本,来存储rpmbuild时在安装前后,卸载前后执行的脚本内容。 最后,root目录提供了rpm的文件列表的一部分(因为scripts的脚本中可能会动态创建文件)。
source 或者源码压缩包提供了源码。
这时,构建rpm的因素就足够了。 spec 文件由 index.yaml 文件和scripts 构成。 对于需要编译类的工程,源码压缩包或者source 目录中的文件提供了源码。

对于不需要编译类的工程,root 中的文件直接提供了rpm的文件列表和安装路径。 这样,在编译时,先通过index.yaml和scripts中的文件替换spec文件模板,生成该工程用的spec文件,然后调整源码和spec文件的目录,调用 rpmbuild命令,作用于源码和spec文件,就形成了rpm包。

multipkg 的目录结构

对于需要编译类的工程,一般就是 index.yaml,scripts/*.sh 和source目录(或者源码包 xxx.tar.gz),例如repobuilder这个工程的目录结构如下:


tree repobuilder/
repobuilder/
├── index.yaml
├── scripts
│   ├── build
│   ├── preun.sh
│   └── run
└── source
    ├── cmthread.c
    ├── colordefine.h
    ├── configserver.c
    ├── configserver.h
    ├── daemon.c
    ├── datadef.h
    ├── inihelper.c
    ├── inihelper.h
    ├── loghelper.c
    ├── main.c
    ├── Makefile
    ├── nethelper.c
    ├── nethelper.h
    ├── os_independent.h
    ├── repo.conf
    └── tags




其中index.yaml的内容如下:


---
default:
  name: repobuilder
  requires:
    - createrepo >= 0.4.11
  summary: muti-thread tasks to update repo of yum server
  version: '1.1.0'
  release: '1'
  group: 'xx'
  packager: 'xxxxx'
  license: 'xxxxx'
  #the multipkg do not support config file for rpm-->need update
  keepopt:
      - %config(noreplace) /etc/repo.conf
      - %defattr(-,root,root)
      - %attr(0777 nobody nobody) /etc/repo.conf



scripts/build 的内容如下:

#!/bin/sh
make clean || exit 1
make || exit 1
mkdir -p $DESTDIR/etc/service/repobuilder
mkdir -p $DESTDIR/usr/bin/
install repobuilder $DESTDIR/usr/bin/
install repo.conf $DESTDIR/etc/

又比如wget 工程的目录结构如下:


tree wget/
wget/
├── index.yaml
├── root
│   └── etc
│       └── wget.conf
├── scripts
│   ├── build
│   ├── post.sh
│   └── preun.sh
└── wget-1.14.tar.gz

其中build的内容就是spec中build段的内容,如下:


#!/bin/sh
exec 2>&1 >/tmp/build.log
./configure --prefix=/usr/local/wget --with-ssl=openssl
make
make install
对于不需要编译类的工程,就更简单了,只需要在root目录中放置你的文件即可,比如 pkg-release 这个包就是如此:
tree pkg-release

输出如下:

pkg-release
├── index.yaml
└── root
    ├── bin
    │   └── pkgrelease
    └── etc
        └── pkgrelease.conf


运行命令:

multipkg pkg-release 
后,生成文件
pkgrelease-1.1.0-1.noarch.rpm
通过命令:

rpm -qpl pkgrelease-1.1.0-1.noarch.rpm
查看该rpm文件包含的文件列表为:

/bin/pkgrelease
/etc/pkgrelease.conf
从上面的结构你应该已经看到了, 在源码目录中,root目录就类似于安装机器的 “/” 目录,这样,在root下怎么存放文件,你的rpm将来就怎样安装到目标机器上去。


使用举例

还是举两个例子,一个是源码编译工程,一个是不需要编译的脚本构成的工程。

源码编译工程


repobuilder 工程的目录树如下:


├── index.yaml
├── scripts
│   ├── build
│   ├── preun.sh
│   └── run
└── source
    ├── cmthread.c
    ├── colordefine.h
    ├── configserver.c
    ├── configserver.h
    ├── daemon.c
    ├── datadef.h
    ├── inihelper.c
    ├── inihelper.h
    ├── loghelper.c
    ├── main.c
    ├── Makefile
    ├── nethelper.c
    ├── nethelper.h
    ├── os_independent.h
    ├── repo.conf
    └── tags
其中source 下的文件就不再重点介绍,是一个标准的C工程,着重看下index.yaml和scripts中内容:

index.yaml:

---
default:
  name: repobuilder
  requires:
    - createrepo >= 0.4.11
  summary: muti-thread tasks to update repo of yum server
  version: '1.1.0'
  release: '1'
  group: 'xxxx'
  packager: 'xxxx'
  license: 'xxxx'
  #the multipkg do not support config file for rpm-->need update
  keepopt:
      - %config(noreplace) /etc/repo.conf
      - %defattr(-,root,root)
      - %attr(0777 nobody nobody) /etc/repo.conf

能看到基本的信息,name,version,release,requires等,requires可以写多行,标示依赖多个包,
需要注意的是keepopt目前在multipkg中还不支持,这几天我会参考以前的代码,尝试把这个功能加进来。 然后看下scripts中的文件:

build:


#!/bin/sh
make clean || exit 1
make || exit 1
mkdir -p $DESTDIR/etc/service/repobuilder
mkdir -p $DESTDIR/usr/bin/
install repobuilder $DESTDIR/usr/bin/
install repo.conf $DESTDIR/etc/

很简单,就是编译,安装。和spec文件中内容一样。


preun:

#!/bin/bash
if [ "$1" = "0" ]; then
        rm /service/repobuilder || exit 1
        /usr/local/bin/svc -dx /etc/service/repobuilder /etc/service/repobuilder/log || exit 1
fi

注意 “$1 = 0”这个判断,在书中,已经说过,preun的第一个参数为0标示是卸载,否则是升级。
删除安装的服务目录。

run:
multipkg中scripts/run这个脚本比较特殊,是服务启动脚本,也就是自启动脚本,所以,只需要把你
的脚本main函数,或者运行主体脚本保存为scripts/run即可,比如repobuilder的例子,或者,你也可以写出如下的scripts/run:

#!/bin/bash
while true
do
    sleep 5
    date
done
都是可以的。当rpm安装后,这个run的安装路径是:/etc/service/repobuilder/run 也就是说,scripts/run脚本,会为每个想要自启动的脚本添加一个服务目录,路径为:/etc/service/xxx
这个动作,和“服务”这个说法比较一致,既然是“自启动”,那么就认为其为一个“服务(service)”,所以把
运行脚本存储在“/etc/service”下,这种设计比较人性化,容易理解。



 脚本/不需编译类工程

这种工程比较简单,只需要理解 root目录的作用就OK了,看下pkgaudit这个工程的目录结构和文件列表,你应该就明白 你的root目录应该怎么存储了:
目录结构:

tree pkgaudit/root/
pkgaudit/root/
├── etc
│   └── pkgaudit.conf
└── usr
    └── local
        └── pkgaudit
            ├── data
            │   └── readme.txt
            └── log
                └── readme
文件列表:

rpm -qpl pkgaudit/pkgaudit-1.0.0-3.noarch.rpm
/etc/pkgaudit.conf
/etc/service/pkgaudit/log/run
/etc/service/pkgaudit/run
/usr/local/pkgaudit/data/readme.txt
/usr/local/pkgaudit/log/readme

两种情况都包括(源码编译+脚本类)

这类情况下,目录结构也比较简单,你可以认为是在源码编译工程下面添加一个root目录即可,不过这时, 你的rpm中包含的文件列表由两部分组成:build安装的文件和root中包含的文件。读者可以自己测试这种情况,并且查看 最终生成的rpm包含的文件列表信息。

关于example

发现原 project 自带的例子有些问题,就把我以前自己做的一个程序做了个example作为附件传上来。
为了在例子中尽可能多的普及 multipkg 的用法和 rpm 的一些知识,我们在 index.yaml 文件中写了很多“无用的例子”,如下:

default:
  name: tskeeper
  version: '1.0.0'
  release: '2'
  packager: 'anyone'
  summary: 'adding tskeeper as an example of multipkg'
  group: ''
  license: 'public'
  arch: 'x86_64'
  requires:
    - procps
    - daemontools
  provides:
    - tskeeper-examples
    - mamimamihong-tskeeper
  conflicts:
    - other-task-keeper
    - all-task-keeper
  obsoletes:
    - old-tskeeper
    - taskeeper
  files:
    - "/etc/test_conf1.conf":
        group: "root"
        perm:  "0666"
        owner: "root"
    - "/etc/test_conf2.conf":
        group: "root"
        perm: "0777"
        owner: "nobody"
        config: "no"
    - "/etc/proclist.ini":
        group: "root"
        perm: "0666"
        owner: "root"
        config: "yes"
    - "/var/doc/tskeeper":
        group: "root"
        perm: "0444"
        owner: "root"
        doc: "xxoo"

进入 tskeeper 目录,当 multipkg 安装好以后,你就可以自己制作包了:

multipkg .
tskeeper-1.0.0-2.x86_64.rpm
然后可以通过 rpm 的命令来查询这个包的信息,与 index.yaml 文件对比:

# rpm -qp tskeeper-1.0.0-2.x86_64.rpm --provides
tskeeper
mamimamihong-tskeeper
tskeeper-examples
tskeeper = 1.0.0-2
tskeeper(x86-64) = 1.0.0-2

# rpm -qp tskeeper-1.0.0-2.x86_64.rpm --requires
procps
daemontools
/bin/sh
/bin/sh
rpmlib(FileDigests) <= 4.6.0-1
rpmlib(PayloadFilesHavePrefix) <= 4.0-1
rpmlib(CompressedFileNames) <= 3.0.4-1
rpmlib(PayloadIsXz) <= 5.2-1

# rpm -qp tskeeper-1.0.0-2.x86_64.rpm --conflicts
all-task-keeper
other-task-keeper

# rpm -qp tskeeper-1.0.0-2.x86_64.rpm --obsoletes
old-tskeeper
taskeeper
关于docfiles 和 configfiles,在我自己的branch中增加了代码通过
config: "yes/no" 或者 doc:"yes/no"
来控制是否为doc或者config文件,所以,在 tskeeper 例子中,通过作者原生 multipkg 生成的包,是看不到这些字段控制产生的效果的。

文末说明

说明:如果没看懂或者还有啥疑问,可以问我,或者买本我的书来学习《Linux 软件管理平台设计与实现》 ^_^
相关文章
|
4月前
|
定位技术
MicroStation软件与Terrasolid插件合集的安装方法
MicroStation软件与Terrasolid插件合集的安装方法
|
4月前
|
Java Linux Shell
Linux安装包制作
Linux安装包制作
44 0
|
10月前
|
IDE 编译器 开发工具
统信UOS系统开发笔记(四):从Qt源码编译安装之编译安装QtCreator4.11.2,并配置编译测试Demo
上一篇已经从Qt源码编译了Qt,那么Qt开发的IDE为QtCreator,本篇从源码编译安装QtCreator,并配置好构建套件,运行Demo并测试。
|
10月前
|
芯片
统信UOS系统开发笔记(三):从Qt源码编译安装之编译安装Qt5.12.8
上一篇,是使用Qt提供的安装包安装的,有些场景需要使用到自己编译的Qt,所以本篇如何在统信UOS系统上编译Qt5.12.8源码。
统信UOS系统开发笔记(三):从Qt源码编译安装之编译安装Qt5.12.8
Photoshop 2019软件安装包+安装教程(所有系统大合集)
Adobe Photoshop 2019简称“PS 2019”,是最强大的图像编辑处理软件。是平面设计行业首选的软件,拥有所有最先进的编辑,合成和绘画功能,该软
|
数据安全/隐私保护 开发者 Python
|
存储 数据库 图形学
CorelDRAW2023版软件汉化补丁包下载CDR23专业矢量软件
CorelDRAW2023中文版是专业矢量软件中的最老牌大哥,功能强大没说的,此外它还集成了Corel PHOTO-PAINT、Corel Font Manager等在内的7个软件包。而且对比于illustrator和freehand,CorelDRAW更为简单易上手设计工具,具有行业标准文件兼容性,支持.DWG、.STL、.PDF和.CDR,具有省时协作和项目共享、自动化和自定义选项等优势,你可以自由的进行绘图环境的设置,可以应用单位、图形边界、网格和捕捉设置,并将这些设置存储在样板图形中。cdr2023下载:http://t.csdn.cn/t8wDL
975 18
|
人工智能 文字识别 小程序
Python小应用 百度接口实现图片文字识别,并打包成安装包软件
整体是用Python实现,所需要使用的第三方库包括aip、PIL、keyboard、pyinstaller,如未安装,可在CMD中使用pip install Baidu-AIP/pillow/keyboard/pyinstaller指令安装。
Python小应用 百度接口实现图片文字识别,并打包成安装包软件
|
Windows
会声会影2022安装包下载功能简介
会声会影2022版本更新了大量新功能,优化了过去的不足,使用户更容易操作和制作视频,处理效果得到了质的提高。我相信很多用户也使用了会声会影系列软件。
199 0
|
Web App开发 JavaScript 网络安全
用jekyll制作高大上的网站(一)——安装与配置
很多人会制作自己的主页,页面美观简洁,一直很在意是怎么做的。 最近公司需要做个文档库的主页,就研究了一些开源的工具,后面发现了jekyll(读杰克尔),将纯文本转换为静态博客网站。
用jekyll制作高大上的网站(一)——安装与配置