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 <[email protected]>
---
 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


Reply via email to