[pacman-dev] [PATCH v4 3/3] Add --assume-installed option

Florian Pritz bluewind at xinu.at
Wed Sep 17 12:40:32 EDT 2014


This allows to ignore specific dependencies.

Signed-off-by: Florian Pritz <bluewind at xinu.at>
---

v4:
 - Incorporate suggestions from Andrew
 - Return 1 if alpm_dep_from_depstring fails since this can only happen
   because of memory problems which already generate an error message. I hope
   this is fine.

 doc/pacman.8.txt                                  |  6 +++
 lib/libalpm/alpm.h                                | 11 +++++
 lib/libalpm/deps.c                                |  8 +++-
 lib/libalpm/handle.c                              | 56 +++++++++++++++++++++++
 lib/libalpm/handle.h                              |  1 +
 src/pacman/conf.c                                 | 18 ++++++++
 src/pacman/conf.h                                 |  4 +-
 src/pacman/pacman.c                               |  4 ++
 test/pacman/tests/TESTS                           |  3 ++
 test/pacman/tests/remove-assumeinstalled.py       | 14 ++++++
 test/pacman/tests/sync-install-assumeinstalled.py | 11 +++++
 test/pacman/tests/sync-update-assumeinstalled.py  | 19 ++++++++
 12 files changed, 152 insertions(+), 3 deletions(-)
 create mode 100644 test/pacman/tests/remove-assumeinstalled.py
 create mode 100644 test/pacman/tests/sync-install-assumeinstalled.py
 create mode 100644 test/pacman/tests/sync-update-assumeinstalled.py

diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt
index 152b261..45741b4 100644
--- a/doc/pacman.8.txt
+++ b/doc/pacman.8.txt
@@ -186,6 +186,12 @@ Transaction Options (apply to '-S', '-R' and '-U')
 	dependencies are installed and there are no package conflicts in the
 	system. Specify this option twice to skip all dependency checks.
 
+*\--assume-installed* <package=version>::
+	Add a virtual package "package" with version "version" to the transaction
+	to satisfy dependencies. This allows to disable specific dependency checks
+	without affecting all dependency checks. To disable all dependency
+	checking, see the '\--nodeps' option.
+
 *\--dbonly*::
 	Adds/removes the database entry only, leaving all files in place.
 
diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h
index 0392cb5..5f08244 100644
--- a/lib/libalpm/alpm.h
+++ b/lib/libalpm/alpm.h
@@ -857,6 +857,17 @@ int alpm_option_set_ignoregroups(alpm_handle_t *handle, alpm_list_t *ignoregrps)
 int alpm_option_remove_ignoregroup(alpm_handle_t *handle, const char *grp);
 /** @} */
 
+/** @name Accessors to the list of ignored dependencies.
+ * These functions modify the list of dependencies that
+ * should be ignored by a sysupgrade.
+ * @{
+ */
+alpm_list_t *alpm_option_get_assumeinstalled(alpm_handle_t *handle);
+int alpm_option_add_assumeinstalled(alpm_handle_t *handle, const alpm_depend_t *dep);
+int alpm_option_set_assumeinstalled(alpm_handle_t *handle, alpm_list_t *deps);
+int alpm_option_remove_assumeinstalled(alpm_handle_t *handle, const alpm_depend_t *dep);
+/** @} */
+
 /** Returns the targeted architecture. */
 const char *alpm_option_get_arch(alpm_handle_t *handle);
 /** Sets the targeted architecture. */
diff --git a/lib/libalpm/deps.c b/lib/libalpm/deps.c
index 830a986..e1c38ca 100644
--- a/lib/libalpm/deps.c
+++ b/lib/libalpm/deps.c
@@ -333,8 +333,10 @@ alpm_list_t SYMEXPORT *alpm_checkdeps(alpm_handle_t *handle,
 			}
 			/* 1. we check the upgrade list */
 			/* 2. we check database for untouched satisfying packages */
+			/* 3. we check the dependency ignore list */
 			if(!find_dep_satisfier(upgrade, depend) &&
-					!find_dep_satisfier(dblist, depend)) {
+					!find_dep_satisfier(dblist, depend) &&
+					!_alpm_depcmp_provides(depend, handle->assumeinstalled)) {
 				/* Unsatisfied dependency in the upgrade list */
 				alpm_depmissing_t *miss;
 				char *missdepstring = alpm_dep_compute_string(depend);
@@ -363,9 +365,11 @@ alpm_list_t SYMEXPORT *alpm_checkdeps(alpm_handle_t *handle,
 				/* we won't break this depend, if it is already broken, we ignore it */
 				/* 1. check upgrade list for satisfiers */
 				/* 2. check dblist for satisfiers */
+				/* 3. we check the dependency ignore list */
 				if(causingpkg &&
 						!find_dep_satisfier(upgrade, depend) &&
-						!find_dep_satisfier(dblist, depend)) {
+						!find_dep_satisfier(dblist, depend) &&
+						!_alpm_depcmp_provides(depend, handle->assumeinstalled)) {
 					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",
diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c
index fdd269b..de6ce5f 100644
--- a/lib/libalpm/handle.c
+++ b/lib/libalpm/handle.c
@@ -37,6 +37,7 @@
 #include "delta.h"
 #include "trans.h"
 #include "alpm.h"
+#include "deps.h"
 
 alpm_handle_t *_alpm_handle_new(void)
 {
@@ -86,6 +87,10 @@ void _alpm_handle_free(alpm_handle_t *handle)
 	FREELIST(handle->noextract);
 	FREELIST(handle->ignorepkg);
 	FREELIST(handle->ignoregroup);
+
+	alpm_list_free_inner(handle->assumeinstalled, (alpm_list_fn_free)alpm_dep_free);
+	alpm_list_free(handle->assumeinstalled);
+
 	FREE(handle);
 }
 
@@ -246,6 +251,12 @@ alpm_list_t SYMEXPORT *alpm_option_get_ignoregroups(alpm_handle_t *handle)
 	return handle->ignoregroup;
 }
 
+alpm_list_t SYMEXPORT *alpm_option_get_assumeinstalled(alpm_handle_t *handle)
+{
+	CHECK_HANDLE(handle, return NULL);
+	return handle->assumeinstalled;
+}
+
 const char SYMEXPORT *alpm_option_get_arch(alpm_handle_t *handle)
 {
 	CHECK_HANDLE(handle, return NULL);
@@ -545,6 +556,51 @@ int SYMEXPORT alpm_option_remove_ignoregroup(alpm_handle_t *handle, const char *
 	return _alpm_option_strlist_rem(handle, &(handle->ignoregroup), grp);
 }
 
+int SYMEXPORT alpm_option_add_assumeinstalled(alpm_handle_t *handle, const alpm_depend_t *dep)
+{
+	CHECK_HANDLE(handle, return -1);
+
+	handle->assumeinstalled = alpm_list_add(handle->assumeinstalled, (void *)dep);
+	return 0;
+}
+
+int SYMEXPORT alpm_option_set_assumeinstalled(alpm_handle_t *handle, alpm_list_t *deps)
+{
+	CHECK_HANDLE(handle, return -1);
+	if(handle->assumeinstalled) {
+		alpm_list_free_inner(handle->assumeinstalled, (alpm_list_fn_free)alpm_dep_free);
+		alpm_list_free(handle->assumeinstalled);
+	}
+	handle->assumeinstalled = deps;
+	return 0;
+}
+
+static int assumeinstalled_cmp(const void *d1, const void *d2)
+{
+	const alpm_depend_t *dep1 = d1;
+	const alpm_depend_t *dep2 = d2;
+
+	if(strcmp(dep1->name, dep2->name) == 0 && strcmp(dep1->version, dep2->version) == 0) {
+		return 0;
+	}
+
+	return -1;
+}
+
+int SYMEXPORT alpm_option_remove_assumeinstalled(alpm_handle_t *handle, const alpm_depend_t *dep)
+{
+	alpm_depend_t *vdata = NULL;
+	CHECK_HANDLE(handle, return -1);
+
+	handle->assumeinstalled = alpm_list_remove(handle->assumeinstalled, dep, &assumeinstalled_cmp, (void **)&vdata);
+	if(vdata != NULL) {
+		alpm_dep_free(vdata);
+		return 1;
+	}
+
+	return 0;
+}
+
 int SYMEXPORT alpm_option_set_arch(alpm_handle_t *handle, const char *arch)
 {
 	CHECK_HANDLE(handle, return -1);
diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h
index 85c64f6..c9c454a 100644
--- a/lib/libalpm/handle.h
+++ b/lib/libalpm/handle.h
@@ -83,6 +83,7 @@ struct __alpm_handle_t {
 	alpm_list_t *noextract;   /* List of files NOT to extract */
 	alpm_list_t *ignorepkg;   /* List of packages to ignore */
 	alpm_list_t *ignoregroup; /* List of groups to ignore */
+	alpm_list_t *assumeinstalled;   /* List of virtual packages used to satisfy dependencies */
 
 	/* options */
 	char *arch;              /* Architecture of packages we should allow */
diff --git a/src/pacman/conf.c b/src/pacman/conf.c
index 0e483f7..d8dfc37 100644
--- a/src/pacman/conf.c
+++ b/src/pacman/conf.c
@@ -134,6 +134,7 @@ int config_free(config_t *oldconfig)
 	FREELIST(oldconfig->holdpkg);
 	FREELIST(oldconfig->ignorepkg);
 	FREELIST(oldconfig->ignoregrp);
+	FREELIST(oldconfig->assumeinstalled);
 	FREELIST(oldconfig->noupgrade);
 	FREELIST(oldconfig->noextract);
 	free(oldconfig->configfile);
@@ -650,6 +651,7 @@ static int setup_libalpm(void)
 	int ret = 0;
 	alpm_errno_t err;
 	alpm_handle_t *handle;
+	alpm_list_t *i;
 
 	pm_printf(ALPM_LOG_DEBUG, "setup_libalpm called\n");
 
@@ -741,6 +743,22 @@ static int setup_libalpm(void)
 	alpm_option_set_noupgrades(handle, config->noupgrade);
 	alpm_option_set_noextracts(handle, config->noextract);
 
+	for(i = config->assumeinstalled; i; i = i->next) {
+		char *entry = i->data;
+		alpm_depend_t *dep = alpm_dep_from_depstring(entry);
+		if(!dep) {
+			return 1;
+		}
+		pm_printf(ALPM_LOG_DEBUG, "parsed assume installed: %s %s\n", dep->name, dep->version);
+
+		ret = alpm_option_add_assumeinstalled(handle, dep);
+		if(ret) {
+			pm_printf(ALPM_LOG_ERROR, _("Failed to pass assume installed entry to libalpm"));
+			alpm_dep_free(dep);
+			return ret;
+		}
+	 }
+
 	return 0;
 }
 
diff --git a/src/pacman/conf.h b/src/pacman/conf.h
index e8cac50..8aed6d6 100644
--- a/src/pacman/conf.h
+++ b/src/pacman/conf.h
@@ -101,6 +101,7 @@ typedef struct __config_t {
 	alpm_list_t *holdpkg;
 	alpm_list_t *ignorepkg;
 	alpm_list_t *ignoregrp;
+	alpm_list_t *assumeinstalled;
 	alpm_list_t *noupgrade;
 	alpm_list_t *noextract;
 	char *xfercommand;
@@ -176,7 +177,8 @@ enum {
 	OP_UNNEEDED,
 	OP_VERBOSE,
 	OP_DOWNLOADONLY,
-	OP_REFRESH
+	OP_REFRESH,
+	OP_ASSUMEINSTALLED
 };
 
 /* clean method */
diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c
index 345fb0a..e079726 100644
--- a/src/pacman/pacman.c
+++ b/src/pacman/pacman.c
@@ -632,6 +632,9 @@ static int parsearg_trans(int opt)
 			free(config->print_format);
 			config->print_format = strdup(optarg);
 			break;
+		case OP_ASSUMEINSTALLED:
+			parsearg_util_addlist(&(config->assumeinstalled));
+			break;
 		default:
 			return 1;
 	}
@@ -855,6 +858,7 @@ static int parseargs(int argc, char *argv[])
 		{"noconfirm",  no_argument,       0, OP_NOCONFIRM},
 		{"config",     required_argument, 0, OP_CONFIG},
 		{"ignore",     required_argument, 0, OP_IGNORE},
+		{"assume-installed",     required_argument, 0, OP_ASSUMEINSTALLED},
 		{"debug",      optional_argument, 0, OP_DEBUG},
 		{"force",      no_argument,       0, OP_FORCE},
 		{"noprogressbar", no_argument,    0, OP_NOPROGRESSBAR},
diff --git a/test/pacman/tests/TESTS b/test/pacman/tests/TESTS
index 1b5a81f..052cf4b 100644
--- a/test/pacman/tests/TESTS
+++ b/test/pacman/tests/TESTS
@@ -92,6 +92,7 @@ TESTS += test/pacman/tests/querycheck001.py
 TESTS += test/pacman/tests/querycheck002.py
 TESTS += test/pacman/tests/querycheck_fast_file_type.py
 TESTS += test/pacman/tests/reason001.py
+TESTS += test/pacman/tests/remove-assumeinstalled.py
 TESTS += test/pacman/tests/remove001.py
 TESTS += test/pacman/tests/remove002.py
 TESTS += test/pacman/tests/remove010.py
@@ -135,12 +136,14 @@ TESTS += test/pacman/tests/symlink010.py
 TESTS += test/pacman/tests/symlink011.py
 TESTS += test/pacman/tests/symlink012.py
 TESTS += test/pacman/tests/symlink020.py
+TESTS += test/pacman/tests/sync-install-assumeinstalled.py
 TESTS += test/pacman/tests/sync-nodepversion01.py
 TESTS += test/pacman/tests/sync-nodepversion02.py
 TESTS += test/pacman/tests/sync-nodepversion03.py
 TESTS += test/pacman/tests/sync-nodepversion04.py
 TESTS += test/pacman/tests/sync-nodepversion05.py
 TESTS += test/pacman/tests/sync-nodepversion06.py
+TESTS += test/pacman/tests/sync-update-assumeinstalled.py
 TESTS += test/pacman/tests/sync-update-package-removing-required-provides.py
 TESTS += test/pacman/tests/sync001.py
 TESTS += test/pacman/tests/sync002.py
diff --git a/test/pacman/tests/remove-assumeinstalled.py b/test/pacman/tests/remove-assumeinstalled.py
new file mode 100644
index 0000000..4f3630c
--- /dev/null
+++ b/test/pacman/tests/remove-assumeinstalled.py
@@ -0,0 +1,14 @@
+self.description = "Remove a package using --assume-installed"
+
+lp1 = pmpkg("pkg1", "1.0-1")
+
+lp2 = pmpkg("pkg2", "1.0-1")
+lp2.depends = ["pkg1=1.0"]
+for p in lp1, lp2:
+	self.addpkg2db("local", p);
+
+self.args = "-R pkg1 --assume-installed pkg1=1.0"
+
+self.addrule("PACMAN_RETCODE=0")
+self.addrule("PKG_EXIST=pkg2")
+self.addrule("!PKG_EXIST=pkg1")
diff --git a/test/pacman/tests/sync-install-assumeinstalled.py b/test/pacman/tests/sync-install-assumeinstalled.py
new file mode 100644
index 0000000..6744dc8
--- /dev/null
+++ b/test/pacman/tests/sync-install-assumeinstalled.py
@@ -0,0 +1,11 @@
+self.description = "Install a package using --assume-installed"
+
+sp1 = pmpkg("pkg2", "2.0-1")
+sp1.depends = ["pkg1"]
+
+self.addpkg2db("sync", sp1);
+
+self.args = "-S pkg2 --assume-installed pkg1"
+
+self.addrule("PACMAN_RETCODE=0")
+self.addrule("PKG_EXIST=pkg2")
diff --git a/test/pacman/tests/sync-update-assumeinstalled.py b/test/pacman/tests/sync-update-assumeinstalled.py
new file mode 100644
index 0000000..c22a20e
--- /dev/null
+++ b/test/pacman/tests/sync-update-assumeinstalled.py
@@ -0,0 +1,19 @@
+self.description = "Update a package using --assume-installed"
+
+lp1 = pmpkg("pkg1", "1.0-1")
+
+lp2 = pmpkg("pkg2", "1.0-1")
+lp2.depends = ["pkg1=1.0"]
+
+sp1 = pmpkg("pkg1", "2.0-1")
+
+for p in lp1, lp2:
+	self.addpkg2db("local", p);
+
+self.addpkg2db("sync", sp1);
+
+self.args = "-Su --assume-installed pkg1=1.0"
+
+self.addrule("PACMAN_RETCODE=0")
+self.addrule("PKG_VERSION=pkg1|2.0-1")
+self.addrule("PKG_EXIST=pkg2")
-- 
2.1.0


More information about the pacman-dev mailing list