Add support for macro-only dependency generators

In some cases generators are remarkably simple, such as just echoing
back the basename of the file in some namespace such as foo(lib.so),
and forking out a shell to perform such a mundane task is both hideously
slow and plain dumb, when we have quite some string processing facilities
and even a full-blown programming language embedded in rpm itself.

This adds support for using macro functions as generators: if the
generator macro is a parametric macro, then we call that macro
with the file name as the first argument instead of shelling out,
and the expansion of the macro is used as the output. Multiple lines
in output are allowed, and generator styles can be mixed freely
(eg shell out for provides but use macro function for requires etc).

Constructing the expand call with "proper" macro arguments runs into all
sorts of trouble with special character escaping, work around that by
defining the file name as literal macro %1 prior to calling the
generator. Which is a bit dirty but works...
This commit is contained in:
Panu Matilainen 2020-02-06 10:41:07 +02:00 committed by Florian Festi
parent 9b37c4b349
commit bc4339071c
2 changed files with 55 additions and 4 deletions

View File

@ -514,6 +514,27 @@ static ARGV_t runCmd(const char *cmd,
return output;
}
static ARGV_t runCall(const char *cmd,
const char *buildRoot, const char *fn)
{
ARGV_t output = NULL;
char *path = rstrscat(NULL, buildRoot ? buildRoot : "", "/", fn, NULL);
if (_rpmfc_debug)
rpmlog(RPMLOG_DEBUG, "Calling %s() on %s\n", cmd, path);
/* Hack to pass in the path as what looks like a macro argument */
rpmPushMacroFlags(NULL, "1", NULL, path, 1, RPMMACRO_LITERAL);
char *exp = rpmExpand(cmd, NULL);
rpmPopMacro(NULL, "1");
if (*exp)
argvSplit(&output, exp, "\n\r");
free(exp);
free(path);
return output;
}
struct addReqProvDataFc {
rpmfc fc;
const char *namespace;
@ -560,7 +581,7 @@ static void exclFini(struct exclreg_s *excl)
static int rpmfcHelper(rpmfc fc, int ix, const struct exclreg_s *excl,
rpmsenseFlags dsContext, rpmTagVal tagN,
const char *namespace, const char *cmd)
const char *namespace, const char *cmd, int callable)
{
ARGV_t pav = NULL;
const char * fn = fc->fn[ix];
@ -574,7 +595,12 @@ static int rpmfcHelper(rpmfc fc, int ix, const struct exclreg_s *excl,
if (regMatch(excl->global_exclude_from, fn+fc->brlen))
goto exit;
if (callable) {
pav = runCall(cmd, fc->buildRoot, fn);
} else {
pav = runCmd(cmd, fc->buildRoot, fn);
}
if (pav == NULL)
goto exit;
@ -976,12 +1002,22 @@ static int applyAttr(rpmfc fc, int aix, const char *aname,
if (fattrHashGetEntry(fc->fahash, aix, &ixs, &n, NULL)) {
char *mname = rstrscat(NULL, "__", aname, "_", dep->name, NULL);
char *cmd = rpmExpand("%{?", mname, ":%{", mname, "} %{?",
char *cmd;
int callable = rpmMacroIsParametric(NULL, mname);
if (callable) {
cmd = rstrscat(NULL, "%{", mname,
" %{?", mname, "_opts}", "}", NULL);
} else {
cmd = rpmExpand("%{?", mname, ":%{", mname, "} %{?",
mname, "_opts}}", NULL);
}
if (!rstreq(cmd, "")) {
char *ns = rpmfcAttrMacro(aname, "namespace", NULL);
for (int i = 0; i < n; i++) {
if (rpmfcHelper(fc, ixs[i], excl, dep->type, dep->tag, ns, cmd))
if (rpmfcHelper(fc, ixs[i], excl, dep->type, dep->tag,
ns, cmd, callable))
rc = 1;
}
free(ns);

View File

@ -508,6 +508,21 @@ runroot rpmbuild -bb --quiet \
])
AT_CLEANUP
AT_SETUP([Dependency generation 4])
AT_KEYWORDS([build])
AT_CHECK([
runroot rpmbuild -bb --quiet \
--define '__script_requires() foo(%{basename:%{1}})' \
/data/SPECS/shebang.spec
runroot rpm -qp --requires /build/RPMS/noarch/shebang-0.1-1.noarch.rpm|grep -v ^rpmlib
],
[0],
[foo(shebang)
],
[])
AT_CLEANUP
# ------------------------------
# Test spec query functionality
AT_SETUP([rpmspec query 1])