From a89f9552ec5bc51ae562236d3c72dce346bffafe Mon Sep 17 00:00:00 2001 From: Silvan Date: Sun, 3 Nov 2024 12:17:16 +0100 Subject: [PATCH] distromatic,distroquery: added support for weak-deps (recommends) --- src/DistroqueryAPI.cpp | 16 ++ src/backend-sqlite3.c | 28 +++ src/distromatic.c | 477 +++++++++++++++++++------------------ src/headerlist.c | 37 ++- src/include/headerlist.h | 4 +- src/include/rpmfunctions.h | 4 + src/reports.c | 40 +++- src/rpmfunctions.c | 11 + 8 files changed, 383 insertions(+), 234 deletions(-) diff --git a/src/DistroqueryAPI.cpp b/src/DistroqueryAPI.cpp index 2d8d104..bed128a 100644 --- a/src/DistroqueryAPI.cpp +++ b/src/DistroqueryAPI.cpp @@ -701,6 +701,22 @@ json DistroqueryAPI::getPackageDetails(string repository, string package, string sqlite3_finalize(stmt2); } + // Recommends + sql = "SELECT * FROM recommends WHERE recommends.id_package=" + to_string(id); + j["recommends"] = json::array(); + if (sqlite3_prepare_v2(db, sql.c_str(), sql.length(), &stmt2, NULL) == SQLITE_OK) { + while (sqlite3_step(stmt2) == SQLITE_ROW) { + json recommend = {}; + recommend["name"] = reinterpret_cast(sqlite3_column_text(stmt2,sqlite3_find_column_id(stmt2, NULL, "recommendname"))); + recommend["flags"] = rpmSenseFlagsToString(sqlite3_column_int(stmt2,sqlite3_find_column_id(stmt2, NULL, "recommendflags"))); + recommend["version"] = reinterpret_cast(sqlite3_column_text(stmt2,sqlite3_find_column_id(stmt2, NULL, "recommendversion"))); + json jproviders = getProvidersForRequirement(repository, recommend["name"], recommend["flags"], recommend["version"], arch); + recommend["providers"] = jproviders["providers"]; + j["recommends"].push_back(recommend); + } + sqlite3_finalize(stmt2); + } + // Package files json files = getPackageFiles(repository, package, arch); if (files.contains("files")) diff --git a/src/backend-sqlite3.c b/src/backend-sqlite3.c index 9abcef1..d480e82 100644 --- a/src/backend-sqlite3.c +++ b/src/backend-sqlite3.c @@ -413,6 +413,9 @@ long generateSQLite_add_needrebuild(sqlite3 *db, struct rebuildList* firstRebuil #define SQLITE_TABLE_requires "id INTEGER PRIMARY KEY, "\ "id_package INTEGER, id_provided STRING, requirename STRING, requireflags INTEGER, requireversion STRING" +#define SQLITE_TABLE_recommends "id INTEGER PRIMARY KEY, "\ + "id_package INTEGER, id_provided STRING, recommendname STRING, recommendflags INTEGER, recommendversion STRING" + int generateSQLite_packages(struct configTag *ct, sqlite3 *db, int arch) { @@ -423,6 +426,7 @@ generateSQLite_packages(struct configTag *ct, sqlite3 *db, int arch) { SQLite_init_table(db, "obsoletes", SQLITE_TABLE_obsoletes); SQLite_init_table(db, "provides", SQLITE_TABLE_provides); SQLite_init_table(db, "requires", SQLITE_TABLE_requires); + SQLite_init_table(db, "recommends", SQLITE_TABLE_recommends); SQLite_begin_transaction(db); currpackage = ct->headerlist[arch]; @@ -513,6 +517,30 @@ generateSQLite_packages(struct configTag *ct, sqlite3 *db, int arch) { fprintf(stderr, "WARNING: package %s requires %s not in provided list\n", currpackage->name, currpackage->require[i]->name); } } + + /* recommends */ + for (i = 0; i < currpackage->recommendcount; i++) { + if (currpackage->recommend[i]->resolved) { + snprintf(sqlite3_query, PATH_MAX, "INSERT INTO recommends VALUES(NULL,%ld,%ld,?,%ld,?);", + currpackage->id, + currpackage->recommend[i]->resolved->id, + currpackage->recommend[i]->flags); + + if (sqlite3_prepare_v2(db, sqlite3_query, -1, &stmt, NULL)) { + fprintf(stderr, "ERROR: SQLite: (%s) %s\n", sqlite3_query, sqlite3_errmsg(db)); + } + sqlite3_bind_text(stmt, 1, currpackage->recommend[i]->name, -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 2, currpackage->recommend[i]->version, -1, SQLITE_STATIC); + if (sqlite3_step(stmt) != SQLITE_DONE) { + fprintf(stderr, "ERROR: SQLite: (%s) %s\n", sqlite3_query, sqlite3_errmsg(db)); + return 3; + } + sqlite3_finalize(stmt); + } else if (currpackage->obsoleted == 0 && strstr(currpackage->recommend[i]->name,"rpmlib(") != currpackage->recommend[i]->name) { + fprintf(stderr, "WARNING: package %s recommends %s not in provided list\n", currpackage->name, currpackage->recommend[i]->name); + } + } + } currpackage = currpackage->next; } diff --git a/src/distromatic.c b/src/distromatic.c index 753aeba..26c36aa 100644 --- a/src/distromatic.c +++ b/src/distromatic.c @@ -362,6 +362,237 @@ handleObsoletedPackages(struct configTag *ct, int archidx) return 0; } +void resolveRequire(struct configTag *ct, int archidx, struct headerList *currheader, struct Require *require) { + struct providedList *provided; + struct headerList *scanheader, **newprovider; + struct fileTree *file; + char warning[PATH_MAX]; + + assert(require != NULL); + assert(require->name != NULL); + if (!strncmp("executable(",require->name,11)) { + /* dynamic requirement for executable file */ + /*fprintf(stderr,"Warning: skipping unhandled requirement %s for package %s\n", + currheader->require[i]->name,currheader->name);*/ + require->resolved=NULL; + } else if (strncmp("rpmlib(",require->name,7) && + strncmp("debuginfo(build-id)",require->name,20)) { + provided=findOrCreateProvidedListEntry((struct providedList**) &ct->providedlist_idx[archidx], + require->name,1,archidx); + if (provided->numproviders == 0) { + // check if require[i]->name requirement is met + scanheader = ct->headerlist[archidx]; + if ((require->name)[0] == '/') { + /* requirement is a file, find who provides it */ + file=findOrCreateFileTreeEntry(&ct->filetree[archidx],require->name, archidx); + if (file->numproviders > 0) { + scanheader=file->provider[0]; + provided->numproviders=file->numproviders; + provided->numbuildproviders=0; + provided->provider=file->provider; + provided->flags=0; + } else { + scanheader=NULL; + } + } else { + /* requirement is not a file, cross-check with provides */ + while (scanheader && !checkRequireWithProvides(require->name, scanheader)) + scanheader = scanheader->next; + if (scanheader) { + provided->numproviders=1; + provided->numbuildproviders=0; + provided->provider=malloc(sizeof(struct headerList*)); + provided->provider[0]=scanheader; + provided->flags=0; + } + } + if (!scanheader && incremental_mode) { + snprintf(warning,PATH_MAX,"%s(%s,%s): missing provider for %s", + currheader->name, + ct->arch[archidx], + ct->repository[currheader->altrepository]->tag, + require->name); + fprintf(stderr,"Warning: %s\n",warning); + addWarning(currheader->sourceheader, currheader, warning); + } + } else { /* provided->numproviders > 0 */ + /* warn about provides only provided by older packages */ + int k=0; + for (int j = 0; j < provided->numproviders; j++) { + if (provided->provider[j]->sourceheader->updatingparent && + provided->provider[j]->sourceheader->updatingparent->firstchild[archidx] && /* skip if not built for arch */ + !currheader->obsoleted) k++; + } + if (k == provided->numproviders) { // all provides are from older packages + snprintf(warning, PATH_MAX, "%s(%s,%s) requires %s which is only provided by older package(s):", + currheader->name, + currheader->arch, + ct->repository[currheader->altrepository]->tag, + provided->name); + for (int j = 0; j < provided->numproviders; j++) { + snprintf(&warning[strlen(warning)], PATH_MAX - strlen(warning), " %s(%s,%s)", + provided->provider[j]->name, + provided->provider[j]->arch, + ct->repository[provided->provider[j]->altrepository]->tag); + addRebuild(provided->provider[j]->sourceheader, + currheader->sourceheader, provided->provider[j]); + addWarning(provided->provider[j]->sourceheader, currheader, warning); + } + fprintf(stderr,"Warning: %s\n",warning); + } else { + /* warn about provides provided by obsoleted packages */ + int k=0; + for (int j = 0; j < provided->numproviders; j++) { + if (provided->provider[j]->obsoleted && + !provided->provider[j]->sourceheader->updatingparent && // don't fall in case above + !currheader->obsoleted) k++; + } + if (k == provided->numproviders) { // all provides are obsoleted + snprintf(warning, PATH_MAX, "%s(%s,%s) requires %s which is only provided by obsoleted package(s):", + currheader->name, + currheader->arch, + ct->repository[currheader->altrepository]->tag, + provided->name); + for (int j = 0; j < provided->numproviders; j++) { + snprintf(&warning[strlen(warning)], PATH_MAX - strlen(warning), " %s(%s,%s)", + provided->provider[j]->name, + provided->provider[j]->arch, + ct->repository[provided->provider[j]->altrepository]->tag); + } + fprintf(stderr,"Warning: %s\n",warning); + addWarning(currheader->sourceheader, currheader, warning); + for (int j = 0; j < provided->numproviders; j++) { + addWarning(provided->provider[j]->sourceheader, currheader, warning); + } + } + } + if ((require->name)[0] == '/') { + /* when there is a Requires: /file/requirement add provide from file tree as well */ + file=findOrCreateFileTreeEntry(&ct->filetree[archidx],require->name, archidx); + for (k = 0; k < file->numproviders; k++) { + int found = 0; + for (int j = 0; j < provided->numproviders; j++) { + /* avoid duplicates */ + if (file->provider[k] == provided->provider[j]) { + found = 1; + break; + } + } + if (!found) { + //printf("%s also provided by %s\n", currheader->require[i]->name, file->provider[k]->name); + provided->numproviders++; + newprovider=malloc(sizeof(struct headerList*)*provided->numproviders); + for (int j = 0; j < provided->numproviders-1; j++) { + newprovider[j]=provided->provider[j]; + } + newprovider[provided->numproviders-1] = file->provider[k]; + if (provided->provider) free(provided->provider); + provided->provider=newprovider; + char **newversion=malloc(sizeof(char *)*provided->numproviders); + for (int j = 0; j < provided->numproviders-1; j++) { + newversion[j]=provided->version[j]; + } + newversion[provided->numproviders-1] = strdup(provided->provider[provided->numproviders-2]->version); + if (provided->version) free(provided->version); + provided->version=newversion; + } + } + } + } + if (provided->numproviders > 0) { + if (strcmp(require->version,"") && + (require->flags & (RPMSENSE_LESS|RPMSENSE_GREATER|RPMSENSE_EQUAL))) { + int found = 0; + int foundprovider = -1; + int foundupstreamprovider = 0; + for (int j = 0; j < provided->numproviders; j++) { + /* updated packages: ignore check with upstream package */ + if ((foundprovider >= 0) && + !strcmp(provided->provider[foundprovider]->name,provided->provider[j]->name) && + provided->provider[foundprovider]->altrepository < provided->provider[j]->altrepository) { + found -= 1; + foundupstreamprovider = foundprovider; + foundprovider = -1; + } + if (!strcmp(provided->version[j],"")) { + /* provider with no version; assume ok */ + found += 1; + foundupstreamprovider = foundprovider; + foundprovider = j; + } else { + if (checkVersionWithFlags( + require->version, + require->flags, + provided->version[j])) { + found += 1; + foundupstreamprovider = foundprovider; + foundprovider = j; + } + } + } /* for */ + if ((found >= 1) && (!foundupstreamprovider) && + (currheader->altrepository != 0) && + (currheader->altrepository = ct->repository_level) && + (provided->provider[foundprovider]->sourceheader != currheader->sourceheader) && + (provided->provider[foundprovider]->altrepository == currheader->altrepository)) { + snprintf(warning, PATH_MAX, "%s(%s,%s) requires %s(%s,%s) because it needs %s=%s", + currheader->name, currheader->arch, + ct->repository[currheader->altrepository]->tag, + provided->provider[foundprovider]->name, + provided->provider[foundprovider]->arch, + ct->repository[provided->provider[foundprovider]->altrepository]->tag, + provided->name, + provided->version[foundprovider]); + logmsg(LOG_WARNING,"%s", warning); + addWarning(currheader->sourceheader, currheader, warning); + } else if (!found) { + for (int j = 0; j < provided->numproviders; j++) { + if (!checkVersionWithFlags( + require->version, + require->flags, + provided->version[j])) { + snprintf(warning, PATH_MAX, "%s=%s from %s(%s,%s) fails to provide %s", + provided->name, + provided->version[j], + provided->provider[j]->name, + provided->provider[j]->arch, + ct->repository[provided->provider[j]->altrepository]->tag, + provided->name); + if (require->flags & RPMSENSE_LESS) + snprintf(&warning[strlen(warning)], PATH_MAX,"<"); + if (require->flags & RPMSENSE_GREATER) + snprintf(&warning[strlen(warning)], PATH_MAX, ">"); + if (require->flags & RPMSENSE_EQUAL) + snprintf(&warning[strlen(warning)], PATH_MAX, "="); + snprintf(&warning[strlen(warning)], PATH_MAX, "%s to %s(%s,%s)", + require->version, + currheader->name, + currheader->arch, + ct->repository[currheader->altrepository]->tag); + logmsg(LOG_WARNING,"%s", warning); + for (int k = 0; k < provided->numproviders; k++) { + if (provided->provider[k]->sourceheader && + (provided->provider[k]->altrepository == ct->repository_level)) { + addWarning(provided->provider[k]->sourceheader, currheader, warning); + addRebuild(provided->provider[k]->sourceheader, + currheader->sourceheader, provided->provider[k]); + } + if ((currheader->altrepository == ct->repository_level)) { + addWarning(currheader->sourceheader, currheader, warning); + } + } + } + } /* for */ + } + } + } + require->resolved=provided; + } else { + require->resolved=NULL; + } /* if */ + +} + /* * resolve first level requires for given headerList * note: this function doesn't free allocated memory so it should be called @@ -369,19 +600,14 @@ handleObsoletedPackages(struct configTag *ct, int archidx) static int resolveFirstLevelDependencies(struct configTag *ct, int archidx) { - struct headerList *currheader, *scanheader, **newprovider; - struct providedList *provided; - struct fileTree *file; - int i,j,k,found,foundprovider, foundupstreamprovider; + struct headerList *currheader; char warning[PATH_MAX]; - char ** newversion; currheader = ct->headerlist[archidx]; logmsg(LOG_DEBUG,"resolveFirstLevelDependencies - binaries"); while (currheader) { - scanheader = ct->headerlist[archidx]; currheader->requirelist = NULL; if ((!currheader->obsoleted) && (currheader->next) && (currheader->sourceheader->updatingparent)) { // mark obsoleted any package with same name in upper level repositories @@ -424,236 +650,27 @@ resolveFirstLevelDependencies(struct configTag *ct, int archidx) currheader = currheader->next; continue; } - // currheader->require.resolved = malloc(sizeof(struct providedList*)*currheader->requirecount); - for (i = 0; i < currheader->requirecount; i++) { - assert(currheader->require[i] != NULL); - assert(currheader->require[i]->name != NULL); - if (!strncmp("executable(",currheader->require[i]->name,11)) { - /* dynamic requirement for executable file */ - /*fprintf(stderr,"Warning: skipping unhandled requirement %s for package %s\n", - currheader->require[i]->name,currheader->name);*/ - currheader->require[i]->resolved=NULL; - } else if (strncmp("rpmlib(",currheader->require[i]->name,7) && - strncmp("debuginfo(build-id)",currheader->require[i]->name,20)) { - provided=findOrCreateProvidedListEntry((struct providedList**) &ct->providedlist_idx[archidx], - currheader->require[i]->name,1,archidx); - if (provided->numproviders == 0) { - // check if require[i]->name requirement is met - scanheader = ct->headerlist[archidx]; - if ((currheader->require[i]->name)[0] == '/') { - /* requirement is a file, find who provides it */ - file=findOrCreateFileTreeEntry(&ct->filetree[archidx],currheader->require[i]->name, archidx); - if (file->numproviders > 0) { - scanheader=file->provider[0]; - provided->numproviders=file->numproviders; - provided->numbuildproviders=0; - provided->provider=file->provider; - provided->flags=0; - } else { - scanheader=NULL; - } - } else { - /* requirement is not a file, cross-check with provides */ - while (scanheader && !checkRequireWithProvides( - currheader->require[i]->name, scanheader)) - scanheader = scanheader->next; - if (scanheader) { - provided->numproviders=1; - provided->numbuildproviders=0; - provided->provider=malloc(sizeof(struct headerList*)); - provided->provider[0]=scanheader; - provided->flags=0; - } - } - if (!scanheader && incremental_mode) { - snprintf(warning,PATH_MAX,"%s(%s,%s): missing provider for %s", - currheader->name, - ct->arch[archidx], - ct->repository[currheader->altrepository]->tag, - currheader->require[i]->name); - fprintf(stderr,"Warning: %s\n",warning); - addWarning(currheader->sourceheader, currheader, warning); - } - } else { /* provided->numproviders > 0 */ - /* warn about provides only provided by older packages */ - k=0; - for (j = 0; j < provided->numproviders; j++) { - if (provided->provider[j]->sourceheader->updatingparent && - provided->provider[j]->sourceheader->updatingparent->firstchild[archidx] && /* skip if not built for arch */ - !currheader->obsoleted) k++; - } - if (k == provided->numproviders) { // all provides are from older packages - snprintf(warning, PATH_MAX, "%s(%s,%s) requires %s which is only provided by older package(s):", - currheader->name, - currheader->arch, - ct->repository[currheader->altrepository]->tag, - provided->name); - for (j = 0; j < provided->numproviders; j++) { - snprintf(&warning[strlen(warning)], PATH_MAX - strlen(warning), " %s(%s,%s)", - provided->provider[j]->name, - provided->provider[j]->arch, - ct->repository[provided->provider[j]->altrepository]->tag); - addRebuild(provided->provider[j]->sourceheader, - currheader->sourceheader, provided->provider[j]); - addWarning(provided->provider[j]->sourceheader, currheader, warning); - } - fprintf(stderr,"Warning: %s\n",warning); - } else { - /* warn about provides provided by obsoleted packages */ - k=0; - for (j = 0; j < provided->numproviders; j++) { - if (provided->provider[j]->obsoleted && - !provided->provider[j]->sourceheader->updatingparent && // don't fall in case above - !currheader->obsoleted) k++; - } - if (k == provided->numproviders) { // all provides are obsoleted - snprintf(warning, PATH_MAX, "%s(%s,%s) requires %s which is only provided by obsoleted package(s):", - currheader->name, - currheader->arch, - ct->repository[currheader->altrepository]->tag, - provided->name); - for (j = 0; j < provided->numproviders; j++) { - snprintf(&warning[strlen(warning)], PATH_MAX - strlen(warning), " %s(%s,%s)", - provided->provider[j]->name, - provided->provider[j]->arch, - ct->repository[provided->provider[j]->altrepository]->tag); - } - fprintf(stderr,"Warning: %s\n",warning); - addWarning(currheader->sourceheader, currheader, warning); - for (j = 0; j < provided->numproviders; j++) { - addWarning(provided->provider[j]->sourceheader, currheader, warning); - } - } - } - if ((currheader->require[i]->name)[0] == '/') { - /* when there is a Requires: /file/requirement add provide from file tree as well */ - file=findOrCreateFileTreeEntry(&ct->filetree[archidx],currheader->require[i]->name, archidx); - for (k = 0; k < file->numproviders; k++) { - for (j = 0, found = 0; j < provided->numproviders; j++) { - /* avoid duplicates */ - if (file->provider[k] == provided->provider[j]) { - found = 1; - break; - } - } - if (! found) { - //printf("%s also provided by %s\n", currheader->require[i]->name, file->provider[k]->name); - provided->numproviders++; - newprovider=malloc(sizeof(struct headerList*)*provided->numproviders); - for (j = 0; j < provided->numproviders-1; j++) { - newprovider[j]=provided->provider[j]; - } - newprovider[provided->numproviders-1] = file->provider[k]; - if (provided->provider) free(provided->provider); - provided->provider=newprovider; - newversion=malloc(sizeof(char *)*provided->numproviders); - for (j = 0; j < provided->numproviders-1; j++) { - newversion[j]=provided->version[j]; - } - newversion[provided->numproviders-1] = strdup(provided->provider[j]->version); - if (provided->version) free(provided->version); - provided->version=newversion; - } - } - } - } - if (provided->numproviders > 0) { - if (strcmp(currheader->require[i]->version,"") && - (currheader->require[i]->flags & (RPMSENSE_LESS|RPMSENSE_GREATER|RPMSENSE_EQUAL))) { - found = 0; - foundprovider = -1; - foundupstreamprovider = 0; - for (j = 0; j < provided->numproviders; j++) { - /* updated packages: ignore check with upstream package */ - if ((foundprovider >= 0) && - !strcmp(provided->provider[foundprovider]->name,provided->provider[j]->name) && - provided->provider[foundprovider]->altrepository < provided->provider[j]->altrepository) { - found -= 1; - foundupstreamprovider = foundprovider; - foundprovider = -1; - } - if (!strcmp(provided->version[j],"")) { - /* provider with no version; assume ok */ - found += 1; - foundupstreamprovider = foundprovider; - foundprovider = j; - } else { - if (checkVersionWithFlags( - currheader->require[i]->version, - currheader->require[i]->flags, - provided->version[j])) { - found += 1; - foundupstreamprovider = foundprovider; - foundprovider = j; - } - } - } /* for */ - if ((found >= 1) && (!foundupstreamprovider) && - (currheader->altrepository != 0) && - (currheader->altrepository = ct->repository_level) && - (provided->provider[foundprovider]->sourceheader != currheader->sourceheader) && - (provided->provider[foundprovider]->altrepository == currheader->altrepository)) { - snprintf(warning, PATH_MAX, "%s(%s,%s) requires %s(%s,%s) because it needs %s=%s", - currheader->name, currheader->arch, - ct->repository[currheader->altrepository]->tag, - provided->provider[foundprovider]->name, - provided->provider[foundprovider]->arch, - ct->repository[provided->provider[foundprovider]->altrepository]->tag, - provided->name, - provided->version[foundprovider]); - logmsg(LOG_WARNING,"%s", warning); - addWarning(currheader->sourceheader, currheader, warning); - } else if (!found) { - for (j = 0; j < provided->numproviders; j++) { - if (!checkVersionWithFlags( - currheader->require[i]->version, - currheader->require[i]->flags, - provided->version[j])) { - snprintf(warning, PATH_MAX, "%s=%s from %s(%s,%s) fails to provide %s", - provided->name, - provided->version[j], - provided->provider[j]->name, - provided->provider[j]->arch, - ct->repository[provided->provider[j]->altrepository]->tag, - provided->name); - if (currheader->require[i]->flags & RPMSENSE_LESS) - snprintf(&warning[strlen(warning)], PATH_MAX,"<"); - if (currheader->require[i]->flags & RPMSENSE_GREATER) - snprintf(&warning[strlen(warning)], PATH_MAX, ">"); - if (currheader->require[i]->flags & RPMSENSE_EQUAL) - snprintf(&warning[strlen(warning)], PATH_MAX, "="); - snprintf(&warning[strlen(warning)], PATH_MAX, "%s to %s(%s,%s)", - currheader->require[i]->version, - currheader->name, - currheader->arch, - ct->repository[currheader->altrepository]->tag); - logmsg(LOG_WARNING,"%s", warning); - for (k = 0; k < provided->numproviders; k++) { - if (provided->provider[k]->sourceheader && - (provided->provider[k]->altrepository == ct->repository_level)) { - addWarning(provided->provider[k]->sourceheader, currheader, warning); - addRebuild(provided->provider[k]->sourceheader, - currheader->sourceheader, provided->provider[k]); - } - if ((currheader->altrepository == ct->repository_level)) { - addWarning(currheader->sourceheader, currheader, warning); - } - } - } - } /* for */ - } - } - } - currheader->require[i]->resolved=provided; - } else { - currheader->require[i]->resolved=NULL; - } /* if */ + + // Resolve requires + for (int i = 0; i < currheader->requirecount; i++) { + resolveRequire(ct, archidx, currheader, currheader->require[i]); } /* for currheader->requirecount */ // sort required list by first provider's name qsort((void *) &currheader->require[0], currheader->requirecount, sizeof(struct Require *), compareRequiredList); + + // Resolve recommends + for (int i = 0; i < currheader->recommendcount; i++) { + resolveRequire(ct, archidx, currheader, currheader->recommend[i]); + } /* for currheader->requirecount */ + // sort recommend list by first provider's name + qsort((void *) &currheader->recommend[0], + currheader->recommendcount, + sizeof(struct Require *), + compareRequiredList); + currheader = currheader->next; } logmsg(LOG_DEBUG,"resolveFirstLevelDependencies - done"); diff --git a/src/headerlist.c b/src/headerlist.c index 1bab0e2..3a7a2c1 100644 --- a/src/headerlist.c +++ b/src/headerlist.c @@ -1472,16 +1472,17 @@ char* advanceXMLPackageNode(xmlNode **primary_node, xmlNode **filelists_node) { char filepath[bufsize + 1], currname[bufsize + 1]; char *filename=NULL; long i ,j , k, n=0, altn[ALT_REPS_MAX]; - int altrepository=0, obsoletecount, providecount, requirecount, + int altrepository=0, obsoletecount, providecount, requirecount, recommendcount, filenamecount, dirnamecount, alt_reps_num = 0; int_16 *fileflags; char **obsoletename, **obsoleteversion, **providename, **provideversion, **requirename, **requireversion, + **recommendname, **recommendversion, **basename, **dirname, **newversion, **fileusername, **filegroupname; const char* errstr; - uint_32 *dirindex, *requireflags, *obsoleteflags, *provideflags; + uint_32 *dirindex, *requireflags, *recommendflags, *obsoleteflags, *provideflags; #if RPM_VERSION >= 0x050000 rpmts ts = rpmtsCreate(); #else @@ -1660,6 +1661,9 @@ char* advanceXMLPackageNode(xmlNode **primary_node, xmlNode **filelists_node) { getXMLPackageNFV(newheaderlist->name, findXMLPropertyByName(format, "requires"), &requirename, &requireflags, &requireversion, &requirecount); + getXMLPackageNFV(newheaderlist->name, + findXMLPropertyByName(format, "recommends"), + &recommendname, &recommendflags, &recommendversion, &recommendcount); newheaderlist->provided = malloc(sizeof(struct providedList*)*providecount); for (i=0; i < providecount; i++) { @@ -1703,6 +1707,7 @@ char* advanceXMLPackageNode(xmlNode **primary_node, xmlNode **filelists_node) { newheaderlist->obsoleteversion = obsoleteversion; newheaderlist->obsoletecount = obsoletecount; newheaderlist->altrepository = altidx; + // Requires newheaderlist->require = malloc(requirecount * sizeof(struct Require *)); for (j=0; j < requirecount; j++) { @@ -1713,6 +1718,18 @@ char* advanceXMLPackageNode(xmlNode **primary_node, xmlNode **filelists_node) { newheaderlist->require[j]->resolved = NULL; } newheaderlist->requirecount = requirecount; + + // Recommends + newheaderlist->recommend = malloc(recommendcount * sizeof(struct Require *)); + for (j=0; j < recommendcount; j++) { + newheaderlist->recommend[j] = malloc(sizeof(struct Require)); + newheaderlist->recommend[j]->name = recommendname[j]; + newheaderlist->recommend[j]->flags = recommendflags[j]; + newheaderlist->recommend[j]->version = recommendversion[j]; + newheaderlist->recommend[j]->resolved = NULL; + } + newheaderlist->recommendcount = recommendcount; + // Files getXMLPackageFiles(filelists_node[altidx], &basename, &fileusername, &filegroupname, &filenamecount, &fileflags); @@ -1826,6 +1843,8 @@ char* advanceXMLPackageNode(xmlNode **primary_node, xmlNode **filelists_node) { &provideversion, &providecount); getPackageRequires(h, &requirename, &requireflags, &requireversion, &requirecount); + getPackageRecommends(h, &recommendname, &recommendflags, + &recommendversion, &recommendcount); getPackageFiles(h, &dirindex, &dirname, &dirnamecount, &basename, &filenamecount, &fileusername, &filegroupname, &fileflags); @@ -1885,6 +1904,8 @@ char* advanceXMLPackageNode(xmlNode **primary_node, xmlNode **filelists_node) { newheaderlist->obsoleteversion = obsoleteversion; newheaderlist->obsoletecount = obsoletecount; newheaderlist->altrepository = altrepository; + + // Requires newheaderlist->require = malloc(requirecount * sizeof(struct Require *)); for (j=0; j < requirecount; j++) { newheaderlist->require[j] = malloc(sizeof(struct Require)); @@ -1894,6 +1915,18 @@ char* advanceXMLPackageNode(xmlNode **primary_node, xmlNode **filelists_node) { newheaderlist->require[j]->resolved = NULL; } newheaderlist->requirecount = requirecount; + + // Recommends + newheaderlist->recommend = malloc(recommendcount * sizeof(struct Require *)); + for (j=0; j < recommendcount; j++) { + newheaderlist->recommend[j] = malloc(sizeof(struct Require)); + newheaderlist->recommend[j]->name = recommendname[j]; + newheaderlist->recommend[j]->flags = recommendflags[j]; + newheaderlist->recommend[j]->version = recommendversion[j]; + newheaderlist->recommend[j]->resolved = NULL; + } + newheaderlist->recommendcount = recommendcount; + newheaderlist->file = malloc(sizeof(struct fileTree*) * filenamecount); newheaderlist->fileflags = diff --git a/src/include/headerlist.h b/src/include/headerlist.h index ebc2a5b..78be585 100644 --- a/src/include/headerlist.h +++ b/src/include/headerlist.h @@ -1,7 +1,7 @@ /* * distromatic - tool for RPM based repositories * - * Copyright (C) 2004-2020 by Silvan Calarco + * Copyright (C) 2004-2024 by Silvan Calarco * Copyright (C) 2006 by Davide Madrisan */ @@ -95,6 +95,8 @@ struct headerList { int providecount; int requirecount; struct Require **require; + int recommendcount; + struct Require **recommend; struct providedList **provided; int filenamecount; struct fileTree **file; diff --git a/src/include/rpmfunctions.h b/src/include/rpmfunctions.h index 5aed840..56ee609 100644 --- a/src/include/rpmfunctions.h +++ b/src/include/rpmfunctions.h @@ -55,6 +55,10 @@ int getPackageRequires( Header h, char ***requirename, uint_32 **requireflags, char ***requireversion, int *requirecount); +int getPackageRecommends( + Header h, char ***recommendname, uint_32 **recommendflags, + char ***recommendversion, int *recommendcount); + int getPackageProvides( Header h, char ***providename, uint_32 **provideflags, char ***provideversion, int *providecount); diff --git a/src/reports.c b/src/reports.c index d765668..16b060c 100644 --- a/src/reports.c +++ b/src/reports.c @@ -26,7 +26,6 @@ #include "reports.h" #include "rpmfunctions.h" #include "functions.h" -#include "requirelist.h" #include #include @@ -1833,6 +1832,8 @@ int print_datatables(struct configTag *ct, int arch) { currheaderlist = ct->headerlist[arch]; while (currheaderlist) { fprintf(fd,"%s: ", currheaderlist->name); + + // Add requires for (i = 0; i < currheaderlist->requirecount; i++) { if (currheaderlist->require[i]->resolved) { if (currheaderlist->require[i]->resolved->numproviders == 0) { @@ -1868,6 +1869,43 @@ int print_datatables(struct configTag *ct, int arch) { } } } + + // Add recommends (weak-deps) + for (i = 0; i < currheaderlist->recommendcount; i++) { + if (currheaderlist->recommend[i]->resolved) { + if (currheaderlist->recommend[i]->resolved->numproviders == 0) { + // Filter out complex deps like "(name >= ver1 with name < ver2) + if (currheaderlist->recommend[i]->resolved->name[0] != '(') { + fprintf_depstable_filtered_var(fd, + currheaderlist->recommend[i]->resolved->name); + fprintf(fd,"_unresolved_ "); + } + } else if (currheaderlist->recommend[i]->resolved->numproviders == 1) { + if ((i == 0 || + !currheaderlist->recommend[i-1]->resolved || + !currheaderlist->recommend[i-1]->resolved->numproviders || + strcmp(currheaderlist->recommend[i-1]->resolved->provider[0]->name, + currheaderlist->recommend[i]->resolved->provider[0]->name)) && + strcmp(currheaderlist->name, + currheaderlist->recommend[i]->resolved->provider[0]->name)) { + fprintf(fd,"%s ",currheaderlist->recommend[i]->resolved->provider[0]->name); + } + } else { + if (i == 0 || + !currheaderlist->recommend[i-1]->resolved || + !currheaderlist->recommend[i-1]->resolved->numproviders || + strcmp(currheaderlist->recommend[i-1]->resolved->name, + currheaderlist->recommend[i]->resolved->name)) { + fprintf_depstable_filtered_var(fd,currheaderlist->recommend[i]->resolved->name); + fprintf(fd," "); + } + } + for (int j = 0; j < currheaderlist->recommend[i]->resolved->numproviders; j++) { + if (currheaderlist->recommend[i]->resolved->provider[j]->sourceheader != currheaderlist->sourceheader) + currheaderlist->recommend[i]->resolved->provider[j]->sourceheader->childrenrequiredcount[arch]++; + } + } + } fprintf(fd,"\n"); // diff --git a/src/rpmfunctions.c b/src/rpmfunctions.c index f8156e0..acde9e7 100644 --- a/src/rpmfunctions.c +++ b/src/rpmfunctions.c @@ -303,6 +303,17 @@ getPackageRequires(Header h, char ***requirename, uint_32 **requireflags, return 0; } +int +getPackageRecommends(Header h, char ***recommendname, uint_32 **recommendflags, + char ***recommendversion, int *recommendcount) +{ + *recommendname = headerGetStringArrayEntry(h, RPMTAG_RECOMMENDNAME, recommendcount); + *recommendflags = headerGetUIntArrayEntry(h, RPMTAG_RECOMMENDFLAGS, recommendcount); + *recommendversion = headerGetStringArrayEntry(h, RPMTAG_RECOMMENDVERSION, recommendcount); + + return 0; +} + int getPackageProvides(Header h, char ***providename, uint_32 **provideflags, char ***provideversion, int *providecount)