[pacman-dev] [PATCH v3 3/3] Add --assume-installed option
Florian Pritz
bluewind at xinu.at
Tue Sep 16 19:02:14 EDT 2014
This allows to ignore specific dependencies.
Signed-off-by: Florian Pritz <bluewind at xinu.at>
---
doc/pacman.8.txt | 6 +++
lib/libalpm/alpm.h | 11 +++++
lib/libalpm/deps.c | 8 +++-
lib/libalpm/handle.c | 79 ++++++++++++++++++++++++++++++++++
lib/libalpm/handle.h | 1 +
src/pacman/conf.c | 17 ++++++++
src/pacman/conf.h | 4 +-
src/pacman/pacman.c | 4 ++
test/pacman/tests/TESTS | 3 ++
test/pacman/tests/assumeinstalled.py | 20 +++++++++
test/pacman/tests/assumeinstalled_2.py | 11 +++++
test/pacman/tests/assumeinstalled_3.py | 14 ++++++
12 files changed, 175 insertions(+), 3 deletions(-)
create mode 100644 test/pacman/tests/assumeinstalled.py
create mode 100644 test/pacman/tests/assumeinstalled_2.py
create mode 100644 test/pacman/tests/assumeinstalled_3.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 12769a4..9a35454 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 0ef5756..55c47a1 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..0f88462 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,30 @@ 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)
+{
+ alpm_list_t *ret = NULL;
+ CHECK_HANDLE(handle, return NULL);
+
+ for(alpm_list_t *i = handle->assumeinstalled; i; i = i->next) {
+ alpm_depend_t *dep = i->data;
+ char *pkg = NULL;
+ int len = strlen(dep->name) + strlen("=") + strlen(dep->version) + 1;
+ MALLOC(pkg, len, goto error);
+ if(snprintf(pkg, len, "%s=%s", dep->name, dep->version) != len - 1) {
+ _alpm_log(handle, ALPM_LOG_DEBUG, "Failed to assemble assumeinstalled string\n");
+ goto error;
+ }
+ ret = alpm_list_add(ret, pkg);
+ }
+ return ret;
+
+error:
+ alpm_list_free_inner(ret, (alpm_list_fn_free)alpm_dep_free);
+ alpm_list_free(ret);
+ return NULL;
+}
+
const char SYMEXPORT *alpm_option_get_arch(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
@@ -545,6 +574,56 @@ 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);
+ }
+ for(alpm_list_t *i = deps; i; i = i->next) {
+ int ret = alpm_option_add_assumeinstalled(handle, i->data);
+ if(ret) {
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int assumeinstalled_cmp(const void *data, const void *pkg)
+{
+ const alpm_depend_t *dep1 = ((alpm_list_t*)data)->data;
+ const alpm_depend_t *dep2 = pkg;
+
+ if(strcmp(dep1->name, dep2->name) && strcmp(dep1->version, dep2->version)) {
+ 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..4573e8e 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);
@@ -741,6 +742,22 @@ static int setup_libalpm(void)
alpm_option_set_noupgrades(handle, config->noupgrade);
alpm_option_set_noextracts(handle, config->noextract);
+ for(alpm_list_t *i = config->assumeinstalled; i; i = i->next) {
+ char *entry = i->data;
+ alpm_depend_t *dep = alpm_splitdep(entry);
+ if(!dep) {
+ pm_printf(ALPM_LOG_WARNING, _("Invalid format for assume installed entry. Skipping '%s'\n"), entry);
+ alpm_dep_free(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) {
+ 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..6c3c548 100644
--- a/test/pacman/tests/TESTS
+++ b/test/pacman/tests/TESTS
@@ -1,3 +1,6 @@
+TESTS += test/pacman/tests/assumeinstalled.py
+TESTS += test/pacman/tests/assumeinstalled_2.py
+TESTS += test/pacman/tests/assumeinstalled_3.py
TESTS += test/pacman/tests/clean001.py
TESTS += test/pacman/tests/clean002.py
TESTS += test/pacman/tests/clean003.py
diff --git a/test/pacman/tests/assumeinstalled.py b/test/pacman/tests/assumeinstalled.py
new file mode 100644
index 0000000..41b7750
--- /dev/null
+++ b/test/pacman/tests/assumeinstalled.py
@@ -0,0 +1,20 @@
+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")
+self.addrule("PKG_EXIST=pkg1")
diff --git a/test/pacman/tests/assumeinstalled_2.py b/test/pacman/tests/assumeinstalled_2.py
new file mode 100644
index 0000000..6744dc8
--- /dev/null
+++ b/test/pacman/tests/assumeinstalled_2.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/assumeinstalled_3.py b/test/pacman/tests/assumeinstalled_3.py
new file mode 100644
index 0000000..4f3630c
--- /dev/null
+++ b/test/pacman/tests/assumeinstalled_3.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")
--
2.1.0
More information about the pacman-dev
mailing list