[pacman-dev] [PATCH 00/14] Full optdep support
Now that 4.0/4.0.1 is out, I thought it might be time to finally send these patches in for review. This will probably still need some polish (maybe quite a bit in some places) but it works quite well and I have been using it for some time. The code is also at https://github.com/moben/pacman branch:optdep And now, please review ald yell at my bad code :) --- Benedikt Benedikt Morbach (14): Split optdep into alpm_depend_t and description Hook new optdepend structures up Only display uninstalled optdepends during install/upgrade Add option for showing all optdeps again Show optdep install status in package info optdepends are not orphans unless --optdeps is specified Make package info show optional requirements Make recursive removal consider optdepends Show list of optrequires with -Qtdn Warn on optdep removal Add flag to recurse through optdepends Add option to install all optdepends by default Add option to ask which optdeps to install Make HandleOptdeps Ask and Install work together better doc/pacman.8.txt | 11 +++ doc/pacman.conf.5.txt | 14 +++ etc/pacman.conf.in | 2 + lib/libalpm/add.c | 4 +- lib/libalpm/alpm.h | 25 +++++- lib/libalpm/be_local.c | 12 ++- lib/libalpm/be_package.c | 5 +- lib/libalpm/be_sync.c | 8 ++- lib/libalpm/deps.c | 127 ++++++++++++++++++++++++++--- lib/libalpm/deps.h | 5 +- lib/libalpm/error.c | 2 + lib/libalpm/package.c | 40 ++++++--- lib/libalpm/remove.c | 22 ++++- lib/libalpm/sync.c | 2 +- lib/libalpm/trans.c | 10 ++- src/pacman/conf.c | 27 ++++++ src/pacman/conf.h | 10 ++ src/pacman/package.c | 24 ++++- src/pacman/pacman.c | 7 ++ src/pacman/query.c | 27 +++++- src/pacman/remove.c | 23 ++++- src/pacman/sync.c | 125 +++++++++++++++++++++++++++-- src/pacman/upgrade.c | 2 +- src/pacman/util.c | 177 ++++++++++++++++++++++++++++++++++------ src/pacman/util.h | 5 +- src/util/pactree.c | 2 +- src/util/testdb.c | 2 +- test/pacman/tests/query010.py | 12 +++ test/pacman/tests/query011.py | 15 ++++ test/pacman/tests/query012.py | 13 +++ test/pacman/tests/query020.py | 14 +++ test/pacman/tests/query021.py | 14 +++ test/pacman/tests/query022.py | 14 +++ test/pacman/tests/remove053.py | 15 ++++ test/pacman/tests/remove054.py | 14 +++ test/pacman/tests/remove055.py | 20 +++++ test/pacman/tests/remove056.py | 20 +++++ test/pacman/tests/sync060.py | 12 +++ test/pacman/tests/sync061.py | 15 ++++ test/pacman/tests/sync062.py | 17 ++++ test/pacman/tests/sync063.py | 17 ++++ 41 files changed, 839 insertions(+), 93 deletions(-) create mode 100644 test/pacman/tests/query010.py create mode 100644 test/pacman/tests/query011.py create mode 100644 test/pacman/tests/query012.py create mode 100644 test/pacman/tests/query020.py create mode 100644 test/pacman/tests/query021.py create mode 100644 test/pacman/tests/query022.py create mode 100644 test/pacman/tests/remove053.py create mode 100644 test/pacman/tests/remove054.py create mode 100644 test/pacman/tests/remove055.py create mode 100644 test/pacman/tests/remove056.py create mode 100644 test/pacman/tests/sync060.py create mode 100644 test/pacman/tests/sync061.py create mode 100644 test/pacman/tests/sync062.py create mode 100644 test/pacman/tests/sync063.py -- 1.7.7.3
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 1751c81..943ceec 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -150,6 +150,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; @@ -1103,6 +1109,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 89f6d69..12d7156 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) { @@ -475,6 +482,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 @@ -872,4 +917,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 ce25bda..69b65df 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); int _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_literal(alpm_pkg_t *pkg, alpm_depend_t *dep); int _alpm_depcmp(alpm_pkg_t *pkg, alpm_depend_t *dep); -- 1.7.7.3
On Wed, Nov 23, 2011 at 9:51 AM, Benedikt Morbach <benedikt.morbach@googlemail.com> wrote:
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 1751c81..943ceec 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -150,6 +150,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; +
Rather than add a whole new type and all of the boilerplate, why don't we just do this for now? diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 1751c81..df49d8e 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -146,6 +146,7 @@ typedef struct __alpm_trans_t alpm_trans_t; typedef struct _alpm_depend_t { char *name; char *version; + char *description; unsigned long name_hash; alpm_depmod_t mod; } alpm_depend_t; Then simply modify the existing free, dup, split, and compute functions to support description, rather than having to reimplement them all. Even though we don't have descriptions on regular depends at the moment, I don't see any reason why we can't support them in pacman (even if their creation isn't supported yet). Yes, we'll have 4 to 8 more bytes per depend struct, but this isn't a whole lot to worry about given the simpler code in this and the following patches.
/** Missing dependency */ typedef struct _alpm_depmissing_t { char *target; @@ -1103,6 +1109,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 89f6d69..12d7156 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) { @@ -475,6 +482,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 @@ -872,4 +917,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 ce25bda..69b65df 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); int _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_literal(alpm_pkg_t *pkg, alpm_depend_t *dep); int _alpm_depcmp(alpm_pkg_t *pkg, alpm_depend_t *dep);
-- 1.7.7.3
No new behaviour introduced, everything should work exactly as before. Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- lib/libalpm/be_local.c | 12 ++++++- lib/libalpm/be_package.c | 5 ++- lib/libalpm/be_sync.c | 8 ++++- lib/libalpm/package.c | 7 +++- src/pacman/package.c | 18 ++++++++++- src/pacman/util.c | 73 ++++++++++++++++++++++++++++++++++++++------- 6 files changed, 102 insertions(+), 21 deletions(-) diff --git a/lib/libalpm/be_local.c b/lib/libalpm/be_local.c index 21d2748..6a578ff 100644 --- a/lib/libalpm/be_local.c +++ b/lib/libalpm/be_local.c @@ -517,6 +517,12 @@ char *_alpm_local_db_pkgpath(alpm_db_t *db, alpm_pkg_t *info, const char *filena f = alpm_list_add(f, _alpm_splitdep(line)); \ } while(1) /* note the while(1) and not (0) */ +#define READ_AND_SPLITOPTDEP(f) do { \ + if(fgets(line, sizeof(line), fp) == NULL && !feof(fp)) goto error; \ + if(_alpm_strip_newline(line) == 0) break; \ + f = alpm_list_add(f, _alpm_splitoptdep(line)); \ +} while(1) /* note the while(1) and not (0) */ + static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq) { FILE *fp = NULL; @@ -613,7 +619,7 @@ static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq) } else if(strcmp(line, "%DEPENDS%") == 0) { READ_AND_SPLITDEP(info->depends); } else if(strcmp(line, "%OPTDEPENDS%") == 0) { - READ_AND_STORE_ALL(info->optdepends); + READ_AND_SPLITOPTDEP(info->optdepends); } else if(strcmp(line, "%CONFLICTS%") == 0) { READ_AND_SPLITDEP(info->conflicts); } else if(strcmp(line, "%PROVIDES%") == 0) { @@ -824,7 +830,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 4f530e0..be6e4c8 100644 --- a/lib/libalpm/be_package.c +++ b/lib/libalpm/be_package.c @@ -38,7 +38,7 @@ #include "log.h" #include "handle.h" #include "package.h" -#include "deps.h" /* _alpm_splitdep */ +#include "deps.h" struct package_changelog { struct archive *archive; @@ -213,7 +213,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) { alpm_depend_t *conflict = _alpm_splitdep(ptr); newpkg->conflicts = alpm_list_add(newpkg->conflicts, conflict); diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c index 54c4f87..0aaf085 100644 --- a/lib/libalpm/be_sync.c +++ b/lib/libalpm/be_sync.c @@ -504,6 +504,12 @@ cleanup: f = alpm_list_add(f, _alpm_splitdep(line)); \ } while(1) /* note the while(1) and not (0) */ +#define READ_AND_SPLITOPTDEP(f) do { \ + if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) goto error; \ + if(_alpm_strip_newline(buf.line) == 0) break; \ + f = alpm_list_add(f, _alpm_splitoptdep(line)); \ +} while(1) /* note the while(1) and not (0) */ + static int sync_db_read(alpm_db_t *db, struct archive *archive, struct archive_entry *entry, alpm_pkg_t **likely_pkg) { @@ -590,7 +596,7 @@ static int sync_db_read(alpm_db_t *db, struct archive *archive, } else if(strcmp(line, "%DEPENDS%") == 0) { READ_AND_SPLITDEP(pkg->depends); } else if(strcmp(line, "%OPTDEPENDS%") == 0) { - READ_AND_STORE_ALL(pkg->optdepends); + READ_AND_SPLITOPTDEP(pkg->optdepends); } else if(strcmp(line, "%CONFLICTS%") == 0) { READ_AND_SPLITDEP(pkg->conflicts); } else if(strcmp(line, "%PROVIDES%") == 0) { diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c index 2a97177..451506b 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -531,7 +531,9 @@ int _alpm_pkg_dup(alpm_pkg_t *pkg, alpm_pkg_t **new_ptr) for(i = pkg->depends; i; i = i->next) { 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 = i->next) { + newpkg->optdepends = alpm_list_add(newpkg->optdepends, _alpm_optdep_dup(i->data)); + } for(i = pkg->conflicts; i; i = i->next) { newpkg->conflicts = alpm_list_add(newpkg->conflicts, _alpm_dep_dup(i->data)); } @@ -593,7 +595,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); alpm_list_free_inner(pkg->conflicts, (alpm_list_fn_free)_alpm_dep_free); alpm_list_free(pkg->conflicts); alpm_list_free_inner(pkg->provides, (alpm_list_fn_free)_alpm_dep_free); diff --git a/src/pacman/package.c b/src/pacman/package.c index d4bbf88..c7bfb14 100644 --- a/src/pacman/package.c +++ b/src/pacman/package.c @@ -40,7 +40,6 @@ /** Turn a depends list into a text list. * @param deps a list with items of type alpm_depend_t - * @return a string list, must be freed */ static void deplist_display(const char *title, alpm_list_t *deps) @@ -54,6 +53,21 @@ static void deplist_display(const char *title, FREELIST(text); } +/** Turn a optdepends list into a text list. + * @param optdeps a list with items of type alpm_optdepend_t + */ +static void optdeplist_display(const char *title, + alpm_list_t *optdeps) +{ + alpm_list_t *i, *text = NULL; + for(i = optdeps; i; i = alpm_list_next(i)) { + alpm_optdepend_t *optdep = i->data; + text = alpm_list_add(text, alpm_optdep_compute_string(optdep)); + } + list_display_linebreak(title, text); + FREELIST(text); +} + /** * Display the details of a package. * Extra information entails 'required by' info for sync packages and backup @@ -113,7 +127,7 @@ void dump_pkg_full(alpm_pkg_t *pkg, int extra) list_display(_("Groups :"), alpm_pkg_get_groups(pkg)); deplist_display(_("Provides :"), alpm_pkg_get_provides(pkg)); deplist_display(_("Depends On :"), alpm_pkg_get_depends(pkg)); - list_display_linebreak(_("Optional Deps :"), alpm_pkg_get_optdepends(pkg)); + optdeplist_display(_("Optional Deps :"), alpm_pkg_get_optdepends(pkg)); if(extra || from == PKG_FROM_LOCALDB) { list_display(_("Required By :"), requiredby); } diff --git a/src/pacman/util.c b/src/pacman/util.c index c0dcb9f..2363e6f 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -1139,32 +1139,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 = i->data; + 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 = i->data; + 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.7.3
On Wed, Nov 23, 2011 at 1:51 PM, Benedikt Morbach <benedikt.morbach@googlemail.com> wrote:
--- a/lib/libalpm/be_local.c +++ b/lib/libalpm/be_local.c @@ -517,6 +517,12 @@ char *_alpm_local_db_pkgpath(alpm_db_t *db, alpm_pkg_t *info, const char *filena f = alpm_list_add(f, _alpm_splitdep(line)); \ } while(1) /* note the while(1) and not (0) */
+#define READ_AND_SPLITOPTDEP(f) do { \ + if(fgets(line, sizeof(line), fp) == NULL && !feof(fp)) goto error; \ + if(_alpm_strip_newline(line) == 0) break; \ + f = alpm_list_add(f, _alpm_splitoptdep(line)); \ +} while(1) /* note the while(1) and not (0) */
This DEFINE is equal to the one bellow. Wouldn't it be possible to separete it in some header file and use from there?
--- a/lib/libalpm/be_sync.c +++ b/lib/libalpm/be_sync.c @@ -504,6 +504,12 @@ cleanup: f = alpm_list_add(f, _alpm_splitdep(line)); \ } while(1) /* note the while(1) and not (0) */
+#define READ_AND_SPLITOPTDEP(f) do { \ + if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) goto error; \ + if(_alpm_strip_newline(buf.line) == 0) break; \ + f = alpm_list_add(f, _alpm_splitoptdep(line)); \ +} while(1) /* note the while(1) and not (0) */ +
diff --git a/src/pacman/util.c b/src/pacman/util.c index c0dcb9f..2363e6f 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -1139,32 +1139,81 @@ void print_packages(const alpm_list_t *packages) 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 = i->data; + optstrings = alpm_list_add(optstrings, alpm_optdep_compute_string(optdep)); + }
This las for also looks quite equal to the one in display_optdepends. I think they could be merged somehow (maybe another DEFINE or a function)
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 = i->data; + optstrings = alpm_list_add(optstrings, alpm_optdep_compute_string(optdep)); + }
-- A: Because it obfuscates the reading. Q: Why is top posting so bad? ------------------------------------------- Denis A. Altoe Falqueto Linux user #524555 -------------------------------------------
On Wed, Nov 23, 2011 at 9:51 AM, Benedikt Morbach <benedikt.morbach@googlemail.com> wrote:
No new behaviour introduced, everything should work exactly as before.
Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- lib/libalpm/be_local.c | 12 ++++++- lib/libalpm/be_package.c | 5 ++- lib/libalpm/be_sync.c | 8 ++++- lib/libalpm/package.c | 7 +++- src/pacman/package.c | 18 ++++++++++- src/pacman/util.c | 73 ++++++++++++++++++++++++++++++++++++++------- 6 files changed, 102 insertions(+), 21 deletions(-)
diff --git a/lib/libalpm/be_local.c b/lib/libalpm/be_local.c index 21d2748..6a578ff 100644 --- a/lib/libalpm/be_local.c +++ b/lib/libalpm/be_local.c @@ -517,6 +517,12 @@ char *_alpm_local_db_pkgpath(alpm_db_t *db, alpm_pkg_t *info, const char *filena f = alpm_list_add(f, _alpm_splitdep(line)); \ } while(1) /* note the while(1) and not (0) */
+#define READ_AND_SPLITOPTDEP(f) do { \ + if(fgets(line, sizeof(line), fp) == NULL && !feof(fp)) goto error; \ + if(_alpm_strip_newline(line) == 0) break; \ + f = alpm_list_add(f, _alpm_splitoptdep(line)); \ +} while(1) /* note the while(1) and not (0) */ + This and the one in be_sync can go away if you implement my suggestion in patch #1; READ_AND_SPLITDEP can simply be reused.
static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq) { FILE *fp = NULL; @@ -613,7 +619,7 @@ static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq) } else if(strcmp(line, "%DEPENDS%") == 0) { READ_AND_SPLITDEP(info->depends); } else if(strcmp(line, "%OPTDEPENDS%") == 0) { - READ_AND_STORE_ALL(info->optdepends); + READ_AND_SPLITOPTDEP(info->optdepends); } else if(strcmp(line, "%CONFLICTS%") == 0) { READ_AND_SPLITDEP(info->conflicts); } else if(strcmp(line, "%PROVIDES%") == 0) { @@ -824,7 +830,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 4f530e0..be6e4c8 100644 --- a/lib/libalpm/be_package.c +++ b/lib/libalpm/be_package.c @@ -38,7 +38,7 @@ #include "log.h" #include "handle.h" #include "package.h" -#include "deps.h" /* _alpm_splitdep */ +#include "deps.h"
struct package_changelog { struct archive *archive; @@ -213,7 +213,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) { alpm_depend_t *conflict = _alpm_splitdep(ptr); newpkg->conflicts = alpm_list_add(newpkg->conflicts, conflict); diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c index 54c4f87..0aaf085 100644 --- a/lib/libalpm/be_sync.c +++ b/lib/libalpm/be_sync.c @@ -504,6 +504,12 @@ cleanup: f = alpm_list_add(f, _alpm_splitdep(line)); \ } while(1) /* note the while(1) and not (0) */
+#define READ_AND_SPLITOPTDEP(f) do { \ + if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) goto error; \ + if(_alpm_strip_newline(buf.line) == 0) break; \ + f = alpm_list_add(f, _alpm_splitoptdep(line)); \ +} while(1) /* note the while(1) and not (0) */ + static int sync_db_read(alpm_db_t *db, struct archive *archive, struct archive_entry *entry, alpm_pkg_t **likely_pkg) { @@ -590,7 +596,7 @@ static int sync_db_read(alpm_db_t *db, struct archive *archive, } else if(strcmp(line, "%DEPENDS%") == 0) { READ_AND_SPLITDEP(pkg->depends); } else if(strcmp(line, "%OPTDEPENDS%") == 0) { - READ_AND_STORE_ALL(pkg->optdepends); + READ_AND_SPLITOPTDEP(pkg->optdepends); } else if(strcmp(line, "%CONFLICTS%") == 0) { READ_AND_SPLITDEP(pkg->conflicts); } else if(strcmp(line, "%PROVIDES%") == 0) { diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c index 2a97177..451506b 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -531,7 +531,9 @@ int _alpm_pkg_dup(alpm_pkg_t *pkg, alpm_pkg_t **new_ptr) for(i = pkg->depends; i; i = i->next) { 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 = i->next) { + newpkg->optdepends = alpm_list_add(newpkg->optdepends, _alpm_optdep_dup(i->data)); + } If we move to all of these being alpm_depend_t typed; implementing a static method to help the dup process might be worthwhile. Patch on the way; feel free to include it in your patch series next submission if it isn't merged already.
for(i = pkg->conflicts; i; i = i->next) { newpkg->conflicts = alpm_list_add(newpkg->conflicts, _alpm_dep_dup(i->data)); } @@ -593,7 +595,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); alpm_list_free_inner(pkg->conflicts, (alpm_list_fn_free)_alpm_dep_free); alpm_list_free(pkg->conflicts); alpm_list_free_inner(pkg->provides, (alpm_list_fn_free)_alpm_dep_free); diff --git a/src/pacman/package.c b/src/pacman/package.c index d4bbf88..c7bfb14 100644 --- a/src/pacman/package.c +++ b/src/pacman/package.c @@ -40,7 +40,6 @@
/** Turn a depends list into a text list. * @param deps a list with items of type alpm_depend_t - * @return a string list, must be freed */ static void deplist_display(const char *title, alpm_list_t *deps) @@ -54,6 +53,21 @@ static void deplist_display(const char *title, FREELIST(text); }
+/** Turn a optdepends list into a text list. + * @param optdeps a list with items of type alpm_optdepend_t + */ +static void optdeplist_display(const char *title, + alpm_list_t *optdeps) +{ + alpm_list_t *i, *text = NULL; + for(i = optdeps; i; i = alpm_list_next(i)) { + alpm_optdepend_t *optdep = i->data; + text = alpm_list_add(text, alpm_optdep_compute_string(optdep)); + } + list_display_linebreak(title, text); + FREELIST(text); +} + /** * Display the details of a package. * Extra information entails 'required by' info for sync packages and backup @@ -113,7 +127,7 @@ void dump_pkg_full(alpm_pkg_t *pkg, int extra) list_display(_("Groups :"), alpm_pkg_get_groups(pkg)); deplist_display(_("Provides :"), alpm_pkg_get_provides(pkg)); deplist_display(_("Depends On :"), alpm_pkg_get_depends(pkg)); - list_display_linebreak(_("Optional Deps :"), alpm_pkg_get_optdepends(pkg)); + optdeplist_display(_("Optional Deps :"), alpm_pkg_get_optdepends(pkg)); if(extra || from == PKG_FROM_LOCALDB) { list_display(_("Required By :"), requiredby); } diff --git a/src/pacman/util.c b/src/pacman/util.c index c0dcb9f..2363e6f 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -1139,32 +1139,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) optdep_cmp at least (depend_cmp if we refactor the type), "opt" all by itself is pretty hard to grok. { - 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; I feel like this could be simplified a bit, but we can tackle that later.
}
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 = i->data; + 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 = i->data; + 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.7.3
We do this in several of the package duplication steps; add a helper function for doing so to reduce some of the repetitive code. Also add a free_deplist function for our repeated depend list free calls of both the data and the list. Signed-off-by: Dan McGee <dan@archlinux.org> --- lib/libalpm/package.c | 58 ++++++++++++++++++++++++++---------------------- 1 files changed, 31 insertions(+), 27 deletions(-) diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c index 2a97177..e96177a 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -461,6 +461,15 @@ alpm_pkg_t *_alpm_pkg_new(void) return pkg; } +static alpm_list_t *list_depdup(alpm_list_t *old) +{ + alpm_list_t *i, *new = NULL; + for(i = old; i; i = i->next) { + new = alpm_list_add(new, _alpm_dep_dup(i->data)); + } + return new; +} + /** * Duplicate a package data struct. * @param pkg the package to duplicate @@ -509,10 +518,19 @@ int _alpm_pkg_dup(alpm_pkg_t *pkg, alpm_pkg_t **new_ptr) newpkg->reason = pkg->reason; newpkg->licenses = alpm_list_strdup(pkg->licenses); - for(i = pkg->replaces; i; i = i->next) { - newpkg->replaces = alpm_list_add(newpkg->replaces, _alpm_dep_dup(i->data)); - } + newpkg->replaces = list_depdup(pkg->replaces); newpkg->groups = alpm_list_strdup(pkg->groups); + for(i = pkg->backup; i; i = i->next) { + newpkg->backup = alpm_list_add(newpkg->backup, _alpm_backup_dup(i->data)); + } + newpkg->depends = list_depdup(pkg->depends); + newpkg->optdepends = alpm_list_strdup(pkg->optdepends); + newpkg->conflicts = list_depdup(pkg->conflicts); + newpkg->provides = list_depdup(pkg->provides); + for(i = pkg->deltas; i; i = i->next) { + newpkg->deltas = alpm_list_add(newpkg->deltas, _alpm_delta_dup(i->data)); + } + if(pkg->files.count) { size_t filenum; size_t len = sizeof(alpm_file_t) * pkg->files.count; @@ -525,22 +543,6 @@ int _alpm_pkg_dup(alpm_pkg_t *pkg, alpm_pkg_t **new_ptr) } newpkg->files.count = pkg->files.count; } - for(i = pkg->backup; i; i = i->next) { - newpkg->backup = alpm_list_add(newpkg->backup, _alpm_backup_dup(i->data)); - } - for(i = pkg->depends; i; i = i->next) { - newpkg->depends = alpm_list_add(newpkg->depends, _alpm_dep_dup(i->data)); - } - newpkg->optdepends = alpm_list_strdup(pkg->optdepends); - for(i = pkg->conflicts; i; i = i->next) { - newpkg->conflicts = alpm_list_add(newpkg->conflicts, _alpm_dep_dup(i->data)); - } - for(i = pkg->provides; i; i = i->next) { - newpkg->provides = alpm_list_add(newpkg->provides, _alpm_dep_dup(i->data)); - } - for(i = pkg->deltas; i; i = i->next) { - newpkg->deltas = alpm_list_add(newpkg->deltas, _alpm_delta_dup(i->data)); - } /* internal */ newpkg->infolevel = pkg->infolevel; @@ -561,6 +563,12 @@ cleanup: RET_ERR(pkg->handle, ALPM_ERR_MEMORY, -1); } +static void free_deplist(alpm_list_t *deps) +{ + alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_dep_free); + alpm_list_free(deps); +} + void _alpm_pkg_free(alpm_pkg_t *pkg) { if(pkg == NULL) { @@ -579,8 +587,7 @@ void _alpm_pkg_free(alpm_pkg_t *pkg) FREE(pkg->arch); FREELIST(pkg->licenses); - alpm_list_free_inner(pkg->replaces, (alpm_list_fn_free)_alpm_dep_free); - alpm_list_free(pkg->replaces); + free_deplist(pkg->replaces); FREELIST(pkg->groups); if(pkg->files.count) { size_t i; @@ -591,13 +598,10 @@ void _alpm_pkg_free(alpm_pkg_t *pkg) } alpm_list_free_inner(pkg->backup, (alpm_list_fn_free)_alpm_backup_free); alpm_list_free(pkg->backup); - alpm_list_free_inner(pkg->depends, (alpm_list_fn_free)_alpm_dep_free); - alpm_list_free(pkg->depends); + free_deplist(pkg->depends); FREELIST(pkg->optdepends); - alpm_list_free_inner(pkg->conflicts, (alpm_list_fn_free)_alpm_dep_free); - alpm_list_free(pkg->conflicts); - alpm_list_free_inner(pkg->provides, (alpm_list_fn_free)_alpm_dep_free); - alpm_list_free(pkg->provides); + free_deplist(pkg->conflicts); + free_deplist(pkg->provides); alpm_list_free_inner(pkg->deltas, (alpm_list_fn_free)_alpm_delta_free); alpm_list_free(pkg->deltas); alpm_list_free(pkg->delta_path); -- 1.7.7.4
Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- src/pacman/util.c | 40 ++++++++++++++++++++++++++-------------- test/pacman/tests/sync060.py | 12 ++++++++++++ test/pacman/tests/sync061.py | 15 +++++++++++++++ 3 files changed, 53 insertions(+), 14 deletions(-) create mode 100644 test/pacman/tests/sync060.py create mode 100644 test/pacman/tests/sync061.py diff --git a/src/pacman/util.c b/src/pacman/util.c index 2363e6f..be4647a 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -1173,19 +1173,37 @@ 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 = alpm_option_get_localdb(config->handle); + + /* turn optdepends list into a text list. */ + for( ; optlist; optlist = alpm_list_next(optlist)) { + optdep = optlist->data; + 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 = i->data; - 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)); @@ -1198,15 +1216,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 = i->data; - 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)); diff --git a/test/pacman/tests/sync060.py b/test/pacman/tests/sync060.py new file mode 100644 index 0000000..ec3d7ca --- /dev/null +++ b/test/pacman/tests/sync060.py @@ -0,0 +1,12 @@ +self.description = "Install a package from a sync db with uninstalled optdepend and optdepend output" + +pkg = pmpkg("dummy") +pkg.optdepends = ["dep: for foobar"] +self.addpkg2db("sync1", pkg) + +self.args = "-S %s" % pkg.name + +self.addrule("PACMAN_RETCODE=0") +self.addrule("PACMAN_OUTPUT=dep: for foobar") +self.addrule("PKG_EXISTS=dummy") +self.addrule("PKG_OPTDEPENDS=dummy|dep: for foobar") diff --git a/test/pacman/tests/sync061.py b/test/pacman/tests/sync061.py new file mode 100644 index 0000000..cb5a892 --- /dev/null +++ b/test/pacman/tests/sync061.py @@ -0,0 +1,15 @@ +self.description = "Install a package from a sync db with installed optdepend and no optdepend output" + +p1 = pmpkg("dummy") +p1.optdepends = ["dep: for foobar"] +self.addpkg2db("sync1", p1) + +p2 = pmpkg("dep") +self.addpkg2db("local", p2) + +self.args = "-S %s" % p1.name + +self.addrule("PACMAN_RETCODE=0") +self.addrule("!PACMAN_OUTPUT=dep: for foobar") +self.addrule("PKG_EXISTS=dummy") +self.addrule("PKG_OPTDEPENDS=dummy|dep: for foobar") -- 1.7.7.3
On Wed, Nov 23, 2011 at 9:51 AM, Benedikt Morbach <benedikt.morbach@googlemail.com> wrote:
Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- src/pacman/util.c | 40 ++++++++++++++++++++++++++-------------- test/pacman/tests/sync060.py | 12 ++++++++++++ test/pacman/tests/sync061.py | 15 +++++++++++++++ 3 files changed, 53 insertions(+), 14 deletions(-) create mode 100644 test/pacman/tests/sync060.py create mode 100644 test/pacman/tests/sync061.py
diff --git a/src/pacman/util.c b/src/pacman/util.c index 2363e6f..be4647a 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -1173,19 +1173,37 @@ 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) This is a very deceiving function. It doesn't do what I expected, given it magically excludes packages it finds in the local DB. Quite surprising to me...
+{ + alpm_list_t *optstrings = NULL; + alpm_optdepend_t *optdep; + alpm_db_t *db_local = alpm_option_get_localdb(config->handle); + + /* turn optdepends list into a text list. */ + for( ; optlist; optlist = alpm_list_next(optlist)) { This is trying to save a local variable for no reason- let the compiler do that for you and just use *i as always, please, and keep the for loop syntax normal. + optdep = optlist->data; optdep can be declared local inside the loop here. + 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 = i->data; - 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)); @@ -1198,15 +1216,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 = i->data; - 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)); diff --git a/test/pacman/tests/sync060.py b/test/pacman/tests/sync060.py new file mode 100644 index 0000000..ec3d7ca --- /dev/null +++ b/test/pacman/tests/sync060.py @@ -0,0 +1,12 @@ +self.description = "Install a package from a sync db with uninstalled optdepend and optdepend output" + +pkg = pmpkg("dummy") +pkg.optdepends = ["dep: for foobar"] +self.addpkg2db("sync1", pkg) + +self.args = "-S %s" % pkg.name + +self.addrule("PACMAN_RETCODE=0") +self.addrule("PACMAN_OUTPUT=dep: for foobar") +self.addrule("PKG_EXISTS=dummy") +self.addrule("PKG_OPTDEPENDS=dummy|dep: for foobar") diff --git a/test/pacman/tests/sync061.py b/test/pacman/tests/sync061.py new file mode 100644 index 0000000..cb5a892 --- /dev/null +++ b/test/pacman/tests/sync061.py @@ -0,0 +1,15 @@ +self.description = "Install a package from a sync db with installed optdepend and no optdepend output" + +p1 = pmpkg("dummy") +p1.optdepends = ["dep: for foobar"] +self.addpkg2db("sync1", p1) + +p2 = pmpkg("dep") +self.addpkg2db("local", p2) + +self.args = "-S %s" % p1.name + +self.addrule("PACMAN_RETCODE=0") +self.addrule("!PACMAN_OUTPUT=dep: for foobar") +self.addrule("PKG_EXISTS=dummy") +self.addrule("PKG_OPTDEPENDS=dummy|dep: for foobar") -- 1.7.7.3
This also shows [installing] after the optdep, if it is part of the same transaction but isn't yet installed Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- doc/pacman.conf.5.txt | 4 +++ etc/pacman.conf.in | 2 + src/pacman/conf.c | 23 +++++++++++++++++ src/pacman/conf.h | 7 +++++ src/pacman/util.c | 35 ++++++++++++++++++++++--- src/pacman/util.h | 1 + test/pacman/tests/{sync061.py => sync062.py} | 8 +++-- 7 files changed, 72 insertions(+), 8 deletions(-) copy test/pacman/tests/{sync061.py => sync062.py} (65%) diff --git a/doc/pacman.conf.5.txt b/doc/pacman.conf.5.txt index 2c1a24b..7232c8b 100644 --- a/doc/pacman.conf.5.txt +++ b/doc/pacman.conf.5.txt @@ -160,6 +160,10 @@ Options packages are only cleaned if not installed locally and not present in any known sync database. +*HandleOptdeps =* ShowAll:: + If set to `ShowAll`, show all optional dependencies on install. + The default is to just show uninstalled optional dependencies. + *SigLevel =* ...:: Set the default signature verification level. For more information, see <<SC,Package and Database Signature Checking>> below. diff --git a/etc/pacman.conf.in b/etc/pacman.conf.in index 932140f..a905757 100644 --- a/etc/pacman.conf.in +++ b/etc/pacman.conf.in @@ -36,6 +36,8 @@ Architecture = auto CheckSpace #VerbosePkgLists +#HandleOptdeps = ShowAll + # PGP signature checking #SigLevel = Optional diff --git a/src/pacman/conf.c b/src/pacman/conf.c index 5328e7c..715399e 100644 --- a/src/pacman/conf.c +++ b/src/pacman/conf.c @@ -361,6 +361,21 @@ static int process_cleanmethods(alpm_list_t *values, return 0; } +static int process_handleoptdeps(alpm_list_t *actions) { + alpm_list_t *i; + for(i = actions; i; i = alpm_list_next(i)) { + const char *action = i->data; + if(strcmp(action, "ShowAll") == 0) { + config->handleoptdeps |= PM_OPTDEPS_SHOWALL; + } else { + pm_printf(ALPM_LOG_ERROR, _("invalid action for 'HandleOptdeps' : '%s'\n"), + action); + return 1; + } + } + return 0; +} + /** Add repeating options such as NoExtract, NoUpgrade, etc to libalpm * settings. Refactored out of the parseconfig code since all of them did * the exact same thing and duplicated code. @@ -464,6 +479,14 @@ static int _parse_options(const char *key, char *value, return 1; } FREELIST(methods); + } else if(strcmp(key, "HandleOptdeps") == 0) { + alpm_list_t *actions = NULL; + setrepeatingoption(value, "HandleOptdeps", &actions); + if(process_handleoptdeps(actions)) { + FREELIST(actions); + return 1; + } + FREELIST(actions); } else if(strcmp(key, "SigLevel") == 0) { alpm_list_t *values = NULL; setrepeatingoption(value, "SigLevel", &values); diff --git a/src/pacman/conf.h b/src/pacman/conf.h index 325fbb6..7ff37ff 100644 --- a/src/pacman/conf.h +++ b/src/pacman/conf.h @@ -83,6 +83,8 @@ typedef struct __config_t { unsigned short totaldownload; /* select -Sc behavior */ unsigned short cleanmethod; + /* wether and how to handle optdeps */ + unsigned short handleoptdeps; alpm_list_t *holdpkg; alpm_list_t *syncfirst; alpm_list_t *ignorepkg; @@ -138,6 +140,11 @@ enum { PM_CLEAN_KEEPCUR = (1 << 1) }; +/* optdepends handling */ +enum { + PM_OPTDEPS_SHOWALL = 1 +}; + /* global config variable */ extern config_t *config; diff --git a/src/pacman/util.c b/src/pacman/util.c index be4647a..1f89663 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -1176,20 +1176,45 @@ 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; alpm_db_t *db_local = alpm_option_get_localdb(config->handle); + /* calculate these outside the loop. */ + alpm_list_t *pkgcache = alpm_db_get_pkgcache(db_local); + alpm_list_t *remove = alpm_trans_get_remove(config->handle); + alpm_list_t *add = alpm_trans_get_add(config->handle); + /* turn optdepends list into a text list. */ for( ; optlist; optlist = alpm_list_next(optlist)) { optdep = optlist->data; - if(alpm_db_get_pkg(db_local, optdep->depend->name) == NULL) { - optstrings = alpm_list_add(optstrings, alpm_optdep_compute_string(optdep)); + char *depstr = alpm_dep_compute_string(optdep->depend); + char *tmp, *str = alpm_optdep_compute_string(optdep); + const char *state = NULL; + + if(alpm_find_satisfier(pkgcache, depstr) && alpm_find_satisfier(remove, depstr) == NULL) { + state = include_installed ? _(" [installed]") : NULL; + } else if(alpm_find_satisfier(add, depstr)) { + state = include_installed ? _(" [installing]") : NULL; + } else if(alpm_find_satisfier(remove, depstr)) { + state = _(" [removing]"); + } else { + optstrings = alpm_list_add(optstrings, str); } + + if(state) { + if((tmp = realloc(str, strlen(str) + strlen(state) + 1)) != NULL) { + strcpy(tmp + strlen(tmp), state); + str = tmp; + } /* if realloc fails, we only loose the state information, which is nonfatal. */ + optstrings = alpm_list_add(optstrings, str); + } + free(depstr); } return optstrings; @@ -1203,7 +1228,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, config->handleoptdeps & PM_OPTDEPS_SHOWALL); if(optstrings) { printf(_("New optional dependencies for %s\n"), alpm_pkg_get_name(newpkg)); @@ -1218,7 +1243,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), config->handleoptdeps & PM_OPTDEPS_SHOWALL); 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 6ec962f..ca33752 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -69,6 +69,7 @@ void display_targets(void); 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); diff --git a/test/pacman/tests/sync061.py b/test/pacman/tests/sync062.py similarity index 65% copy from test/pacman/tests/sync061.py copy to test/pacman/tests/sync062.py index cb5a892..dc90002 100644 --- a/test/pacman/tests/sync061.py +++ b/test/pacman/tests/sync062.py @@ -1,4 +1,6 @@ -self.description = "Install a package from a sync db with installed optdepend and no optdepend output" +self.description = "Install a package from a sync db with installed optdepend and forced optdepend output" + +self.option["HandleOptdeps"] = ["ShowAll"] p1 = pmpkg("dummy") p1.optdepends = ["dep: for foobar"] @@ -10,6 +12,6 @@ self.args = "-S %s" % p1.name self.addrule("PACMAN_RETCODE=0") -self.addrule("!PACMAN_OUTPUT=dep: for foobar") -self.addrule("PKG_EXISTS=dummy") +self.addrule("PACMAN_OUTPUT=dep: for foobar") +self.addrule("PKG_EXIST=dummy") self.addrule("PKG_OPTDEPENDS=dummy|dep: for foobar") -- 1.7.7.3
This also shows [installing] after the optdep, if it is part of the same transaction but isn't yet installed
Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- doc/pacman.conf.5.txt | 4 +++ etc/pacman.conf.in | 2 + src/pacman/conf.c | 23 +++++++++++++++++ src/pacman/conf.h | 7 +++++ src/pacman/util.c | 35 ++++++++++++++++++++++--- src/pacman/util.h | 1 + test/pacman/tests/{sync061.py => sync062.py} | 8 +++-- 7 files changed, 72 insertions(+), 8 deletions(-) copy test/pacman/tests/{sync061.py => sync062.py} (65%)
diff --git a/doc/pacman.conf.5.txt b/doc/pacman.conf.5.txt index 2c1a24b..7232c8b 100644 --- a/doc/pacman.conf.5.txt +++ b/doc/pacman.conf.5.txt @@ -160,6 +160,10 @@ Options packages are only cleaned if not installed locally and not present in any known sync database.
+*HandleOptdeps =* ShowAll:: + If set to `ShowAll`, show all optional dependencies on install. + The default is to just show uninstalled optional dependencies. + -1 on adding another option for this. We should just do "the right
On Wed, Nov 23, 2011 at 9:51 AM, Benedikt Morbach <benedikt.morbach@googlemail.com> wrote: thing" and be done with it. I would prefer to simply show the uninstalled ones all the time as running -Qi after the fact will eventually show the already installed ones. So the whole first part of this patch should be dropped. The second part is much more important, but I'm not going to review it right now given it is intertwined a bit with this option stuff.
*SigLevel =* ...:: Set the default signature verification level. For more information, see <<SC,Package and Database Signature Checking>> below. diff --git a/etc/pacman.conf.in b/etc/pacman.conf.in index 932140f..a905757 100644 --- a/etc/pacman.conf.in +++ b/etc/pacman.conf.in @@ -36,6 +36,8 @@ Architecture = auto CheckSpace #VerbosePkgLists
+#HandleOptdeps = ShowAll + # PGP signature checking #SigLevel = Optional
diff --git a/src/pacman/conf.c b/src/pacman/conf.c index 5328e7c..715399e 100644 --- a/src/pacman/conf.c +++ b/src/pacman/conf.c @@ -361,6 +361,21 @@ static int process_cleanmethods(alpm_list_t *values, return 0; }
+static int process_handleoptdeps(alpm_list_t *actions) { + alpm_list_t *i; + for(i = actions; i; i = alpm_list_next(i)) { + const char *action = i->data; + if(strcmp(action, "ShowAll") == 0) { + config->handleoptdeps |= PM_OPTDEPS_SHOWALL; + } else { + pm_printf(ALPM_LOG_ERROR, _("invalid action for 'HandleOptdeps' : '%s'\n"), + action); + return 1; + } + } + return 0; +} + /** Add repeating options such as NoExtract, NoUpgrade, etc to libalpm * settings. Refactored out of the parseconfig code since all of them did * the exact same thing and duplicated code. @@ -464,6 +479,14 @@ static int _parse_options(const char *key, char *value, return 1; } FREELIST(methods); + } else if(strcmp(key, "HandleOptdeps") == 0) { + alpm_list_t *actions = NULL; + setrepeatingoption(value, "HandleOptdeps", &actions); + if(process_handleoptdeps(actions)) { + FREELIST(actions); + return 1; + } + FREELIST(actions); } else if(strcmp(key, "SigLevel") == 0) { alpm_list_t *values = NULL; setrepeatingoption(value, "SigLevel", &values); diff --git a/src/pacman/conf.h b/src/pacman/conf.h index 325fbb6..7ff37ff 100644 --- a/src/pacman/conf.h +++ b/src/pacman/conf.h @@ -83,6 +83,8 @@ typedef struct __config_t { unsigned short totaldownload; /* select -Sc behavior */ unsigned short cleanmethod; + /* wether and how to handle optdeps */ whether + unsigned short handleoptdeps; alpm_list_t *holdpkg; alpm_list_t *syncfirst; alpm_list_t *ignorepkg; @@ -138,6 +140,11 @@ enum { PM_CLEAN_KEEPCUR = (1 << 1) };
+/* optdepends handling */ +enum { + PM_OPTDEPS_SHOWALL = 1 +}; + /* global config variable */ extern config_t *config;
diff --git a/src/pacman/util.c b/src/pacman/util.c index be4647a..1f89663 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -1176,20 +1176,45 @@ 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; alpm_db_t *db_local = alpm_option_get_localdb(config->handle);
+ /* calculate these outside the loop. */ + alpm_list_t *pkgcache = alpm_db_get_pkgcache(db_local); + alpm_list_t *remove = alpm_trans_get_remove(config->handle); + alpm_list_t *add = alpm_trans_get_add(config->handle); + /* turn optdepends list into a text list. */ for( ; optlist; optlist = alpm_list_next(optlist)) { optdep = optlist->data; - if(alpm_db_get_pkg(db_local, optdep->depend->name) == NULL) { - optstrings = alpm_list_add(optstrings, alpm_optdep_compute_string(optdep)); + char *depstr = alpm_dep_compute_string(optdep->depend); + char *tmp, *str = alpm_optdep_compute_string(optdep); + const char *state = NULL; + + if(alpm_find_satisfier(pkgcache, depstr) && alpm_find_satisfier(remove, depstr) == NULL) { + state = include_installed ? _(" [installed]") : NULL; + } else if(alpm_find_satisfier(add, depstr)) { + state = include_installed ? _(" [installing]") : NULL; + } else if(alpm_find_satisfier(remove, depstr)) { + state = _(" [removing]"); + } else { + optstrings = alpm_list_add(optstrings, str); } + + if(state) { + if((tmp = realloc(str, strlen(str) + strlen(state) + 1)) != NULL) { + strcpy(tmp + strlen(tmp), state); + str = tmp; + } /* if realloc fails, we only loose the state information, which is nonfatal. */ + optstrings = alpm_list_add(optstrings, str); + } + free(depstr); }
return optstrings; @@ -1203,7 +1228,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, config->handleoptdeps & PM_OPTDEPS_SHOWALL);
if(optstrings) { printf(_("New optional dependencies for %s\n"), alpm_pkg_get_name(newpkg)); @@ -1218,7 +1243,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), config->handleoptdeps & PM_OPTDEPS_SHOWALL);
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 6ec962f..ca33752 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -69,6 +69,7 @@ void display_targets(void); 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); diff --git a/test/pacman/tests/sync061.py b/test/pacman/tests/sync062.py similarity index 65% copy from test/pacman/tests/sync061.py copy to test/pacman/tests/sync062.py index cb5a892..dc90002 100644 --- a/test/pacman/tests/sync061.py +++ b/test/pacman/tests/sync062.py @@ -1,4 +1,6 @@ -self.description = "Install a package from a sync db with installed optdepend and no optdepend output" +self.description = "Install a package from a sync db with installed optdepend and forced optdepend output" + +self.option["HandleOptdeps"] = ["ShowAll"]
p1 = pmpkg("dummy") p1.optdepends = ["dep: for foobar"] @@ -10,6 +12,6 @@ self.args = "-S %s" % p1.name
self.addrule("PACMAN_RETCODE=0") -self.addrule("!PACMAN_OUTPUT=dep: for foobar") -self.addrule("PKG_EXISTS=dummy") +self.addrule("PACMAN_OUTPUT=dep: for foobar") +self.addrule("PKG_EXIST=dummy") self.addrule("PKG_OPTDEPENDS=dummy|dep: for foobar") -- 1.7.7.3
Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- src/pacman/package.c | 7 ++----- test/pacman/tests/query010.py | 12 ++++++++++++ test/pacman/tests/query011.py | 15 +++++++++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 test/pacman/tests/query010.py create mode 100644 test/pacman/tests/query011.py diff --git a/src/pacman/package.c b/src/pacman/package.c index c7bfb14..49192bf 100644 --- a/src/pacman/package.c +++ b/src/pacman/package.c @@ -59,11 +59,8 @@ static void deplist_display(const char *title, static void optdeplist_display(const char *title, alpm_list_t *optdeps) { - alpm_list_t *i, *text = NULL; - for(i = optdeps; i; i = alpm_list_next(i)) { - alpm_optdepend_t *optdep = i->data; - text = alpm_list_add(text, alpm_optdep_compute_string(optdep)); - } + alpm_list_t *text = NULL; + text = optdep_string_list(optdeps, 1); list_display_linebreak(title, text); FREELIST(text); } diff --git a/test/pacman/tests/query010.py b/test/pacman/tests/query010.py new file mode 100644 index 0000000..76f82d9 --- /dev/null +++ b/test/pacman/tests/query010.py @@ -0,0 +1,12 @@ +self.description = "Query info on a package (optdep install status [uninstalled])" + +optstr = "dep: for foobar" + +pkg = pmpkg("dummy", "1.0-2") +pkg.optdepends = [optstr] +self.addpkg2db("local", pkg) + +self.args = "-Qi %s" % pkg.name + +self.addrule("PACMAN_RETCODE=0") +self.addrule("PACMAN_OUTPUT=^Optional Deps.*%s$" % optstr) diff --git a/test/pacman/tests/query011.py b/test/pacman/tests/query011.py new file mode 100644 index 0000000..f487fb2 --- /dev/null +++ b/test/pacman/tests/query011.py @@ -0,0 +1,15 @@ +self.description = "Query info on a package (optdep install status [installed])" + +optstr = "dep: for foobar" + +pkg = pmpkg("dummy", "1.0-2") +pkg.optdepends = [optstr] +self.addpkg2db("local", pkg) + +dep = pmpkg("dep") +self.addpkg2db("local", dep) + +self.args = "-Qi %s" % pkg.name + +self.addrule("PACMAN_RETCODE=0") +self.addrule("PACMAN_OUTPUT=^Optional Deps.*%s \[installed\]$" % optstr) -- 1.7.7.3
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 +- test/pacman/tests/query020.py | 14 ++++++++++++++ test/pacman/tests/query021.py | 14 ++++++++++++++ 10 files changed, 77 insertions(+), 16 deletions(-) create mode 100644 test/pacman/tests/query020.py create mode 100644 test/pacman/tests/query021.py diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt index 39551e1..62dd908 100644 --- a/doc/pacman.8.txt +++ b/doc/pacman.8.txt @@ -280,6 +280,12 @@ Query Options[[QO]] database(s). Typically these are packages that were downloaded manually and installed with '\--upgrade'. +*-n, \--optdeps*:: + 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 943ceec..d06ad0d 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -715,7 +715,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 451506b..3c217b7 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -382,7 +382,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; @@ -390,11 +391,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)); + } } } } @@ -402,7 +415,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; @@ -413,17 +426,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->status & DB_STATUS_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 7ff37ff..9858f7d 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_optdeps; 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 49192bf..642307c 100644 --- a/src/pacman/package.c +++ b/src/pacman/package.c @@ -109,7 +109,7 @@ void dump_pkg_full(alpm_pkg_t *pkg, 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 fa35e8d..fd93133 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -145,6 +145,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, --optdeps 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")); @@ -461,6 +462,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_optdeps = 1; break; case 'g': (config->group)++; break; case 'i': (config->op_q_info)++; break; case 'k': config->op_q_check = 1; break; @@ -603,6 +605,7 @@ static int parseargs(int argc, char *argv[]) {"list", no_argument, 0, 'l'}, {"foreign", no_argument, 0, 'm'}, {"nosave", no_argument, 0, 'n'}, + {"optdeps", 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 4c2ea81..fbff341 100644 --- a/src/pacman/query.c +++ b/src/pacman/query.c @@ -363,9 +363,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; } @@ -390,7 +396,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_optdeps && !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 f95c5e8..700bfe8 100644 --- a/src/util/pactree.c +++ b/src/util/pactree.c @@ -383,7 +383,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 = i->data; diff --git a/test/pacman/tests/query020.py b/test/pacman/tests/query020.py new file mode 100644 index 0000000..a6c8ffe --- /dev/null +++ b/test/pacman/tests/query020.py @@ -0,0 +1,14 @@ +self.description = "Query unneeded deps (installed optdeps required)" + +p1 = pmpkg("dummy", "1.0-2") +p1.optdepends = ["dep: for foobar"] +self.addpkg2db("local", p1) + +p2 = pmpkg("dep") +p2.reason = 1 +self.addpkg2db("local", p2) + +self.args = "-Qtd" + +self.addrule("PACMAN_RETCODE=1") +self.addrule("!PACMAN_OUTPUT=^dep") diff --git a/test/pacman/tests/query021.py b/test/pacman/tests/query021.py new file mode 100644 index 0000000..1a0ad40 --- /dev/null +++ b/test/pacman/tests/query021.py @@ -0,0 +1,14 @@ +self.description = "Query unneeded deps (installed optdeps not required)" + +p1 = pmpkg("dummy", "1.0-2") +p1.optdepends = ["dep: for foobar"] +self.addpkg2db("local", p1) + +p2 = pmpkg("dep") +p2.reason = 1 +self.addpkg2db("local", p2) + +self.args = "-Qtdn" + +self.addrule("PACMAN_RETCODE=0") +self.addrule("PACMAN_OUTPUT=^dep") -- 1.7.7.3
On Wed, Nov 23, 2011 at 9:51 AM, Benedikt Morbach <benedikt.morbach@googlemail.com> wrote: > 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 +- > test/pacman/tests/query020.py | 14 ++++++++++++++ > test/pacman/tests/query021.py | 14 ++++++++++++++ > 10 files changed, 77 insertions(+), 16 deletions(-) > create mode 100644 test/pacman/tests/query020.py > create mode 100644 test/pacman/tests/query021.py > > diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt > index 39551e1..62dd908 100644 > --- a/doc/pacman.8.txt > +++ b/doc/pacman.8.txt > @@ -280,6 +280,12 @@ Query Options[[QO]] > database(s). Typically these are packages that were downloaded manually > and installed with '\--upgrade'. > > +*-n, \--optdeps*:: > + 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 943ceec..d06ad0d 100644 > --- a/lib/libalpm/alpm.h > +++ b/lib/libalpm/alpm.h > @@ -715,7 +715,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); 1. You didn't add the new param to the documentation 2. This is definitely not self-documenting; when I looked at the code I was completely surprised to find it either finds depends OR optdepends, but not both. I'm honestly not sure overloading this *public* method makes sense. Given you ask for alpm_pkg_get_depends() or alpm_pkg_get_optdepends(), I would expect the reciprocals to also have two methods. Something like alpm_pkg_compute_requiredby() and alpm_pkg_compute_optrequiredby(). > /** @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 451506b..3c217b7 100644 > --- a/lib/libalpm/package.c > +++ b/lib/libalpm/package.c > @@ -382,7 +382,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) Making the int const here doesn't really help much; we don't tend to do this in any of our functions. > { > const alpm_list_t *i; > pkg->handle->pm_errno = 0; > @@ -390,11 +391,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)); > + } This won't have to change near as much if both are the same type; simply initialize j based on find_optdeps() and keep the rest of the loop body intact and unchanged indent. > } > } > } > @@ -402,7 +415,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; > @@ -413,17 +426,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->status & DB_STATUS_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 7ff37ff..9858f7d 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_optdeps; > 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 49192bf..642307c 100644 > --- a/src/pacman/package.c > +++ b/src/pacman/package.c > @@ -109,7 +109,7 @@ void dump_pkg_full(alpm_pkg_t *pkg, 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 fa35e8d..fd93133 100644 > --- a/src/pacman/pacman.c > +++ b/src/pacman/pacman.c > @@ -145,6 +145,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, --optdeps 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")); > @@ -461,6 +462,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_optdeps = 1; break; > case 'g': (config->group)++; break; > case 'i': (config->op_q_info)++; break; > case 'k': config->op_q_check = 1; break; > @@ -603,6 +605,7 @@ static int parseargs(int argc, char *argv[]) > {"list", no_argument, 0, 'l'}, > {"foreign", no_argument, 0, 'm'}, > {"nosave", no_argument, 0, 'n'}, > + {"optdeps", no_argument, 0, 'n'}, -2 on using 'n' for the shortopt here: -1) Doubling the meaning of -n -2) This seems like a very useful and implementable flag down the line for -R, similar to existing -c and -s, but you have precluded this by choosing -n. Also, the name '--optdepts' is quite deceiving, as it seems specifying it makes pacman *ignore* them rather than include them. Quite odd from an outside perspective. > {"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 4c2ea81..fbff341 100644 > --- a/src/pacman/query.c > +++ b/src/pacman/query.c > @@ -363,9 +363,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; > } > @@ -390,7 +396,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_optdeps && !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 f95c5e8..700bfe8 100644 > --- a/src/util/pactree.c > +++ b/src/util/pactree.c > @@ -383,7 +383,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 = i->data; > diff --git a/test/pacman/tests/query020.py b/test/pacman/tests/query020.py > new file mode 100644 > index 0000000..a6c8ffe > --- /dev/null > +++ b/test/pacman/tests/query020.py > @@ -0,0 +1,14 @@ > +self.description = "Query unneeded deps (installed optdeps required)" > + > +p1 = pmpkg("dummy", "1.0-2") > +p1.optdepends = ["dep: for foobar"] > +self.addpkg2db("local", p1) > + > +p2 = pmpkg("dep") > +p2.reason = 1 > +self.addpkg2db("local", p2) > + > +self.args = "-Qtd" > + > +self.addrule("PACMAN_RETCODE=1") > +self.addrule("!PACMAN_OUTPUT=^dep") > diff --git a/test/pacman/tests/query021.py b/test/pacman/tests/query021.py > new file mode 100644 > index 0000000..1a0ad40 > --- /dev/null > +++ b/test/pacman/tests/query021.py > @@ -0,0 +1,14 @@ > +self.description = "Query unneeded deps (installed optdeps not required)" > + > +p1 = pmpkg("dummy", "1.0-2") > +p1.optdepends = ["dep: for foobar"] > +self.addpkg2db("local", p1) > + > +p2 = pmpkg("dep") > +p2.reason = 1 > +self.addpkg2db("local", p2) > + > +self.args = "-Qtdn" > + > +self.addrule("PACMAN_RETCODE=0") > +self.addrule("PACMAN_OUTPUT=^dep") > -- > 1.7.7.3 > >
Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- src/pacman/package.c | 9 ++++++--- test/pacman/tests/query012.py | 13 +++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 test/pacman/tests/query012.py diff --git a/src/pacman/package.c b/src/pacman/package.c index 642307c..53f44bc 100644 --- a/src/pacman/package.c +++ b/src/pacman/package.c @@ -67,8 +67,8 @@ static void optdeplist_display(const char *title, /** * Display the details of a package. - * Extra information entails 'required by' info for sync packages and backup - * files info for local packages. + * Extra information entails 'required by' and 'optrequired by' info + * for sync packages and backup files info for local packages. * @param pkg package to display information for * @param from the type of package we are dealing with * @param extra should we show extra information @@ -81,6 +81,7 @@ void dump_pkg_full(alpm_pkg_t *pkg, int extra) const char *label; double size; alpm_list_t *requiredby = NULL; + alpm_list_t *optrequiredby = NULL; alpm_pkgfrom_t from; from = alpm_pkg_get_origin(pkg); @@ -109,7 +110,8 @@ void dump_pkg_full(alpm_pkg_t *pkg, 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 */ @@ -127,6 +129,7 @@ void dump_pkg_full(alpm_pkg_t *pkg, int extra) optdeplist_display(_("Optional Deps :"), alpm_pkg_get_optdepends(pkg)); if(extra || from == PKG_FROM_LOCALDB) { list_display(_("Required By :"), requiredby); + list_display(_("Optional For :"), optrequiredby); } deplist_display(_("Conflicts With :"), alpm_pkg_get_conflicts(pkg)); deplist_display(_("Replaces :"), alpm_pkg_get_replaces(pkg)); diff --git a/test/pacman/tests/query012.py b/test/pacman/tests/query012.py new file mode 100644 index 0000000..cdb7120 --- /dev/null +++ b/test/pacman/tests/query012.py @@ -0,0 +1,13 @@ +self.description = "Query info on a package (reverse optdeps)" + +pkg = pmpkg("dummy", "1.0-2") +pkg.optdepends = ["dep: for foobar"] +self.addpkg2db("local", pkg) + +dep = pmpkg("dep") +self.addpkg2db("local", dep) + +self.args = "-Qi %s" % dep.name + +self.addrule("PACMAN_RETCODE=0") +self.addrule("PACMAN_OUTPUT=^Optional For.*%s" % pkg.name) -- 1.7.7.3
Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- lib/libalpm/deps.c | 18 +++++++++++++++++- test/pacman/tests/remove053.py | 15 +++++++++++++++ test/pacman/tests/remove054.py | 14 ++++++++++++++ test/pacman/tests/remove055.py | 20 ++++++++++++++++++++ 4 files changed, 66 insertions(+), 1 deletions(-) create mode 100644 test/pacman/tests/remove053.py create mode 100644 test/pacman/tests/remove054.py create mode 100644 test/pacman/tests/remove055.py diff --git a/lib/libalpm/deps.c b/lib/libalpm/deps.c index 12d7156..83bc619 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) @@ -554,6 +567,9 @@ static int can_remove_package(alpm_db_t *db, alpm_pkg_t *pkg, 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 */ @@ -583,7 +599,7 @@ int _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_pkg_t *copy; _alpm_log(db->handle, ALPM_LOG_DEBUG, "adding '%s' to the targets\n", diff --git a/test/pacman/tests/remove053.py b/test/pacman/tests/remove053.py new file mode 100644 index 0000000..52d86dd --- /dev/null +++ b/test/pacman/tests/remove053.py @@ -0,0 +1,15 @@ +self.description = "-Rs test (unneeded optdeps)" + +p1 = pmpkg("dummy") +p1.optdepends = ["dep: for foobar"] +self.addpkg2db("local", p1) + +p2 = pmpkg("dep") +p2.reason = 1 +self.addpkg2db("local", p2) + +self.args = "-Rs %s" % p1.name + +self.addrule("PACMAN_RETCODE=0") +self.addrule("!PKG_EXIST=dummy") +self.addrule("!PKG_EXIST=dep") diff --git a/test/pacman/tests/remove054.py b/test/pacman/tests/remove054.py new file mode 100644 index 0000000..0653449 --- /dev/null +++ b/test/pacman/tests/remove054.py @@ -0,0 +1,14 @@ +self.description = "-Rss test (unneeded optdeps, explicit)" + +p1 = pmpkg("dummy") +p1.optdepends = ["dep: for foobar"] +self.addpkg2db("local", p1) + +p2 = pmpkg("dep") +self.addpkg2db("local", p2) + +self.args = "-Rss %s" % p1.name + +self.addrule("PACMAN_RETCODE=0") +self.addrule("!PKG_EXIST=dummy") +self.addrule("!PKG_EXIST=dep") diff --git a/test/pacman/tests/remove055.py b/test/pacman/tests/remove055.py new file mode 100644 index 0000000..e8134ad --- /dev/null +++ b/test/pacman/tests/remove055.py @@ -0,0 +1,20 @@ +self.description = "-Rs test (needed optdeps)" + +p1 = pmpkg("dummy") +p1.optdepends = ["dep: for foobar"] +self.addpkg2db("local", p1) + +p2 = pmpkg("keep") +p2.optdepends = ["dep: for baz"] +self.addpkg2db("local", p2) + +p3 = pmpkg("dep") +p3.reason = 1 +self.addpkg2db("local", p3) + +self.args = "-Rs %s" % p1.name + +self.addrule("PACMAN_RETCODE=0") +self.addrule("!PKG_EXIST=dummy") +self.addrule("PKG_EXIST=keep") +self.addrule("PKG_EXIST=dep") -- 1.7.7.3
Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- src/pacman/query.c | 11 ++++++++++- src/pacman/util.c | 27 ++++++++++++++++++++------- src/pacman/util.h | 1 + test/pacman/tests/query022.py | 14 ++++++++++++++ 4 files changed, 45 insertions(+), 8 deletions(-) create mode 100644 test/pacman/tests/query022.py diff --git a/src/pacman/query.c b/src/pacman/query.c index fbff341..0017918 100644 --- a/src/pacman/query.c +++ b/src/pacman/query.c @@ -488,7 +488,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_optdeps && + (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 1f89663..c54975e 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -657,16 +657,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; size_t 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 unsigned short maxcols = getcols(); size_t cols = len; @@ -680,20 +688,25 @@ void list_display(const char *title, const alpm_list_t *list) if(maxcols > len && cols + s + 2 >= maxcols) { size_t j; cols = len; - printf("\n"); + putchar('\n'); for (j = 1; j <= len; j++) { - printf(" "); + putchar(' '); } } 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. */ + fputs(delim, stdout); + cols += strlen(delim); } fputs(str, stdout); cols += s; } - putchar('\n'); } + + if(after) { + fputs(after, stdout); + } + + putchar('\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 ca33752..ffff4b5 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -63,6 +63,7 @@ void string_display(const char *title, const char *string); double humanize_size(off_t bytes, const char target_unit, 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_siglist_t *siglist); void display_targets(void); diff --git a/test/pacman/tests/query022.py b/test/pacman/tests/query022.py new file mode 100644 index 0000000..f5e3458 --- /dev/null +++ b/test/pacman/tests/query022.py @@ -0,0 +1,14 @@ +self.description = "Query unneeded deps (installed optdeps not required)" + +pkg = pmpkg("dummy") +pkg.optdepends = ["dep: for foobar"] +self.addpkg2db("local", pkg) + +dep = pmpkg("dep") +self.addpkg2db("local", dep) +dep.reason = 1 + +self.args = "-Qtdn" + +self.addrule("PACMAN_RETCODE=0") +self.addrule("PACMAN_OUTPUT=^dep.*dummy") -- 1.7.7.3
On Wed, Nov 23, 2011 at 9:51 AM, Benedikt Morbach <benedikt.morbach@googlemail.com> wrote:
Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- Can you provide some example output from this?
Overall, I'm not liking what I think this is, as it seems like an extremely narrow implementation of https://bugs.archlinux.org/task/25236 ...
src/pacman/query.c | 11 ++++++++++- src/pacman/util.c | 27 ++++++++++++++++++++------- src/pacman/util.h | 1 + test/pacman/tests/query022.py | 14 ++++++++++++++ 4 files changed, 45 insertions(+), 8 deletions(-) create mode 100644 test/pacman/tests/query022.py
diff --git a/src/pacman/query.c b/src/pacman/query.c index fbff341..0017918 100644 --- a/src/pacman/query.c +++ b/src/pacman/query.c @@ -488,7 +488,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_optdeps && + (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 1f89663..c54975e 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -657,16 +657,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; size_t 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 unsigned short maxcols = getcols(); size_t cols = len; @@ -680,20 +688,25 @@ void list_display(const char *title, const alpm_list_t *list) if(maxcols > len && cols + s + 2 >= maxcols) { size_t j; cols = len; - printf("\n"); + putchar('\n'); for (j = 1; j <= len; j++) { - printf(" "); + putchar(' '); } } 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. */ + fputs(delim, stdout); + cols += strlen(delim); } fputs(str, stdout); cols += s; } - putchar('\n'); } + + if(after) { + fputs(after, stdout); + } + + putchar('\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 ca33752..ffff4b5 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -63,6 +63,7 @@ void string_display(const char *title, const char *string); double humanize_size(off_t bytes, const char target_unit, 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_siglist_t *siglist); void display_targets(void); diff --git a/test/pacman/tests/query022.py b/test/pacman/tests/query022.py new file mode 100644 index 0000000..f5e3458 --- /dev/null +++ b/test/pacman/tests/query022.py @@ -0,0 +1,14 @@ +self.description = "Query unneeded deps (installed optdeps not required)" + +pkg = pmpkg("dummy") +pkg.optdepends = ["dep: for foobar"] +self.addpkg2db("local", pkg) + +dep = pmpkg("dep") +self.addpkg2db("local", dep) +dep.reason = 1 + +self.args = "-Qtdn" + +self.addrule("PACMAN_RETCODE=0") +self.addrule("PACMAN_OUTPUT=^dep.*dummy") -- 1.7.7.3
Issue a warning if the user for whatever reason tries to remove an optdepend of an installed package. Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- lib/libalpm/alpm.h | 5 ++++- lib/libalpm/deps.c | 35 ++++++++++++++++++++++++++--------- lib/libalpm/error.c | 2 ++ lib/libalpm/remove.c | 16 +++++++++++++--- lib/libalpm/sync.c | 2 +- lib/libalpm/trans.c | 10 ++++++++-- src/pacman/remove.c | 23 +++++++++++++++++++---- src/util/testdb.c | 2 +- 8 files changed, 74 insertions(+), 21 deletions(-) diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index d06ad0d..34dbaa1 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -162,6 +162,8 @@ typedef struct _alpm_depmissing_t { alpm_depend_t *depend; /* this is used in case of remove dependency error only */ char *causingpkg; + /* this is used for optdepends only */ + char *description; } alpm_depmissing_t; /** Conflict */ @@ -1096,7 +1098,7 @@ int alpm_remove_pkg(alpm_handle_t *handle, alpm_pkg_t *pkg); */ alpm_list_t *alpm_checkdeps(alpm_handle_t *handle, alpm_list_t *pkglist, - alpm_list_t *remove, alpm_list_t *upgrade, int reversedeps); + alpm_list_t *remove, alpm_list_t *upgrade, int reversedeps, int consider_optdeps); alpm_pkg_t *alpm_find_satisfier(alpm_list_t *pkgs, const char *depstring); alpm_pkg_t *alpm_find_dbs_satisfier(alpm_handle_t *handle, alpm_list_t *dbs, const char *depstring); @@ -1184,6 +1186,7 @@ typedef enum _alpm_errno_t { ALPM_ERR_DLT_PATCHFAILED, /* Dependencies */ ALPM_ERR_UNSATISFIED_DEPS, + ALPM_ERR_UNSATISFIED_OPTDEPS, ALPM_ERR_CONFLICTING_DEPS, ALPM_ERR_FILE_CONFLICTS, /* Misc */ diff --git a/lib/libalpm/deps.c b/lib/libalpm/deps.c index 83bc619..c9efce4 100644 --- a/lib/libalpm/deps.c +++ b/lib/libalpm/deps.c @@ -52,7 +52,7 @@ void _alpm_optdep_free(alpm_optdepend_t *optdep) } static alpm_depmissing_t *depmiss_new(const char *target, alpm_depend_t *dep, - const char *causingpkg) + const char *causingpkg, const char *description) { alpm_depmissing_t *miss; @@ -61,6 +61,7 @@ static alpm_depmissing_t *depmiss_new(const char *target, alpm_depend_t *dep, STRDUP(miss->target, target, return NULL); miss->depend = _alpm_dep_dup(dep); STRDUP(miss->causingpkg, causingpkg, return NULL); + STRDUP(miss->description, description, return NULL); return miss; } @@ -70,6 +71,7 @@ void _alpm_depmiss_free(alpm_depmissing_t *miss) _alpm_dep_free(miss->depend); FREE(miss->target); FREE(miss->causingpkg); + FREE(miss->description); FREE(miss); } @@ -283,11 +285,12 @@ alpm_pkg_t SYMEXPORT *alpm_find_satisfier(alpm_list_t *pkgs, const char *depstri * @param remove an alpm_list_t* of packages to be removed * @param upgrade an alpm_list_t* of packages to be upgraded (remove-then-upgrade) * @param reversedeps handles the backward dependencies + * @param consider_optdeps handles optional dependencies instead of normal ones * @return an alpm_list_t* of alpm_depmissing_t pointers. */ alpm_list_t SYMEXPORT *alpm_checkdeps(alpm_handle_t *handle, alpm_list_t *pkglist, alpm_list_t *remove, alpm_list_t *upgrade, - int reversedeps) + int reversedeps, int consider_optdeps) { alpm_list_t *i, *j; alpm_list_t *dblist = NULL, *modified = NULL; @@ -326,7 +329,7 @@ alpm_list_t SYMEXPORT *alpm_checkdeps(alpm_handle_t *handle, _alpm_log(handle, ALPM_LOG_DEBUG, "checkdeps: missing dependency '%s' for package '%s'\n", missdepstring, tp->name); free(missdepstring); - miss = depmiss_new(tp->name, depend, NULL); + miss = depmiss_new(tp->name, depend, NULL, NULL); baddeps = alpm_list_add(baddeps, miss); } release_filtered_depend(depend, nodepversion); @@ -338,8 +341,17 @@ alpm_list_t SYMEXPORT *alpm_checkdeps(alpm_handle_t *handle, * the packages listed in the requiredby field. */ for(i = dblist; i; i = i->next) { alpm_pkg_t *lp = i->data; - for(j = alpm_pkg_get_depends(lp); j; j = j->next) { - alpm_depend_t *depend = j->data; + j = consider_optdeps ? alpm_pkg_get_optdepends(lp) : alpm_pkg_get_depends(lp); + for(; j; j = j->next) { + alpm_depend_t *depend; + const char *description = NULL; + if(consider_optdeps) { + alpm_optdepend_t *optdep = j->data; + depend = optdep->depend; + description = optdep->description; + } else { + depend = j->data; + } depend = filtered_depend(depend, nodepversion); alpm_pkg_t *causingpkg = find_dep_satisfier(modified, depend); /* we won't break this depend, if it is already broken, we ignore it */ @@ -350,10 +362,15 @@ alpm_list_t SYMEXPORT *alpm_checkdeps(alpm_handle_t *handle, !find_dep_satisfier(dblist, depend)) { alpm_depmissing_t *miss; char *missdepstring = alpm_dep_compute_string(depend); - _alpm_log(handle, ALPM_LOG_DEBUG, "checkdeps: transaction would break '%s' dependency of '%s'\n", - missdepstring, lp->name); + if(consider_optdeps) { + _alpm_log(handle, ALPM_LOG_DEBUG, "checkdeps: transaction would break '%s' optional dependency of '%s'\n", + missdepstring, lp->name); + } else { + _alpm_log(handle, ALPM_LOG_DEBUG, "checkdeps: transaction would break '%s' dependency of '%s'\n", + missdepstring, lp->name); + } free(missdepstring); - miss = depmiss_new(lp->name, depend, causingpkg->name); + miss = depmiss_new(lp->name, depend, causingpkg->name, description); baddeps = alpm_list_add(baddeps, miss); } release_filtered_depend(depend, nodepversion); @@ -801,7 +818,7 @@ int _alpm_resolvedeps(alpm_handle_t *handle, alpm_list_t *localpkgs, for(i = alpm_list_last(*packages); i; i = i->next) { alpm_pkg_t *tpkg = i->data; targ = alpm_list_add(NULL, tpkg); - deps = alpm_checkdeps(handle, localpkgs, remove, targ, 0); + deps = alpm_checkdeps(handle, localpkgs, remove, targ, 0, 0); alpm_list_free(targ); for(j = deps; j; j = j->next) { diff --git a/lib/libalpm/error.c b/lib/libalpm/error.c index 044dec7..5283392 100644 --- a/lib/libalpm/error.c +++ b/lib/libalpm/error.c @@ -136,6 +136,8 @@ const char SYMEXPORT *alpm_strerror(alpm_errno_t err) /* Dependencies */ case ALPM_ERR_UNSATISFIED_DEPS: return _("could not satisfy dependencies"); + case ALPM_ERR_UNSATISFIED_OPTDEPS: + return _("could not satisfy optional dependencies"); case ALPM_ERR_CONFLICTING_DEPS: return _("conflicting dependencies"); case ALPM_ERR_FILE_CONFLICTS: diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c index d7e06bc..012f9c8 100644 --- a/lib/libalpm/remove.c +++ b/lib/libalpm/remove.c @@ -102,7 +102,7 @@ static int remove_prepare_cascade(alpm_handle_t *handle, alpm_list_t *lp) alpm_list_free_inner(lp, (alpm_list_fn_free)_alpm_depmiss_free); alpm_list_free(lp); lp = alpm_checkdeps(handle, _alpm_db_get_pkgcache(handle->db_local), - trans->remove, NULL, 1); + trans->remove, NULL, 1, 0); } return 0; } @@ -133,7 +133,7 @@ static void remove_prepare_keep_needed(alpm_handle_t *handle, alpm_list_t *lp) alpm_list_free_inner(lp, (alpm_list_fn_free)_alpm_depmiss_free); alpm_list_free(lp); lp = alpm_checkdeps(handle, _alpm_db_get_pkgcache(handle->db_local), - trans->remove, NULL, 1); + trans->remove, NULL, 1, 0); } } @@ -164,7 +164,7 @@ int _alpm_remove_prepare(alpm_handle_t *handle, alpm_list_t **data) EVENT(handle, ALPM_EVENT_CHECKDEPS_START, NULL, NULL); _alpm_log(handle, ALPM_LOG_DEBUG, "looking for unsatisfied dependencies\n"); - lp = alpm_checkdeps(handle, _alpm_db_get_pkgcache(db), trans->remove, NULL, 1); + lp = alpm_checkdeps(handle, _alpm_db_get_pkgcache(db), trans->remove, NULL, 1, 0); if(lp != NULL) { if(trans->flags & ALPM_TRANS_FLAG_CASCADE) { @@ -206,6 +206,16 @@ int _alpm_remove_prepare(alpm_handle_t *handle, alpm_list_t **data) if(!(trans->flags & ALPM_TRANS_FLAG_NODEPS)) { EVENT(handle, ALPM_EVENT_CHECKDEPS_DONE, NULL, NULL); + lp = alpm_checkdeps(handle, _alpm_db_get_pkgcache(db), trans->remove, NULL, 1, 1); + if(lp != NULL) { + if(data) { + *data = lp; + } else { + alpm_list_free_inner(lp, (alpm_list_fn_free)_alpm_depmiss_free); + alpm_list_free(lp); + } + RET_ERR(handle, ALPM_ERR_UNSATISFIED_OPTDEPS, -1); + } } return 0; diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index 3817ec8..b501807 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -605,7 +605,7 @@ int _alpm_sync_prepare(alpm_handle_t *handle, alpm_list_t **data) if(!(trans->flags & ALPM_TRANS_FLAG_NODEPS)) { _alpm_log(handle, ALPM_LOG_DEBUG, "checking dependencies\n"); deps = alpm_checkdeps(handle, _alpm_db_get_pkgcache(handle->db_local), - trans->remove, trans->add, 1); + trans->remove, trans->add, 1, 0); if(deps) { handle->pm_errno = ALPM_ERR_UNSATISFIED_DEPS; ret = -1; diff --git a/lib/libalpm/trans.c b/lib/libalpm/trans.c index cb97a4a..40e6786 100644 --- a/lib/libalpm/trans.c +++ b/lib/libalpm/trans.c @@ -101,6 +101,7 @@ static alpm_list_t *check_arch(alpm_handle_t *handle, alpm_list_t *pkgs) int SYMEXPORT alpm_trans_prepare(alpm_handle_t *handle, alpm_list_t **data) { alpm_trans_t *trans; + int retval = 0; /* Sanity checks */ CHECK_HANDLE(handle, return -1); @@ -127,7 +128,12 @@ int SYMEXPORT alpm_trans_prepare(alpm_handle_t *handle, alpm_list_t **data) if(trans->add == NULL) { if(_alpm_remove_prepare(handle, data) == -1) { /* pm_errno is set by _alpm_remove_prepare() */ - return -1; + /* UNSATISFIED_OPTDEPS is nonfatal. */ + if(alpm_errno(handle) == ALPM_ERR_UNSATISFIED_OPTDEPS) { + retval = -1; + } else { + return -1; + } } } else { if(_alpm_sync_prepare(handle, data) == -1) { @@ -138,7 +144,7 @@ int SYMEXPORT alpm_trans_prepare(alpm_handle_t *handle, alpm_list_t **data) trans->state = STATE_PREPARED; - return 0; + return retval; } /** Commit a transaction. */ diff --git a/src/pacman/remove.c b/src/pacman/remove.c index f56c1ec..739a6eb 100644 --- a/src/pacman/remove.c +++ b/src/pacman/remove.c @@ -111,8 +111,8 @@ int pacman_remove(alpm_list_t *targets) /* Step 2: prepare the transaction based on its type, targets and flags */ if(alpm_trans_prepare(config->handle, &data) == -1) { alpm_errno_t err = alpm_errno(config->handle); - pm_printf(ALPM_LOG_ERROR, _("failed to prepare transaction (%s)\n"), - alpm_strerror(err)); + retval = 1; + switch(err) { case ALPM_ERR_PKG_INVALID_ARCH: for(i = data; i; i = alpm_list_next(i)) { @@ -128,12 +128,27 @@ int pacman_remove(alpm_list_t *targets) free(depstring); } break; + case ALPM_ERR_UNSATISFIED_OPTDEPS: + for(i = data; i; i = alpm_list_next(i)) { + alpm_depmissing_t *miss = i->data; + char *depstring = alpm_dep_compute_string(miss->depend); + if(miss->description) { + printf(_(":: %s: optionally requires %s (%s)\n"), miss->target, depstring, miss->description); + } else { + printf(_(":: %s: optionally requires %s\n"), miss->target, depstring); + } + free(depstring); + } + retval = 0; + break; default: break; } FREELIST(data); - retval = 1; - goto cleanup; + if(retval) { + pm_printf(ALPM_LOG_ERROR, _("failed to prepare transaction (%s)\n"), alpm_strerror(err)); + goto cleanup; + } } /* Search for holdpkg in target list */ diff --git a/src/util/testdb.c b/src/util/testdb.c index b15bbe5..e1401cc 100644 --- a/src/util/testdb.c +++ b/src/util/testdb.c @@ -99,7 +99,7 @@ static int checkdeps(alpm_list_t *pkglist) alpm_list_t *data, *i; int ret = 0; /* check dependencies */ - data = alpm_checkdeps(handle, pkglist, NULL, pkglist, 0); + data = alpm_checkdeps(handle, pkglist, NULL, pkglist, 0, 0); for(i = data; i; i = alpm_list_next(i)) { alpm_depmissing_t *miss = i->data; char *depstring = alpm_dep_compute_string(miss->depend); -- 1.7.7.3
On Wed, Nov 23, 2011 at 9:51 AM, Benedikt Morbach <benedikt.morbach@googlemail.com> wrote:
Issue a warning if the user for whatever reason tries to remove an optdepend of an installed package.
Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- lib/libalpm/alpm.h | 5 ++++- lib/libalpm/deps.c | 35 ++++++++++++++++++++++++++--------- lib/libalpm/error.c | 2 ++ lib/libalpm/remove.c | 16 +++++++++++++--- lib/libalpm/sync.c | 2 +- lib/libalpm/trans.c | 10 ++++++++-- src/pacman/remove.c | 23 +++++++++++++++++++---- src/util/testdb.c | 2 +- 8 files changed, 74 insertions(+), 21 deletions(-)
diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index d06ad0d..34dbaa1 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -162,6 +162,8 @@ typedef struct _alpm_depmissing_t { alpm_depend_t *depend; /* this is used in case of remove dependency error only */ char *causingpkg; + /* this is used for optdepends only */ + char *description; This is needed only because depmissing_t points at a depend_t and not an optdepend_t? Yet another reason to make them one and the same.
} alpm_depmissing_t;
/** Conflict */ @@ -1096,7 +1098,7 @@ int alpm_remove_pkg(alpm_handle_t *handle, alpm_pkg_t *pkg); */
alpm_list_t *alpm_checkdeps(alpm_handle_t *handle, alpm_list_t *pkglist, - alpm_list_t *remove, alpm_list_t *upgrade, int reversedeps); + alpm_list_t *remove, alpm_list_t *upgrade, int reversedeps, int consider_optdeps); alpm_pkg_t *alpm_find_satisfier(alpm_list_t *pkgs, const char *depstring); alpm_pkg_t *alpm_find_dbs_satisfier(alpm_handle_t *handle, alpm_list_t *dbs, const char *depstring); @@ -1184,6 +1186,7 @@ typedef enum _alpm_errno_t { ALPM_ERR_DLT_PATCHFAILED, /* Dependencies */ ALPM_ERR_UNSATISFIED_DEPS, + ALPM_ERR_UNSATISFIED_OPTDEPS, ALPM_ERR_CONFLICTING_DEPS, ALPM_ERR_FILE_CONFLICTS, /* Misc */ diff --git a/lib/libalpm/deps.c b/lib/libalpm/deps.c index 83bc619..c9efce4 100644 --- a/lib/libalpm/deps.c +++ b/lib/libalpm/deps.c @@ -52,7 +52,7 @@ void _alpm_optdep_free(alpm_optdepend_t *optdep) }
static alpm_depmissing_t *depmiss_new(const char *target, alpm_depend_t *dep, - const char *causingpkg) + const char *causingpkg, const char *description) { alpm_depmissing_t *miss;
@@ -61,6 +61,7 @@ static alpm_depmissing_t *depmiss_new(const char *target, alpm_depend_t *dep, STRDUP(miss->target, target, return NULL); miss->depend = _alpm_dep_dup(dep); STRDUP(miss->causingpkg, causingpkg, return NULL); + STRDUP(miss->description, description, return NULL);
return miss; } @@ -70,6 +71,7 @@ void _alpm_depmiss_free(alpm_depmissing_t *miss) _alpm_dep_free(miss->depend); FREE(miss->target); FREE(miss->causingpkg); + FREE(miss->description); FREE(miss); }
@@ -283,11 +285,12 @@ alpm_pkg_t SYMEXPORT *alpm_find_satisfier(alpm_list_t *pkgs, const char *depstri * @param remove an alpm_list_t* of packages to be removed * @param upgrade an alpm_list_t* of packages to be upgraded (remove-then-upgrade) * @param reversedeps handles the backward dependencies + * @param consider_optdeps handles optional dependencies instead of normal ones * @return an alpm_list_t* of alpm_depmissing_t pointers. */ alpm_list_t SYMEXPORT *alpm_checkdeps(alpm_handle_t *handle, alpm_list_t *pkglist, alpm_list_t *remove, alpm_list_t *upgrade, - int reversedeps) + int reversedeps, int consider_optdeps) { alpm_list_t *i, *j; alpm_list_t *dblist = NULL, *modified = NULL; @@ -326,7 +329,7 @@ alpm_list_t SYMEXPORT *alpm_checkdeps(alpm_handle_t *handle, _alpm_log(handle, ALPM_LOG_DEBUG, "checkdeps: missing dependency '%s' for package '%s'\n", missdepstring, tp->name); free(missdepstring); - miss = depmiss_new(tp->name, depend, NULL); + miss = depmiss_new(tp->name, depend, NULL, NULL); baddeps = alpm_list_add(baddeps, miss); } release_filtered_depend(depend, nodepversion); @@ -338,8 +341,17 @@ alpm_list_t SYMEXPORT *alpm_checkdeps(alpm_handle_t *handle, * the packages listed in the requiredby field. */ for(i = dblist; i; i = i->next) { alpm_pkg_t *lp = i->data; - for(j = alpm_pkg_get_depends(lp); j; j = j->next) { - alpm_depend_t *depend = j->data; + j = consider_optdeps ? alpm_pkg_get_optdepends(lp) : alpm_pkg_get_depends(lp); + for(; j; j = j->next) { + alpm_depend_t *depend; + const char *description = NULL; + if(consider_optdeps) { + alpm_optdepend_t *optdep = j->data; + depend = optdep->depend; + description = optdep->description; + } else { + depend = j->data; + } OMG please unify depend_t and optdepend_t. :)
depend = filtered_depend(depend, nodepversion); alpm_pkg_t *causingpkg = find_dep_satisfier(modified, depend); /* we won't break this depend, if it is already broken, we ignore it */ @@ -350,10 +362,15 @@ alpm_list_t SYMEXPORT *alpm_checkdeps(alpm_handle_t *handle, !find_dep_satisfier(dblist, depend)) { alpm_depmissing_t *miss; char *missdepstring = alpm_dep_compute_string(depend); - _alpm_log(handle, ALPM_LOG_DEBUG, "checkdeps: transaction would break '%s' dependency of '%s'\n", - missdepstring, lp->name); + if(consider_optdeps) { + _alpm_log(handle, ALPM_LOG_DEBUG, "checkdeps: transaction would break '%s' optional dependency of '%s'\n", We're way over the normal line wrap width here, so please move the start of the string to the next line. + missdepstring, lp->name); + } else { + _alpm_log(handle, ALPM_LOG_DEBUG, "checkdeps: transaction would break '%s' dependency of '%s'\n", + missdepstring, lp->name); + } free(missdepstring); - miss = depmiss_new(lp->name, depend, causingpkg->name); + miss = depmiss_new(lp->name, depend, causingpkg->name, description); baddeps = alpm_list_add(baddeps, miss); } release_filtered_depend(depend, nodepversion); @@ -801,7 +818,7 @@ int _alpm_resolvedeps(alpm_handle_t *handle, alpm_list_t *localpkgs, for(i = alpm_list_last(*packages); i; i = i->next) { alpm_pkg_t *tpkg = i->data; targ = alpm_list_add(NULL, tpkg); - deps = alpm_checkdeps(handle, localpkgs, remove, targ, 0); + deps = alpm_checkdeps(handle, localpkgs, remove, targ, 0, 0); alpm_list_free(targ);
for(j = deps; j; j = j->next) { diff --git a/lib/libalpm/error.c b/lib/libalpm/error.c index 044dec7..5283392 100644 --- a/lib/libalpm/error.c +++ b/lib/libalpm/error.c @@ -136,6 +136,8 @@ const char SYMEXPORT *alpm_strerror(alpm_errno_t err) /* Dependencies */ case ALPM_ERR_UNSATISFIED_DEPS: return _("could not satisfy dependencies"); + case ALPM_ERR_UNSATISFIED_OPTDEPS: + return _("could not satisfy optional dependencies"); case ALPM_ERR_CONFLICTING_DEPS: return _("conflicting dependencies"); case ALPM_ERR_FILE_CONFLICTS: diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c index d7e06bc..012f9c8 100644 --- a/lib/libalpm/remove.c +++ b/lib/libalpm/remove.c @@ -102,7 +102,7 @@ static int remove_prepare_cascade(alpm_handle_t *handle, alpm_list_t *lp) alpm_list_free_inner(lp, (alpm_list_fn_free)_alpm_depmiss_free); alpm_list_free(lp); lp = alpm_checkdeps(handle, _alpm_db_get_pkgcache(handle->db_local), - trans->remove, NULL, 1); + trans->remove, NULL, 1, 0); } return 0; } @@ -133,7 +133,7 @@ static void remove_prepare_keep_needed(alpm_handle_t *handle, alpm_list_t *lp) alpm_list_free_inner(lp, (alpm_list_fn_free)_alpm_depmiss_free); alpm_list_free(lp); lp = alpm_checkdeps(handle, _alpm_db_get_pkgcache(handle->db_local), - trans->remove, NULL, 1); + trans->remove, NULL, 1, 0); } }
@@ -164,7 +164,7 @@ int _alpm_remove_prepare(alpm_handle_t *handle, alpm_list_t **data) EVENT(handle, ALPM_EVENT_CHECKDEPS_START, NULL, NULL);
_alpm_log(handle, ALPM_LOG_DEBUG, "looking for unsatisfied dependencies\n"); - lp = alpm_checkdeps(handle, _alpm_db_get_pkgcache(db), trans->remove, NULL, 1); + lp = alpm_checkdeps(handle, _alpm_db_get_pkgcache(db), trans->remove, NULL, 1, 0); if(lp != NULL) {
if(trans->flags & ALPM_TRANS_FLAG_CASCADE) { @@ -206,6 +206,16 @@ int _alpm_remove_prepare(alpm_handle_t *handle, alpm_list_t **data)
if(!(trans->flags & ALPM_TRANS_FLAG_NODEPS)) { EVENT(handle, ALPM_EVENT_CHECKDEPS_DONE, NULL, NULL); + lp = alpm_checkdeps(handle, _alpm_db_get_pkgcache(db), trans->remove, NULL, 1, 1); + if(lp != NULL) { + if(data) { + *data = lp; + } else { + alpm_list_free_inner(lp, (alpm_list_fn_free)_alpm_depmiss_free); + alpm_list_free(lp); + } + RET_ERR(handle, ALPM_ERR_UNSATISFIED_OPTDEPS, -1); + } We should not be checking deps, whether optional or required, after we have issued CHECKDEPS_DONE. This can't be done here, you need to move this to a more logical place earlier in teh method.
}
return 0; diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index 3817ec8..b501807 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -605,7 +605,7 @@ int _alpm_sync_prepare(alpm_handle_t *handle, alpm_list_t **data) if(!(trans->flags & ALPM_TRANS_FLAG_NODEPS)) { _alpm_log(handle, ALPM_LOG_DEBUG, "checking dependencies\n"); deps = alpm_checkdeps(handle, _alpm_db_get_pkgcache(handle->db_local), - trans->remove, trans->add, 1); + trans->remove, trans->add, 1, 0); if(deps) { handle->pm_errno = ALPM_ERR_UNSATISFIED_DEPS; ret = -1; diff --git a/lib/libalpm/trans.c b/lib/libalpm/trans.c index cb97a4a..40e6786 100644 --- a/lib/libalpm/trans.c +++ b/lib/libalpm/trans.c @@ -101,6 +101,7 @@ static alpm_list_t *check_arch(alpm_handle_t *handle, alpm_list_t *pkgs) int SYMEXPORT alpm_trans_prepare(alpm_handle_t *handle, alpm_list_t **data) { alpm_trans_t *trans; + int retval = 0;
/* Sanity checks */ CHECK_HANDLE(handle, return -1); @@ -127,7 +128,12 @@ int SYMEXPORT alpm_trans_prepare(alpm_handle_t *handle, alpm_list_t **data) if(trans->add == NULL) { if(_alpm_remove_prepare(handle, data) == -1) { /* pm_errno is set by _alpm_remove_prepare() */ - return -1; + /* UNSATISFIED_OPTDEPS is nonfatal. */ + if(alpm_errno(handle) == ALPM_ERR_UNSATISFIED_OPTDEPS) { + retval = -1; + } else { + return -1; + } I don't like this special case at all, -1 from me implemented this way. Please use callbacks and resolve it during checkdeps resolution, rather than whatever we have going on here.
} } else { if(_alpm_sync_prepare(handle, data) == -1) { @@ -138,7 +144,7 @@ int SYMEXPORT alpm_trans_prepare(alpm_handle_t *handle, alpm_list_t **data)
trans->state = STATE_PREPARED;
- return 0; + return retval; }
/** Commit a transaction. */ diff --git a/src/pacman/remove.c b/src/pacman/remove.c index f56c1ec..739a6eb 100644 --- a/src/pacman/remove.c +++ b/src/pacman/remove.c @@ -111,8 +111,8 @@ int pacman_remove(alpm_list_t *targets) /* Step 2: prepare the transaction based on its type, targets and flags */ if(alpm_trans_prepare(config->handle, &data) == -1) { alpm_errno_t err = alpm_errno(config->handle); - pm_printf(ALPM_LOG_ERROR, _("failed to prepare transaction (%s)\n"), - alpm_strerror(err)); + retval = 1; + switch(err) { case ALPM_ERR_PKG_INVALID_ARCH: for(i = data; i; i = alpm_list_next(i)) { @@ -128,12 +128,27 @@ int pacman_remove(alpm_list_t *targets) free(depstring); } break; + case ALPM_ERR_UNSATISFIED_OPTDEPS: + for(i = data; i; i = alpm_list_next(i)) { + alpm_depmissing_t *miss = i->data; + char *depstring = alpm_dep_compute_string(miss->depend); + if(miss->description) { + printf(_(":: %s: optionally requires %s (%s)\n"), miss->target, depstring, miss->description); + } else { + printf(_(":: %s: optionally requires %s\n"), miss->target, depstring); + } + free(depstring); + } + retval = 0; + break; default: break; } FREELIST(data); - retval = 1; - goto cleanup; + if(retval) { + pm_printf(ALPM_LOG_ERROR, _("failed to prepare transaction (%s)\n"), alpm_strerror(err)); + goto cleanup; + } }
/* Search for holdpkg in target list */ diff --git a/src/util/testdb.c b/src/util/testdb.c index b15bbe5..e1401cc 100644 --- a/src/util/testdb.c +++ b/src/util/testdb.c @@ -99,7 +99,7 @@ static int checkdeps(alpm_list_t *pkglist) alpm_list_t *data, *i; int ret = 0; /* check dependencies */ - data = alpm_checkdeps(handle, pkglist, NULL, pkglist, 0); + data = alpm_checkdeps(handle, pkglist, NULL, pkglist, 0, 0); for(i = data; i; i = alpm_list_next(i)) { alpm_depmissing_t *miss = i->data; char *depstring = alpm_dep_compute_string(miss->depend); -- 1.7.7.3
Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- doc/pacman.8.txt | 5 +++++ lib/libalpm/alpm.h | 4 +++- lib/libalpm/deps.c | 8 ++++---- lib/libalpm/deps.h | 2 +- lib/libalpm/remove.c | 6 ++++-- src/pacman/pacman.c | 4 ++++ test/pacman/tests/{remove055.py => remove056.py} | 6 +++--- 7 files changed, 24 insertions(+), 11 deletions(-) copy test/pacman/tests/{remove055.py => remove056.py} (69%) diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt index 62dd908..2c1748a 100644 --- a/doc/pacman.8.txt +++ b/doc/pacman.8.txt @@ -340,6 +340,11 @@ Remove Options[[RO]] to a backwards '\--sync' operation, and helps keep a clean system without orphans. If you want to omit condition (B), pass this option twice. +*-o, \--recursive-optdeps*:: + When recursively removing packages, also remove optional dependencies that + might still be in use by other packages. You will be warned which packages + might still optionally use the removed ones. + *-u, \--unneeded*:: Removes targets that are not required by any other packages. This is mostly useful when removing a group without using the '-c' option, diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 34dbaa1..5df833a 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -1006,7 +1006,9 @@ typedef enum _alpm_transflag_t { /** Remove also explicitly installed unneeded deps (use with ALPM_TRANS_FLAG_RECURSE). */ ALPM_TRANS_FLAG_RECURSEALL = (1 << 16), /** Do not lock the database during the operation. */ - ALPM_TRANS_FLAG_NOLOCK = (1 << 17) + ALPM_TRANS_FLAG_NOLOCK = (1 << 17), + /** Recurse through optdepends, even if needed by other packages. */ + ALPM_TRANS_FLAG_RECURSE_OPTDEPS = (1 << 18) } alpm_transflag_t; /** Returns the bitfield of flags for the current transaction. diff --git a/lib/libalpm/deps.c b/lib/libalpm/deps.c index c9efce4..ee13ed9 100644 --- a/lib/libalpm/deps.c +++ b/lib/libalpm/deps.c @@ -555,7 +555,7 @@ alpm_optdepend_t *_alpm_optdep_dup(const alpm_optdepend_t *optdep) * target list, or if if the package was explictly installed and * include_explicit == 0 */ static int can_remove_package(alpm_db_t *db, alpm_pkg_t *pkg, - alpm_list_t *targets, int include_explicit) + alpm_list_t *targets, int include_explicit, int include_optdeps) { alpm_list_t *i; @@ -584,7 +584,7 @@ static int can_remove_package(alpm_db_t *db, alpm_pkg_t *pkg, 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)) { + if(!include_optdeps && _alpm_optdep_edge(lpkg, pkg) && !_alpm_pkg_find(targets, lpkg->name)) { return 0; } } @@ -604,7 +604,7 @@ static int can_remove_package(alpm_db_t *db, alpm_pkg_t *pkg, * @param include_explicit if 0, explicitly installed packages are not included * @return 0 on success, -1 on errors */ -int _alpm_recursedeps(alpm_db_t *db, alpm_list_t *targs, int include_explicit) +int _alpm_recursedeps(alpm_db_t *db, alpm_list_t *targs, int include_explicit, int include_optdeps) { alpm_list_t *i, *j; @@ -617,7 +617,7 @@ int _alpm_recursedeps(alpm_db_t *db, alpm_list_t *targs, int include_explicit) for(j = _alpm_db_get_pkgcache(db); j; j = j->next) { alpm_pkg_t *deppkg = j->data; if((_alpm_dep_edge(pkg, deppkg) || _alpm_optdep_edge(pkg, deppkg)) - && can_remove_package(db, deppkg, targs, include_explicit)) { + && can_remove_package(db, deppkg, targs, include_explicit, include_optdeps)) { alpm_pkg_t *copy; _alpm_log(db->handle, ALPM_LOG_DEBUG, "adding '%s' to the targets\n", deppkg->name); diff --git a/lib/libalpm/deps.h b/lib/libalpm/deps.h index 69b65df..13e92b8 100644 --- a/lib/libalpm/deps.h +++ b/lib/libalpm/deps.h @@ -33,7 +33,7 @@ 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); -int _alpm_recursedeps(alpm_db_t *db, alpm_list_t *targs, int include_explicit); +int _alpm_recursedeps(alpm_db_t *db, alpm_list_t *targs, int include_explicit, int include_optdeps); int _alpm_resolvedeps(alpm_handle_t *handle, alpm_list_t *localpkgs, alpm_pkg_t *pkg, alpm_list_t *preferred, alpm_list_t **packages, alpm_list_t *remove, alpm_list_t **data); diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c index 012f9c8..704bc69 100644 --- a/lib/libalpm/remove.c +++ b/lib/libalpm/remove.c @@ -155,7 +155,8 @@ int _alpm_remove_prepare(alpm_handle_t *handle, alpm_list_t **data) && !(trans->flags & ALPM_TRANS_FLAG_CASCADE)) { _alpm_log(handle, ALPM_LOG_DEBUG, "finding removable dependencies\n"); if(_alpm_recursedeps(db, trans->remove, - trans->flags & ALPM_TRANS_FLAG_RECURSEALL)) { + trans->flags & ALPM_TRANS_FLAG_RECURSEALL, + trans->flags & ALPM_TRANS_FLAG_RECURSE_OPTDEPS)) { return -1; } } @@ -199,7 +200,8 @@ int _alpm_remove_prepare(alpm_handle_t *handle, alpm_list_t **data) && (trans->flags & ALPM_TRANS_FLAG_RECURSE)) { _alpm_log(handle, ALPM_LOG_DEBUG, "finding removable dependencies\n"); if(_alpm_recursedeps(db, trans->remove, - trans->flags & ALPM_TRANS_FLAG_RECURSEALL)) { + trans->flags & ALPM_TRANS_FLAG_RECURSEALL, + trans->flags & ALPM_TRANS_FLAG_RECURSE_OPTDEPS)) { return -1; } } diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index fd93133..ec7a4e2 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -128,6 +128,8 @@ static void usage(int op, const char * const myname) addlist(_(" -n, --nosave remove configuration files\n")); addlist(_(" -s, --recursive remove unnecessary dependencies\n" " (-ss includes explicitly installed dependencies)\n")); + addlist(_(" -o, remove optional dependencies,\n" + " --recurse-optdeps even if they might be used by other packages\n")); addlist(_(" -u, --unneeded remove unneeded packages\n")); } else if(op == PM_OP_UPGRADE) { printf("%s: %s {-U --upgrade} [%s] <%s>\n", str_usg, myname, str_opt, str_file); @@ -510,6 +512,7 @@ static int parsearg_remove(int opt) switch(opt) { case 'c': config->flags |= ALPM_TRANS_FLAG_CASCADE; break; case 'n': config->flags |= ALPM_TRANS_FLAG_NOSAVE; break; + case 'o': config->flags |= ALPM_TRANS_FLAG_RECURSE_OPTDEPS; break; case 's': case OP_RECURSIVE: /* 's' is the legacy flag here, but since recursive is used in -S without @@ -607,6 +610,7 @@ static int parseargs(int argc, char *argv[]) {"nosave", no_argument, 0, 'n'}, {"optdeps", no_argument, 0, 'n'}, {"owns", no_argument, 0, 'o'}, + {"recurse-optdeps", no_argument, 0, 'o'}, {"file", no_argument, 0, 'p'}, {"print", no_argument, 0, 'p'}, {"quiet", no_argument, 0, 'q'}, diff --git a/test/pacman/tests/remove055.py b/test/pacman/tests/remove056.py similarity index 69% copy from test/pacman/tests/remove055.py copy to test/pacman/tests/remove056.py index e8134ad..24eb36e 100644 --- a/test/pacman/tests/remove055.py +++ b/test/pacman/tests/remove056.py @@ -1,4 +1,4 @@ -self.description = "-Rs test (needed optdeps)" +self.description = "-Rs test (recurse through needed optdeps)" p1 = pmpkg("dummy") p1.optdepends = ["dep: for foobar"] @@ -12,9 +12,9 @@ p3.reason = 1 self.addpkg2db("local", p3) -self.args = "-Rs %s" % p1.name +self.args = "-Rs --recurse-optdeps %s" % p1.name self.addrule("PACMAN_RETCODE=0") self.addrule("!PKG_EXIST=dummy") +self.addrule("!PKG_EXIST=dep") self.addrule("PKG_EXIST=keep") -self.addrule("PKG_EXIST=dep") -- 1.7.7.3
On Wed, Nov 23, 2011 at 9:51 AM, Benedikt Morbach <benedikt.morbach@googlemail.com> wrote:
Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- doc/pacman.8.txt | 5 +++++ lib/libalpm/alpm.h | 4 +++- lib/libalpm/deps.c | 8 ++++---- lib/libalpm/deps.h | 2 +- lib/libalpm/remove.c | 6 ++++-- src/pacman/pacman.c | 4 ++++ test/pacman/tests/{remove055.py => remove056.py} | 6 +++--- 7 files changed, 24 insertions(+), 11 deletions(-) copy test/pacman/tests/{remove055.py => remove056.py} (69%)
diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt index 62dd908..2c1748a 100644 --- a/doc/pacman.8.txt +++ b/doc/pacman.8.txt @@ -340,6 +340,11 @@ Remove Options[[RO]] to a backwards '\--sync' operation, and helps keep a clean system without orphans. If you want to omit condition (B), pass this option twice.
+*-o, \--recursive-optdeps*:: + When recursively removing packages, also remove optional dependencies that + might still be in use by other packages. You will be warned which packages + might still optionally use the removed ones. + *-u, \--unneeded*:: Removes targets that are not required by any other packages. This is mostly useful when removing a group without using the '-c' option, diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 34dbaa1..5df833a 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -1006,7 +1006,9 @@ typedef enum _alpm_transflag_t { /** Remove also explicitly installed unneeded deps (use with ALPM_TRANS_FLAG_RECURSE). */ ALPM_TRANS_FLAG_RECURSEALL = (1 << 16), /** Do not lock the database during the operation. */ - ALPM_TRANS_FLAG_NOLOCK = (1 << 17) + ALPM_TRANS_FLAG_NOLOCK = (1 << 17), + /** Recurse through optdepends, even if needed by other packages. */ + ALPM_TRANS_FLAG_RECURSE_OPTDEPS = (1 << 18) } alpm_transflag_t;
/** Returns the bitfield of flags for the current transaction. diff --git a/lib/libalpm/deps.c b/lib/libalpm/deps.c index c9efce4..ee13ed9 100644 --- a/lib/libalpm/deps.c +++ b/lib/libalpm/deps.c @@ -555,7 +555,7 @@ alpm_optdepend_t *_alpm_optdep_dup(const alpm_optdepend_t *optdep) * target list, or if if the package was explictly installed and * include_explicit == 0 */ static int can_remove_package(alpm_db_t *db, alpm_pkg_t *pkg, - alpm_list_t *targets, int include_explicit) + alpm_list_t *targets, int include_explicit, int include_optdeps) { alpm_list_t *i;
@@ -584,7 +584,7 @@ static int can_remove_package(alpm_db_t *db, alpm_pkg_t *pkg, 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)) { + if(!include_optdeps && _alpm_optdep_edge(lpkg, pkg) && !_alpm_pkg_find(targets, lpkg->name)) { return 0; } } @@ -604,7 +604,7 @@ static int can_remove_package(alpm_db_t *db, alpm_pkg_t *pkg, * @param include_explicit if 0, explicitly installed packages are not included * @return 0 on success, -1 on errors */ -int _alpm_recursedeps(alpm_db_t *db, alpm_list_t *targs, int include_explicit) +int _alpm_recursedeps(alpm_db_t *db, alpm_list_t *targs, int include_explicit, int include_optdeps) { alpm_list_t *i, *j;
@@ -617,7 +617,7 @@ int _alpm_recursedeps(alpm_db_t *db, alpm_list_t *targs, int include_explicit) for(j = _alpm_db_get_pkgcache(db); j; j = j->next) { alpm_pkg_t *deppkg = j->data; if((_alpm_dep_edge(pkg, deppkg) || _alpm_optdep_edge(pkg, deppkg)) - && can_remove_package(db, deppkg, targs, include_explicit)) { + && can_remove_package(db, deppkg, targs, include_explicit, include_optdeps)) { alpm_pkg_t *copy; _alpm_log(db->handle, ALPM_LOG_DEBUG, "adding '%s' to the targets\n", deppkg->name); diff --git a/lib/libalpm/deps.h b/lib/libalpm/deps.h index 69b65df..13e92b8 100644 --- a/lib/libalpm/deps.h +++ b/lib/libalpm/deps.h @@ -33,7 +33,7 @@ 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); -int _alpm_recursedeps(alpm_db_t *db, alpm_list_t *targs, int include_explicit); +int _alpm_recursedeps(alpm_db_t *db, alpm_list_t *targs, int include_explicit, int include_optdeps); int _alpm_resolvedeps(alpm_handle_t *handle, alpm_list_t *localpkgs, alpm_pkg_t *pkg, alpm_list_t *preferred, alpm_list_t **packages, alpm_list_t *remove, alpm_list_t **data); diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c index 012f9c8..704bc69 100644 --- a/lib/libalpm/remove.c +++ b/lib/libalpm/remove.c @@ -155,7 +155,8 @@ int _alpm_remove_prepare(alpm_handle_t *handle, alpm_list_t **data) && !(trans->flags & ALPM_TRANS_FLAG_CASCADE)) { _alpm_log(handle, ALPM_LOG_DEBUG, "finding removable dependencies\n"); if(_alpm_recursedeps(db, trans->remove, - trans->flags & ALPM_TRANS_FLAG_RECURSEALL)) { + trans->flags & ALPM_TRANS_FLAG_RECURSEALL, + trans->flags & ALPM_TRANS_FLAG_RECURSE_OPTDEPS)) { Might be a bit cleaner to just pass trans->flags in and do the bitflagging in the method.
return -1; } } @@ -199,7 +200,8 @@ int _alpm_remove_prepare(alpm_handle_t *handle, alpm_list_t **data) && (trans->flags & ALPM_TRANS_FLAG_RECURSE)) { _alpm_log(handle, ALPM_LOG_DEBUG, "finding removable dependencies\n"); if(_alpm_recursedeps(db, trans->remove, - trans->flags & ALPM_TRANS_FLAG_RECURSEALL)) { + trans->flags & ALPM_TRANS_FLAG_RECURSEALL, + trans->flags & ALPM_TRANS_FLAG_RECURSE_OPTDEPS)) { return -1; } } diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index fd93133..ec7a4e2 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -128,6 +128,8 @@ static void usage(int op, const char * const myname) addlist(_(" -n, --nosave remove configuration files\n")); addlist(_(" -s, --recursive remove unnecessary dependencies\n" " (-ss includes explicitly installed dependencies)\n")); + addlist(_(" -o, remove optional dependencies,\n" + " --recurse-optdeps even if they might be used by other packages\n")); Whoa. You can't do this. You are making translations impossible by splitting up this option and long option in some crazy fashion that no other single option does.
This also does not deserve a precious allocation of a short option, especially one that is already used. Please drop the short option completely.
addlist(_(" -u, --unneeded remove unneeded packages\n")); } else if(op == PM_OP_UPGRADE) { printf("%s: %s {-U --upgrade} [%s] <%s>\n", str_usg, myname, str_opt, str_file); @@ -510,6 +512,7 @@ static int parsearg_remove(int opt) switch(opt) { case 'c': config->flags |= ALPM_TRANS_FLAG_CASCADE; break; case 'n': config->flags |= ALPM_TRANS_FLAG_NOSAVE; break; + case 'o': config->flags |= ALPM_TRANS_FLAG_RECURSE_OPTDEPS; break; case 's': case OP_RECURSIVE: /* 's' is the legacy flag here, but since recursive is used in -S without @@ -607,6 +610,7 @@ static int parseargs(int argc, char *argv[]) {"nosave", no_argument, 0, 'n'}, {"optdeps", no_argument, 0, 'n'}, {"owns", no_argument, 0, 'o'}, + {"recurse-optdeps", no_argument, 0, 'o'}, {"file", no_argument, 0, 'p'}, {"print", no_argument, 0, 'p'}, {"quiet", no_argument, 0, 'q'}, diff --git a/test/pacman/tests/remove055.py b/test/pacman/tests/remove056.py similarity index 69% copy from test/pacman/tests/remove055.py copy to test/pacman/tests/remove056.py index e8134ad..24eb36e 100644 --- a/test/pacman/tests/remove055.py +++ b/test/pacman/tests/remove056.py @@ -1,4 +1,4 @@ -self.description = "-Rs test (needed optdeps)" +self.description = "-Rs test (recurse through needed optdeps)"
p1 = pmpkg("dummy") p1.optdepends = ["dep: for foobar"] @@ -12,9 +12,9 @@ p3.reason = 1 self.addpkg2db("local", p3)
-self.args = "-Rs %s" % p1.name +self.args = "-Rs --recurse-optdeps %s" % p1.name
self.addrule("PACMAN_RETCODE=0") self.addrule("!PKG_EXIST=dummy") +self.addrule("!PKG_EXIST=dep") self.addrule("PKG_EXIST=keep") -self.addrule("PKG_EXIST=dep") -- 1.7.7.3
Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- doc/pacman.conf.5.txt | 4 +- etc/pacman.conf.in | 2 +- lib/libalpm/add.c | 4 +- lib/libalpm/alpm.h | 2 +- src/pacman/conf.c | 2 + src/pacman/conf.h | 3 +- src/pacman/sync.c | 55 +++++++++++++++++++++++-- src/pacman/upgrade.c | 2 +- test/pacman/tests/{sync062.py => sync063.py} | 8 ++-- 9 files changed, 66 insertions(+), 16 deletions(-) copy test/pacman/tests/{sync062.py => sync063.py} (53%) diff --git a/doc/pacman.conf.5.txt b/doc/pacman.conf.5.txt index 7232c8b..985f22d 100644 --- a/doc/pacman.conf.5.txt +++ b/doc/pacman.conf.5.txt @@ -160,9 +160,11 @@ Options packages are only cleaned if not installed locally and not present in any known sync database. -*HandleOptdeps =* ShowAll:: +*HandleOptdeps =* ShowAll &| Install:: If set to `ShowAll`, show all optional dependencies on install. The default is to just show uninstalled optional dependencies. + If set to `Install`, the optional dependencies of all targets are + automatically installed. *SigLevel =* ...:: Set the default signature verification level. For more information, see diff --git a/etc/pacman.conf.in b/etc/pacman.conf.in index a905757..bf9f200 100644 --- a/etc/pacman.conf.in +++ b/etc/pacman.conf.in @@ -36,7 +36,7 @@ Architecture = auto CheckSpace #VerbosePkgLists -#HandleOptdeps = ShowAll +#HandleOptdeps = ShowAll Install # PGP signature checking #SigLevel = Optional diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c index 78615bb..e7a5a55 100644 --- a/lib/libalpm/add.c +++ b/lib/libalpm/add.c @@ -50,7 +50,7 @@ #include "handle.h" /** Add a package to the transaction. */ -int SYMEXPORT alpm_add_pkg(alpm_handle_t *handle, alpm_pkg_t *pkg) +int SYMEXPORT alpm_add_pkg(alpm_handle_t *handle, alpm_pkg_t *pkg, alpm_pkgreason_t reason) { const char *pkgname, *pkgver; alpm_trans_t *trans; @@ -98,7 +98,7 @@ int SYMEXPORT alpm_add_pkg(alpm_handle_t *handle, alpm_pkg_t *pkg) } /* add the package to the transaction */ - pkg->reason = ALPM_PKG_REASON_EXPLICIT; + pkg->reason = reason; _alpm_log(handle, ALPM_LOG_DEBUG, "adding package %s-%s to the transaction add list\n", pkgname, pkgver); trans->add = alpm_list_add(trans->add, pkg); diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 5df833a..8bbfaef 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -1082,7 +1082,7 @@ int alpm_sync_sysupgrade(alpm_handle_t *handle, int enable_downgrade); * @param pkg the package to add * @return 0 on success, -1 on error (pm_errno is set accordingly) */ -int alpm_add_pkg(alpm_handle_t *handle, alpm_pkg_t *pkg); +int alpm_add_pkg(alpm_handle_t *handle, alpm_pkg_t *pkg, alpm_pkgreason_t reason); /** Add a package removal action to the transaction. * @param handle the context handle diff --git a/src/pacman/conf.c b/src/pacman/conf.c index 715399e..4d06bfc 100644 --- a/src/pacman/conf.c +++ b/src/pacman/conf.c @@ -367,6 +367,8 @@ static int process_handleoptdeps(alpm_list_t *actions) { const char *action = i->data; if(strcmp(action, "ShowAll") == 0) { config->handleoptdeps |= PM_OPTDEPS_SHOWALL; + } else if(strcmp(action, "Install") == 0) { + config->handleoptdeps |= PM_OPTDEPS_INSTALL; } else { pm_printf(ALPM_LOG_ERROR, _("invalid action for 'HandleOptdeps' : '%s'\n"), action); diff --git a/src/pacman/conf.h b/src/pacman/conf.h index 9858f7d..9128c48 100644 --- a/src/pacman/conf.h +++ b/src/pacman/conf.h @@ -143,7 +143,8 @@ enum { /* optdepends handling */ enum { - PM_OPTDEPS_SHOWALL = 1 + PM_OPTDEPS_SHOWALL = 1, + PM_OPTDEPS_INSTALL = (1 << 1) }; /* global config variable */ diff --git a/src/pacman/sync.c b/src/pacman/sync.c index 1003a42..b9c1901 100644 --- a/src/pacman/sync.c +++ b/src/pacman/sync.c @@ -595,9 +595,14 @@ static alpm_db_t *get_db(const char *dbname) return NULL; } -static int process_pkg(alpm_pkg_t *pkg) +static int process_pkg(alpm_pkg_t *pkg, int as_dep) { - int ret = alpm_add_pkg(config->handle, pkg); + int ret; + if(as_dep) { + ret = alpm_add_pkg(config->handle, pkg, ALPM_PKG_REASON_DEPEND); + } else { + ret = alpm_add_pkg(config->handle, pkg, ALPM_PKG_REASON_EXPLICIT); + } if(ret == -1) { alpm_errno_t err = alpm_errno(config->handle); @@ -616,6 +621,34 @@ static int process_pkg(alpm_pkg_t *pkg) return 0; } +static int process_optdeps(alpm_list_t *dblist, alpm_pkg_t *pkg) +{ + if(config->handleoptdeps & PM_OPTDEPS_INSTALL) { + alpm_list_t *optdeps = alpm_pkg_get_optdepends(pkg); + alpm_list_t *i; + + for(i = optdeps; i; i = alpm_list_next(i)) { + alpm_optdepend_t *optdep = i->data; + char *depstring = alpm_dep_compute_string(optdep->depend); + alpm_pkg_t *pkg = alpm_find_dbs_satisfier(config->handle, dblist, depstring); + free(depstring); + + if(alpm_errno(config->handle) == ALPM_ERR_PKG_IGNORED) { + pm_printf(ALPM_LOG_WARNING, _("skipping optdepend: %s\n"), optdep->depend->name); + continue; + } + + if(pkg) { + if(process_pkg(pkg, 1) == 1) { + return 1; + } + } + } + } + + return 0; +} + static int process_group(alpm_list_t *dbs, const char *group) { int ret = 0; @@ -649,7 +682,11 @@ static int process_group(alpm_list_t *dbs, const char *group) continue; alpm_pkg_t *pkg = i->data; - if(process_pkg(pkg) == 1) { + if(process_pkg(pkg, 0) == 1) { + ret = 1; + free(array); + goto cleanup; + } else if(process_optdeps(dbs, pkg) == 1) { ret = 1; free(array); goto cleanup; @@ -660,7 +697,10 @@ static int process_group(alpm_list_t *dbs, const char *group) for(i = pkgs; i; i = alpm_list_next(i)) { alpm_pkg_t *pkg = i->data; - if(process_pkg(pkg) == 1) { + if(process_pkg(pkg, 0) == 1) { + ret = 1; + goto cleanup; + } else if(process_optdeps(dbs, pkg) == 1) { ret = 1; goto cleanup; } @@ -674,6 +714,7 @@ cleanup: static int process_targname(alpm_list_t *dblist, const char *targname) { alpm_pkg_t *pkg = alpm_find_dbs_satisfier(config->handle, dblist, targname); + int retval = 0; /* #FS#23342 - skip ignored packages when user says no */ if(alpm_errno(config->handle) == ALPM_ERR_PKG_IGNORED) { @@ -682,7 +723,11 @@ static int process_targname(alpm_list_t *dblist, const char *targname) } if(pkg) { - return process_pkg(pkg); + retval = process_pkg(pkg, 0); + if(retval == 0) { + retval = process_optdeps(dblist, pkg); + } + return retval; } /* fallback on group */ return process_group(dblist, targname); diff --git a/src/pacman/upgrade.c b/src/pacman/upgrade.c index 0ca6fec..0fdba37 100644 --- a/src/pacman/upgrade.c +++ b/src/pacman/upgrade.c @@ -82,7 +82,7 @@ int pacman_upgrade(alpm_list_t *targets) trans_release(); return 1; } - if(alpm_add_pkg(config->handle, pkg) == -1) { + if(alpm_add_pkg(config->handle, pkg, ALPM_PKG_REASON_EXPLICIT) == -1) { pm_printf(ALPM_LOG_ERROR, "'%s': %s\n", targ, alpm_strerror(alpm_errno(config->handle))); alpm_pkg_free(pkg); diff --git a/test/pacman/tests/sync062.py b/test/pacman/tests/sync063.py similarity index 53% copy from test/pacman/tests/sync062.py copy to test/pacman/tests/sync063.py index dc90002..8151eb9 100644 --- a/test/pacman/tests/sync062.py +++ b/test/pacman/tests/sync063.py @@ -1,17 +1,17 @@ -self.description = "Install a package from a sync db with installed optdepend and forced optdepend output" +self.description = "Install a package from a sync db with automatic optdepend install" -self.option["HandleOptdeps"] = ["ShowAll"] +self.option["HandleOptdeps"] = ["Install"] p1 = pmpkg("dummy") p1.optdepends = ["dep: for foobar"] self.addpkg2db("sync1", p1) p2 = pmpkg("dep") -self.addpkg2db("local", p2) +self.addpkg2db("sync1", p2) self.args = "-S %s" % p1.name self.addrule("PACMAN_RETCODE=0") -self.addrule("PACMAN_OUTPUT=dep: for foobar") self.addrule("PKG_EXIST=dummy") +self.addrule("PKG_EXIST=dep") self.addrule("PKG_OPTDEPENDS=dummy|dep: for foobar") -- 1.7.7.3
Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- doc/pacman.conf.5.txt | 7 ++++- etc/pacman.conf.in | 2 +- src/pacman/conf.c | 2 + src/pacman/conf.h | 3 +- src/pacman/sync.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++- src/pacman/util.c | 59 ++++++++++++++++++++++++++++------------ src/pacman/util.h | 1 + 7 files changed, 122 insertions(+), 22 deletions(-) diff --git a/doc/pacman.conf.5.txt b/doc/pacman.conf.5.txt index 985f22d..7e9017a 100644 --- a/doc/pacman.conf.5.txt +++ b/doc/pacman.conf.5.txt @@ -160,11 +160,16 @@ Options packages are only cleaned if not installed locally and not present in any known sync database. -*HandleOptdeps =* ShowAll &| Install:: +*HandleOptdeps =* ShowAll &| Install &| Ask:: If set to `ShowAll`, show all optional dependencies on install. The default is to just show uninstalled optional dependencies. If set to `Install`, the optional dependencies of all targets are automatically installed. + If set to `Ask`, display a prompt for each target, where the user can select + which of the optional dependencies of that target will be installed. + Also, the optional dependencies of the targets won't be shown during installation. + If `ShowAll` and `Ask` are set, the prompt also shows optional dependencies + which are already installed. *SigLevel =* ...:: Set the default signature verification level. For more information, see diff --git a/etc/pacman.conf.in b/etc/pacman.conf.in index bf9f200..889afc3 100644 --- a/etc/pacman.conf.in +++ b/etc/pacman.conf.in @@ -36,7 +36,7 @@ Architecture = auto CheckSpace #VerbosePkgLists -#HandleOptdeps = ShowAll Install +#HandleOptdeps = ShowAll Install Ask # PGP signature checking #SigLevel = Optional diff --git a/src/pacman/conf.c b/src/pacman/conf.c index 4d06bfc..1c45a80 100644 --- a/src/pacman/conf.c +++ b/src/pacman/conf.c @@ -369,6 +369,8 @@ static int process_handleoptdeps(alpm_list_t *actions) { config->handleoptdeps |= PM_OPTDEPS_SHOWALL; } else if(strcmp(action, "Install") == 0) { config->handleoptdeps |= PM_OPTDEPS_INSTALL; + } else if(strcmp(action, "Ask") == 0) { + config->handleoptdeps |= PM_OPTDEPS_ASK; } else { pm_printf(ALPM_LOG_ERROR, _("invalid action for 'HandleOptdeps' : '%s'\n"), action); diff --git a/src/pacman/conf.h b/src/pacman/conf.h index 9128c48..71f049e 100644 --- a/src/pacman/conf.h +++ b/src/pacman/conf.h @@ -144,7 +144,8 @@ enum { /* optdepends handling */ enum { PM_OPTDEPS_SHOWALL = 1, - PM_OPTDEPS_INSTALL = (1 << 1) + PM_OPTDEPS_INSTALL = (1 << 1), + PM_OPTDEPS_ASK = (1 << 2) }; /* global config variable */ diff --git a/src/pacman/sync.c b/src/pacman/sync.c index b9c1901..8fbdf78 100644 --- a/src/pacman/sync.c +++ b/src/pacman/sync.c @@ -623,7 +623,75 @@ static int process_pkg(alpm_pkg_t *pkg, int as_dep) static int process_optdeps(alpm_list_t *dblist, alpm_pkg_t *pkg) { - if(config->handleoptdeps & PM_OPTDEPS_INSTALL) { + if(config->print == 0 && (config->handleoptdeps & PM_OPTDEPS_ASK)) { + alpm_list_t *optdeps = alpm_pkg_get_optdepends(pkg); + int retval = 0; + + if(optdeps) { + alpm_list_t *i, *depstrings, *optstrings; + depstrings = optstrings = NULL; + + if((config->handleoptdeps & PM_OPTDEPS_SHOWALL) == 0) { + alpm_db_t *db_local = alpm_option_get_localdb(config->handle); + alpm_list_t *pkgcache = alpm_db_get_pkgcache(db_local); + + for(i = optdeps; i; i = alpm_list_next(i)) { + alpm_optdepend_t *optdep = i->data; + char *depstring = alpm_dep_compute_string(optdep->depend); + if(alpm_find_satisfier(pkgcache, depstring) == NULL) { + depstrings = alpm_list_add(depstrings, depstring); + optstrings = alpm_list_add(optstrings, alpm_optdep_compute_string(optdep)); + } else { + free(depstring); + } + } + } else { + for(i = optdeps; i; i = alpm_list_next(i)) { + alpm_optdepend_t *optdep = i->data; + depstrings = alpm_list_add(depstrings, alpm_dep_compute_string(optdep->depend)); + optstrings = alpm_list_add(optstrings, alpm_optdep_compute_string(optdep)); + } + } + + int count = alpm_list_count(optstrings); + + if(count) { + printf(_(":: %s has %d optional dependencies:\n"), alpm_pkg_get_name(pkg), count); + select_optdep_display(optstrings); + + char *array = malloc(count); + if(!array) { + retval = 1; + goto cleanup; + } + + if(multiselect_question(array, count)) { + retval = 1; + goto cleanup; + } + + int n = 0; + for(i = depstrings; i; i = alpm_list_next(i)) { + if(array[n++] == 0) { continue; } + + char *depstring = i->data; + alpm_pkg_t *pkg = alpm_find_dbs_satisfier(config->handle, dblist, depstring); + + if(process_pkg(pkg, 1) == 1) { + retval = 1; + goto cleanup; + } + } + + cleanup: + free(array); + } + + FREELIST(depstrings); + FREELIST(optstrings); + return retval; + } + } else if(config->handleoptdeps & PM_OPTDEPS_INSTALL) { alpm_list_t *optdeps = alpm_pkg_get_optdepends(pkg); alpm_list_t *i; diff --git a/src/pacman/util.c b/src/pacman/util.c index c54975e..8e5e480 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -1235,35 +1235,43 @@ alpm_list_t *optdep_string_list(const alpm_list_t *optlist, int include_installe void display_new_optdepends(alpm_pkg_t *oldpkg, alpm_pkg_t *newpkg) { - alpm_list_t *old, *new, *optdeps, *optstrings; + /* don't show optdepends if we already asked for them. '*/ + if(!((config->handleoptdeps & PM_OPTDEPS_ASK) && + alpm_find_satisfier(alpm_trans_get_add(config->handle), alpm_pkg_get_name(newpkg)))) { + 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); + old = alpm_pkg_get_optdepends(oldpkg); + new = alpm_pkg_get_optdepends(newpkg); + optdeps = alpm_list_diff(new, old, opt_cmp); - optstrings = optdep_string_list(optdeps, config->handleoptdeps & PM_OPTDEPS_SHOWALL); + optstrings = optdep_string_list(optdeps, config->handleoptdeps & PM_OPTDEPS_SHOWALL); - if(optstrings) { - printf(_("New optional dependencies for %s\n"), alpm_pkg_get_name(newpkg)); - list_display_linebreak(" ", optstrings); + if(optstrings) { + printf(_("New optional dependencies for %s\n"), alpm_pkg_get_name(newpkg)); + list_display_linebreak(" ", optstrings); + } + + alpm_list_free(optdeps); + FREELIST(optstrings); } - - alpm_list_free(optdeps); - FREELIST(optstrings); } void display_optdepends(alpm_pkg_t *pkg) { - alpm_list_t *optstrings; + /* don't show optdepends if we already asked for them. '*/ + if(!((config->handleoptdeps & PM_OPTDEPS_ASK) && + alpm_find_satisfier(alpm_trans_get_add(config->handle), alpm_pkg_get_name(pkg)))) { + alpm_list_t *optstrings; - optstrings = optdep_string_list(alpm_pkg_get_optdepends(pkg), config->handleoptdeps & PM_OPTDEPS_SHOWALL); + optstrings = optdep_string_list(alpm_pkg_get_optdepends(pkg), config->handleoptdeps & PM_OPTDEPS_SHOWALL); - if(optstrings) { - printf(_("Optional dependencies for %s\n"), alpm_pkg_get_name(pkg)); - list_display_linebreak(" ", optstrings); + if(optstrings) { + printf(_("Optional dependencies for %s\n"), alpm_pkg_get_name(pkg)); + list_display_linebreak(" ", optstrings); + } + + FREELIST(optstrings); } - - FREELIST(optstrings); } static void display_repo_list(const char *dbname, alpm_list_t *list) @@ -1303,6 +1311,21 @@ void select_display(const alpm_list_t *pkglist) FREELIST(list); } +void select_optdep_display(alpm_list_t *optstrings) +{ + const alpm_list_t *i; + int nth = 1; + char number[8]; /* 2 padding left, 2 number, 1 ')', 2 padding right, 1 '\0' */ + + for(i = optstrings; i; i = i->next, nth++) { + char *str = i->data; + if(str) { + snprintf(number, 8, " %2d) ", nth); + string_display(number, str); + } + } +} + static int parseindex(char *s, int *val, int min, int max) { char *endptr = NULL; diff --git a/src/pacman/util.h b/src/pacman/util.h index ffff4b5..0fbc6b9 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -73,6 +73,7 @@ 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); +void select_optdep_display(alpm_list_t *optstrings); int select_question(int count); int multiselect_question(char *array, int count); int yesno(char *fmt, ...); -- 1.7.7.3
Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- doc/pacman.conf.5.txt | 3 +++ src/pacman/sync.c | 4 ++-- src/pacman/util.c | 11 ++++++++--- src/pacman/util.h | 2 +- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/doc/pacman.conf.5.txt b/doc/pacman.conf.5.txt index 7e9017a..42bf1c2 100644 --- a/doc/pacman.conf.5.txt +++ b/doc/pacman.conf.5.txt @@ -170,6 +170,9 @@ Options Also, the optional dependencies of the targets won't be shown during installation. If `ShowAll` and `Ask` are set, the prompt also shows optional dependencies which are already installed. + The prompt selects none of the optional dependencies by default. + If `Install` and `Ask` are both specified, all optional dependencies + are selected by default. *SigLevel =* ...:: Set the default signature verification level. For more information, see diff --git a/src/pacman/sync.c b/src/pacman/sync.c index 8fbdf78..ec90616 100644 --- a/src/pacman/sync.c +++ b/src/pacman/sync.c @@ -665,7 +665,7 @@ static int process_optdeps(alpm_list_t *dblist, alpm_pkg_t *pkg) goto cleanup; } - if(multiselect_question(array, count)) { + if(multiselect_question(array, count, config->handleoptdeps & PM_OPTDEPS_INSTALL)) { retval = 1; goto cleanup; } @@ -739,7 +739,7 @@ static int process_group(alpm_list_t *dbs, const char *group) ret = 1; goto cleanup; } - if(multiselect_question(array, count)) { + if(multiselect_question(array, count, 1)) { ret = 1; free(array); goto cleanup; diff --git a/src/pacman/util.c b/src/pacman/util.c index 8e5e480..4055127 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -1400,11 +1400,12 @@ static int multiselect_parse(char *array, int count, char *response) return 0; } -int multiselect_question(char *array, int count) +int multiselect_question(char *array, int count, int default_state) { char *response, *lastchar; FILE *stream; size_t response_len = 64; + default_state = default_state ? 1 : 0; if(config->noconfirm) { stream = stdout; @@ -1422,10 +1423,14 @@ int multiselect_question(char *array, int count) *lastchar = 1; while(1) { - memset(array, 1, count); + memset(array, default_state, count); fprintf(stream, "\n"); - fprintf(stream, _("Enter a selection (default=all)")); + if(default_state) { + fprintf(stream, _("Enter a selection (default=all)")); + } else { + fprintf(stream, _("Enter a selection (default=none)")); + } fprintf(stream, ": "); fflush(stream); diff --git a/src/pacman/util.h b/src/pacman/util.h index 0fbc6b9..229167c 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -75,7 +75,7 @@ void print_packages(const alpm_list_t *packages); void select_display(const alpm_list_t *pkglist); void select_optdep_display(alpm_list_t *optstrings); int select_question(int count); -int multiselect_question(char *array, int count); +int multiselect_question(char *array, int count, int default_state); int yesno(char *fmt, ...); int noyes(char *fmt, ...); -- 1.7.7.3
participants (4)
-
Benedikt Morbach
-
Dan McGee
-
Dan McGee
-
Denis A. Altoé Falqueto