[pacman-dev] [PATCH 10/14] Warn on optdep removal

Benedikt Morbach benedikt.morbach at googlemail.com
Wed Nov 23 10:51:24 EST 2011


Issue a warning if the user for whatever reason tries to remove
an optdepend of an installed package.

Signed-off-by: Benedikt Morbach <benedikt.morbach at googlemail.com>
---
 lib/libalpm/alpm.h   |    5 ++++-
 lib/libalpm/deps.c   |   35 ++++++++++++++++++++++++++---------
 lib/libalpm/error.c  |    2 ++
 lib/libalpm/remove.c |   16 +++++++++++++---
 lib/libalpm/sync.c   |    2 +-
 lib/libalpm/trans.c  |   10 ++++++++--
 src/pacman/remove.c  |   23 +++++++++++++++++++----
 src/util/testdb.c    |    2 +-
 8 files changed, 74 insertions(+), 21 deletions(-)

diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h
index d06ad0d..34dbaa1 100644
--- a/lib/libalpm/alpm.h
+++ b/lib/libalpm/alpm.h
@@ -162,6 +162,8 @@ typedef struct _alpm_depmissing_t {
 	alpm_depend_t *depend;
 	/* this is used in case of remove dependency error only */
 	char *causingpkg;
+	/* this is used for optdepends only */
+	char *description;
 } alpm_depmissing_t;
 
 /** Conflict */
@@ -1096,7 +1098,7 @@ int alpm_remove_pkg(alpm_handle_t *handle, alpm_pkg_t *pkg);
  */
 
 alpm_list_t *alpm_checkdeps(alpm_handle_t *handle, alpm_list_t *pkglist,
-		alpm_list_t *remove, alpm_list_t *upgrade, int reversedeps);
+		alpm_list_t *remove, alpm_list_t *upgrade, int reversedeps, int consider_optdeps);
 alpm_pkg_t *alpm_find_satisfier(alpm_list_t *pkgs, const char *depstring);
 alpm_pkg_t *alpm_find_dbs_satisfier(alpm_handle_t *handle,
 		alpm_list_t *dbs, const char *depstring);
@@ -1184,6 +1186,7 @@ typedef enum _alpm_errno_t {
 	ALPM_ERR_DLT_PATCHFAILED,
 	/* Dependencies */
 	ALPM_ERR_UNSATISFIED_DEPS,
+	ALPM_ERR_UNSATISFIED_OPTDEPS,
 	ALPM_ERR_CONFLICTING_DEPS,
 	ALPM_ERR_FILE_CONFLICTS,
 	/* Misc */
diff --git a/lib/libalpm/deps.c b/lib/libalpm/deps.c
index 83bc619..c9efce4 100644
--- a/lib/libalpm/deps.c
+++ b/lib/libalpm/deps.c
@@ -52,7 +52,7 @@ void _alpm_optdep_free(alpm_optdepend_t *optdep)
 }
 
 static alpm_depmissing_t *depmiss_new(const char *target, alpm_depend_t *dep,
-		const char *causingpkg)
+		const char *causingpkg, const char *description)
 {
 	alpm_depmissing_t *miss;
 
@@ -61,6 +61,7 @@ static alpm_depmissing_t *depmiss_new(const char *target, alpm_depend_t *dep,
 	STRDUP(miss->target, target, return NULL);
 	miss->depend = _alpm_dep_dup(dep);
 	STRDUP(miss->causingpkg, causingpkg, return NULL);
+	STRDUP(miss->description, description, return NULL);
 
 	return miss;
 }
@@ -70,6 +71,7 @@ void _alpm_depmiss_free(alpm_depmissing_t *miss)
 	_alpm_dep_free(miss->depend);
 	FREE(miss->target);
 	FREE(miss->causingpkg);
+	FREE(miss->description);
 	FREE(miss);
 }
 
@@ -283,11 +285,12 @@ alpm_pkg_t SYMEXPORT *alpm_find_satisfier(alpm_list_t *pkgs, const char *depstri
  * @param remove an alpm_list_t* of packages to be removed
  * @param upgrade an alpm_list_t* of packages to be upgraded (remove-then-upgrade)
  * @param reversedeps handles the backward dependencies
+ * @param consider_optdeps handles optional dependencies instead of normal ones
  * @return an alpm_list_t* of alpm_depmissing_t pointers.
  */
 alpm_list_t SYMEXPORT *alpm_checkdeps(alpm_handle_t *handle,
 		alpm_list_t *pkglist, alpm_list_t *remove, alpm_list_t *upgrade,
-		int reversedeps)
+		int reversedeps, int consider_optdeps)
 {
 	alpm_list_t *i, *j;
 	alpm_list_t *dblist = NULL, *modified = NULL;
@@ -326,7 +329,7 @@ alpm_list_t SYMEXPORT *alpm_checkdeps(alpm_handle_t *handle,
 				_alpm_log(handle, ALPM_LOG_DEBUG, "checkdeps: missing dependency '%s' for package '%s'\n",
 						missdepstring, tp->name);
 				free(missdepstring);
-				miss = depmiss_new(tp->name, depend, NULL);
+				miss = depmiss_new(tp->name, depend, NULL, NULL);
 				baddeps = alpm_list_add(baddeps, miss);
 			}
 			release_filtered_depend(depend, nodepversion);
@@ -338,8 +341,17 @@ alpm_list_t SYMEXPORT *alpm_checkdeps(alpm_handle_t *handle,
 		 * the packages listed in the requiredby field. */
 		for(i = dblist; i; i = i->next) {
 			alpm_pkg_t *lp = i->data;
-			for(j = alpm_pkg_get_depends(lp); j; j = j->next) {
-				alpm_depend_t *depend = j->data;
+			j = consider_optdeps ? alpm_pkg_get_optdepends(lp) : alpm_pkg_get_depends(lp);
+			for(; j; j = j->next) {
+				alpm_depend_t *depend;
+				const char *description = NULL;
+				if(consider_optdeps) {
+					alpm_optdepend_t *optdep = j->data;
+					depend = optdep->depend;
+					description = optdep->description;
+				} else {
+					depend = j->data;
+				}
 				depend = filtered_depend(depend, nodepversion);
 				alpm_pkg_t *causingpkg = find_dep_satisfier(modified, depend);
 				/* we won't break this depend, if it is already broken, we ignore it */
@@ -350,10 +362,15 @@ alpm_list_t SYMEXPORT *alpm_checkdeps(alpm_handle_t *handle,
 				   !find_dep_satisfier(dblist, depend)) {
 					alpm_depmissing_t *miss;
 					char *missdepstring = alpm_dep_compute_string(depend);
-					_alpm_log(handle, ALPM_LOG_DEBUG, "checkdeps: transaction would break '%s' dependency of '%s'\n",
-							missdepstring, lp->name);
+					if(consider_optdeps) {
+						_alpm_log(handle, ALPM_LOG_DEBUG, "checkdeps: transaction would break '%s' optional dependency of '%s'\n",
+											missdepstring, lp->name);
+					} else {
+						_alpm_log(handle, ALPM_LOG_DEBUG, "checkdeps: transaction would break '%s' dependency of '%s'\n",
+											missdepstring, lp->name);
+					}
 					free(missdepstring);
-					miss = depmiss_new(lp->name, depend, causingpkg->name);
+					miss = depmiss_new(lp->name, depend, causingpkg->name, description);
 					baddeps = alpm_list_add(baddeps, miss);
 				}
 				release_filtered_depend(depend, nodepversion);
@@ -801,7 +818,7 @@ int _alpm_resolvedeps(alpm_handle_t *handle, alpm_list_t *localpkgs,
 	for(i = alpm_list_last(*packages); i; i = i->next) {
 		alpm_pkg_t *tpkg = i->data;
 		targ = alpm_list_add(NULL, tpkg);
-		deps = alpm_checkdeps(handle, localpkgs, remove, targ, 0);
+		deps = alpm_checkdeps(handle, localpkgs, remove, targ, 0, 0);
 		alpm_list_free(targ);
 
 		for(j = deps; j; j = j->next) {
diff --git a/lib/libalpm/error.c b/lib/libalpm/error.c
index 044dec7..5283392 100644
--- a/lib/libalpm/error.c
+++ b/lib/libalpm/error.c
@@ -136,6 +136,8 @@ const char SYMEXPORT *alpm_strerror(alpm_errno_t err)
 		/* Dependencies */
 		case ALPM_ERR_UNSATISFIED_DEPS:
 			return _("could not satisfy dependencies");
+		case ALPM_ERR_UNSATISFIED_OPTDEPS:
+			return _("could not satisfy optional dependencies");
 		case ALPM_ERR_CONFLICTING_DEPS:
 			return _("conflicting dependencies");
 		case ALPM_ERR_FILE_CONFLICTS:
diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c
index d7e06bc..012f9c8 100644
--- a/lib/libalpm/remove.c
+++ b/lib/libalpm/remove.c
@@ -102,7 +102,7 @@ static int remove_prepare_cascade(alpm_handle_t *handle, alpm_list_t *lp)
 		alpm_list_free_inner(lp, (alpm_list_fn_free)_alpm_depmiss_free);
 		alpm_list_free(lp);
 		lp = alpm_checkdeps(handle, _alpm_db_get_pkgcache(handle->db_local),
-				trans->remove, NULL, 1);
+				trans->remove, NULL, 1, 0);
 	}
 	return 0;
 }
@@ -133,7 +133,7 @@ static void remove_prepare_keep_needed(alpm_handle_t *handle, alpm_list_t *lp)
 		alpm_list_free_inner(lp, (alpm_list_fn_free)_alpm_depmiss_free);
 		alpm_list_free(lp);
 		lp = alpm_checkdeps(handle, _alpm_db_get_pkgcache(handle->db_local),
-				trans->remove, NULL, 1);
+				trans->remove, NULL, 1, 0);
 	}
 }
 
@@ -164,7 +164,7 @@ int _alpm_remove_prepare(alpm_handle_t *handle, alpm_list_t **data)
 		EVENT(handle, ALPM_EVENT_CHECKDEPS_START, NULL, NULL);
 
 		_alpm_log(handle, ALPM_LOG_DEBUG, "looking for unsatisfied dependencies\n");
-		lp = alpm_checkdeps(handle, _alpm_db_get_pkgcache(db), trans->remove, NULL, 1);
+		lp = alpm_checkdeps(handle, _alpm_db_get_pkgcache(db), trans->remove, NULL, 1, 0);
 		if(lp != NULL) {
 
 			if(trans->flags & ALPM_TRANS_FLAG_CASCADE) {
@@ -206,6 +206,16 @@ int _alpm_remove_prepare(alpm_handle_t *handle, alpm_list_t **data)
 
 	if(!(trans->flags & ALPM_TRANS_FLAG_NODEPS)) {
 		EVENT(handle, ALPM_EVENT_CHECKDEPS_DONE, NULL, NULL);
+		lp = alpm_checkdeps(handle, _alpm_db_get_pkgcache(db), trans->remove, NULL, 1, 1);
+		if(lp != NULL) {
+			if(data) {
+				*data = lp;
+			} else {
+				alpm_list_free_inner(lp, (alpm_list_fn_free)_alpm_depmiss_free);
+				alpm_list_free(lp);
+			}
+			RET_ERR(handle, ALPM_ERR_UNSATISFIED_OPTDEPS, -1);
+		}
 	}
 
 	return 0;
diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c
index 3817ec8..b501807 100644
--- a/lib/libalpm/sync.c
+++ b/lib/libalpm/sync.c
@@ -605,7 +605,7 @@ int _alpm_sync_prepare(alpm_handle_t *handle, alpm_list_t **data)
 	if(!(trans->flags & ALPM_TRANS_FLAG_NODEPS)) {
 		_alpm_log(handle, ALPM_LOG_DEBUG, "checking dependencies\n");
 		deps = alpm_checkdeps(handle, _alpm_db_get_pkgcache(handle->db_local),
-				trans->remove, trans->add, 1);
+				trans->remove, trans->add, 1, 0);
 		if(deps) {
 			handle->pm_errno = ALPM_ERR_UNSATISFIED_DEPS;
 			ret = -1;
diff --git a/lib/libalpm/trans.c b/lib/libalpm/trans.c
index cb97a4a..40e6786 100644
--- a/lib/libalpm/trans.c
+++ b/lib/libalpm/trans.c
@@ -101,6 +101,7 @@ static alpm_list_t *check_arch(alpm_handle_t *handle, alpm_list_t *pkgs)
 int SYMEXPORT alpm_trans_prepare(alpm_handle_t *handle, alpm_list_t **data)
 {
 	alpm_trans_t *trans;
+	int retval = 0;
 
 	/* Sanity checks */
 	CHECK_HANDLE(handle, return -1);
@@ -127,7 +128,12 @@ int SYMEXPORT alpm_trans_prepare(alpm_handle_t *handle, alpm_list_t **data)
 	if(trans->add == NULL) {
 		if(_alpm_remove_prepare(handle, data) == -1) {
 			/* pm_errno is set by _alpm_remove_prepare() */
-			return -1;
+			/* UNSATISFIED_OPTDEPS is nonfatal. */
+			if(alpm_errno(handle) == ALPM_ERR_UNSATISFIED_OPTDEPS) {
+				retval = -1;
+			} else {
+			  return -1;
+			}
 		}
 	}	else {
 		if(_alpm_sync_prepare(handle, data) == -1) {
@@ -138,7 +144,7 @@ int SYMEXPORT alpm_trans_prepare(alpm_handle_t *handle, alpm_list_t **data)
 
 	trans->state = STATE_PREPARED;
 
-	return 0;
+	return retval;
 }
 
 /** Commit a transaction. */
diff --git a/src/pacman/remove.c b/src/pacman/remove.c
index f56c1ec..739a6eb 100644
--- a/src/pacman/remove.c
+++ b/src/pacman/remove.c
@@ -111,8 +111,8 @@ int pacman_remove(alpm_list_t *targets)
 	/* Step 2: prepare the transaction based on its type, targets and flags */
 	if(alpm_trans_prepare(config->handle, &data) == -1) {
 		alpm_errno_t err = alpm_errno(config->handle);
-		pm_printf(ALPM_LOG_ERROR, _("failed to prepare transaction (%s)\n"),
-		        alpm_strerror(err));
+		retval = 1;
+
 		switch(err) {
 			case ALPM_ERR_PKG_INVALID_ARCH:
 				for(i = data; i; i = alpm_list_next(i)) {
@@ -128,12 +128,27 @@ int pacman_remove(alpm_list_t *targets)
 					free(depstring);
 				}
 				break;
+			case ALPM_ERR_UNSATISFIED_OPTDEPS:
+				for(i = data; i; i = alpm_list_next(i)) {
+					alpm_depmissing_t *miss = i->data;
+					char *depstring = alpm_dep_compute_string(miss->depend);
+					if(miss->description) {
+						printf(_(":: %s: optionally requires %s (%s)\n"), miss->target, depstring, miss->description);
+					} else {
+						printf(_(":: %s: optionally requires %s\n"), miss->target, depstring);
+					}
+					free(depstring);
+				}
+				retval = 0;
+				break;
 			default:
 				break;
 		}
 		FREELIST(data);
-		retval = 1;
-		goto cleanup;
+		if(retval) {
+			pm_printf(ALPM_LOG_ERROR, _("failed to prepare transaction (%s)\n"), alpm_strerror(err));
+			goto cleanup;
+		}
 	}
 
 	/* Search for holdpkg in target list */
diff --git a/src/util/testdb.c b/src/util/testdb.c
index b15bbe5..e1401cc 100644
--- a/src/util/testdb.c
+++ b/src/util/testdb.c
@@ -99,7 +99,7 @@ static int checkdeps(alpm_list_t *pkglist)
 	alpm_list_t *data, *i;
 	int ret = 0;
 	/* check dependencies */
-	data = alpm_checkdeps(handle, pkglist, NULL, pkglist, 0);
+	data = alpm_checkdeps(handle, pkglist, NULL, pkglist, 0, 0);
 	for(i = data; i; i = alpm_list_next(i)) {
 		alpm_depmissing_t *miss = i->data;
 		char *depstring = alpm_dep_compute_string(miss->depend);
-- 
1.7.7.3



More information about the pacman-dev mailing list