diff --git a/build/parsePreamble.c b/build/parsePreamble.c index a23e5a8f65..29ba4a2d67 100644 --- a/build/parsePreamble.c +++ b/build/parsePreamble.c @@ -797,8 +797,9 @@ static int addBuildOption(rpmSpec spec, const char *sect, const char *opt) return rc; } -static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag, - const char *macro, const char *lang) +static rpmRC handlePreambleTag(rpmSpec spec, enum parseStages stage, + Package pkg, rpmTagVal tag, + const char *macro, const char *lang) { char * field = spec->line; char * end; @@ -1009,6 +1010,14 @@ static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag, BANames = _free(BANames); goto exit; } + if (stage == PARSE_GENERATED && + (BACount != 1 || !rstreq(BANames[0], "noarch"))) { + rpmlog(RPMLOG_ERR, + _("line %d: Only noarch is allowed after the build: %s\n"), + spec->lineNum, spec->line); + BANames = _free(BANames); + goto exit; + } spec->BACount = BACount; spec->BANames = BANames; } else { @@ -1060,71 +1069,72 @@ typedef const struct PreambleRec_s { int type; int deprecated; int ismacro; + int notgenerated; size_t len; const char * token; } * PreambleRec; static struct PreambleRec_s const preambleList[] = { - {RPMTAG_NAME, 0, 0, 1, LEN_AND_STR("name")}, - {RPMTAG_VERSION, 0, 0, 1, LEN_AND_STR("version")}, - {RPMTAG_RELEASE, 0, 0, 1, LEN_AND_STR("release")}, - {RPMTAG_EPOCH, 0, 0, 1, LEN_AND_STR("epoch")}, - {RPMTAG_SUMMARY, 1, 0, 1, LEN_AND_STR("summary")}, - {RPMTAG_LICENSE, 0, 0, 1, LEN_AND_STR("license")}, - {RPMTAG_SOURCELICENSE, 0, 0, 1, LEN_AND_STR("sourcelicense")}, - {RPMTAG_DISTRIBUTION, 0, 0, 1, LEN_AND_STR("distribution")}, - {RPMTAG_DISTURL, 0, 0, 1, LEN_AND_STR("disturl")}, - {RPMTAG_VENDOR, 0, 0, 1, LEN_AND_STR("vendor")}, - {RPMTAG_GROUP, 1, 0, 1, LEN_AND_STR("group")}, - {RPMTAG_PACKAGER, 0, 0, 1, LEN_AND_STR("packager")}, - {RPMTAG_URL, 0, 0, 1, LEN_AND_STR("url")}, - {RPMTAG_VCS, 0, 0, 1, LEN_AND_STR("vcs")}, - {RPMTAG_SOURCE, 0, 0, 0, LEN_AND_STR("source")}, - {RPMTAG_PATCH, 0, 0, 0, LEN_AND_STR("patch")}, - {RPMTAG_NOSOURCE, 0, 0, 0, LEN_AND_STR("nosource")}, - {RPMTAG_NOPATCH, 0, 0, 0, LEN_AND_STR("nopatch")}, - {RPMTAG_EXCLUDEARCH, 0, 0, 0, LEN_AND_STR("excludearch")}, - {RPMTAG_EXCLUSIVEARCH, 0, 0, 0, LEN_AND_STR("exclusivearch")}, - {RPMTAG_EXCLUDEOS, 0, 0, 0, LEN_AND_STR("excludeos")}, - {RPMTAG_EXCLUSIVEOS, 0, 0, 0, LEN_AND_STR("exclusiveos")}, - {RPMTAG_ICON, 0, 0, 0, LEN_AND_STR("icon")}, - {RPMTAG_PROVIDENAME, 0, 0, 0, LEN_AND_STR("provides")}, - {RPMTAG_REQUIRENAME, 2, 0, 0, LEN_AND_STR("requires")}, - {RPMTAG_RECOMMENDNAME, 0, 0, 0, LEN_AND_STR("recommends")}, - {RPMTAG_SUGGESTNAME, 0, 0, 0, LEN_AND_STR("suggests")}, - {RPMTAG_SUPPLEMENTNAME, 0, 0, 0, LEN_AND_STR("supplements")}, - {RPMTAG_ENHANCENAME, 0, 0, 0, LEN_AND_STR("enhances")}, - {RPMTAG_PREREQ, 2, 1, 0, LEN_AND_STR("prereq")}, - {RPMTAG_CONFLICTNAME, 0, 0, 0, LEN_AND_STR("conflicts")}, - {RPMTAG_OBSOLETENAME, 0, 0, 0, LEN_AND_STR("obsoletes")}, - {RPMTAG_PREFIXES, 0, 0, 1, LEN_AND_STR("prefixes")}, - {RPMTAG_PREFIXES, 0, 0, 1, LEN_AND_STR("prefix")}, - {RPMTAG_BUILDROOT, 0, 0, 0, LEN_AND_STR("buildroot")}, - {RPMTAG_BUILDARCHS, 0, 0, 0, LEN_AND_STR("buildarchitectures")}, - {RPMTAG_BUILDARCHS, 0, 0, 0, LEN_AND_STR("buildarch")}, - {RPMTAG_BUILDCONFLICTS, 0, 0, 0, LEN_AND_STR("buildconflicts")}, - {RPMTAG_BUILDOPTION, 2, 0, 0, LEN_AND_STR("buildoption")}, - {RPMTAG_BUILDPREREQ, 0, 1, 0, LEN_AND_STR("buildprereq")}, - {RPMTAG_BUILDREQUIRES, 0, 0, 0, LEN_AND_STR("buildrequires")}, - {RPMTAG_BUILDSYSTEM, 0, 0, 1, LEN_AND_STR("buildsystem")}, - {RPMTAG_AUTOREQPROV, 0, 0, 0, LEN_AND_STR("autoreqprov")}, - {RPMTAG_AUTOREQ, 0, 0, 0, LEN_AND_STR("autoreq")}, - {RPMTAG_AUTOPROV, 0, 0, 0, LEN_AND_STR("autoprov")}, - {RPMTAG_DOCDIR, 0, 0, 0, LEN_AND_STR("docdir")}, - {RPMTAG_DISTTAG, 0, 0, 1, LEN_AND_STR("disttag")}, - {RPMTAG_BUGURL, 0, 0, 1, LEN_AND_STR("bugurl")}, - {RPMTAG_TRANSLATIONURL, 0, 0, 1, LEN_AND_STR("translationurl")}, - {RPMTAG_UPSTREAMRELEASES, 0, 0, 1, LEN_AND_STR("upstreamreleases")}, - {RPMTAG_ORDERNAME, 2, 0, 0, LEN_AND_STR("orderwithrequires")}, - {RPMTAG_REMOVEPATHPOSTFIXES,0, 0, 1, LEN_AND_STR("removepathpostfixes")}, - {RPMTAG_MODULARITYLABEL, 0, 0, 1, LEN_AND_STR("modularitylabel")}, + {RPMTAG_NAME, 0, 0, 1, 0, LEN_AND_STR("name")}, + {RPMTAG_VERSION, 0, 0, 1, 0, LEN_AND_STR("version")}, + {RPMTAG_RELEASE, 0, 0, 1, 0, LEN_AND_STR("release")}, + {RPMTAG_EPOCH, 0, 0, 1, 0, LEN_AND_STR("epoch")}, + {RPMTAG_SUMMARY, 1, 0, 1, 0, LEN_AND_STR("summary")}, + {RPMTAG_LICENSE, 0, 0, 1, 0, LEN_AND_STR("license")}, + {RPMTAG_SOURCELICENSE, 0, 0, 1, 0, LEN_AND_STR("sourcelicense")}, + {RPMTAG_DISTRIBUTION, 0, 0, 1, 0, LEN_AND_STR("distribution")}, + {RPMTAG_DISTURL, 0, 0, 1, 0, LEN_AND_STR("disturl")}, + {RPMTAG_VENDOR, 0, 0, 1, 0, LEN_AND_STR("vendor")}, + {RPMTAG_GROUP, 1, 0, 1, 0, LEN_AND_STR("group")}, + {RPMTAG_PACKAGER, 0, 0, 1, 0, LEN_AND_STR("packager")}, + {RPMTAG_URL, 0, 0, 1, 0, LEN_AND_STR("url")}, + {RPMTAG_VCS, 0, 0, 1, 0, LEN_AND_STR("vcs")}, + {RPMTAG_SOURCE, 0, 0, 0, 1, LEN_AND_STR("source")}, + {RPMTAG_PATCH, 0, 0, 0, 1, LEN_AND_STR("patch")}, + {RPMTAG_NOSOURCE, 0, 0, 0, 1, LEN_AND_STR("nosource")}, + {RPMTAG_NOPATCH, 0, 0, 0, 1, LEN_AND_STR("nopatch")}, + {RPMTAG_EXCLUDEARCH, 0, 0, 0, 1, LEN_AND_STR("excludearch")}, + {RPMTAG_EXCLUSIVEARCH, 0, 0, 0, 1, LEN_AND_STR("exclusivearch")}, + {RPMTAG_EXCLUDEOS, 0, 0, 0, 1, LEN_AND_STR("excludeos")}, + {RPMTAG_EXCLUSIVEOS, 0, 0, 0, 1, LEN_AND_STR("exclusiveos")}, + {RPMTAG_ICON, 0, 0, 0, 0, LEN_AND_STR("icon")}, + {RPMTAG_PROVIDENAME, 0, 0, 0, 0, LEN_AND_STR("provides")}, + {RPMTAG_REQUIRENAME, 2, 0, 0, 0, LEN_AND_STR("requires")}, + {RPMTAG_RECOMMENDNAME, 0, 0, 0, 0, LEN_AND_STR("recommends")}, + {RPMTAG_SUGGESTNAME, 0, 0, 0, 0, LEN_AND_STR("suggests")}, + {RPMTAG_SUPPLEMENTNAME, 0, 0, 0, 0, LEN_AND_STR("supplements")}, + {RPMTAG_ENHANCENAME, 0, 0, 0, 0, LEN_AND_STR("enhances")}, + {RPMTAG_PREREQ, 2, 1, 0, 0, LEN_AND_STR("prereq")}, + {RPMTAG_CONFLICTNAME, 0, 0, 0, 0, LEN_AND_STR("conflicts")}, + {RPMTAG_OBSOLETENAME, 0, 0, 0, 0, LEN_AND_STR("obsoletes")}, + {RPMTAG_PREFIXES, 0, 0, 1, 0, LEN_AND_STR("prefixes")}, + {RPMTAG_PREFIXES, 0, 0, 1, 0, LEN_AND_STR("prefix")}, + {RPMTAG_BUILDROOT, 0, 0, 0, 1, LEN_AND_STR("buildroot")}, + {RPMTAG_BUILDARCHS, 0, 0, 0, 0, LEN_AND_STR("buildarchitectures")}, + {RPMTAG_BUILDARCHS, 0, 0, 0, 0, LEN_AND_STR("buildarch")}, + {RPMTAG_BUILDCONFLICTS, 0, 0, 0, 1, LEN_AND_STR("buildconflicts")}, + {RPMTAG_BUILDOPTION, 2, 0, 0, 1, LEN_AND_STR("buildoption")}, + {RPMTAG_BUILDPREREQ, 0, 1, 0, 1, LEN_AND_STR("buildprereq")}, + {RPMTAG_BUILDREQUIRES, 0, 0, 0, 1, LEN_AND_STR("buildrequires")}, + {RPMTAG_BUILDSYSTEM, 0, 0, 1, 1, LEN_AND_STR("buildsystem")}, + {RPMTAG_AUTOREQPROV, 0, 0, 0, 0, LEN_AND_STR("autoreqprov")}, + {RPMTAG_AUTOREQ, 0, 0, 0, 0, LEN_AND_STR("autoreq")}, + {RPMTAG_AUTOPROV, 0, 0, 0, 0, LEN_AND_STR("autoprov")}, + {RPMTAG_DOCDIR, 0, 0, 0, 0, LEN_AND_STR("docdir")}, + {RPMTAG_DISTTAG, 0, 0, 1, 0, LEN_AND_STR("disttag")}, + {RPMTAG_BUGURL, 0, 0, 1, 0, LEN_AND_STR("bugurl")}, + {RPMTAG_TRANSLATIONURL, 0, 0, 1, 0, LEN_AND_STR("translationurl")}, + {RPMTAG_UPSTREAMRELEASES, 0, 0, 1, 0, LEN_AND_STR("upstreamreleases")}, + {RPMTAG_ORDERNAME, 2, 0, 0, 0, LEN_AND_STR("orderwithrequires")}, + {RPMTAG_REMOVEPATHPOSTFIXES,0, 0, 1, 0, LEN_AND_STR("removepathpostfixes")}, + {RPMTAG_MODULARITYLABEL, 0, 0, 1, 0, LEN_AND_STR("modularitylabel")}, {0, 0, 0, 0} }; /** */ static int findPreambleTag(rpmSpec spec,rpmTagVal * tag, - const char ** macro, char * lang) + const char ** macro, char * lang, int * notgenerated) { PreambleRec p; char *s; @@ -1176,10 +1186,11 @@ static int findPreambleTag(rpmSpec spec,rpmTagVal * tag, *tag = p->tag; *macro = p->ismacro ? p->token : NULL; + *notgenerated = p->notgenerated; return 0; } -int parsePreamble(rpmSpec spec, int initialPackage) +int parsePreamble(rpmSpec spec, int initialPackage, enum parseStages stage) { int nextPart = PART_ERROR; int res = PART_ERROR; /* assume failure */ @@ -1235,7 +1246,8 @@ int parsePreamble(rpmSpec spec, int initialPackage) linep = spec->line; SKIPSPACE(linep); if (*linep != '\0') { - if (findPreambleTag(spec, &tag, ¯o, lang)) { + int notgenerated; + if (findPreambleTag(spec, &tag, ¯o, lang, ¬generated)) { if (spec->lineNum == 1 && (unsigned char)(spec->line[0]) == 0xed && (unsigned char)(spec->line[1]) == 0xab && @@ -1248,7 +1260,12 @@ int parsePreamble(rpmSpec spec, int initialPackage) spec->lineNum, spec->line); goto exit; } - if (handlePreambleTag(spec, pkg, tag, macro, lang)) { + if (stage == PARSE_GENERATED && notgenerated) { + rpmlog(RPMLOG_ERR, _("line %d: Tag not allowed after build is done: %s\n"), + spec->lineNum, spec->line); + goto exit; + } + if (handlePreambleTag(spec, stage, pkg, tag, macro, lang)) { goto exit; } if (spec->BANames && !spec->recursing) { diff --git a/build/parseSpec.c b/build/parseSpec.c index f456e77a11..4be57944b5 100644 --- a/build/parseSpec.c +++ b/build/parseSpec.c @@ -100,6 +100,18 @@ int isPart(const char *line) return (p->token ? p->part : PART_NONE); } +static const char * partName(int part) +{ + const struct PartRec *p; + + for (p = partList; p->token != NULL; p++) { + if (p->part == part) { + return p->token; + } + } + return NULL; +} + /** */ static int matchTok(const char *token, const char *line) @@ -1022,7 +1034,7 @@ static rpmRC parseSpecSection(rpmSpec *specptr, enum parseStages stage) parsePart = parseEmpty(spec, prevParsePart); break; case PART_PREAMBLE: - parsePart = parsePreamble(spec, initialPackage); + parsePart = parsePreamble(spec, initialPackage, stage); initialPackage = 0; break; case PART_PATCHLIST: @@ -1111,6 +1123,25 @@ static rpmRC parseSpecSection(rpmSpec *specptr, enum parseStages stage) goto errxit; } + if (stage == PARSE_GENERATED) { + switch (parsePart) { + case PART_PREP: + case PART_BUILD: + case PART_INSTALL: + case PART_CHECK: + case PART_CLEAN: /* ???? */ + case PART_BUILDARCHITECTURES: + case PART_PATCHLIST: + case PART_SOURCELIST: + case PART_BUILDREQUIRES: + case PART_CONF: + rpmlog(RPMLOG_ERR, _("Section %s is not allowed after build is done!\n"), partName(parsePart)); + goto errxit; + break; + default: + ; + } + } if (parsePart == PART_BUILDARCHITECTURES) { int index; int x; diff --git a/docs/manual/dynamic_specs.md b/docs/manual/dynamic_specs.md index 44e6ca2fc4..2084028707 100644 --- a/docs/manual/dynamic_specs.md +++ b/docs/manual/dynamic_specs.md @@ -34,3 +34,14 @@ interpreted right away. [Example](https://github.com/rpm-software-management/rpm/blob/master/tests/data/SPECS/dynamic.spec) from our tests set. + +As dynamic spec parts are generate during build they cannot include +directives that are needed for or influence building. This includes +all build scripts, sources and patches, Build dependencies, tags +regarding the build environment (**ExcludeArch**, **ExclusiveArch**, +**ExcludeOS**, **ExclusiveOS**), **BuildArch** except for declaring +sub packages **noarch** and **BuildSystem**. These will create an +error if encountered in a dynamically generated spec part. + +While declaring macros used in the build scripts are not an error they +won't have an influence on the build for obvious reasons. diff --git a/tests/data/SPECS/dynamic.spec b/tests/data/SPECS/dynamic.spec index ce31ed2828..511675d051 100644 --- a/tests/data/SPECS/dynamic.spec +++ b/tests/data/SPECS/dynamic.spec @@ -41,6 +41,8 @@ echo "LicenseToKill: True" >> %{specpartsdir}/mainpkg.specpart echo "%package docs" >> %{specpartsdir}/docs.specpart %{?!FAIL:echo "Summary: Documentation for dynamic spec" >> %{specpartsdir}/docs.specpart} echo "BuildArch: noarch" >> %{specpartsdir}/docs.specpart +%{?FORBIDDENTAG:echo "BuildRequires: python3" >> %{specpartsdir}/docs.specpart} +%{?FORBIDDENSECTION:echo "%check" >> %{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 diff --git a/tests/rpmbuild.at b/tests/rpmbuild.at index c47a532e9b..0857e76d8d 100644 --- a/tests/rpmbuild.at +++ b/tests/rpmbuild.at @@ -2764,6 +2764,40 @@ error: parsing failed RPMTEST_CLEANUP +# ------------------------------ +# Check failing dynamic spec generation +AT_SETUP([rpmbuild with dynamic spec generation fail]) +AT_KEYWORDS([build]) +RPMDB_INIT +RPMTEST_CHECK([ + +runroot rpmbuild --quiet -D "FULLDYNAMIC 1" -D "FORBIDDENSECTION 1" -ba /data/SPECS/dynamic.spec +], +[1], +[], +[error: Section %check is not allowed after build is done! +error: parsing failed +]) + +RPMTEST_CLEANUP + +# ------------------------------ +# Check failing dynamic spec generation +AT_SETUP([rpmbuild with dynamic spec generation fail]) +AT_KEYWORDS([build]) +RPMDB_INIT +RPMTEST_CHECK([ + +runroot rpmbuild --quiet -D "FULLDYNAMIC 1" -D "FORBIDDENTAG 1" -ba /data/SPECS/dynamic.spec +], +[1], +[], +[error: line 4: Tag not allowed after build is done: BuildRequires: python3 +error: parsing failed +]) + +RPMTEST_CLEANUP + # ------------------------------ # Check source name with space