On 09/17/14 at 01:02am, Florian Pritz wrote:
This allows to ignore specific dependencies.
Signed-off-by: Florian Pritz <bluewind@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;
You're still returning a list of strings...
+} + 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; + } + }
No need to bother with add_assumeinstalled anymore. This can be a simple assignment like (most of) our other setters.
+ return 0; +} + +static int assumeinstalled_cmp(const void *data, const void *pkg)
data and pkg are misleading names, convention would have d1 and d2.
+{ + const alpm_depend_t *dep1 = ((alpm_list_t*)data)->data;
The comparison function gets the list item data, not an alpm_list_t*.
+ const alpm_depend_t *dep2 = pkg; + + if(strcmp(dep1->name, dep2->name) && strcmp(dep1->version, dep2->version)) {
Those should both be strcmp(...) == 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..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) {
i should be declared at the top of the block.
+ 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);
This is inconsistent. It's printed as a warning and says it's just skipping the invalid depend but then aborts pacman. Also, please wrap this closer to 80 columns.
+ alpm_dep_free(dep);
dep is NULL, there's nothing to free here.
+ 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) {
dep should be freed here and there should be an error message before aborting.
+ 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
These test names don't follow either our previous naming convention or the newer descriptive convention.
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")
PKG_VERSION already requires the package to exist, checking pkg1 again is redundant.
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