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