diff options
author | Florian Festi <ffesti@redhat.com> | 2021-01-11 11:07:59 +0100 |
---|---|---|
committer | Panu Matilainen <pmatilai@redhat.com> | 2022-11-09 16:23:43 +0200 |
commit | e8e2a121ba6c604f342f86d0c73dca32bd7d687c (patch) | |
tree | 2336ca3fe1669d301a6c0f7c6e4bfe82232b4f0b | |
parent | 524bfcb816ea0fa21bbe9891073409df9d239d4f (diff) | |
download | rpm-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.c | 4 | ||||
-rw-r--r-- | build/parsePrep.c | 9 | ||||
-rw-r--r-- | build/parseSpec.c | 27 | ||||
-rw-r--r-- | build/rpmbuild_internal.h | 9 | ||||
-rw-r--r-- | docs/CMakeLists.txt | 1 | ||||
-rw-r--r-- | docs/manual/buildprocess.md | 1 | ||||
-rw-r--r-- | docs/manual/dynamic_specs.md | 31 | ||||
-rw-r--r-- | docs/manual/index.md | 2 | ||||
-rw-r--r-- | macros.in | 3 | ||||
-rw-r--r-- | tests/data/SPECS/dynamic.spec | 39 | ||||
-rw-r--r-- | tests/rpmbuild.at | 43 | ||||
-rw-r--r-- | tests/rpmspec.at | 1 |
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 @@ -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 |