rpm %config(noreplace) 用 %config 覆盖

rpm %config(noreplace) override with %config

在我的 rpm 中,我有一个完整的目录,我想用 %config(noreplace) 标记它。在那个目录中有一个文件,我想在每次安装时用 rpm 的最新版本替换它,使用 %config 的语义。

使用此处的指南:http://www-uxsup.csx.cam.ac.uk/~jw35/docs/rpm_config.html,我尝试了以下操作:

%files
%config(noreplace) /my/saved/dir/*
%config /my/saved/dir/file1

%files
%config /my/saved/dir/file1
%config(noreplace) /my/saved/dir/*

希望特定命令会覆盖 glob,但它没有用。是否有任何类似 RPM 的命令可用于对嵌套在 %config(noreplace) 目录下的文件强制执行 %config 行为?

来自: http://ftp.rpm.org/max-rpm/s1-rpm-inside-files-list-directives.html

There is a restriction to the %config directive, and that restriction is that no more than one filename may follow the %config. This means that the following example is the only allowable way to specify config files:

%config /etc/foonly

Note that the full path to the file, as it is installed at build time, is required.

但是您可以在 %install 部分中动态制作该列表:

%install
echo '%dir /etc' >> list.txt
echo '%config(noreplace) /etc/foo' >> list.txt
# use for-loop or any other shell scripting technique

%files -f list.txt

假设包中的每个文件都列在 .spec 文件的 %files 部分(列表)中 恰好一次。我敢打赌,当你 运行 rpmbuild 时,输出中有以下行

warning: File listed twice: /my/saved/dir/file1

解决方案是列出配置文件(你希望它总是被覆盖)只列出一次并使用正确的指令%config(noreplace)。这与直接指定或通过通配符间接指定无关。

msuchy 的回答中引用的语句

There is a restriction to the %config directive, and that restriction is that no more than one filename may follow the %config.

一定是很久以前的事了,因为早在 2008.

年就有在 %config 指令中使用通配符的规范文件示例

问题不在于使用通配符本身。问题是同一个文件被列出两次(一次是直接的,一次是由于使用通配符而间接列出的)使用不同的 %config 指令(一次是普通的 %config 一次 %config(noreplace))。您的测试——更改这两个声明的顺序——以及您观察到的结果表明 rpm 将这两个声明合并为一个 %config(noreplace)。这可以解释为什么声明的顺序无关紧要。但是,正如我在上面所写的,假设每个文件都只列出一次,这可能是我找不到任何关于当某些文件被多次列出时应该发生什么的信息的原因。

请注意,使用 %config(noreplace) 指定的文件必须已更改 – 在包中 – 版本之间已经已安装并正在为要写入的 .rpmnew 文件安装较新的版本 – 参见 .rpmnew file not created on package upgrade?

另请注意,安装某些软件包的较新版本不被视为更新软件包 - 请参阅 Unexpected RPM conflict on %config(noreplace) files

下面是供想要自己尝试的人使用的规范文件。

我的包-old.spec:

Summary: old version
Name: mypackage
Version: 1
Release: 1
License: BSD

%description


%prep

%build

%install
rm -rf %{buildroot}
mkdir -p %{buildroot}/foo
echo 'replace' > %{buildroot}/foo/replace
echo 'noreplace' > %{buildroot}/foo/noreplace

%clean
rm -rf %{buildroot}


%files
%defattr(-,root,root,-)
%config /foo/replace
%config(noreplace) /foo/*

我的包-new.spec:

Summary: new version
Name: mypackage
Version: 2
Release: 1
License: BSD

%description


%prep

%build

%install
rm -rf %{buildroot}
mkdir -p %{buildroot}/foo
echo 'new replace' > %{buildroot}/foo/replace
echo 'new noreplace' > %{buildroot}/foo/noreplace

%clean
rm -rf %{buildroot}

%files
%defattr(-,root,root,-)
# declaration A    
%config /foo/replace    
# declaration B
%config(noreplace) /foo/*

无论我们在上面声明 A 和 B 的顺序如何,RPM 版本 4.14.0 的结果都是相同的:

% rpmbuild -ba ./mypackge-old.spec
% rpmbuild -ba ./mypackge-new.spec
% sudo rpm -i ~/rpmbuild/RPMS/x86_64/mypackage-1-1.x86_64.rpm
% echo modified >> /foo/replace
% echo modified >> /foo/noreplace
% sudo rpm -U ~/rpmbuild/RPMS/x86_64/mypackage-2-1.x86_64.rpm
warning: /foo/noreplace created as /foo/noreplace.rpmnew
warning: /foo/replace created as /foo/replace.rpmnew