From 7238dea982c2207222e7d53af88fa80f852f638d Mon Sep 17 00:00:00 2001 From: Michal Domonkos Date: Thu, 8 Oct 2020 10:45:46 +0200 Subject: [PATCH] Separate build warnings from error summary Confusingly, the "RPM build errors" section also includes messages logged as warnings. That gives the false impression that they somehow contributed to the actual build failure and therefore were turned into errors. This appears to be a historical artifact; when a message passes through the logging system and is of the priority RPMLOG_WARNING or higher, we save it in a global buffer (ctx->recs), which is then simply dumped with rpmlogPrint() in the error summary. This was probably good enough when the summary was introduced (commit f2efc72, year 2000), as there were almost no warnings generated by RPM at that time, however as they became more abundant, the summary code was never revisited. There are 3 ways to fix this discrepancy: 1) Change the summary's title to "RPM build problems" 2) Remove the summary altogether 3) Don't show warnings in it Options #1 and #2 would be too disruptive. The error summary needs to stay as is, for the following reasons: - While it usually just repeats the last error, not all errors terminate a build right away, so those can get drown in the output that follows after. Examples: "File not found" in rpmInstall(), or macro expansion errors (note: we may have these terminate a build in the future). - It makes it immediately obvious that something went wrong when examining build logs, and the title "RPM build errors" undoubtedly has become the de-facto text string to search for. That leaves us with option #3. To further lessen the disruption, do keep a summary of warnings, but put them under their own heading, and only show it on build failures. That way, we restrict all the extra verbosity to error time (as it is now) and don't pollute the output of otherwise good builds. There may be packages with long-standing warnings that are not feasible to fix for any reason, and having an indented block of text resembling "RPM build errors" at the end of every build would do no good. Effectively, this commit is just cosmetic - it splits the error summary into two, without any functional or API changes (apart from two function additions). Fixes: #793 (cherry picked from commit 7fd7a60ea29aab018359037058de95b116455db1) --- build/build.c | 18 ++++++++++++++---- rpmio/rpmlog.c | 34 +++++++++++++++++++++++++++++----- rpmio/rpmlog.h | 15 +++++++++++++++ 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/build/build.c b/build/build.c index 5a067c8306..2ef6d02049 100644 --- a/build/build.c +++ b/build/build.c @@ -431,11 +431,21 @@ static rpmRC buildSpec(rpmts ts, BTA_t buildArgs, rpmSpec spec, int what) freeStringBuf(sink); free(cookie); spec->rootDir = NULL; - if (rc != RPMRC_OK && rc != RPMRC_MISSINGBUILDREQUIRES && - rpmlogGetNrecs() > 0) { - rpmlog(RPMLOG_NOTICE, _("\n\nRPM build errors:\n")); - rpmlogPrint(NULL); + + if (rc != RPMRC_OK && rc != RPMRC_MISSINGBUILDREQUIRES) { + unsigned maskWarn = RPMLOG_MASK(RPMLOG_WARNING); + unsigned maskErrs = RPMLOG_UPTO(RPMLOG_ERR); + + if (rpmlogGetNrecsByMask(maskWarn)) { + rpmlog(RPMLOG_NOTICE, _("\n\nRPM build warnings:\n")); + rpmlogPrintByMask(NULL, maskWarn); + } + if (rpmlogGetNrecsByMask(maskErrs)) { + rpmlog(RPMLOG_NOTICE, _("\n\nRPM build errors:\n")); + rpmlogPrintByMask(NULL, maskErrs); + } } + rpmugFree(); if (missing_buildreqs && !rc) { rc = RPMRC_MISSINGBUILDREQUIRES; diff --git a/rpmio/rpmlog.c b/rpmio/rpmlog.c index d52b897fc3..51cbdea018 100644 --- a/rpmio/rpmlog.c +++ b/rpmio/rpmlog.c @@ -16,6 +16,7 @@ struct rpmlogCtx_s { pthread_rwlock_t lock; unsigned mask; int nrecs; + int nrecsPri[RPMLOG_NPRIS]; rpmlogRec recs; rpmlogCallback cbfunc; rpmlogCallbackData cbdata; @@ -33,7 +34,7 @@ static rpmlogCtx rpmlogCtxAcquire(int write) { static struct rpmlogCtx_s _globalCtx = { PTHREAD_RWLOCK_INITIALIZER, RPMLOG_UPTO(RPMLOG_NOTICE), - 0, NULL, NULL, NULL, NULL }; + 0, {0}, NULL, NULL, NULL, NULL }; rpmlogCtx ctx = &_globalCtx; int xx; @@ -54,16 +55,30 @@ static rpmlogCtx rpmlogCtxRelease(rpmlogCtx ctx) return NULL; } -int rpmlogGetNrecs(void) +int rpmlogGetNrecsByMask(unsigned mask) { rpmlogCtx ctx = rpmlogCtxAcquire(0); - int nrecs = -1; - if (ctx) + int nrecs = 0; + + if (ctx == NULL) + return -1; + + if (mask) { + for (int i = 0; i < RPMLOG_NPRIS; i++, mask >>= 1) + if (mask & 1) + nrecs += ctx->nrecsPri[i]; + } else nrecs = ctx->nrecs; + rpmlogCtxRelease(ctx); return nrecs; } +int rpmlogGetNrecs(void) +{ + return rpmlogGetNrecsByMask(0); +} + int rpmlogCode(void) { int code = -1; @@ -98,7 +113,7 @@ rpmlogLvl rpmlogRecPriority(rpmlogRec rec) return (rec != NULL) ? rec->pri : (rpmlogLvl)-1; } -void rpmlogPrint(FILE *f) +void rpmlogPrintByMask(FILE *f, unsigned mask) { rpmlogCtx ctx = rpmlogCtxAcquire(0); @@ -110,6 +125,8 @@ void rpmlogPrint(FILE *f) for (int i = 0; i < ctx->nrecs; i++) { rpmlogRec rec = ctx->recs + i; + if (mask && ((RPMLOG_MASK(rec->pri) & mask) == 0)) + continue; if (rec->message && *rec->message) fprintf(f, " %s", rec->message); } @@ -117,6 +134,11 @@ void rpmlogPrint(FILE *f) rpmlogCtxRelease(ctx); } +void rpmlogPrint(FILE *f) +{ + rpmlogPrintByMask(f, 0); +} + void rpmlogClose (void) { rpmlogCtx ctx = rpmlogCtxAcquire(1); @@ -130,6 +152,7 @@ void rpmlogClose (void) } ctx->recs = _free(ctx->recs); ctx->nrecs = 0; + memset(ctx->nrecsPri, 0, sizeof(ctx->nrecsPri)); rpmlogCtxRelease(ctx); } @@ -378,6 +401,7 @@ static void dolog(struct rpmlogRec_s *rec, int saverec) ctx->recs[ctx->nrecs+1].code = 0; ctx->recs[ctx->nrecs+1].message = NULL; ctx->nrecs++; + ctx->nrecsPri[rec->pri]++; } cbfunc = ctx->cbfunc; cbdata = ctx->cbdata; diff --git a/rpmio/rpmlog.h b/rpmio/rpmlog.h index 6f3da1d5dd..1752259fce 100644 --- a/rpmio/rpmlog.h +++ b/rpmio/rpmlog.h @@ -41,6 +41,7 @@ typedef enum rpmlogLvl_e { /* extract priority */ #define RPMLOG_PRI(p) ((p) & RPMLOG_PRIMASK) #define RPMLOG_MAKEPRI(fac, pri) ((((unsigned)(fac)) << 3) | (pri)) +#define RPMLOG_NPRIS (RPMLOG_DEBUG + 1) /** \ingroup rpmlog * facility codes @@ -132,12 +133,26 @@ typedef void * rpmlogCallbackData; */ typedef int (*rpmlogCallback) (rpmlogRec rec, rpmlogCallbackData data); +/** \ingroup rpmlog + * Return number of rpmError() messages matching a log mask. + * @param mask log mask to filter by (0 is no filtering) + * @return number of messages matching the mask + */ +int rpmlogGetNrecsByMask(unsigned mask); + /** \ingroup rpmlog * Return number of rpmError() ressages. * @return number of messages */ int rpmlogGetNrecs(void) ; +/** \ingroup rpmlog + * Print all rpmError() messages matching a log mask. + * @param f file handle (NULL uses stderr) + * @param mask log mask to filter by (0 is no filtering) + */ +void rpmlogPrintByMask(FILE *f, unsigned mask); + /** \ingroup rpmlog * Print all rpmError() messages. * @param f file handle (NULL uses stderr)