[pacman-dev] [PATCH 4/5] Reimplement advanced group handling

Jakob Gruber jakob.gruber at gmail.com
Sat Sep 25 05:40:05 EDT 2010


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 at 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



More information about the pacman-dev mailing list