在 RPM 规范文件中使用脚本定义版本

Posted

技术标签:

【中文标题】在 RPM 规范文件中使用脚本定义版本【英文标题】:Define Version with script in RPM spec file 【发布时间】:2016-02-19 16:43:41 【问题描述】:

我有一个 RPM Spec 文件,使用 rpmbuild 在 rhel7 上构建,我想在其中使用脚本定义版本。

我在这里读到http://www.techrepublic.com/article/rpmproc-spec-file/,我可以这样做:

%define version 1.2

Version: %version

这里是RPM spec file - Is it possible to dynamically populate a spec file variable,我可以用脚本来定义:

%define whoami %(cmd)

所以我尝试在我的规范文件中这样做:

%define version %(echo "$(sed -n 's|^[ ]*appVersion = "\(.*\)"|\1|p' /fullfilepath/values.txt | sed 's/^\(.*\)-.*$/\1/')")

Version: %version  **Line 23**

但我得到了一个

error: line 23: Empty tag: Version:

到目前为止我测试过的东西:

%define version %(echo "12") --basic script works ok, version becomes 12

//As a command straight in terminal
$ echo "$(sed -n 's|^[ ]*appVersion = "\(.*\)"|\1|p' /fullfilepath/values.txt | sed 's/^\(.*\)-.*$/\1/')"
//returns 1.2

这些运作良好,所以我不知道是什么导致它失败。当我在规范文件的定义标签中调用相同的东西时,有什么想法会导致它失败?

更新

我尝试用实际值替换文件名,所以它看起来像这样

echo "$(sed -n 's|^[ ]*appVersion = "\(.*\)"|\1|p' <<< "appVersion = \"1.2-SNAPSHOT\"" | sed 's/^\(.*\)-.*$/\1/')"

在终端调用时有效,但作为

%(echo "$(sed -n 's|^[ ]*appVersion = "\(.*\)"|\1|p' <<< "appVersion = \"1.2-SNAPSHOT\"" | sed 's/^\(.*\)-.*$/\1/')") 

但我还是得到了

Empty tag: Version: Error

更新 2

我测试了一个不同的更复杂的命令然后echo "12"

%define version %(echo "$(git log -1 | grep commit | awk -F"commit " 'print $2' | cut -c1-8)")

这也可以!使版本成为提交哈希的前 7 个数字。

更新 3

谜团还在继续,我做了一个测试来检查它是否是 sed 命令导致的,但是下面的命令给了我 1.2 作为版本

%define version %(echo "$( sed 's/.*= //' <<< "appVersion = 1.2" )")

如果此命令有效但不是我的第一个命令,那么它必须与我的第一个命令中的某些内容有关,该命令仅在直接在终端中调用时才有效,而不是在 %(cmd) 中。越来越近了!

更新 4

好的,所以我似乎已经隔离了它必须是什么,好奇,看起来它可能是 rpmbuild 不喜欢的 -ns| | \1 |p 语法。我制作了一个更简单的原始版本。看看吧:

#Error, doesn`t set version to 1.2
%define version %(echo "$( sed -n 's|^.*-\(-*\)|\1|p' <<< "foo-1.2" )") 

#Works ok! sets version to 1.2
%define version %(echo "$( sed 's/.*= //' <<< "appVersion = 1.2" )") 

不幸的是,尽管我认为我无法再隔离并找出问题所在。以第二个命令的样式使用 sed 没有任何问题,但对于为什么第一个命令不起作用仍然非常有趣。

更新 5

我发现在使用 %() 中的任何脚本以及规范文件和 rpmbuild 时,这里存在一些深层问题。我尝试使用 awk 只是为了看看会发生什么,它也坏了!这比我最初想象的要深入得多,就像发现了一个阴谋:

#In terminal it prints 1.2-SNAPSHOT, but in Spec it's an error 
%define version %(echo "$(awk '/appVersion / print $3 ' <<< "appVersion = \"1.2-SNAPSHOT\"" | tr -d \")")

sh: -c: line 0: unexpected EOF while looking for matching `)'
sh: -c: line 1: syntax error: unexpected end of file
error: line 23: Empty tag: Version:

更新 6

对每个人来说都是好消息和坏消息,我发现rpm似乎在后台做一些自己的工作而不显示它在做什么,我终于找到了一个通过rpm调用时给出不同值的命令:

%define version %(echo "$(awk '/midonetVersion / print $3 ' <<< "midonetVersion = \"5.1-SNAPSHOT\"")")
#In terminal it echos "5.1-SNAPSHOT" (literally wrapped in "" )
#When in spec it set version to 5.1-SNAPSHOT , rpmbuild is removing the ""

所以现在我做了一个调整并称之为:

#echos "5.1 in terminal and sets version to 5.1 in spec
%define version %(echo "$(awk '/appVersion / print $3 ' <<< "appVersion = \"1.2-SNAPSHOT\"")"| cut -d'-' -f1)

因此,从这个角度来看,我认为在后台解析我的第一个 sed 命令从 rpm 的结果可能存在类似的类型。我们将有自己的方式 rpm!

最终更新

已与 rpm 休战,我将使用此命令代替:

%define version %(echo "$(awk '/ appVersion =/ print $3 ' /filepath/values.txt" | sed 's/\"//g' | cut -d'-' -f1)

它与我的第一个命令执行相同的操作,并在 specfile 中正确设置版本号。如果有人对为什么第一个命令不会运行有任何猜测,我会很高兴阅读它。和平!

【问题讨论】:

可能是因为/fullfilepath/values.txt 的权限问题。尝试用实际(或简化)值替换它。 【参考方案1】:

您必须有一个调用 rpmbuild 命令的 shell 脚本。您可以使用该脚本来计算版本(或就此而言,您尝试在 rpm 规范文件中使用的任何命令)。

更改您的原始代码,

%define version %(echo "$(sed -n 's|^[ ]*appVersion = "\(.*\)"|\1|p' /fullfilepath/values.txt | sed 's/^\(.*\)-.*$/\1/')")
Version: %version

到,

%define version _VERSION_
Version: %version

和 sed VERSION 到它在调用 rpmbuild 的 shell 脚本中的计算值(在调用 rpmbuild 之前)。将实际规范内容转储到某个文件后,将生成的文件传递给同一 shell 脚本中的 rpmbuild。

以下是步骤摘要:

假设您有一个调用 rpmbuild 的 builder.sh shell 脚本,请执行以下步骤:

    更新您的规范文件,使其具有 VERSION 占位符字符串/宏,如上所示 将当前 rpm 规范文件移动到 my_package_template.spec 在 builder.sh 中,运行命令以获取您的版本并将版本保存到变量中 在 my_package_template.spec 文件上使用 sed 命令将 VERSION 替换为此计算的版本,并将 sed 输出保存到 my_package.spec 将 my_package.spec 传递给 rpmbuild 命令。

重复第 1 步、第 3 步和第 4 步以替换规范文件中任何其他 shell 命令的使用。

【讨论】:

rpmbuild 允许从命令行设置变量,这比需要sed 和临时文件要容易得多。【参考方案2】:

我会做一个包装脚本。这使您可以决定是常规版本还是开发版本等。然后您可以使用--define 选项传递变量 - 请参阅this question for more options。

要回应@Herrgott 的评论“如果你在规范中%define 它并尝试用--define 重新定义它不会覆盖它”(在 cmets 中不能有换行符) - 你可以设置一个“@987654325 @" 与--define同名的变量。

%if 0%?val_override:1
%define val %val_override
%else
%define val whatever
%endif

【讨论】:

如果你在规范中 %define 它并尝试用 --define 重新定义它不会覆盖它 @Herrgott 在主要回复中回复;不能在 cmets 中换行。

以上是关于在 RPM 规范文件中使用脚本定义版本的主要内容,如果未能解决你的问题,请参考以下文章

从 RPM 规范文件中提取 shell 脚本以进行静态分析

rpm 规范文件的安装后脚本中的 yum/rpm install 命令

从 rpm 包中提取规范文件

RPM 规范文件 - 是不是可以动态填充规范文件变量

rpm 规范文件中的 chkconfig 命令

如何在 rpmbuild 规范文件中检查操作系统版本