rpm 神器第二篇-multipkg 高阶用法介绍与实战

前言

前一篇文章中介绍了 multipkg 的安装和基本用法,这两天又结合之前的例子,整理了一篇类似于“实战系列”的文档,

详细说明了 rpm 中的一些细节配置在multipkg中怎么写,以便读者能通过multipkg实现rpm/spec的高阶功能;另外,

晚上总结了最近和以前的几个思路,给multipkg加了一些功能,还未合并到作者的master分支,需要使用的同学可以直接从我

的仓库来获取:

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

cd multipkg

git checkout duanjigang1983

即可。

另外,examples/tskeeper 是我新加到其中的一个例子,tskeeper 的index.yaml详细展示了multipkg的配置方法,读者可以参考其写法(源代码是大概10年前

写的,如果有丑陋的地方,请包涵,因为我们的目的是为了展示multipkg的用法,并不是例子代码本身)。

下面,我们结合几个用法展开本文的内容:

rpm 安装空目录

为了能在 rpm 包中自带一个空目录,你需要在 spec 文件中通过这样的语法:

%dir dirname

告知 rpmbuild 这个目录需要保留在rpm文件中,而在multipkg中,spec 文件被封装起来了,如果要在rpm中自带空目录, 该怎么办呢?

查看源代码可以知道,在 multipkg 中,是通过每个目录中的 “.keep”文件来实现空目录保留的。比如:

root/
├── etc
│   ├── pkgaudit.conf
│   └── test.conf
├── usr
│   └── local
│       └── pkgaudit
│           ├── data
│           │   └── readme.txt
│           └── log
│               └── readme
└── var

目录 var 是一个空目录,直接:

multipkg .

编译得到的 rpm 文件通过

rpm -qpl xxx.rpm

命令看到的输出列表中,不包含 "/var"这个目录,如果 :

touch root/var/.keep

后,再次 multipkg 生成 rpm后,就能看到这个目录。

这个功能在multipkg的源码在文件 multipkg/source/lib/Seco/Multipkg.pm 中:

921     if ( -d _ ) {
 922       print $f $rpmattr . "\%dir /$_\n" if ( -e "$path/.keep" );
 923     }
 924     else {
 925       print $f $rpmattr . "/$_\n";
 926     }
 927   }
 928

如果是一个目录,并且其中包含了 ".keep "文件,就增加 “%dir” 语法到 spec 文件中。

读者可以参考我的git fork出来multipkg的例子(branch:duanjigang1983):

ls examples/tskeeper/root/usr/local/tskeeper/ -a
.  ..  .keep

首先,你可以删除 .keep 文件后生成 rpm 包,然后 rpm -qpl xxx.rpm 查看,rpm 包中是否有该目录,应该是没有的。

然后再touch 上.keep文件,编译rpm,进行查看验证。

requires 依赖等

依赖包的问题,直接在 index.yaml中编写就行,比如:

 arch: noarch
    provides:
        - Seco::Multipkg
        - perl-seco-class
        - perl-seco-cpan
    requires:
        - perl-YAML-Syck
        - subversion-perl
        - perl-Git
        - perl-Error

这样的写法,当然 conflicts,provides,requires 和 obsoletes 都支持如此写法。
configfiles 和 docfiles

configfiles 在 multipkg 中已经有支持,只不过原作者并未提供例子,在对代码进行分析后,我们得到了配置文件的书写语法。

如果在index.yaml中不添加files:这一项的话,所有安装的文件,multipkg都会把其添加到files列表中,默认属性是 :

%default(-,root,root)

比如,一个工程中,multipkg生成的 spec 文件如下:

%files
%defattr(-,root,root)
/usr/local/pkgaudit/log/readme
/usr/local/pkgaudit/data/readme.txt
/etc/pkgaudit.conf

/etc/test.conf
/etc/service/pkgaudit/run
/etc/service/pkgaudit/log/run
%dir /var

这时,/etc/test.conf 和 /etc/pkgaudit.conf 并不是conf 文件,因此通过:

rpm -qp xxx.rpm --configfiles

并不能看到任何配置文件输出。

这时,如果要把 某个文件加入到配置文件列表中,就需要在 index.yaml 中增加 files: 项了,格式如下( 仍以 tskeeper 为例):

 requires: ## tskeeper requires 'procps' and daemontools to be installed firstly
    - procps
    - daemontools
  provides:  ### The package 'tskeeper' will provide something named as 'tskeeper-examples' and 'cmesoft-tskeeper'
    - tskeeper-examples
    - cmesoft-tskeeper
  conflicts: ### sorry, i am conflicted with some rpms such as 'other-task-keeper' and 'all-task-keeper',
    - other-task-keeper
    - all-task-keeper
  obsoletes: ## when u want to install old-tskeeper with 'yum install old-tskeeper', you will get me -'tkeeper' ^_^
    - old-tskeeper
    - taskeeper
  files:
    - "/etc/test_conf1.conf":  ##just set attributes of this file, but not a configfile
        group: "root"
        perm:  "0666"
        owner: "root"
    - "/etc/test_conf2.conf":
        group: "root"
        perm: "0777"
        owner: "nobody"
        config: "no" ## no matter what this value will be, 'config' tells multipkg 'please set me as a config file'
    - "/etc/proclist.ini":
        group: "root"
        perm: "0666"
        owner: "root"
        config: "yes" ## no matter what this value will be, 'config' tells multipkg 'please set me as a config file'
    - "/var/doc/tskeeper":
        group: "root"
        perm: "0444"
        owner: "root"
        doc: "xxoo"  ## yes, 'doc' is a newlly-added feature for multipkg

生成 rpm 文件后,可以看到 configfiles 为:

/etc/proclist.ini
/etc/test_conf2.conf

docfiles 为:

/var/doc/tskeeper

说明:docfiles这个属性支持属于新增加到multipkg中的功能,作者master分支中尚不支持。

接着,配置文件的 perm, owner 和 group 在安装后会如配置中填写的一样,如果你只是想设置某个文件的属性,而不想将其配置为config(也就是说在

包升级或者卸载时老的配置文件会保留),你可以删除 config: "yes"这项(注意 config:"xx",xx可以是任何值,他只是个标志,并无特殊意义),

比如,去除 /etc/test_conf2.conf 的 config: "yes"项后,

再次通过 --configfiles 查看rpm包时,就看不到 /etc/test_conf2.conf这个配置文件了。但是,有一点要注意,attributes 还会继续生效。

另外,config 类型的文件已经默认有了 noreplace 属性了,不需要再在spec中或者 index.yaml 文件中添加。

configfiles 更新原则

配置文件更新的原则是:

(1) 升级/安装一个package 时,如果老的配置文件不存在或者无修改,则生成新的配置文件,或者替换老的配置文件。

(2) 升级时,如果老的配置文件有改动,而新包中的配置文件和老包中自带的配置一样的话,使用老的修改了的配置文件,不安装新包中的配置文件,

而且 rpm -qf  查询时,老的配置文件属于新版本的rpm包。

(3) 升级时,如果配置文件有更新,而老的配置文件又被修改了,那么老的修改的配置文件会被更名为 “配置文件名称.save”以做保存。

(4)卸载时,配置文件保存为 “配置文件名.save”,不做删除。

输出或者定制 spec 文件

 multipkg 生成 rpm 并不需要使用者编写spec文件,但是其自身还是依赖spec文件的,所以,在build rpm 的过程中,必然有 spec文件生成。

我们可以看下 multipkg 的帮助:

-f, --force          Force build on sanity-check failure
-h, --help           Display this help
-k, --keep-files     Keep files after build
-p, --platform       Include this platform
-s, --set            List of variables to set
-t, --testbuild      When building from a work dir, not source control
-v, --verbose        Be verbose

其中 -v -k 就能看到spec文件,比如:

# multipkg -v -k examples/tskeeper

可以看到:

INFO: RUNNING: INSTALLROOT=/tmp/vCfqjg2WVR/install rpmbuild -bb --define '_topdir /tmp/vCfqjg2WVR/rpm/rpmtop' --buildroot /tmp/vCfqjg2WVR/install /tmp/vCfqjg2WVR/spec

然后自己打开:

/tmp/vCfqjg2WVR/spec

这个文件,你一定会恍然大悟的。注意这个路径是随机的,应该参考命令行输出去获取。

另外,multipkg 在build 时,其实是基于一个spec模版文件来生成每个package的spec文件的,这个模版在

源码中的路径为:

root/usr/share/multipkg/templates/spec.template

看了之后,你一定会对 multipkg的原理又有更深的了解了。

请留意本版本中本人对spec.template的修改(description, group, packager 等字段)

关于rpm文件的description属性(新增加功能)

在rpm中,读者可以通过大量文本内容来描述他的rpm包,但是在 multipkg中始终还未支持这个属性的配置,反而采取了较为简单的

作法,配置 description的内容为summary的内容,这个通过spec.template中的:

%description
%summary%

看到,所以,你通过 multipkg 制作的rpm,在 -qpi 查看时,总能看到 summary 和 description 是相同的。

虽然 Desc 不是 rpm 的核心,但是总是影响雅观的,所以,我在multipkg中增加了 setdesc 函数,使得用户在index.yaml中

既可以配置其为一个 字符串,也可以配置其值为一个命令的执行结果(不知道这个功能会不会被人诟病)。

具体说明是:

A: 字符串

 配置

description:"this is a description"

你通过

rpm -qpi xxx.rpm

看到的 description 就是 "this is a description"这个内容。

B: 配置为命令

配置为命令时,rpm -qpi xx.rpm 看到的 desc 的内容就是命令执行的结果,一般建议配置为打印desc文件的内容,比如你可以写:

description:"cmd:cat /source/desc.txt"

注意格式为:

[description:"命令关键字(cmd):命令内容"]

如果没有"cmd:"开头,multipkg 就会认为是情况A(字符串)。

建议:在实际中不要配置description为乱七八糟的内容,比如:

description:"cmd:hostname,ps aux;"

并没啥意思,因为 multipkg 会把 build 机器的 hostname 和 ps aux 命令的结果作为desc 的内容。

另外,如果有文件操作,参数如果是相对目录,那么 默认 当前目录是你的工程的根目录,这个一定要注意。

比如:

# multipkg  /root/multipkg/examples/tskeeper

tskeepr 的 description 为:

description: 'cmd:cat source/desc.txt;hostname'

build rpm包时,

"cat source/desc.txt"

会在

/root/multipkg/examples/tskeeper

目录下去找

"source/desc.txt"

文件。

后记

关于 multipkg 的使用配置和一些功能细节就介绍到这里,如果您还有更好的建议或者使用,开发的问题,欢迎与我联系: cmesoft@126.com。关于rpm/yum的基础知识,以及rpm管理平台的建设等问题和专业知识可以参考《Linux 软件管理平台设计与实现》一书。

时间: 2024-10-23 05:00:47

rpm 神器第二篇-multipkg 高阶用法介绍与实战的相关文章

Javascript中的高阶函数介绍_javascript技巧

这是一个有趣的东西,这或许也在说明Javascript对象的强大.我们要做的就是在上一篇说到的那样,输出一个Hello,World,而输入的东西是print('Hello')('World'),而这就是所谓的高阶函数. 高阶函数 高阶看上去就像是一种先进的编程技术的一个深奥术语,一开始我看到的时候我也这样认为的. Javascript的高阶函数 然而,高阶函数只是将函数作为参数或返回值的函数.以上面的Hello,World作为一个简单的例子. 复制代码 代码如下: var Moqi = func

手把手教你用永恒之蓝(Eternalblue)勒索病毒漏洞的高阶用法

安装 MSF Linux & Mac OS X 如果遇到问题,点开这个链接,然后自己想想办法-- 查看是否安装成功 然后输入 msfconsole 看看安装是不是成功了-- 这样的话就算成功了. 安装 WINE 和 winetricks Linux OSX 安装 Windows Python 环境 跟着 wizard 走完就行了--一路下一步. 复制工具包到 Windows 分区 默认 WINE 环境的虚拟磁盘在 ~/.wine/drive_c 把那个工具包里的 windows 文件夹改个名字,

iOS 10 推送高阶篇(必看)_IOS

推荐阅读: iOS10推送之基础知识(必看篇) 这篇文章开始,我会跟大家好好讲讲,苹果新发布的iOS10的所有通知类. 一.创建本地通知事例详解: 注意啊,小伙伴们,本地通知也必须在appdelegate中注册中心,通知的开关打不打开无所谓的,毕竟是本地通知,但是通知的接收的代理,以及通知点击的代理,苹果给合二为一了.所以大家还是需要在appdelegate中写上这2个方法,还有不要忘记在- (BOOL)application:(UIApplication *)application didFi

上海交大CS系博士生李泽凡:利用高阶残差量化(HORQ)方法进行网络加速

本文讲的是上海交大CS系博士生李泽凡:利用高阶残差量化(HORQ)方法进行网络加速, 神经网络的压缩和加速现在已经成为一个热门课题,这个领域有多种研究方法,网络量化就是其中之一.网络量化分为输入量化和权值量化两种.而同时将输入和权值量化会造成网络精度的大幅下降.在Performance Guaranteed Network Acceleration via High-Order Residual Quantization (性能保障的高阶残差量化网络加速方法)一文中,作者针对这个问题,提出了高阶

函数式接口、默认方法、纯函数、函数的副作用、高阶函数、可变的和不可变的、函数式编程和 Lambda 表达式 - 响应式编程 [Android RxJava2](这到底是什么)第三部分

本文讲的是函数式接口.默认方法.纯函数.函数的副作用.高阶函数.可变的和不可变的.函数式编程和 Lambda 表达式 - 响应式编程 [Android RxJava2](这到底是什么)第三部分, 太棒了,我们又来到新的一天.这一次,我们要学一些新的东西让今天变得有意思起来. 大家好,希望你们都过得不错.这是我们的 RxJava2 Android 系列的第三篇文章. 第一部分 第二部分 在这篇文章中,我们将讨论函数式的接口,函数式编程,Lambda 表达式以及与 Java 8 的相关的其它内容.这

Mapper映射语句高阶应用——ResultMap

    resultMap 元素是 MyBatis 中最重要最强大的元素.它就是让你远离 90% 的需要从结果 集中取出数据的 JDBC 代码的那个东西 , 而且在一些情形下允许你做一些 JDBC 不支持的事 情. 事实上 , 编写相似于对复杂语句联合映射这些等同的代码, 也许可以跨过上千行的代码. ResultMap 的设计就是简单语句不需要明确的结果映射 , 而很多复杂语句确实需要描述它们 的关系.     我们通过一个连续的例子,来逐步讲解 ReusltMap .     要进行 Resu

F#教程:高阶函数

所谓高阶函数就是将某个函数作为输入参数或者返回值的函数.从名字上来看挺难理解的,不过从C#的角度来看就是传入或返回delegate之类的. 在我们自己定义高阶函数之前我们还是先学会使用高阶函数. List中定义了很多高阶函数,这回就学习下其中的几个.首先试下find函数. let list = [15; 7; 8; 3; 6; 10] let even n = n % 2 = 0 let x = List.find even list printfn "%A" x 其中,find的第一

F#教程-定义高阶函数

目前为止我们已经尝试写了些高阶函数代码.这回我们学着定义如下高阶函数: f(g,a) = g(g(a)) 该函数在得到函数g和传入g的参数a后计算g(a),并将结果作为再次调用函数g的参数.语言描述确实很复杂. F#表示如下: let f g a = g (g a) 使用Pipeline就可以改写成: let f g a = g a |> g C#的话可能会像这样: public T f<T>(Func<T,T> g, T a) { return g(g(a)); } F#就

Javascript 高阶函数使用介绍

  高阶函数(higher-order function)-如果一个函数接收的参数为或返回的值为函数,那么我们可以将这个函数称为高阶函数.众所周知,JavaScript是一种弱类型的语言:JavaScript的函数既不对输入的参数,也不对函数的输出值作强定义和类型检查,那么函数可以成为参数,也可以成为输出值,这就体现了JavaScript对高阶函数的原生支持. 一.参数为函数的高阶函数: ? 1 2 3 4 5 6 function funcTest(f){ //简易判断一下实参是否为函数 if