Skip to content

Commit

Permalink
Don't allow build directives in generated specs
Browse files Browse the repository at this point in the history
Many things need to be known before the build can be started. Make
declaring these sections or directives an error when encountered parsing
the generated Spec parts.

Resolves: rpm-software-management#2693
  • Loading branch information
ffesti committed Mar 6, 2024
1 parent e9d3eae commit 8dcf882
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 103 deletions.
139 changes: 76 additions & 63 deletions build/parsePreamble.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -1060,71 +1069,71 @@ typedef const struct PreambleRec_s {
int type;
int deprecated;
int ismacro;
int prebuildonly;
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)
static int findPreambleTag(rpmSpec spec, PreambleRec * pr, const char ** macro, char * lang)
{
PreambleRec p;
char *s;
Expand Down Expand Up @@ -1173,13 +1182,12 @@ static int findPreambleTag(rpmSpec spec,rpmTagVal * tag,
if (*s != ':') return 1;
break;
}

*tag = p->tag;
*macro = p->ismacro ? p->token : NULL;
*pr = p;
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 */
Expand Down Expand Up @@ -1229,13 +1237,13 @@ int parsePreamble(rpmSpec spec, int initialPackage)
} else {
while (! (nextPart = isPart(spec->line))) {
const char * macro;
rpmTagVal tag;
PreambleRec p;

/* Skip blank lines */
linep = spec->line;
SKIPSPACE(linep);
if (*linep != '\0') {
if (findPreambleTag(spec, &tag, &macro, lang)) {
if (findPreambleTag(spec, &p, &macro, lang)) {
if (spec->lineNum == 1 &&
(unsigned char)(spec->line[0]) == 0xed &&
(unsigned char)(spec->line[1]) == 0xab &&
Expand All @@ -1248,7 +1256,12 @@ int parsePreamble(rpmSpec spec, int initialPackage)
spec->lineNum, spec->line);
goto exit;
}
if (handlePreambleTag(spec, pkg, tag, macro, lang)) {
if (stage == PARSE_GENERATED && p->prebuildonly) {
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, p->tag, macro, lang)) {
goto exit;
}
if (spec->BANames && !spec->recursing) {
Expand Down
107 changes: 68 additions & 39 deletions build/parseSpec.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,47 +41,48 @@ typedef struct OpenFileInfo {

static const struct PartRec {
int part;
int prebuildonly;
size_t len;
const char * token;
} partList[] = {
{ PART_PREAMBLE, LEN_AND_STR("%package")},
{ PART_PREP, LEN_AND_STR("%prep")},
{ PART_BUILDREQUIRES, LEN_AND_STR("%generate_buildrequires")},
{ PART_CONF, LEN_AND_STR("%conf")},
{ PART_BUILD, LEN_AND_STR("%build")},
{ PART_INSTALL, LEN_AND_STR("%install")},
{ PART_CHECK, LEN_AND_STR("%check")},
{ PART_CLEAN, LEN_AND_STR("%clean")},
{ PART_PREUN, LEN_AND_STR("%preun")},
{ PART_POSTUN, LEN_AND_STR("%postun")},
{ PART_PRETRANS, LEN_AND_STR("%pretrans")},
{ PART_POSTTRANS, LEN_AND_STR("%posttrans")},
{ PART_PREUNTRANS, LEN_AND_STR("%preuntrans")},
{ PART_POSTUNTRANS, LEN_AND_STR("%postuntrans")},
{ PART_PRE, LEN_AND_STR("%pre")},
{ PART_POST, LEN_AND_STR("%post")},
{ PART_FILES, LEN_AND_STR("%files")},
{ PART_CHANGELOG, LEN_AND_STR("%changelog")},
{ PART_DESCRIPTION, LEN_AND_STR("%description")},
{ PART_TRIGGERPOSTUN, LEN_AND_STR("%triggerpostun")},
{ PART_TRIGGERPREIN, LEN_AND_STR("%triggerprein")},
{ PART_TRIGGERUN, LEN_AND_STR("%triggerun")},
{ PART_TRIGGERIN, LEN_AND_STR("%triggerin")},
{ PART_TRIGGERIN, LEN_AND_STR("%trigger")},
{ PART_VERIFYSCRIPT, LEN_AND_STR("%verifyscript")},
{ PART_POLICIES, LEN_AND_STR("%sepolicy")},
{ PART_FILETRIGGERIN, LEN_AND_STR("%filetriggerin")},
{ PART_FILETRIGGERIN, LEN_AND_STR("%filetrigger")},
{ PART_FILETRIGGERUN, LEN_AND_STR("%filetriggerun")},
{ PART_FILETRIGGERPOSTUN, LEN_AND_STR("%filetriggerpostun")},
{ PART_TRANSFILETRIGGERIN, LEN_AND_STR("%transfiletriggerin")},
{ PART_TRANSFILETRIGGERIN, LEN_AND_STR("%transfiletrigger")},
{ PART_TRANSFILETRIGGERUN, LEN_AND_STR("%transfiletriggerun")},
{ PART_TRANSFILETRIGGERPOSTUN, LEN_AND_STR("%transfiletriggerpostun")},
{ PART_EMPTY, LEN_AND_STR("%end")},
{ PART_PATCHLIST, LEN_AND_STR("%patchlist")},
{ PART_SOURCELIST, LEN_AND_STR("%sourcelist")},
{0, 0, 0}
{ PART_PREAMBLE, 0, LEN_AND_STR("%package")},
{ PART_PREP, 1, LEN_AND_STR("%prep")},
{ PART_BUILDREQUIRES, 1, LEN_AND_STR("%generate_buildrequires")},
{ PART_CONF, 1, LEN_AND_STR("%conf")},
{ PART_BUILD, 1, LEN_AND_STR("%build")},
{ PART_INSTALL, 1, LEN_AND_STR("%install")},
{ PART_CHECK, 1, LEN_AND_STR("%check")},
{ PART_CLEAN, 1, LEN_AND_STR("%clean")},
{ PART_PREUN, 0, LEN_AND_STR("%preun")},
{ PART_POSTUN, 0, LEN_AND_STR("%postun")},
{ PART_PRETRANS, 0, LEN_AND_STR("%pretrans")},
{ PART_POSTTRANS, 0, LEN_AND_STR("%posttrans")},
{ PART_PREUNTRANS, 0, LEN_AND_STR("%preuntrans")},
{ PART_POSTUNTRANS, 0, LEN_AND_STR("%postuntrans")},
{ PART_PRE, 0, LEN_AND_STR("%pre")},
{ PART_POST, 0, LEN_AND_STR("%post")},
{ PART_FILES, 0, LEN_AND_STR("%files")},
{ PART_CHANGELOG, 0, LEN_AND_STR("%changelog")},
{ PART_DESCRIPTION, 0, LEN_AND_STR("%description")},
{ PART_TRIGGERPOSTUN, 0, LEN_AND_STR("%triggerpostun")},
{ PART_TRIGGERPREIN, 0, LEN_AND_STR("%triggerprein")},
{ PART_TRIGGERUN, 0, LEN_AND_STR("%triggerun")},
{ PART_TRIGGERIN, 0, LEN_AND_STR("%triggerin")},
{ PART_TRIGGERIN, 0, LEN_AND_STR("%trigger")},
{ PART_VERIFYSCRIPT, 0, LEN_AND_STR("%verifyscript")},
{ PART_POLICIES, 0, LEN_AND_STR("%sepolicy")},
{ PART_FILETRIGGERIN, 0, LEN_AND_STR("%filetriggerin")},
{ PART_FILETRIGGERIN, 0, LEN_AND_STR("%filetrigger")},
{ PART_FILETRIGGERUN, 0, LEN_AND_STR("%filetriggerun")},
{ PART_FILETRIGGERPOSTUN, 0, LEN_AND_STR("%filetriggerpostun")},
{ PART_TRANSFILETRIGGERIN, 0, LEN_AND_STR("%transfiletriggerin")},
{ PART_TRANSFILETRIGGERIN, 0, LEN_AND_STR("%transfiletrigger")},
{ PART_TRANSFILETRIGGERUN, 0, LEN_AND_STR("%transfiletriggerun")},
{ PART_TRANSFILETRIGGERPOSTUN, 0, LEN_AND_STR("%transfiletriggerpostun")},
{ PART_EMPTY, 0, LEN_AND_STR("%end")},
{ PART_PATCHLIST, 1, LEN_AND_STR("%patchlist")},
{ PART_SOURCELIST, 1, LEN_AND_STR("%sourcelist")},
{0, 0, 0, 0}
};

int isPart(const char *line)
Expand All @@ -100,6 +101,30 @@ 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 const int partPrebuildonly(int part)
{
const struct PartRec *p;

for (p = partList; p->token != NULL; p++) {
if (p->part == part) {
return p->prebuildonly;
}
}
return 0;
}

/**
*/
static int matchTok(const char *token, const char *line)
Expand Down Expand Up @@ -1022,7 +1047,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:
Expand Down Expand Up @@ -1111,6 +1136,10 @@ static rpmRC parseSpecSection(rpmSpec *specptr, enum parseStages stage)
goto errxit;
}

if (stage == PARSE_GENERATED && partPrebuildonly(parsePart)) {
rpmlog(RPMLOG_ERR, _("Section %s is not allowed after build is done!\n"), partName(parsePart));
goto errxit;
}
if (parsePart == PART_BUILDARCHITECTURES) {
int index;
int x;
Expand Down
11 changes: 11 additions & 0 deletions docs/manual/dynamic_specs.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
2 changes: 1 addition & 1 deletion po
Submodule po updated 7 files
+9 −8 POTFILES.in
+559 −558 cmn.po
+485 −504 cs.po
+69 −85 id.po
+17 −17 ka.po
+44 −52 tr.po
+186 −190 zh_CN.po
2 changes: 2 additions & 0 deletions tests/data/SPECS/dynamic.spec
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 8dcf882

Please sign in to comment.