From 283935b9206ce09de8f0ddef707cfa5e346bb06c Mon Sep 17 00:00:00 2001 From: Panu Matilainen Date: Fri, 20 Oct 2023 10:44:36 +0300 Subject: [PATCH] Implement prepend and append modes for all build scriptlets Allows %prep, %conf, %build, %install, %check, %clean and %generate_depends to be augmented arbitrary number of times by appending or prepending to them. The main use-case is to support automatic population of these sections (declarative builds) while still allowing packagers to easily tweak them, but could also be useful for complicated conditional specs and such. Related: #1087 --- build/parseSimpleScript.c | 59 ++++++++++++++++++++++++++++++++---- docs/manual/spec.md | 13 ++++++-- tests/data/SPECS/append.spec | 33 ++++++++++++++++++++ tests/rpmbuild.at | 18 +++++++++++ 4 files changed, 115 insertions(+), 8 deletions(-) create mode 100644 tests/data/SPECS/append.spec diff --git a/build/parseSimpleScript.c b/build/parseSimpleScript.c index f78dbd71c8..28ff670cc4 100644 --- a/build/parseSimpleScript.c +++ b/build/parseSimpleScript.c @@ -12,17 +12,64 @@ int parseSimpleScript(rpmSpec spec, const char * name, StringBuf *sbp) { int res = PART_ERROR; - - if (*sbp != NULL) { + poptContext optCon = NULL; + int argc; + const char **argv = NULL; + StringBuf *target = sbp; + StringBuf buf = NULL; + int rc, append = 0, prepend = 0; + struct poptOption optionsTable[] = { + { NULL, 'a', POPT_ARG_NONE, &append, 'a', NULL, NULL }, + { NULL, 'p', POPT_ARG_NONE, &prepend, 'p', NULL, NULL }, + { NULL, 0, 0, NULL, 0, NULL, NULL } + }; + + + if ((rc = poptParseArgvString(spec->line, &argc, &argv))) { + rpmlog(RPMLOG_ERR, _("line %d: Error parsing script: %s: %s\n"), + spec->lineNum, spec->line, poptStrerror(rc)); + goto exit; + } + + optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); + while ((rc = poptGetNextOpt(optCon)) > 0) {}; + if (rc < -1) { + rpmlog(RPMLOG_ERR, _("line %d: Bad %s option %s: %s\n"), + spec->lineNum, argv[0], + poptBadOption(optCon, POPT_BADOPTION_NOALIAS), + poptStrerror(rc)); + goto exit; + } + + if (*sbp != NULL && append == 0 && prepend == 0) { rpmlog(RPMLOG_ERR, _("line %d: second %s\n"), spec->lineNum, name); goto exit; } - - /* There are no options to %build, %install, %check, or %clean */ - res = parseLines(spec, STRIP_NOTHING, NULL, sbp); - + + if (append && prepend) { + rpmlog(RPMLOG_ERR, _("line %d: append and prepend specified: %s\n"), + spec->lineNum, spec->line); + goto exit; + } + + /* Prepend is only special if the section already exists */ + if (prepend && *sbp) { + buf = newStringBuf(); + target = &buf; + } + + res = parseLines(spec, STRIP_NOTHING, NULL, target); + + if (buf) { + appendStringBuf(buf, getStringBuf(*sbp)); + freeStringBuf(*sbp); + *sbp = buf; + } + exit: + free(argv); + poptFreeContext(optCon); return res; } diff --git a/docs/manual/spec.md b/docs/manual/spec.md index 0980998753..aedf495b11 100644 --- a/docs/manual/spec.md +++ b/docs/manual/spec.md @@ -458,8 +458,17 @@ when name is omitted, the description refers to the main package. ## Build scriptlets -Package build is divided into multiple separate steps, each executed -in a separate shell. +Package build is divided into multiple separate steps, each executed in a +separate shell: `%prep`, `%conf`, `%build`, `%install`, `%check`, `%clean` +and `%generate_buildrequires`. Any unnecessary scriptlet sections can be +omitted. + +Each section may be present only once, but in rpm >= 4.20 it is +possible to augment them by appending or prepending to them using +`-a` and `-p` options. +If the main section exists, it must come first to avoid ambiguity. +Otherwise, append and prepend can be used in any order and multiple +times, even if the corresponding main section does not exist. ### %prep diff --git a/tests/data/SPECS/append.spec b/tests/data/SPECS/append.spec new file mode 100644 index 0000000000..01046c65a9 --- /dev/null +++ b/tests/data/SPECS/append.spec @@ -0,0 +1,33 @@ +Name: append +Version: 1.0 +Release: 1 +BuildArch: noarch +Summary: Testing scriptlet append/prepend +License: GPL + +%description +%{summary} + +%build +echo BBB >> out + +%build -a +echo CCC >> out + +%build -p +echo AAA >> out + +%build -a +echo DDD >> out + +%build -p +echo 000 >> out + +%install -a +cp out ${RPM_BUILD_ROOT}/opt/ + +%install -p +mkdir -p ${RPM_BUILD_ROOT}/opt/ + +%files +/opt/out diff --git a/tests/rpmbuild.at b/tests/rpmbuild.at index 0c1ed556ac..03fcd1bb7e 100644 --- a/tests/rpmbuild.at +++ b/tests/rpmbuild.at @@ -152,6 +152,24 @@ runroot rpmbuild -bs /data/SPECS/specstep.spec 2>&1|grep ^Executing|cut -d: -f1 []) RPMTEST_CLEANUP +AT_SETUP([rpmbuild script prepend/append]) +AT_KEYWORDS([build]) +RPMDB_INIT +RPMTEST_CHECK([ +runroot rpmbuild -bb --quiet ${RPMDATA}/SPECS/append.spec +runroot_other rpm2cpio /build/RPMS/noarch/append-1.0-1.noarch.rpm | cpio -id 2> /dev/null +cat opt/out +], +[0], +[000 +AAA +BBB +CCC +DDD +], +[]) +RPMTEST_CLEANUP + AT_SETUP([rpmbuild -ba autosetup]) AT_KEYWORDS([build]) RPMDB_INIT