From 9b6b39f88304c06378d57d86235ad9fc901a2d29 Mon Sep 17 00:00:00 2001 From: Jonathan Perkin Date: Thu, 20 Sep 2018 10:37:36 +0100 Subject: [PATCH] Fix handling of unavailable and preferred packages. During some of the earlier rototilling, the package not available message was no longer printed for unavailable packages due to changes in the download code. This is now fixed, and also differentiates correctly between packages that are not available, and those that do not match the requirements stated in preferred.conf. Use separate functions for install and show-* commands, the former using the preferred.conf logic, the latter using regular matches to match local queries and other tools. This also avoids "not preferred" messages leaking into show-* output, they belong in trace/debug output. Abstract away some of the logic that will help in future cleanups, and improve the output messages. Upgrades still do not support preferred matches, this will be fixed in due course. --- impact.c | 13 ++++----- messages.h | 3 +- pkg_str.c | 83 +++++++++++++++++++++++++++++++++++++++++------------ pkgin.h | 3 +- preferred.c | 27 +++++++++++------ 5 files changed, 91 insertions(+), 38 deletions(-) diff --git a/impact.c b/impact.c index fdf056f..d9c5eac 100644 --- a/impact.c +++ b/impact.c @@ -346,7 +346,7 @@ pkg_impact(char **pkgargs, int *rc) Plisthead *impacthead, *pdphead = NULL; Pkglist *pimpact, *tmpimpact, *pdp; char **ppkgargs, *pkgname; - int istty; + int istty, rv; #ifndef DEBUG char tmpicon; #endif @@ -369,12 +369,11 @@ pkg_impact(char **pkgargs, int *rc) /* retreive impact list for all packages listed in the command line */ for (ppkgargs = pkgargs; *ppkgargs != NULL; ppkgargs++) { - /* check if this is a multiple-version package (apache, ...) - * and that the wanted package actually exists. Get pkgname - * from unique_pkg, full package format. - */ - if ((pkgname = unique_pkg(*ppkgargs, REMOTE_PKG)) == NULL) { - /* package is not available in the repository */ + if ((rv = find_preferred_pkg(*ppkgargs, &pkgname)) != 0) { + if (pkgname == NULL) + fprintf(stderr, MSG_PKG_NOT_AVAIL, *ppkgargs); + else + fprintf(stderr, MSG_PKG_NOT_PREFERRED, *ppkgargs, pkgname); *rc = EXIT_FAILURE; continue; } diff --git a/messages.h b/messages.h index 498835a..c971e3a 100644 --- a/messages.h +++ b/messages.h @@ -116,8 +116,7 @@ "there's more than one version available for this package.\n\ please re-run %s with a package name matching one of the following:\n" #define MSG_PKG_NOT_AVAIL "%s is not available in the repository\n" -#define MSG_PKG_IS_PREFERRED "\rnot choosing %s, %s is preferred\n" -#define MSG_PKG_NOT_INSTALLABLE "\r\n%s is not installable\n" +#define MSG_PKG_NOT_PREFERRED "No %s package available that satisfies preferred match %s\n" #define MSG_BROKEN_DEP "%s has no dependency in pkg_summary(5), while it's a reverse dependency for %s (missing package in repository ?). Default behaviour is to remove %s. " /* pkglist.c */ diff --git a/pkg_str.c b/pkg_str.c index 8a9e06d..484324b 100644 --- a/pkg_str.c +++ b/pkg_str.c @@ -31,6 +31,70 @@ #define GLOBCHARS "{<>[]?*" +/* + * Return list of potential candidates from a package match, or NULL if no + * valid matches are found. + */ +static Plistnumbered * +find_remote_pkgs(const char *pkgname) +{ + const char *query; + + query = exact_pkgfmt(pkgname) ? UNIQUE_EXACT_PKG : UNIQUE_PKG; + + return rec_pkglist(query, REMOTE_PKG, pkgname); +} + +/* + * Return best candidate for a remote package, taking into consideration any + * preferred.conf matches. + * + * A return value of -1 indicates no remote packages matched the request. A + * return value of 0 with a NULL result indicates that all remote packages + * failed to pass the preferred.conf requirements. Otherwise 0 is returned + * and result contains the best available package. + */ +int +find_preferred_pkg(const char *pkgname, char **result) +{ + Plistnumbered *plist; + Pkglist *p, *pkg = NULL; + + *result = NULL; + + /* No matching packages available */ + if ((plist = find_remote_pkgs(pkgname)) == NULL) + return -1; + + /* Find best match */ + SLIST_FOREACH(p, plist->P_Plisthead, next) { + /* + * Check that the candidate matches any potential + * preferred.conf restrictions, if not then skip. + */ + if (chk_preferred(p->full, result) != 0) + continue; + + /* Save best match */ + if (pkg == NULL) + pkg = p; + else if (dewey_cmp(p->version, DEWEY_GT, pkg->version)) + pkg = p; + } + + if (pkg != NULL) { + /* In case a previous version failed the match */ + if (*result != NULL) + free(*result); + *result = xstrdup(pkg->full); + } + + free_pkglist(&plist->P_Plisthead); + free(plist); + + return (pkg == NULL) ? 1 : 0; +} + /** * \fn unique_pkg * @@ -39,7 +103,6 @@ char * unique_pkg(const char *pkgname, const char *dest) { - uint8_t ispref = 0; char *u_pkg = NULL; Plistnumbered *plist; Pkglist *best_match = NULL, *current; @@ -53,19 +116,6 @@ unique_pkg(const char *pkgname, const char *dest) return NULL; SLIST_FOREACH(current, plist->P_Plisthead, next) { - /* - * there was a preferred.conf file and the current package - * matches one of the lines - */ - if (chk_preferred(current->full)) { - /* - * package is listed in preferred.conf but the - * version doesn't match requirement - */ - ispref = 1; - continue; - } - /* first result */ if (best_match == NULL) best_match = current; @@ -80,11 +130,6 @@ unique_pkg(const char *pkgname, const char *dest) free_pkglist(&plist->P_Plisthead); free(plist); - /* chosen package has no installation candidate */ - if (u_pkg == NULL && !ispref) - printf(MSG_PKG_NOT_INSTALLABLE, pkgname); - - /* u_pkg might be NULL if a version is preferred and not available */ return u_pkg; } diff --git a/pkgin.h b/pkgin.h index 0843a17..bdf97af 100644 --- a/pkgin.h +++ b/pkgin.h @@ -259,6 +259,7 @@ uint64_t fs_room(const char *); void clean_cache(void); char *read_repos(void); /* pkg_str.c */ +int find_preferred_pkg(const char *, char **); char *unique_pkg(const char *, const char *); Pkglist *map_pkg_to_dep(Plisthead *, char *); uint8_t non_trivial_glob(char *); @@ -311,6 +312,6 @@ void pkgindb_stats(void); /* preferred.c */ void load_preferred(void); void free_preferred(void); -uint8_t chk_preferred(char *); +uint8_t chk_preferred(char *, char **); #endif diff --git a/preferred.c b/preferred.c index 67dea48..8fec35b 100644 --- a/preferred.c +++ b/preferred.c @@ -105,18 +105,27 @@ is_preferred(char *fullpkg) return NULL; } +/* + * Given a full package name in "pkg" (e.g. "foo-1.0"), look for any + * corresponding entries for "foo" in preferred.conf and if so check that + * any version requirements are satisfied. + * + * Return 0 if either there are no matches or the requirement is satisfied, + * otherwise return 1. If there is a match it is stored in *matchp. + */ uint8_t -chk_preferred(char *match) +chk_preferred(char *pkg, char **matchp) { char *pref; - if ((pref = is_preferred(match)) != NULL && !pkg_match(pref, match)) { - /* - * package is listed in preferred.conf but the - * version doesn't match requirement - */ - printf(MSG_PKG_IS_PREFERRED, match, pref); - return 1; + if ((pref = is_preferred(pkg)) == NULL) { + /* No matches for pkg in preferred.conf */ + *matchp = NULL; + return 0; } - return 0; + + if (*matchp == NULL) + *matchp = xstrdup(pref); + + return (pkg_match(pref, pkg) == 0) ? 1 : 0; }