Allows user interaction during group installation, and makes groups installation use the same code paths as individual packages which should ensure proper handling of additional flag (like --needed, --ignore, ...). Implemented in libalpm using callbacks for user interaction. Reimplements group handling lost in b4317a740ac2d4f5e4d1aa56a97171c52be70d02. Related issues: * http://www.archlinux.org/pipermail/pacman-dev/2009-June/008847.html operation aborts when a package from a group is ignored and user chooses not to install it * FS#15141 'pacman -S <repo>/<group>' syntax * FS#19854 --ignore is ignored when installing a group * FS#19853 no prompting about groups * FS#20221 installing group from multiple repos with --needed Signed-off-by: Jakob Gruber <jakob.gruber@gmail.com> --- lib/libalpm/alpm.h | 11 ++++++++- lib/libalpm/sync.c | 51 ++++++++++++++++++++++++++++++++++++++++++------ src/pacman/callback.c | 21 ++++++++++++++++++++ src/pacman/util.c | 12 ++++++++-- 4 files changed, 83 insertions(+), 12 deletions(-) diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 0c01f21..f02bcbf 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -368,6 +368,11 @@ typedef enum _pmtransevt_t { * The repository's tree name is passed to the callback. */ PM_TRANS_EVT_RETRIEVE_START, + /** Package not found during sync, looking for group */ + PM_TRANS_EVT_PKG_NOT_FOUND, + /** Group will be installed, group and db is + * passed to the callback. */ + PM_TRANS_EVT_INSTALL_GROUP, } pmtransevt_t; /*@}*/ @@ -379,6 +384,8 @@ typedef enum _pmtransconv_t { PM_TRANS_CONV_CORRUPTED_PKG = (1 << 3), PM_TRANS_CONV_LOCAL_NEWER = (1 << 4), PM_TRANS_CONV_REMOVE_PKGS = (1 << 5), + PM_TRANS_CONV_INSTALL_GROUPPKG = (1 << 6), + PM_TRANS_CONV_INSTALL_GROUP = (1 << 7), } pmtransconv_t; /* Transaction Progress */ @@ -411,8 +418,8 @@ int alpm_trans_interrupt(void); int alpm_trans_release(void); int alpm_sync_sysupgrade(int enable_downgrade); -int alpm_sync_target(char *target); -int alpm_sync_dbtarget(char *db, char *target); +int alpm_sync_target(const char *target); +int alpm_sync_dbtarget(char *db, const char *target); int alpm_add_target(char *target); int alpm_remove_target(char *target); diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index f819396..8982874 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -248,7 +248,7 @@ static int sync_pkg(pmpkg_t *spkg, alpm_list_t *pkg_list) return(0); } -static int sync_target(alpm_list_t *dbs_sync, char *target) +static int sync_target(alpm_list_t *dbs_sync, const char *target) { alpm_list_t *i, *j; alpm_list_t *known_pkgs = NULL; @@ -271,15 +271,53 @@ static int sync_target(alpm_list_t *dbs_sync, char *target) return(sync_pkg(spkg, handle->trans->add)); } + /* begin group handling. this section is responsible for looking for + * groups, user interaction, and finally adding group members to the + * queue. to stay consistent with individual package handling, it + * calls sync_target() for each group member to be installed */ _alpm_log(PM_LOG_DEBUG, "%s package not found, searching for group...\n", target); + EVENT(handle->trans, PM_TRANS_EVT_PKG_NOT_FOUND, (void*)target, NULL); + for(i = dbs_sync; i; i = i->next) { pmdb_t *db = i->data; grp = alpm_db_readgrp(db, target); + if(grp) { found = 1; - for(j = alpm_grp_get_pkgs(grp); j; j = j->next) { - pmpkg_t *pkg = j->data; - if(sync_pkg(pkg, known_pkgs) == -1) { + + /* display group members */ + EVENT(handle->trans, PM_TRANS_EVT_INSTALL_GROUP, (void*)grp, + (void*)db); + + /* ask if user wants to install all group members */ + int installall = 1; + QUESTION(handle->trans, PM_TRANS_CONV_INSTALL_GROUP, db, grp, + NULL, &installall); + + /* individually process all member packages */ + for(j = alpm_grp_get_pkgs(grp); j; j = alpm_list_next(j)) { + pmpkg_t *pkg = alpm_list_getdata(j); + const char *pkgname = alpm_pkg_get_name(pkg); + + /* package already processed in another repo, skip */ + if(known_pkgs && alpm_list_find_str(known_pkgs, pkgname)) { + continue; + } + known_pkgs = alpm_list_add(known_pkgs, (void*)pkgname); + + /* confirm user wants to install group member */ + if(installall == 0) { + int install = 1; + QUESTION(handle->trans, PM_TRANS_CONV_INSTALL_GROUPPKG, pkg, grp, + NULL, &install); + if(install == 0) { + continue; + } + } + + /* try adding pkg to transaction list (and run it through all + * checks - needed, ignored, ...) */ + if(sync_target(i, alpm_pkg_get_name(pkg)) == -1) { if(pm_errno == PM_ERR_TRANS_DUP_TARGET || pm_errno == PM_ERR_PKG_IGNORED) { /* just skip duplicate or ignored targets */ continue; @@ -288,7 +326,6 @@ static int sync_target(alpm_list_t *dbs_sync, char *target) return(-1); } } - known_pkgs = alpm_list_add(known_pkgs, pkg); } } } @@ -309,7 +346,7 @@ static int sync_target(alpm_list_t *dbs_sync, char *target) * @param target the name of the sync target to add * @return 0 on success, -1 on error (pm_errno is set accordingly) */ -int SYMEXPORT alpm_sync_dbtarget(char *dbname, char *target) +int SYMEXPORT alpm_sync_dbtarget(char *dbname, const char *target) { alpm_list_t *i; alpm_list_t *dbs_sync; @@ -340,7 +377,7 @@ int SYMEXPORT alpm_sync_dbtarget(char *dbname, char *target) * @param target the name of the sync target to add * @return 0 on success, -1 on error (pm_errno is set accordingly) */ -int SYMEXPORT alpm_sync_target(char *target) +int SYMEXPORT alpm_sync_target(const char *target) { alpm_list_t *dbs_sync; diff --git a/src/pacman/callback.c b/src/pacman/callback.c index 32dafb5..b91358b 100644 --- a/src/pacman/callback.c +++ b/src/pacman/callback.c @@ -229,6 +229,16 @@ void cb_trans_evt(pmtransevt_t event, void *data1, void *data2) case PM_TRANS_EVT_RETRIEVE_START: printf(_(":: Retrieving packages from %s...\n"), (char*)data1); break; + case PM_TRANS_EVT_PKG_NOT_FOUND: + printf(_("%s package not found, searching for group...\n"), + (char*)data1); + break; + case PM_TRANS_EVT_INSTALL_GROUP: + printf( _(":: group %s/%s:\n"), + (char*)alpm_db_get_name(data2), + (char*)alpm_grp_get_name(data1)); + display_targets(alpm_grp_get_pkgs(data1), 2); + break; /* all the simple done events, with fallthrough for each */ case PM_TRANS_EVT_FILECONFLICTS_DONE: case PM_TRANS_EVT_CHECKDEPS_DONE: @@ -309,6 +319,17 @@ void cb_trans_conv(pmtransconv_t event, void *data1, void *data2, *response = yesno(_(":: File %s is corrupted. Do you want to delete it?"), (char *)data1); break; + case PM_TRANS_CONV_INSTALL_GROUP: + *response = yesno(_(":: Install whole content from group %s/%s?"), + alpm_db_get_name(data1), + alpm_grp_get_name(data2)); + break; + case PM_TRANS_CONV_INSTALL_GROUPPKG: + *response = yesno(_(":: Install %s from group %s?"), + alpm_pkg_get_name(data1), + alpm_grp_get_name(data2)); + break; + } if(config->noask) { if(config->ask & event) { diff --git a/src/pacman/util.c b/src/pacman/util.c index b0824cf..9ccda90 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -506,8 +506,9 @@ void list_display_linebreak(const char *title, const alpm_list_t *list) } } } -/* prepare a list of pkgs to display */ -void display_targets(const alpm_list_t *pkgs, int install) +/* prepare a list of pkgs to display + * mode: 0=remove, 1=install, 2=group display */ +void display_targets(const alpm_list_t *pkgs, int mode) { char *str; const alpm_list_t *i; @@ -544,7 +545,7 @@ void display_targets(const alpm_list_t *pkgs, int install) mbdlsize = dlsize / (1024.0 * 1024.0); mbisize = isize / (1024.0 * 1024.0); - if(install) { + if(mode == 1) { asprintf(&str, _("Targets (%d):"), alpm_list_count(targets)); list_display(str, targets); free(str); @@ -554,6 +555,11 @@ void display_targets(const alpm_list_t *pkgs, int install) if(!(config->flags & PM_TRANS_FLAG_DOWNLOADONLY)) { printf(_("Total Installed Size: %.2f MB\n"), mbisize); } + } else if(mode == 2) { + asprintf(&str, _("Members (%d):"), alpm_list_count(targets)); + list_display(str, targets); + free(str); + printf("\n"); } else { asprintf(&str, _("Remove (%d):"), alpm_list_count(targets)); list_display(str, targets); -- 1.7.3