[pacman-dev] [PATCH v3 0/8] Patches for better optdep support
I'm flooding your inbox one last time (for the next two weeks), so you can all bitch about how crappy my patches are while I'm away ;-) This implements most features from https://wiki.archlinux.org/index.php/User:Allan/Pacman_OptDepends (I've added some things regarding package removal there) I'v also added this here: https://wiki.archlinux.org/index.php/Pacman_Roadmap Github link: https://github.com/moben/pacman/tree/optdep What is there: - No regressions afaics - Only show uninstalled optdepends during install/upgrade - In package info, show [installed] after installed optdepends - In package info (local or -ii) show packages which optionally depend on the queried package - '-Qt' doesn't consider optdepends to be orphans, unless '--nooptdeps/-n' is given if it is given, display them like this: 'sqlite3 3.7.7.1-1 (optdepend for: dbmail, python)' - Recursive removal of unneeded optdeps What is still missing: - In package info display the description alongside the "reverse optdeps" [1] - Cascading to optdepends on package removal with an optional flag [2] - Warn when removing optdepends for installed packages [3] - Anything listed under "Other Ideas" - Tests (mainly needed for the package removal stuff I think) - Docs with less sucky english ;-) [1] Not sure if this would be to much and clutter the whole thing, especially for sync repos [2] Maybe '--optdeps/-o' (Related: make 'pacman -So foobar' install all optdepends) [3] like ':: foo: requires bar', but nonfatal Suggestions on how to implement [3]? I've looked at how it works for normal requires by getting ALPM_ERR_UNSATISFIED_DEPS from libalpm, but we don't want to raise an error here, so what to do? I'm still not sure about http://mailman.archlinux.org/pipermail/pacman-dev/2011-July/013886.html It sounds like a good idea, but would also mean changing (some|many|most|all) dep allocating functions from alpm_depend_t *func(foo) to int func(foo, alpm_depend_t *WriteThis) and make them not allocate the alpm_depend_t themselves. An alternative would be to create a new set of functions and make the current ones thin wrappers around those, so most code can stay as simple as it is now and use the allocated object. Comments? --- Benedikt Benedikt Morbach (8): Split optdep into alpm_depend_t and description Hook new optdepend structures up Only display uninstalled optdepends during install/upgrade Show optdep install status in package info optdepends are not orphans unless --nooptdepends is specified Make package info show optional requirements Make recursive removal consider optdepends Show list of optrequires with -Qtdn doc/pacman.8.txt | 6 ++ lib/libalpm/alpm.h | 14 +++++- lib/libalpm/be_local.c | 11 ++++- lib/libalpm/be_package.c | 5 +- lib/libalpm/be_sync.c | 7 ++- lib/libalpm/deps.c | 86 ++++++++++++++++++++++++++++++++- lib/libalpm/deps.h | 3 + lib/libalpm/package.c | 40 +++++++++++----- src/pacman/conf.h | 1 + src/pacman/package.c | 13 ++++- src/pacman/pacman.c | 3 + src/pacman/query.c | 27 +++++++++-- src/pacman/util.c | 120 +++++++++++++++++++++++++++++++++++++++------- src/pacman/util.h | 2 + src/util/pactree.c | 2 +- 15 files changed, 296 insertions(+), 44 deletions(-) -- 1.7.6
This is done as a preparation to better handle optdepends. This commit should not change pacman's behaviour, as it simply adds new functions and data structures and doesn't yet hook them up anywhere. Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- lib/libalpm/alpm.h | 12 +++++++++ lib/libalpm/deps.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/libalpm/deps.h | 3 ++ 3 files changed, 83 insertions(+), 0 deletions(-) diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index d9f3504..e457359 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -130,6 +130,12 @@ typedef struct _alpm_depend_t { alpm_depmod_t mod; } alpm_depend_t; +/** Optional dependency */ +typedef struct _alpm_optdepend_t { + alpm_depend_t *depend; + char *description; +} alpm_optdepend_t; + /** Missing dependency */ typedef struct _alpm_depmissing_t { char *target; @@ -1028,6 +1034,12 @@ alpm_list_t *alpm_checkconflicts(alpm_handle_t *handle, alpm_list_t *pkglist); */ char *alpm_dep_compute_string(const alpm_depend_t *dep); +/** Returns a newly allocated string representing the optional dependency information. + * @param dep a optional dependency info structure + * @return a formatted string, e.g. "sqlite: for Database support" + */ +char *alpm_optdep_compute_string(const alpm_optdepend_t *optdep); + /** @} */ /** @} */ diff --git a/lib/libalpm/deps.c b/lib/libalpm/deps.c index c3681b3..e8ce13b 100644 --- a/lib/libalpm/deps.c +++ b/lib/libalpm/deps.c @@ -44,6 +44,13 @@ void _alpm_dep_free(alpm_depend_t *dep) FREE(dep); } +void _alpm_optdep_free(alpm_optdepend_t *optdep) +{ + _alpm_dep_free(optdep->depend); + FREE(optdep->description); + FREE(optdep); +} + static alpm_depmissing_t *depmiss_new(const char *target, alpm_depend_t *dep, const char *causingpkg) { @@ -466,6 +473,44 @@ alpm_depend_t *_alpm_dep_dup(const alpm_depend_t *dep) return newdep; } +alpm_optdepend_t *_alpm_splitoptdep(const char *optstring) +{ + alpm_optdepend_t *optdep; + char *depstring; + const char *ptr; + + ASSERT(optstring != NULL, return NULL); + + CALLOC(optdep, 1, sizeof(alpm_optdepend_t), return NULL); + + /* Note the extra space in ": " to avoid matching the epoch */ + if((ptr = strstr(optstring, ": ")) == NULL) { + ptr = optstring + strlen(optstring); + } + + STRNDUP(depstring, optstring, ptr - optstring, return NULL); + optdep->depend = _alpm_splitdep(depstring); + FREE(depstring); + + if(*ptr != '\0') { + STRDUP(optdep->description, ptr + 2, return NULL); + optdep->description = _alpm_strtrim(optdep->description); + } + + return optdep; +} + +alpm_optdepend_t *_alpm_optdep_dup(const alpm_optdepend_t *optdep) +{ + alpm_optdepend_t *newdep; + CALLOC(newdep, 1, sizeof(alpm_optdepend_t), return NULL); + + newdep->depend = _alpm_dep_dup(optdep->depend); + STRDUP(newdep->description, optdep->description, return NULL); + + return newdep; +} + /* These parameters are messy. We check if this package, given a list of * targets and a db is safe to remove. We do NOT remove it if it is in the * target list, or if if the package was explictly installed and @@ -820,4 +865,27 @@ char SYMEXPORT *alpm_dep_compute_string(const alpm_depend_t *dep) return str; } + +/** Reverse of splitoptdep; make a optdep string from a alpm_optdepend_t struct. + * The string must be freed! + * @param optdep the optdepend to turn into a string + * @return a string-formatted optional dependency with description + */ +char SYMEXPORT *alpm_optdep_compute_string(const alpm_optdepend_t *optdep) +{ + ASSERT(optdep != NULL, return NULL); + + char *depstring = alpm_dep_compute_string(optdep->depend); + + if(optdep->description != NULL) { + char *str; + size_t len = strlen(depstring) + strlen(optdep->description) + 3; + MALLOC(str, len, return NULL); + snprintf(str, len, "%s: %s", depstring, optdep->description); + free(depstring); + return str; + } + + return depstring; +} /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/deps.h b/lib/libalpm/deps.h index 6ef4cbb..acdd25a 100644 --- a/lib/libalpm/deps.h +++ b/lib/libalpm/deps.h @@ -28,7 +28,9 @@ #include "alpm.h" void _alpm_dep_free(alpm_depend_t *dep); +void _alpm_optdep_free(alpm_optdepend_t *optdep); alpm_depend_t *_alpm_dep_dup(const alpm_depend_t *dep); +alpm_optdepend_t *_alpm_optdep_dup(const alpm_optdepend_t *optdep); void _alpm_depmiss_free(alpm_depmissing_t *miss); alpm_list_t *_alpm_sortbydeps(alpm_handle_t *handle, alpm_list_t *targets, int reverse); void _alpm_recursedeps(alpm_db_t *db, alpm_list_t *targs, int include_explicit); @@ -36,6 +38,7 @@ int _alpm_resolvedeps(alpm_handle_t *handle, alpm_list_t *localpkgs, alpm_pkg_t alpm_list_t *preferred, alpm_list_t **packages, alpm_list_t *remove, alpm_list_t **data); alpm_depend_t *_alpm_splitdep(const char *depstring); +alpm_optdepend_t *_alpm_splitoptdep(const char *optstring); int _alpm_depcmp(alpm_pkg_t *pkg, alpm_depend_t *dep); #endif /* _ALPM_DEPS_H */ -- 1.7.6
No new behaviour introduced, everything should work exactly as before. Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- lib/libalpm/be_local.c | 11 ++++++- lib/libalpm/be_package.c | 5 ++- lib/libalpm/be_sync.c | 7 ++++- lib/libalpm/package.c | 7 +++- src/pacman/package.c | 11 ++++++- src/pacman/util.c | 73 ++++++++++++++++++++++++++++++++++++++------- 6 files changed, 93 insertions(+), 21 deletions(-) diff --git a/lib/libalpm/be_local.c b/lib/libalpm/be_local.c index 261ad87..401bc64 100644 --- a/lib/libalpm/be_local.c +++ b/lib/libalpm/be_local.c @@ -610,7 +610,12 @@ static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq) info->depends = alpm_list_add(info->depends, _alpm_splitdep(line)); } } else if(strcmp(line, "%OPTDEPENDS%") == 0) { - READ_AND_STORE_ALL(info->optdepends); + /* Different than the rest because of the _alpm_splitoptdep call. */ + while(1) { + READ_NEXT(); + if(strlen(line) == 0) break; + info->optdepends = alpm_list_add(info->optdepends, _alpm_splitoptdep(line)); + } } else if(strcmp(line, "%CONFLICTS%") == 0) { READ_AND_STORE_ALL(info->conflicts); } else if(strcmp(line, "%PROVIDES%") == 0) { @@ -822,7 +827,9 @@ int _alpm_local_db_write(alpm_db_t *db, alpm_pkg_t *info, alpm_dbinfrq_t inforeq if(info->optdepends) { fputs("%OPTDEPENDS%\n", fp); for(lp = info->optdepends; lp; lp = lp->next) { - fprintf(fp, "%s\n", (char *)lp->data); + char *optstring = alpm_optdep_compute_string(lp->data); + fprintf(fp, "%s\n", optstring); + free(optstring); } fprintf(fp, "\n"); } diff --git a/lib/libalpm/be_package.c b/lib/libalpm/be_package.c index 0edaa5a..2cf3e46 100644 --- a/lib/libalpm/be_package.c +++ b/lib/libalpm/be_package.c @@ -35,7 +35,7 @@ #include "log.h" #include "handle.h" #include "package.h" -#include "deps.h" /* _alpm_splitdep */ +#include "deps.h" /** * Open a package changelog for reading. Similar to fopen in functionality, @@ -192,7 +192,8 @@ static int parse_descfile(alpm_handle_t *handle, struct archive *a, alpm_pkg_t * alpm_depend_t *dep = _alpm_splitdep(ptr); newpkg->depends = alpm_list_add(newpkg->depends, dep); } else if(strcmp(key, "optdepend") == 0) { - newpkg->optdepends = alpm_list_add(newpkg->optdepends, strdup(ptr)); + alpm_optdepend_t *optdep = _alpm_splitoptdep(ptr); + newpkg->optdepends = alpm_list_add(newpkg->optdepends, optdep); } else if(strcmp(key, "conflict") == 0) { newpkg->conflicts = alpm_list_add(newpkg->conflicts, strdup(ptr)); } else if(strcmp(key, "replaces") == 0) { diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c index 07356f0..2b6f98e 100644 --- a/lib/libalpm/be_sync.c +++ b/lib/libalpm/be_sync.c @@ -555,7 +555,12 @@ static int sync_db_read(alpm_db_t *db, struct archive *archive, pkg->depends = alpm_list_add(pkg->depends, _alpm_splitdep(line)); } } else if(strcmp(line, "%OPTDEPENDS%") == 0) { - READ_AND_STORE_ALL(pkg->optdepends); + /* Different than the rest because of the _alpm_splitoptdep call. */ + while(1) { + READ_NEXT(); + if(strlen(line) == 0) break; + pkg->optdepends = alpm_list_add(pkg->optdepends, _alpm_splitoptdep(line)); + } } else if(strcmp(line, "%CONFLICTS%") == 0) { READ_AND_STORE_ALL(pkg->conflicts); } else if(strcmp(line, "%PROVIDES%") == 0) { diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c index fd3d0c6..1d30503 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -503,7 +503,9 @@ alpm_pkg_t *_alpm_pkg_dup(alpm_pkg_t *pkg) for(i = pkg->depends; i; i = alpm_list_next(i)) { newpkg->depends = alpm_list_add(newpkg->depends, _alpm_dep_dup(i->data)); } - newpkg->optdepends = alpm_list_strdup(pkg->optdepends); + for(i = pkg->optdepends; i; i = alpm_list_next(i)) { + newpkg->optdepends = alpm_list_add(newpkg->optdepends, _alpm_optdep_dup(i->data)); + } newpkg->conflicts = alpm_list_strdup(pkg->conflicts); newpkg->provides = alpm_list_strdup(pkg->provides); for(i = pkg->deltas; i; i = alpm_list_next(i)) { @@ -557,7 +559,8 @@ void _alpm_pkg_free(alpm_pkg_t *pkg) alpm_list_free(pkg->backup); alpm_list_free_inner(pkg->depends, (alpm_list_fn_free)_alpm_dep_free); alpm_list_free(pkg->depends); - FREELIST(pkg->optdepends); + alpm_list_free_inner(pkg->optdepends, (alpm_list_fn_free)_alpm_optdep_free); + alpm_list_free(pkg->optdepends); FREELIST(pkg->conflicts); FREELIST(pkg->provides); alpm_list_free_inner(pkg->deltas, (alpm_list_fn_free)_alpm_delta_free); diff --git a/src/pacman/package.c b/src/pacman/package.c index 45afded..7b1442e 100644 --- a/src/pacman/package.c +++ b/src/pacman/package.c @@ -53,7 +53,7 @@ void dump_pkg_full(alpm_pkg_t *pkg, enum pkg_from from, int extra) const char *label; double size; const alpm_list_t *i; - alpm_list_t *requiredby = NULL, *depstrings = NULL; + alpm_list_t *depstrings = NULL, *optstrings = NULL, *requiredby = NULL; if(pkg == NULL) { return; @@ -87,6 +87,12 @@ void dump_pkg_full(alpm_pkg_t *pkg, enum pkg_from from, int extra) depstrings = alpm_list_add(depstrings, alpm_dep_compute_string(dep)); } + /* turn optdepends list into a text list */ + for(i = alpm_pkg_get_optdepends(pkg); i; i = alpm_list_next(i)) { + alpm_optdepend_t *optdep = alpm_list_getdata(i); + optstrings = alpm_list_add(optstrings, alpm_optdep_compute_string(optdep)); + } + if(extra || from == PKG_FROM_LOCALDB) { /* compute this here so we don't get a pause in the middle of output */ requiredby = alpm_pkg_compute_requiredby(pkg); @@ -104,7 +110,7 @@ void dump_pkg_full(alpm_pkg_t *pkg, enum pkg_from from, int extra) list_display(_("Groups :"), alpm_pkg_get_groups(pkg)); list_display(_("Provides :"), alpm_pkg_get_provides(pkg)); list_display(_("Depends On :"), depstrings); - list_display_linebreak(_("Optional Deps :"), alpm_pkg_get_optdepends(pkg)); + list_display_linebreak(_("Optional Deps :"), optstrings); if(extra || from == PKG_FROM_LOCALDB) { list_display(_("Required By :"), requiredby); } @@ -158,6 +164,7 @@ void dump_pkg_full(alpm_pkg_t *pkg, enum pkg_from from, int extra) printf("\n"); FREELIST(depstrings); + FREELIST(optstrings); FREELIST(requiredby); } diff --git a/src/pacman/util.c b/src/pacman/util.c index 7065abd..f66d6e1 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -974,32 +974,81 @@ void print_packages(const alpm_list_t *packages) } } -/* Helper function for comparing strings using the - * alpm "compare func" signature */ -int str_cmp(const void *s1, const void *s2) +/* Helper function for comparing optdepends using the + * alpm "compare func" signature. */ +static int opt_cmp(const void *o1, const void *o2) { - return strcmp(s1, s2); + const alpm_optdepend_t *od1 = o1; + const alpm_optdepend_t *od2 = o2; + int ret; + + ret = strcmp(od1->depend->name, od2->depend->name); + if(ret == 0) { + ret = od1->depend->mod - od2->depend->mod; + } + if(ret == 0 && od1->depend->version != od2->depend->version) { + if(od1->depend->version && od2->depend->version) { + ret = strcmp(od1->depend->version, od2->depend->version); + } else if(!od1->depend->version && od2->depend->version) { + return -1; + } else if(od1->depend->version && !od2->depend->version) { + return 1; + } + } + if(ret == 0 && od1->description != od2->description) { + if(od1->description && od2->description) { + ret = strcmp(od1->description, od2->description); + } else if(!od1->description && od2->description) { + return -1; + } else if(od1->description && !od2->description) { + return 1; + } + } + + return ret; } void display_new_optdepends(alpm_pkg_t *oldpkg, alpm_pkg_t *newpkg) { - alpm_list_t *old = alpm_pkg_get_optdepends(oldpkg); - alpm_list_t *new = alpm_pkg_get_optdepends(newpkg); - alpm_list_t *optdeps = alpm_list_diff(new,old,str_cmp); - if(optdeps) { + alpm_list_t *i, *old, *new, *optdeps, *optstrings = NULL; + + old = alpm_pkg_get_optdepends(oldpkg); + new = alpm_pkg_get_optdepends(newpkg); + optdeps = alpm_list_diff(new, old, opt_cmp); + + /* turn optdepends list into a text list */ + for(i = optdeps; i; i = alpm_list_next(i)) { + alpm_optdepend_t *optdep = alpm_list_getdata(i); + optstrings = alpm_list_add(optstrings, alpm_optdep_compute_string(optdep)); + } + + if(optstrings) { printf(_("New optional dependencies for %s\n"), alpm_pkg_get_name(newpkg)); - list_display_linebreak(" ", optdeps); + list_display_linebreak(" ", optstrings); } + alpm_list_free(optdeps); + FREELIST(optstrings); } void display_optdepends(alpm_pkg_t *pkg) { - alpm_list_t *optdeps = alpm_pkg_get_optdepends(pkg); - if(optdeps) { + alpm_list_t *i, *optdeps, *optstrings = NULL; + + optdeps = alpm_pkg_get_optdepends(pkg); + + /* turn optdepends list into a text list */ + for(i = optdeps; i; i = alpm_list_next(i)) { + alpm_optdepend_t *optdep = alpm_list_getdata(i); + optstrings = alpm_list_add(optstrings, alpm_optdep_compute_string(optdep)); + } + + if(optstrings) { printf(_("Optional dependencies for %s\n"), alpm_pkg_get_name(pkg)); - list_display_linebreak(" ", optdeps); + list_display_linebreak(" ", optstrings); } + + FREELIST(optstrings); } static void display_repo_list(const char *dbname, alpm_list_t *list) -- 1.7.6
Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- src/pacman/util.c | 42 ++++++++++++++++++++++++++++-------------- 1 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/pacman/util.c b/src/pacman/util.c index f66d6e1..37059d1 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -1008,19 +1008,39 @@ static int opt_cmp(const void *o1, const void *o2) return ret; } +/** Creates a newly-allocated list of optdepend strings from a list of optdepends. + * The list must be freed! + * @param optlist an alpm_list_t of optdepends to turn into a strings + * @return an alpm_list_t of optdepend formatted strings with description + */ +alpm_list_t *optdep_string_list(const alpm_list_t *optlist) +{ + alpm_list_t *optstrings = NULL; + alpm_optdepend_t *optdep; + alpm_db_t *db_local; + + db_local = alpm_option_get_localdb(config->handle); + + /* turn optdepends list into a text list */ + for( ; optlist; optlist = alpm_list_next(optlist)) { + optdep = alpm_list_getdata(optlist); + if(alpm_db_get_pkg(db_local, optdep->depend->name) == NULL) { + optstrings = alpm_list_add(optstrings, alpm_optdep_compute_string(optdep)); + } + } + + return optstrings; +} + void display_new_optdepends(alpm_pkg_t *oldpkg, alpm_pkg_t *newpkg) { - alpm_list_t *i, *old, *new, *optdeps, *optstrings = NULL; + alpm_list_t *old, *new, *optdeps, *optstrings; old = alpm_pkg_get_optdepends(oldpkg); new = alpm_pkg_get_optdepends(newpkg); optdeps = alpm_list_diff(new, old, opt_cmp); - /* turn optdepends list into a text list */ - for(i = optdeps; i; i = alpm_list_next(i)) { - alpm_optdepend_t *optdep = alpm_list_getdata(i); - optstrings = alpm_list_add(optstrings, alpm_optdep_compute_string(optdep)); - } + optstrings = optdep_string_list(optdeps); if(optstrings) { printf(_("New optional dependencies for %s\n"), alpm_pkg_get_name(newpkg)); @@ -1033,15 +1053,9 @@ void display_new_optdepends(alpm_pkg_t *oldpkg, alpm_pkg_t *newpkg) void display_optdepends(alpm_pkg_t *pkg) { - alpm_list_t *i, *optdeps, *optstrings = NULL; + alpm_list_t *optstrings; - optdeps = alpm_pkg_get_optdepends(pkg); - - /* turn optdepends list into a text list */ - for(i = optdeps; i; i = alpm_list_next(i)) { - alpm_optdepend_t *optdep = alpm_list_getdata(i); - optstrings = alpm_list_add(optstrings, alpm_optdep_compute_string(optdep)); - } + optstrings = optdep_string_list(alpm_pkg_get_optdepends(pkg)); if(optstrings) { printf(_("Optional dependencies for %s\n"), alpm_pkg_get_name(pkg)); -- 1.7.6
Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- src/pacman/package.c | 5 +---- src/pacman/util.c | 18 ++++++++++++++---- src/pacman/util.h | 1 + 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/pacman/package.c b/src/pacman/package.c index 7b1442e..790b20c 100644 --- a/src/pacman/package.c +++ b/src/pacman/package.c @@ -88,10 +88,7 @@ void dump_pkg_full(alpm_pkg_t *pkg, enum pkg_from from, int extra) } /* turn optdepends list into a text list */ - for(i = alpm_pkg_get_optdepends(pkg); i; i = alpm_list_next(i)) { - alpm_optdepend_t *optdep = alpm_list_getdata(i); - optstrings = alpm_list_add(optstrings, alpm_optdep_compute_string(optdep)); - } + optstrings = optdep_string_list(alpm_pkg_get_optdepends(pkg), 1); if(extra || from == PKG_FROM_LOCALDB) { /* compute this here so we don't get a pause in the middle of output */ diff --git a/src/pacman/util.c b/src/pacman/util.c index 37059d1..f633241 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -1011,9 +1011,10 @@ static int opt_cmp(const void *o1, const void *o2) /** Creates a newly-allocated list of optdepend strings from a list of optdepends. * The list must be freed! * @param optlist an alpm_list_t of optdepends to turn into a strings + * @param include_installed if false, installed packages are excluded from the list. * @return an alpm_list_t of optdepend formatted strings with description */ -alpm_list_t *optdep_string_list(const alpm_list_t *optlist) +alpm_list_t *optdep_string_list(const alpm_list_t *optlist, int include_installed) { alpm_list_t *optstrings = NULL; alpm_optdepend_t *optdep; @@ -1026,9 +1027,18 @@ alpm_list_t *optdep_string_list(const alpm_list_t *optlist) optdep = alpm_list_getdata(optlist); if(alpm_db_get_pkg(db_local, optdep->depend->name) == NULL) { optstrings = alpm_list_add(optstrings, alpm_optdep_compute_string(optdep)); + } else if(include_installed) { + const char * const installed = _(" [installed]"); + char *str, *tmp; + tmp = alpm_optdep_compute_string(optdep); + if((str = realloc(tmp, strlen(tmp) + strlen(installed) + 1)) != NULL) { + strcpy(str + strlen(str), installed); + optstrings = alpm_list_add(optstrings, str); + } else { + free(tmp); + } } } - return optstrings; } @@ -1040,7 +1050,7 @@ void display_new_optdepends(alpm_pkg_t *oldpkg, alpm_pkg_t *newpkg) new = alpm_pkg_get_optdepends(newpkg); optdeps = alpm_list_diff(new, old, opt_cmp); - optstrings = optdep_string_list(optdeps); + optstrings = optdep_string_list(optdeps, 0); if(optstrings) { printf(_("New optional dependencies for %s\n"), alpm_pkg_get_name(newpkg)); @@ -1055,7 +1065,7 @@ void display_optdepends(alpm_pkg_t *pkg) { alpm_list_t *optstrings; - optstrings = optdep_string_list(alpm_pkg_get_optdepends(pkg)); + optstrings = optdep_string_list(alpm_pkg_get_optdepends(pkg), 0); if(optstrings) { printf(_("Optional dependencies for %s\n"), alpm_pkg_get_name(pkg)); diff --git a/src/pacman/util.h b/src/pacman/util.h index ee3dbd1..ff1cec3 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -62,6 +62,7 @@ void display_targets(const alpm_list_t *pkgs, int install); int str_cmp(const void *s1, const void *s2); void display_new_optdepends(alpm_pkg_t *oldpkg, alpm_pkg_t *newpkg); void display_optdepends(alpm_pkg_t *pkg); +alpm_list_t *optdep_string_list(const alpm_list_t *optdeps, int include_installed); void print_packages(const alpm_list_t *packages); void select_display(const alpm_list_t *pkglist); int select_question(int count); -- 1.7.6
Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- doc/pacman.8.txt | 6 ++++++ lib/libalpm/alpm.h | 2 +- lib/libalpm/package.c | 33 +++++++++++++++++++++++---------- src/pacman/conf.h | 1 + src/pacman/package.c | 2 +- src/pacman/pacman.c | 3 +++ src/pacman/query.c | 16 +++++++++++++--- src/util/pactree.c | 2 +- 8 files changed, 49 insertions(+), 16 deletions(-) diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt index 64b1ff3..90fb040 100644 --- a/doc/pacman.8.txt +++ b/doc/pacman.8.txt @@ -269,6 +269,12 @@ Query Options[[QO]] database(s). Typically these are packages that were downloaded manually and installed with '\--upgrade'. +*-n, \--nooptdeps*:: + When using the '-t' option with this flag, do not treat installed + optional dependencies as if they were normal dependencies. This option + can be used to list packages which were installed as dependencies but are + only optionally used by other packages. + *-o, \--owns* <file>:: Search for packages that own the specified file(s). The path can be relative or absolute and one or more files can be specified. diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index e457359..b6dc37a 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -541,7 +541,7 @@ int alpm_pkg_vercmp(const char *a, const char *b); * @param pkg a package * @return the list of packages requiring pkg */ -alpm_list_t *alpm_pkg_compute_requiredby(alpm_pkg_t *pkg); +alpm_list_t *alpm_pkg_compute_requiredby(alpm_pkg_t *pkg, const int find_optdeps); /** @name Package Property Accessors * Any pointer returned by these functions points to internal structures diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c index 1d30503..6f6e957 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -376,7 +376,8 @@ int SYMEXPORT alpm_pkg_has_scriptlet(alpm_pkg_t *pkg) return pkg->ops->has_scriptlet(pkg); } -static void find_requiredby(alpm_pkg_t *pkg, alpm_db_t *db, alpm_list_t **reqs) +static void find_requiredby(alpm_pkg_t *pkg, alpm_db_t *db, + alpm_list_t **reqs, const int find_optdeps) { const alpm_list_t *i; pkg->handle->pm_errno = 0; @@ -384,11 +385,23 @@ static void find_requiredby(alpm_pkg_t *pkg, alpm_db_t *db, alpm_list_t **reqs) for(i = _alpm_db_get_pkgcache(db); i; i = i->next) { alpm_pkg_t *cachepkg = i->data; alpm_list_t *j; - for(j = alpm_pkg_get_depends(cachepkg); j; j = j->next) { - if(_alpm_depcmp(pkg, j->data)) { - const char *cachepkgname = cachepkg->name; - if(alpm_list_find_str(*reqs, cachepkgname) == NULL) { - *reqs = alpm_list_add(*reqs, strdup(cachepkgname)); + if(find_optdeps) { + for(j = alpm_pkg_get_optdepends(cachepkg); j; j = j->next) { + alpm_optdepend_t *optdep = j->data; + if(_alpm_depcmp(pkg, optdep->depend)) { + const char *cachepkgname = cachepkg->name; + if(alpm_list_find_str(*reqs, cachepkgname) == NULL) { + *reqs = alpm_list_add(*reqs, strdup(cachepkgname)); + } + } + } + } else { + for(j = alpm_pkg_get_depends(cachepkg); j; j = j->next) { + if(_alpm_depcmp(pkg, j->data)) { + const char *cachepkgname = cachepkg->name; + if(alpm_list_find_str(*reqs, cachepkgname) == NULL) { + *reqs = alpm_list_add(*reqs, strdup(cachepkgname)); + } } } } @@ -396,7 +409,7 @@ static void find_requiredby(alpm_pkg_t *pkg, alpm_db_t *db, alpm_list_t **reqs) } /** Compute the packages requiring a given package. */ -alpm_list_t SYMEXPORT *alpm_pkg_compute_requiredby(alpm_pkg_t *pkg) +alpm_list_t SYMEXPORT *alpm_pkg_compute_requiredby(alpm_pkg_t *pkg, const int find_optdeps) { const alpm_list_t *i; alpm_list_t *reqs = NULL; @@ -407,17 +420,17 @@ alpm_list_t SYMEXPORT *alpm_pkg_compute_requiredby(alpm_pkg_t *pkg) if(pkg->origin == PKG_FROM_FILE) { /* The sane option; search locally for things that require this. */ - find_requiredby(pkg, pkg->handle->db_local, &reqs); + find_requiredby(pkg, pkg->handle->db_local, &reqs, find_optdeps); } else { /* We have a DB package. if it is a local package, then we should * only search the local DB; else search all known sync databases. */ db = pkg->origin_data.db; if(db->is_local) { - find_requiredby(pkg, db, &reqs); + find_requiredby(pkg, db, &reqs, find_optdeps); } else { for(i = pkg->handle->dbs_sync; i; i = i->next) { db = i->data; - find_requiredby(pkg, db, &reqs); + find_requiredby(pkg, db, &reqs, find_optdeps); } reqs = alpm_list_msort(reqs, alpm_list_count(reqs), _alpm_str_cmp); } diff --git a/src/pacman/conf.h b/src/pacman/conf.h index bce42ab..2330e9a 100644 --- a/src/pacman/conf.h +++ b/src/pacman/conf.h @@ -54,6 +54,7 @@ typedef struct __config_t { unsigned short op_q_unrequired; unsigned short op_q_deps; unsigned short op_q_explicit; + unsigned short op_q_nooptdeps; unsigned short op_q_owns; unsigned short op_q_search; unsigned short op_q_changelog; diff --git a/src/pacman/package.c b/src/pacman/package.c index 790b20c..6725bdc 100644 --- a/src/pacman/package.c +++ b/src/pacman/package.c @@ -92,7 +92,7 @@ void dump_pkg_full(alpm_pkg_t *pkg, enum pkg_from from, int extra) if(extra || from == PKG_FROM_LOCALDB) { /* compute this here so we don't get a pause in the middle of output */ - requiredby = alpm_pkg_compute_requiredby(pkg); + requiredby = alpm_pkg_compute_requiredby(pkg, 0); } /* actual output */ diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index e855203..54ddbc0 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -146,6 +146,7 @@ static void usage(int op, const char * const myname) addlist(_(" -k, --check check that the files owned by the package(s) are present\n")); addlist(_(" -l, --list list the contents of the queried package\n")); addlist(_(" -m, --foreign list installed packages not found in sync db(s) [filter]\n")); + addlist(_(" -n, --nooptdeps don't consider installed optdepends to be required\n")); addlist(_(" -o, --owns <file> query the package that owns <file>\n")); addlist(_(" -p, --file <package> query a package file instead of the database\n")); addlist(_(" -q, --quiet show less information for query and search\n")); @@ -458,6 +459,7 @@ static int parsearg_query(int opt) case 'c': config->op_q_changelog = 1; break; case 'd': config->op_q_deps = 1; break; case 'e': config->op_q_explicit = 1; break; + case 'n': config->op_q_nooptdeps = 1; break; case 'g': (config->group)++; break; case 'i': (config->op_q_info)++; break; case 'k': config->op_q_check = 1; break; @@ -598,6 +600,7 @@ static int parseargs(int argc, char *argv[]) {"list", no_argument, 0, 'l'}, {"foreign", no_argument, 0, 'm'}, {"nosave", no_argument, 0, 'n'}, + {"nooptdeps", no_argument, 0, 'n'}, {"owns", no_argument, 0, 'o'}, {"file", no_argument, 0, 'p'}, {"print", no_argument, 0, 'p'}, diff --git a/src/pacman/query.c b/src/pacman/query.c index 163c331..ef10220 100644 --- a/src/pacman/query.c +++ b/src/pacman/query.c @@ -361,9 +361,15 @@ static int is_foreign(alpm_pkg_t *pkg) return 0; } -static int is_unrequired(alpm_pkg_t *pkg) +static int is_unrequired(alpm_pkg_t *pkg, const int find_optdeps) { - alpm_list_t *requiredby = alpm_pkg_compute_requiredby(pkg); + alpm_list_t *requiredby; + if(find_optdeps) { + requiredby = alpm_pkg_compute_requiredby(pkg, 1); + } else { + requiredby = alpm_pkg_compute_requiredby(pkg, 0); + } + if(requiredby == NULL) { return 1; } @@ -388,7 +394,11 @@ static int filter(alpm_pkg_t *pkg) return 0; } /* check if this pkg is unrequired */ - if(config->op_q_unrequired && !is_unrequired(pkg)) { + if(config->op_q_unrequired && !is_unrequired(pkg, 0)) { + return 0; + } + /* check if this pkg is optionally required */ + if(config->op_q_unrequired && !config->op_q_nooptdeps && !is_unrequired(pkg, 1)) { return 0; } /* check if this pkg is outdated */ diff --git a/src/util/pactree.c b/src/util/pactree.c index 9b67863..c7f2b20 100644 --- a/src/util/pactree.c +++ b/src/util/pactree.c @@ -342,7 +342,7 @@ static void walk_reverse_deps(alpm_list_t *dblist, alpm_pkg_t *pkg, int depth) } walked = alpm_list_add(walked, (void *)alpm_pkg_get_name(pkg)); - required_by = alpm_pkg_compute_requiredby(pkg); + required_by = alpm_pkg_compute_requiredby(pkg, 0); for(i = required_by; i; i = alpm_list_next(i)) { const char *pkgname = alpm_list_getdata(i); -- 1.7.6
Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- src/pacman/package.c | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/pacman/package.c b/src/pacman/package.c index 6725bdc..fc404b9 100644 --- a/src/pacman/package.c +++ b/src/pacman/package.c @@ -53,7 +53,8 @@ void dump_pkg_full(alpm_pkg_t *pkg, enum pkg_from from, int extra) const char *label; double size; const alpm_list_t *i; - alpm_list_t *depstrings = NULL, *optstrings = NULL, *requiredby = NULL; + alpm_list_t *depstrings, *optstrings, *requiredby, *optrequiredby; + depstrings = optstrings = requiredby = optrequiredby = NULL; if(pkg == NULL) { return; @@ -92,7 +93,8 @@ void dump_pkg_full(alpm_pkg_t *pkg, enum pkg_from from, int extra) if(extra || from == PKG_FROM_LOCALDB) { /* compute this here so we don't get a pause in the middle of output */ - requiredby = alpm_pkg_compute_requiredby(pkg, 0); + requiredby = alpm_pkg_compute_requiredby(pkg, 0); + optrequiredby = alpm_pkg_compute_requiredby(pkg, 1); } /* actual output */ @@ -110,6 +112,7 @@ void dump_pkg_full(alpm_pkg_t *pkg, enum pkg_from from, int extra) list_display_linebreak(_("Optional Deps :"), optstrings); if(extra || from == PKG_FROM_LOCALDB) { list_display(_("Required By :"), requiredby); + list_display(_("Optional For :"), optrequiredby); } list_display(_("Conflicts With :"), alpm_pkg_get_conflicts(pkg)); list_display(_("Replaces :"), alpm_pkg_get_replaces(pkg)); -- 1.7.6
Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- lib/libalpm/deps.c | 18 +++++++++++++++++- 1 files changed, 17 insertions(+), 1 deletions(-) diff --git a/lib/libalpm/deps.c b/lib/libalpm/deps.c index e8ce13b..8fb6b5f 100644 --- a/lib/libalpm/deps.c +++ b/lib/libalpm/deps.c @@ -85,6 +85,19 @@ static int _alpm_dep_edge(alpm_pkg_t *pkg1, alpm_pkg_t *pkg2) return 0; } +/* Does pkg1 optdepend on pkg2, ie. does pkg2 satisfy a optional dependency of pkg1? */ +static int _alpm_optdep_edge(alpm_pkg_t *pkg1, alpm_pkg_t *pkg2) +{ + alpm_list_t *i; + for(i = alpm_pkg_get_optdepends(pkg1); i; i = i->next) { + alpm_optdepend_t *optdep = i->data; + if(_alpm_depcmp(pkg2, optdep->depend)) { + return 1; + } + } + return 0; +} + /* Convert a list of alpm_pkg_t * to a graph structure, * with a edge for each dependency. * Returns a list of vertices (one vertex = one package) @@ -545,6 +558,9 @@ static int can_remove_package(alpm_db_t *db, alpm_pkg_t *pkg, alpm_list_t *targe if(_alpm_dep_edge(lpkg, pkg) && !_alpm_pkg_find(targets, lpkg->name)) { return 0; } + if(_alpm_optdep_edge(lpkg, pkg) && !_alpm_pkg_find(targets, lpkg->name)) { + return 0; + } } /* it's ok to remove */ @@ -573,7 +589,7 @@ void _alpm_recursedeps(alpm_db_t *db, alpm_list_t *targs, int include_explicit) alpm_pkg_t *pkg = i->data; for(j = _alpm_db_get_pkgcache(db); j; j = j->next) { alpm_pkg_t *deppkg = j->data; - if(_alpm_dep_edge(pkg, deppkg) + if((_alpm_dep_edge(pkg, deppkg) || _alpm_optdep_edge(pkg, deppkg)) && can_remove_package(db, deppkg, targs, include_explicit)) { _alpm_log(db->handle, ALPM_LOG_DEBUG, "adding '%s' to the targets\n", alpm_pkg_get_name(deppkg)); -- 1.7.6
Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- src/pacman/query.c | 11 ++++++++++- src/pacman/util.c | 23 ++++++++++++++++++----- src/pacman/util.h | 1 + 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/pacman/query.c b/src/pacman/query.c index ef10220..f35729a 100644 --- a/src/pacman/query.c +++ b/src/pacman/query.c @@ -487,7 +487,16 @@ static int display(alpm_pkg_t *pkg) if(!config->op_q_info && !config->op_q_list && !config->op_q_changelog && !config->op_q_check) { if(!config->quiet) { - printf("%s %s\n", alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg)); + printf("%s %s", alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg)); + + alpm_list_t *optrequires; + if(config->op_q_unrequired && config->op_q_nooptdeps && + (optrequires = alpm_pkg_compute_requiredby(pkg, 1)) != NULL) { + list_display_extra(_(" (optdepend for:"), optrequires, ", ", ")"); + FREELIST(optrequires); + } else { + printf("\n"); + } } else { printf("%s\n", alpm_pkg_get_name(pkg)); } diff --git a/src/pacman/util.c b/src/pacman/util.c index f633241..ba23356 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -597,16 +597,24 @@ int table_display(const char *title, const alpm_list_t *header, void list_display(const char *title, const alpm_list_t *list) { + list_display_extra(title, list, NULL, NULL); +} + +void list_display_extra(const char *title, const alpm_list_t *list, + const char *delim, const char *after) +{ const alpm_list_t *i; int len = 0; + delim = delim ? delim : " "; + if(title) { len = string_length(title) + 1; printf("%s ", title); } if(!list) { - printf("%s\n", _("None")); + printf("%s", _("None")); } else { const int maxcols = getcols(); int cols = len; @@ -625,15 +633,20 @@ void list_display(const char *title, const alpm_list_t *list) printf(" "); } } else if(cols != len) { - /* 2 spaces are added if this is not the first element on a line. */ - printf(" "); - cols += 2; + /* delimiter is added if this is not the first element on a line. */ + printf("%s", delim); + cols += strlen(delim); } printf("%s", str); cols += s; } - printf("\n"); } + + if(after) { + printf("%s", after); + } + + printf("\n"); } void list_display_linebreak(const char *title, const alpm_list_t *list) diff --git a/src/pacman/util.h b/src/pacman/util.h index ff1cec3..8daddbc 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -56,6 +56,7 @@ void string_display(const char *title, const char *string); double humanize_size(off_t bytes, const char target_unit, int long_labels, const char **label); int table_display(const char *title, const alpm_list_t *header, const alpm_list_t *rows); void list_display(const char *title, const alpm_list_t *list); +void list_display_extra(const char *title, const alpm_list_t *list, const char *delim, const char *after); void list_display_linebreak(const char *title, const alpm_list_t *list); void signature_display(const char *title, alpm_sigresult_t *result); void display_targets(const alpm_list_t *pkgs, int install); -- 1.7.6
On Mon, Aug 1, 2011 at 8:31 PM, Benedikt Morbach <benedikt.morbach@googlemail.com> wrote: <snip>
- '-Qt' doesn't consider optdepends to be orphans, unless '--nooptdeps/-n' is given if it is given, display them like this: 'sqlite3 3.7.7.1-1 (optdepend for: dbmail, python)' <snip>
not sure if I can follow the logic here: --nooptdeps/-n is about not considering optdeps being no orphans - so, technically this is a double negation? As far as I can tell here that flag will add more to the output? mar77i
participants (2)
-
Benedikt Morbach
-
Martti Kühne