summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Festi <ffesti@redhat.com>2021-01-11 11:07:59 +0100
committerPanu Matilainen <pmatilai@redhat.com>2022-11-09 16:23:43 +0200
commite8e2a121ba6c604f342f86d0c73dca32bd7d687c (patch)
tree2336ca3fe1669d301a6c0f7c6e4bfe82232b4f0b
parent524bfcb816ea0fa21bbe9891073409df9d239d4f (diff)
downloadrpm-e8e2a121ba6c604f342f86d0c73dca32bd7d687c.tar.gz
Add Dynamic Spec generation
Read in *.specpart files from %{specpartsdir} aka $RPM_SPECPARTS_DIR after the %install script. This allows the build process to add sub packages to the build. In the future more changes to the packages may be possible - like amending package declarations. The %{specpartsdir} is created by the %setup pseudo macro inside of the buildsubdir. It's presence allows build scripts to check if this feature is supported in the running rpmbuild instance.
-rw-r--r--build/build.c4
-rw-r--r--build/parsePrep.c9
-rw-r--r--build/parseSpec.c27
-rw-r--r--build/rpmbuild_internal.h9
-rw-r--r--docs/CMakeLists.txt1
-rw-r--r--docs/manual/buildprocess.md1
-rw-r--r--docs/manual/dynamic_specs.md31
-rw-r--r--docs/manual/index.md2
-rw-r--r--macros.in3
-rw-r--r--tests/data/SPECS/dynamic.spec39
-rw-r--r--tests/rpmbuild.at43
-rw-r--r--tests/rpmspec.at1
12 files changed, 168 insertions, 2 deletions
diff --git a/build/build.c b/build/build.c
index 88ad2d48a..29afbdd4f 100644
--- a/build/build.c
+++ b/build/build.c
@@ -424,6 +424,10 @@ static rpmRC buildSpec(rpmts ts, BTA_t buildArgs, rpmSpec spec, int what)
getStringBuf(spec->install), test, sbp)))
goto exit;
+ if (((what & RPMBUILD_INSTALL) || (what & RPMBUILD_PACKAGEBINARY)) &&
+ (rc = parseGeneratedSpecs(spec)))
+ goto exit;
+
if ((what & RPMBUILD_CHECK) &&
(rc = doScript(spec, RPMBUILD_CHECK, "%check",
getStringBuf(spec->check), test, sbp)))
diff --git a/build/parsePrep.c b/build/parsePrep.c
index 62529956d..b704f3e37 100644
--- a/build/parsePrep.c
+++ b/build/parsePrep.c
@@ -273,6 +273,15 @@ static int doSetupMacro(rpmSpec spec, const char *line)
free(buf);
}
+ /* mkdir for dynamic specparts */
+ buf = rpmExpand("%{__mkdir} SPECPARTS", NULL);
+ appendBuf(spec, buf, 1);
+ free(buf);
+
+ buf = rpmGenPath("%{_builddir}", "%{buildsubdir}", "SPECPARTS");
+ rpmPushMacro(spec->macros, "specpartsdir", NULL, buf, RMIL_SPEC);
+ free(buf);
+
appendBuf(spec, getStringBuf(after), 0);
/* Fix the permissions of the setup build tree */
diff --git a/build/parseSpec.c b/build/parseSpec.c
index 8b1311623..35e2c7573 100644
--- a/build/parseSpec.c
+++ b/build/parseSpec.c
@@ -1131,3 +1131,30 @@ rpmSpec rpmSpecParse(const char *specFile, rpmSpecFlags flags,
{
return parseSpec(specFile, flags, buildRoot, 0);
}
+
+rpmRC parseGeneratedSpecs(rpmSpec spec)
+{
+ ARGV_t argv = NULL;
+ int argc = 0;
+ int i;
+ rpmRC rc = RPMRC_OK;
+
+ char * specPattern = rpmGenPath("%{specpartsdir}", NULL, "*.specpart");
+ /* rpmGlob returns files sorted */
+ if (rpmGlob(specPattern, &argc, &argv) == 0) {
+ for (i = 0; i < argc; i++) {
+ rpmlog(RPMLOG_NOTICE, "Reading %s\n", argv[i]);
+ pushOFI(spec, argv[i]);
+ snprintf(spec->fileStack->readBuf, spec->fileStack->readBufLen,
+ "# Spec part read from %s\n\n", argv[i]);
+ if (parseSpecSection(&spec, 1) != RPMRC_OK) {
+ rpmlog(RPMLOG_ERR, "parsing failed\n");
+ rc = RPMRC_FAIL;
+ break;
+ }
+ }
+ argvFree(argv);
+ }
+ free(specPattern);
+ return rc;
+}
diff --git a/build/rpmbuild_internal.h b/build/rpmbuild_internal.h
index df23e1cd8..2d4e0c0d6 100644
--- a/build/rpmbuild_internal.h
+++ b/build/rpmbuild_internal.h
@@ -414,6 +414,15 @@ rpmRC parseRCPOT(rpmSpec spec, Package pkg, const char * field, rpmTagVal tagN,
int index, rpmsenseFlags tagflags, addReqProvFunction cb, void *cbdata);
/** \ingroup rpmbuild
+ * Parse spec piece generated during build
+ *
+ * @param spec spec file control structure
+ * @return RPMRC_OK on success
+ */
+RPM_GNUC_INTERNAL
+rpmRC parseGeneratedSpecs(rpmSpec spec);
+
+/** \ingroup rpmbuild
* Run a build script, assembled from spec file scriptlet section.
*
* @param spec spec file control structure
diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt
index ee5fa1ac3..1ce548e3e 100644
--- a/docs/CMakeLists.txt
+++ b/docs/CMakeLists.txt
@@ -20,6 +20,7 @@ set(refman
manual/dependencies.md
manual/dependency_generators.md
manual/devel_documentation.md
+ manual/dynamic_specs.md
manual/file_triggers.md
manual/format.md
manual/hregions.md
diff --git a/docs/manual/buildprocess.md b/docs/manual/buildprocess.md
index fb840b40a..f436436be 100644
--- a/docs/manual/buildprocess.md
+++ b/docs/manual/buildprocess.md
@@ -16,6 +16,7 @@ title: rpm.org - Package Build Process
* %conf
* %build
* %install
+ * Read [dynamic spec parts](dynamic_specs.md)
* %check - if present
* Process files
* Turn %files lines into actual files (evaluate globs)
diff --git a/docs/manual/dynamic_specs.md b/docs/manual/dynamic_specs.md
new file mode 100644
index 000000000..8a3370b84
--- /dev/null
+++ b/docs/manual/dynamic_specs.md
@@ -0,0 +1,31 @@
+---
+layout: default
+title: rpm.org - Package Build Process
+---
+# Dynamic Spec Generation
+
+Since rpm 4.19 RPM supports parsing dynamically generated specs. This
+allows the build scripts (**%build** or **%install**) to create parts
+of the spec file. The parts are read in and parsed after **%install**
+and before **%check**. Because of this they obviously can't contain
+the build scripts but are intended to create sub packages based on the
+build results.
+
+The files need to be placed in the **%{specpartsdir}** (also available
+as **$RPM_SPECPARTS_DIR** in the build scripts) and have a
+**.specpart** postfix. The directory is created by **%setup** in the
+**buildsubdir**. Scripts must not create it themselves but must either
+fail if it is not present or switch to an alternative that does not
+require the feature. They should give an error message that dynamic
+spec generation is not supported on the given RPM version when failing.
+
+The **.specparts** files are read in alphabetical order. If build
+script rely on a specific order they should use a common prefix and
+have postfixes take care of the ordering.
+
+Generally the specparts should be generated by separate scripts and not
+directly from the build scripts themselves. This can be done for
+testing but one needs to be careful that the spec syntax is not
+already parsed when the spec file is read. Avoid Spec directives or
+sections starting right at the beginning of the line as they will be
+interpreted right away.
diff --git a/docs/manual/index.md b/docs/manual/index.md
index 207504fdc..045c75704 100644
--- a/docs/manual/index.md
+++ b/docs/manual/index.md
@@ -33,7 +33,7 @@ title: rpm.org - RPM Reference Manual
* [Conditional Builds](conditionalbuilds.md)
* [Relocatable Packages](relocatable.md)
* [Multiple build areas](multiplebuilds.md)
-
+* [Dynamic Spec Generation](dynamic_specs.md)
## Developer Information
diff --git a/macros.in b/macros.in
index ab5645733..04bcc95dd 100644
--- a/macros.in
+++ b/macros.in
@@ -731,7 +731,8 @@ package or when debugging this package.\
RPM_ARCH=\"%{_arch}\"\
RPM_OS=\"%{_os}\"\
RPM_BUILD_NCPUS=\"%{_smp_build_ncpus}\"\
- export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_ARCH RPM_OS RPM_BUILD_NCPUS\
+ RPM_SPECPARTS_DIR=\"%{specpartsdir}\"\
+ export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_ARCH RPM_OS RPM_BUILD_NCPUS RPM_SPECPARTS_DIR\
RPM_DOC_DIR=\"%{_docdir}\"\
export RPM_DOC_DIR\
RPM_PACKAGE_NAME=\"%{NAME}\"\
diff --git a/tests/data/SPECS/dynamic.spec b/tests/data/SPECS/dynamic.spec
new file mode 100644
index 000000000..5dbaa8584
--- /dev/null
+++ b/tests/data/SPECS/dynamic.spec
@@ -0,0 +1,39 @@
+Summary: dynamic hello -- hello, world rpm
+Name: dynamic
+Version: 1.0
+Release: 1
+Group: Utilities
+License: GPL
+Distribution: RPM test suite.
+URL: http://rpm.org
+BuildArch: noarch
+
+%description
+Simple rpm demonstration.
+
+%prep
+%setup -q -T -c
+
+%build
+echo "Q: Why?\nA: Because we can!" > FAQ
+
+%install
+mkdir -p $RPM_BUILD_ROOT/usr/local/bin
+echo " " > $RPM_BUILD_ROOT/usr/local/bin/hello
+
+
+echo "%package docs" >> %{specpartsdir}/docs.specpart
+%{?!FAIL:echo "Summary: Documentation for dynamic spec" >> %{specpartsdir}/docs.specpart}
+echo "BuildArch: noarch" >> %{specpartsdir}/docs.specpart
+echo "%description docs" >> %{specpartsdir}/docs.specpart
+echo "Test for dynamically generated spec files" >> %{specpartsdir}/docs.specpart
+echo "%files docs" >> $RPM_SPECPARTS_DIR/docs.specpart
+echo "%doc FAQ" >> $RPM_SPECPARTS_DIR/docs.specpart
+
+%files
+%defattr(-,root,root)
+%attr(0751,root,root) /usr/local/bin/hello
+
+%changelog
+* Mon Oct 24 2022 Florian Festi <ffesti@redhat.com>
+- create.
diff --git a/tests/rpmbuild.at b/tests/rpmbuild.at
index 2fe29705e..00f89209b 100644
--- a/tests/rpmbuild.at
+++ b/tests/rpmbuild.at
@@ -2272,3 +2272,46 @@ runroot rpmbuild \
],
[ignore])
AT_CLEANUP
+
+# ------------------------------
+# Check if dynamic spec generation works
+AT_SETUP([rpmbuild with dynamic spec generation])
+AT_KEYWORDS([build])
+RPMDB_INIT
+AT_CHECK([
+
+runroot rpmbuild --define "_prefix /usr/local" -ba /data/SPECS/dynamic.spec
+],
+[0],
+[ignore],
+[ignore])
+
+AT_CHECK([
+
+runroot rpm -qp --qf "%{Summary}\n" /build/RPMS/noarch/dynamic-docs-1.0-1.noarch.rpm
+runroot rpm -ql /build/RPMS/noarch/dynamic-docs-1.0-1.noarch.rpm
+],
+[0],
+[Documentation for dynamic spec
+/usr/local/share/doc/dynamic-docs-1.0
+/usr/local/share/doc/dynamic-docs-1.0/FAQ
+],
+[])
+AT_CLEANUP
+
+# ------------------------------
+# Check failing dynamic spec generation
+AT_SETUP([rpmbuild with dynamic spec generation fail])
+AT_KEYWORDS([build])
+RPMDB_INIT
+AT_CHECK([
+
+runroot rpmbuild --quiet -D "FAIL 1" -ba /data/SPECS/dynamic.spec
+],
+[1],
+[],
+[error: Summary field must be present in package: dynamic-docs
+error: parsing failed
+])
+
+AT_CLEANUP
diff --git a/tests/rpmspec.at b/tests/rpmspec.at
index 5dfd18d5a..1e1792bfb 100644
--- a/tests/rpmspec.at
+++ b/tests/rpmspec.at
@@ -333,6 +333,7 @@ if [ $STATUS -ne 0 ]; then
exit $STATUS
fi
cd 'hello-1.0'
+/usr/bin/mkdir SPECPARTS
/usr/bin/chmod -Rf a+rX,u+w,g-w,o-w .
echo "Patch #0 (hello-1.0-modernize.patch):"
/usr/bin/patch --no-backup-if-mismatch -f -p1 -b --suffix .modernize --fuzz=0 < /build/SOURCES/hello-1.0-modernize.patch