Signed-off-by: Benedikt Morbach <benedikt.morbach@googlemail.com> --- doc/pacman.conf.5.txt | 5 +++- 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, 120 insertions(+), 22 deletions(-) diff --git a/doc/pacman.conf.5.txt b/doc/pacman.conf.5.txt index 5354358..2bfe757 100644 --- a/doc/pacman.conf.5.txt +++ b/doc/pacman.conf.5.txt @@ -156,9 +156,12 @@ Options packages are only cleaned if not installed locally and not present in any known sync database. -*HandleOptdeps =* Install:: +*HandleOptdeps =* Install &| Ask:: 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. *SigLevel =* ...:: Set the default signature verification level. For more information, see diff --git a/etc/pacman.conf.in b/etc/pacman.conf.in index cfd96e1..06f4846 100644 --- a/etc/pacman.conf.in +++ b/etc/pacman.conf.in @@ -37,7 +37,7 @@ Architecture = auto #VerbosePkgLists #ShowAllOptdeps -#HandleOptdeps = Install +#HandleOptdeps = Install Ask # PGP signature checking #SigLevel = Optional diff --git a/src/pacman/conf.c b/src/pacman/conf.c index e88e916..35de34a 100644 --- a/src/pacman/conf.c +++ b/src/pacman/conf.c @@ -339,6 +339,8 @@ static int process_handleoptdeps(alpm_list_t *actions) { const char *action = i->data; 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 384f379..6948abd 100644 --- a/src/pacman/conf.h +++ b/src/pacman/conf.h @@ -140,7 +140,8 @@ enum { /* optdepends handling */ enum { - PM_OPTDEPS_INSTALL = 1 + PM_OPTDEPS_INSTALL = 1, + PM_OPTDEPS_ASK = (1 << 1) }; /* global config variable */ diff --git a/src/pacman/sync.c b/src/pacman/sync.c index 1bb09e9..f073b59 100644 --- a/src/pacman/sync.c +++ b/src/pacman/sync.c @@ -618,7 +618,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->showalloptdeps == 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 = alpm_list_getdata(i); + 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 = alpm_list_getdata(i); + 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); /* use config->showalloptdeps ! */ + + 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 = alpm_list_getdata(i); + 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 1f54f65..72a78d9 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -1091,35 +1091,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->showalloptdeps); + optstrings = optdep_string_list(optdeps, config->showalloptdeps); - 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->showalloptdeps); + optstrings = optdep_string_list(alpm_pkg_get_optdepends(pkg), config->showalloptdeps); - 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) @@ -1159,6 +1167,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 = alpm_list_getdata(i); + 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 0eac77a..2e35e84 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -67,6 +67,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.6.1