Files
Laurent CoustetandLaurent Coustet edf3552720 feat(rpm): add script_requires to require script interpreters (#1151)
rpmbuild runs script.req on the executable files of a package, so a
package that ships a "#!/bin/bash" script requires /bin/bash without
any work from the packager. nfpm has no such generator, so the
interpreter of every script must be listed by hand, which is
error-prone.

Add the opt-in rpm.script_requires option. Like script.req with the
exeonly flag of script.attr, it reads the "#!" line of each executable
file and requires its interpreter, and the absolute program run by
env, flagged RPMSENSE_FIND_REQUIRES like the dependencies rpmbuild
generates. Documentation files, symlinks, directories and ghosts are
skipped. The mode checked is the one in the package, so file_info.mode
is honored and the option also works when building on Windows.

The generated spec sets AutoReqProv: no, so the requires are written
to it explicitly and rpmbuild --rebuild keeps them.

Add unit tests, a scriptrequires acceptance stage that reads the
requires back with rpm, and an executable script to the srpm rebuild
acceptance test.

Co-authored-by: Laurent Coustet <laurent.coustet@bluemind.net>
2026-10-28 16:45:58 +00:00

53 lines
2.4 KiB
Docker

FROM fedora AS test_base
ARG package
RUN echo "${package}"
COPY ${package} /tmp/foo.src.rpm
# ---- rebuild test ----
# Proves the generated source package is a real, rebuildable .src.rpm:
# rpmbuild --rebuild reproduces the binary RPM, which then installs cleanly.
FROM test_base AS rebuild
RUN dnf install -y rpm-build
# The source package is arch "src" and is flagged as a source package.
RUN test "$(rpm -qp --qf '%{ARCH}' /tmp/foo.src.rpm)" = "src"
RUN test "$(rpm -qp --qf '%{SOURCEPACKAGE}' /tmp/foo.src.rpm)" = "1"
RUN test "$(rpm -qp --qf '%{SOURCERPM}' /tmp/foo.src.rpm)" = "(none)"
# Its file list is the generated spec plus the bundled source tarball (source
# packages list flat basenames, not absolute paths).
RUN rpm -qpl /tmp/foo.src.rpm | grep -E 'foo\.spec$'
RUN rpm -qpl /tmp/foo.src.rpm | grep -E 'foo-1\.2\.3\.tar\.gz$'
# Rebuild the binary RPM from source.
RUN rpmbuild --rebuild /tmp/foo.src.rpm
RUN cp "$(find /root/rpmbuild/RPMS -name 'foo-*.rpm' | head -1)" /tmp/foo.rpm
# The rebuilt binary RPM carries the expected metadata and file set.
RUN test "$(rpm -qp --qf '%{EPOCH}:%{NAME}-%{VERSION}-%{RELEASE}' /tmp/foo.rpm)" = "1:foo-1.2.3-4"
RUN rpm -qp -c /tmp/foo.rpm | grep -E '^/etc/foo/whatever\.conf$'
RUN rpm -qp -d /tmp/foo.rpm | grep -E '^/usr/share/doc/foo/README$'
RUN rpm -qp --qf '[%{FILENAMES} %{FILEFLAGS}\n]' /tmp/foo.rpm | grep -E '^/var/lib/foo/state 64$'
RUN test "$(rpm -qp --provides /tmp/foo.rpm | grep '^foo-tool$')" = "foo-tool"
RUN rpm -qp --requires /tmp/foo.rpm | grep -E '^bash$'
# The generated script requires survive the rebuild as explicit requires.
RUN rpm -qp --requires /tmp/foo.rpm | grep -Fx '/bin/bash'
RUN rpm -qp --scripts /tmp/foo.rpm | grep -E 'postinstall scriptlet'
# %-sequences in scriptlets must survive the rebuild literally; without the
# spec escaping, ${host%%.*} would be silently mangled to ${host%.*}.
RUN rpm -qp --scripts /tmp/foo.rpm | grep -F '${host%%.*}'
# rpmbuild colors ELF files on rebuild, as nfpm does in the binary RPM.
RUN rpm -qp --qf '[%{FILECOLORS} %{FILENAMES}\n]' /tmp/foo.rpm | grep -Fx '2 /usr/lib/foo/elf64'
# Install it and verify the payload landed on disk.
RUN rpm -ivh /tmp/foo.rpm
RUN test -f /usr/bin/fake
RUN test -f /etc/foo/whatever.conf
RUN test -d /var/log/whatever
RUN test -L /usr/bin/fake-link
RUN test "$(readlink /usr/bin/fake-link)" = "/usr/bin/fake"
RUN test ! -e /var/lib/foo/state
RUN rpm -e foo
RUN test ! -f /usr/bin/fake