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; }