This allows to ignore specific dependencies. TODO: documentation Signed-off-by: Florian Pritz <bluewind@xinu.at> --- This patch is still missing documentation as noted in the commit message, but apart from that it works (at least alpm_option_set_ignoredeps(), didn't test _remove_). Now that I have a POC, could I get some feedback on the idea and the code? lib/libalpm/alpm.h | 11 ++++++ lib/libalpm/deps.c | 8 +++- lib/libalpm/handle.c | 89 ++++++++++++++++++++++++++++++++++++++++++ lib/libalpm/handle.h | 1 + src/pacman/conf.c | 2 + src/pacman/conf.h | 4 +- src/pacman/pacman.c | 4 ++ test/pacman/tests/TESTS | 1 + test/pacman/tests/ignoredep.py | 20 ++++++++++ 9 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 test/pacman/tests/ignoredep.py diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index db1e0cd..d5b2c4c 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_ignoredeps(alpm_handle_t *handle); +int alpm_option_add_ignoredep(alpm_handle_t *handle, const char *dep); +int alpm_option_set_ignoredeps(alpm_handle_t *handle, alpm_list_t *ignoredeps); +int alpm_option_remove_ignoredep(alpm_handle_t *handle, const char *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 1cbbc5f..6185542 100644 --- a/lib/libalpm/deps.c +++ b/lib/libalpm/deps.c @@ -338,8 +338,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) && + !find_dep_satisfier(handle->ignoredep, depend)) { /* Unsatisfied dependency in the upgrade list */ alpm_depmissing_t *miss; char *missdepstring = alpm_dep_compute_string(depend); @@ -368,9 +370,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) && + !find_dep_satisfier(handle->ignoredep, 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", diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c index 0842d51..cb378cc 100644 --- a/lib/libalpm/handle.c +++ b/lib/libalpm/handle.c @@ -86,6 +86,10 @@ void _alpm_handle_free(alpm_handle_t *handle) FREELIST(handle->noextract); FREELIST(handle->ignorepkg); FREELIST(handle->ignoregroup); + + alpm_list_free_inner(handle->ignoredep, (alpm_list_fn_free)_alpm_pkg_free); + alpm_list_free(handle->ignoredep); + FREE(handle); } @@ -234,6 +238,12 @@ alpm_list_t SYMEXPORT *alpm_option_get_ignoregroups(alpm_handle_t *handle) return handle->ignoregroup; } +alpm_list_t SYMEXPORT *alpm_option_get_ignoredeps(alpm_handle_t *handle) +{ + CHECK_HANDLE(handle, return NULL); + return handle->ignoredep; +} + const char SYMEXPORT *alpm_option_get_arch(alpm_handle_t *handle) { CHECK_HANDLE(handle, return NULL); @@ -552,6 +562,85 @@ int SYMEXPORT alpm_option_remove_ignoregroup(alpm_handle_t *handle, const char * return 0; } +static alpm_pkg_t* parse_ignoredep(const char *dep) +{ + char *entry = strdup(dep); + char *save, *token; + + alpm_pkg_t *pkg = _alpm_pkg_new(); + pkg->ops = &default_pkg_ops; + + pkg->name = strdup(strtok_r(entry, "=", &save)); + pkg->name_hash = _alpm_hash_sdbm(pkg->name); + + token = strtok_r(save, "=", &save); + if (token) { + pkg->version = strdup(token); + } else { + _alpm_pkg_free(pkg); + pkg = NULL; + } + + free(entry); + return pkg; +} + +int SYMEXPORT alpm_option_add_ignoredep(alpm_handle_t *handle, const char *dep) +{ + CHECK_HANDLE(handle, return -1); + + alpm_pkg_t *pkg = parse_ignoredep(dep); + if (!pkg) { + _alpm_log(handle, ALPM_LOG_WARNING, "Invalid format for dependency ignore entry. Skipping '%s'\n", dep); + return 1; + } + + pkg->handle = handle; + handle->ignoredep = alpm_list_add(handle->ignoredep, pkg); + return 0; +} + +int SYMEXPORT alpm_option_set_ignoredeps(alpm_handle_t *handle, alpm_list_t *ignoredeps) +{ + CHECK_HANDLE(handle, return -1); + if(handle->ignoredep) { + alpm_list_free_inner(handle->ignoredep, (alpm_list_fn_free)_alpm_pkg_free); + alpm_list_free(handle->ignoredep); + } + for (alpm_list_t *i = ignoredeps; i; i = i->next) { + alpm_option_add_ignoredep(handle, i->data); + } + return 0; +} + +static int ignoredep_cmp(const void *data, const void *dep) +{ + alpm_pkg_t *pkg1 = ((alpm_list_t*)data)->data; + alpm_pkg_t *pkg2 = parse_ignoredep(dep); + + if (!pkg2) { + return -1; + } + + if (pkg1->name == pkg2->name && pkg1->version == pkg2->version) { + return 0; + } + + return -1; +} + +int SYMEXPORT alpm_option_remove_ignoredep(alpm_handle_t *handle, const char *dep) +{ + alpm_pkg_t *vdata = NULL; + CHECK_HANDLE(handle, return -1); + handle->ignoredep = alpm_list_remove(handle->ignoredep, dep, &ignoredep_cmp, (void **)&vdata); + if(vdata != NULL) { + alpm_pkg_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..f164e1c 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 *ignoredep; /* List of packages to ignore dependencies on */ /* options */ char *arch; /* Architecture of packages we should allow */ diff --git a/src/pacman/conf.c b/src/pacman/conf.c index 0e483f7..0d7a605 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->ignoredep); FREELIST(oldconfig->noupgrade); FREELIST(oldconfig->noextract); free(oldconfig->configfile); @@ -738,6 +739,7 @@ static int setup_libalpm(void) alpm_option_set_ignorepkgs(handle, config->ignorepkg); alpm_option_set_ignoregroups(handle, config->ignoregrp); + alpm_option_set_ignoredeps(handle, config->ignoredep); alpm_option_set_noupgrades(handle, config->noupgrade); alpm_option_set_noextracts(handle, config->noextract); diff --git a/src/pacman/conf.h b/src/pacman/conf.h index e8cac50..0e5c86f 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 *ignoredep; 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_IGNOREDEP }; /* clean method */ diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index e8c5f9e..3837df4 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -704,6 +704,9 @@ static int parsearg_upgrade(int opt) case OP_IGNOREGROUP: parsearg_util_addlist(&(config->ignoregrp)); break; + case OP_IGNOREDEP: + parsearg_util_addlist(&(config->ignoredep)); + break; default: return 1; } return 0; @@ -852,6 +855,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}, + {"ignore-depends", required_argument, 0, OP_IGNOREDEP}, {"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 dc47294..8528000 100644 --- a/test/pacman/tests/TESTS +++ b/test/pacman/tests/TESTS @@ -57,6 +57,7 @@ TESTS += test/pacman/tests/ignore005.py TESTS += test/pacman/tests/ignore006.py TESTS += test/pacman/tests/ignore007.py TESTS += test/pacman/tests/ignore008.py +TESTS += test/pacman/tests/ignoredep.py TESTS += test/pacman/tests/ldconfig001.py TESTS += test/pacman/tests/ldconfig002.py TESTS += test/pacman/tests/ldconfig003.py diff --git a/test/pacman/tests/ignoredep.py b/test/pacman/tests/ignoredep.py new file mode 100644 index 0000000..d66ec09 --- /dev/null +++ b/test/pacman/tests/ignoredep.py @@ -0,0 +1,20 @@ +self.description = "Update a package using --ignore-depends" + +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 --ignore-depends 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") -- 2.0.0