diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c index 1ae7ab1d..c3ea3169 100644 --- a/lib/libalpm/remove.c +++ b/lib/libalpm/remove.c @@ -22,6 +22,7 @@ * along with this program. If not, see . */ +#include #include #include #include @@ -161,7 +162,7 @@ static void remove_prepare_keep_needed(alpm_handle_t *handle, alpm_list_t *lp) * @param handle the context handle * @param lp list of packages to be removed */ -static void remove_notify_needed_optdepends(alpm_handle_t *handle, alpm_list_t *lp) +static void remove_notify_needed_optdepends(alpm_handle_t *handle, alpm_list_t *lp, int remove_optdepends) { alpm_list_t *i; @@ -169,21 +170,29 @@ static void remove_notify_needed_optdepends(alpm_handle_t *handle, alpm_list_t * alpm_pkg_t *pkg = i->data; alpm_list_t *optdeps = alpm_pkg_get_optdepends(pkg); - if(optdeps && !alpm_pkg_find(lp, pkg->name)) { - alpm_list_t *j; - for(j = optdeps; j; j = alpm_list_next(j)) { - alpm_depend_t *optdep = j->data; - char *optstring = alpm_dep_compute_string(optdep); - if(alpm_find_satisfier(lp, optstring)) { + if (!optdeps || alpm_pkg_find(lp, pkg->name)) { + continue; + } + + alpm_list_t *j; + for(j = optdeps; j; j = alpm_list_next(j)) { + alpm_depend_t *optdep = j->data; + char *optstring = alpm_dep_compute_string(optdep); + if(alpm_find_satisfier(lp, optstring)) { + if (remove_optdepends) { + // -Rss, we delete optdepends alpm_event_optdep_removal_t event = { .type = ALPM_EVENT_OPTDEP_REMOVAL, .pkg = pkg, .optdep = optdep }; EVENT(handle, &event); + } else { + // -Rs, we keep optdepends + alpm_list_remove(lp, optdep, _alpm_pkg_dep_cmp, NULL); } - free(optstring); } + free(optstring); } } } @@ -257,7 +266,7 @@ int _alpm_remove_prepare(alpm_handle_t *handle, alpm_list_t **data) /* Note packages being removed that are optdepends for installed packages */ if(!(trans->flags & ALPM_TRANS_FLAG_NODEPS)) { - remove_notify_needed_optdepends(handle, trans->remove); + remove_notify_needed_optdepends(handle, trans->remove, (trans->flags & ALPM_TRANS_FLAG_RECURSEALL)); } if(!(trans->flags & ALPM_TRANS_FLAG_NODEPS)) { diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c index 7877b17a..f89b0001 100644 --- a/lib/libalpm/util.c +++ b/lib/libalpm/util.c @@ -835,6 +835,19 @@ int _alpm_ldconfig(alpm_handle_t *handle) return 0; } +/** Helper function for comparing names of a dependency and a package + * @param p1 void pointer of the package + * @param p2 void pointer of the dependency + * @return result of the comparison of the names + * */ +int _alpm_pkg_dep_cmp(const void *p1, const void *p2) +{ + alpm_pkg_t *pkg = (alpm_pkg_t *) p1; + alpm_depend_t *dep = (alpm_depend_t *) p2; + + return _alpm_str_cmp(pkg->name, dep->name); +} + /** Helper function for comparing strings using the alpm "compare func" * signature. * @param s1 first string to be compared diff --git a/lib/libalpm/util.h b/lib/libalpm/util.h index 5090c545..9af97c89 100644 --- a/lib/libalpm/util.h +++ b/lib/libalpm/util.h @@ -160,6 +160,8 @@ void *_alpm_realloc(void **data, size_t *current, const size_t required); void *_alpm_greedy_grow(void **data, size_t *current, const size_t required); alpm_errno_t _alpm_read_file(const char *filepath, unsigned char **data, size_t *data_len); +int _alpm_pkg_dep_cmp(const void *p1, const void *p2); + #ifndef HAVE_STRSEP char *strsep(char **, const char *); #endif diff --git a/test/pacman/meson.build b/test/pacman/meson.build index 4a73b600..3de04cd0 100644 --- a/test/pacman/meson.build +++ b/test/pacman/meson.build @@ -126,6 +126,7 @@ pacman_tests = [ 'tests/reason001.py', 'tests/remove-assumeinstalled.py', 'tests/remove-directory-replaced-with-symlink.py', + 'tests/remove-keep-optdepend-of-installed-package.py', 'tests/remove-optdepend-of-installed-package.py', 'tests/remove-print-empty-replacements.py', 'tests/remove-recursive-cycle.py', diff --git a/test/pacman/tests/remove-keep-optdepend-of-installed-package.py b/test/pacman/tests/remove-keep-optdepend-of-installed-package.py new file mode 100644 index 00000000..103e4802 --- /dev/null +++ b/test/pacman/tests/remove-keep-optdepend-of-installed-package.py @@ -0,0 +1,21 @@ +self.description = "Do not remove packages which is an optdepend of another package" + +p1 = pmpkg("a") +p1.depends = ["b"] +self.addpkg2db("local", p1) + +p2 = pmpkg("b") +self.addpkg2db("local", p2) + + +p3 = pmpkg("c") +p3.optdepends = ["b: for foobar"] +self.addpkg2db("local", p3) + +self.args = "-Rs %s" % p1.name + +self.addrule("PACMAN_RETCODE=0") +self.addrule("!PKG_EXIST=%s" % p1.name) +self.addrule("PKG_EXIST=%s" % p2.name) +self.addrule("PKG_EXIST=%s" % p3.name) +self.addrule("!PACMAN_OUTPUT=%s optionally requires %s" % (p3.name, p2.name)) diff --git a/test/pacman/tests/remove-optdepend-of-installed-package.py b/test/pacman/tests/remove-optdepend-of-installed-package.py index 4973df5f..10cbae3b 100644 --- a/test/pacman/tests/remove-optdepend-of-installed-package.py +++ b/test/pacman/tests/remove-optdepend-of-installed-package.py @@ -1,15 +1,21 @@ self.description = "Remove packages which is an optdepend of another package" -p1 = pmpkg("dep") +p1 = pmpkg("a") +p1.depends = ["b"] self.addpkg2db("local", p1) -p2 = pmpkg("pkg") -p2.optdepends = ["dep: for foobar"] +p2 = pmpkg("b") self.addpkg2db("local", p2) -self.args = "-R %s" % p1.name + +p3 = pmpkg("c") +p3.optdepends = ["b: for foobar"] +self.addpkg2db("local", p3) + +self.args = "-Rss %s" % p1.name self.addrule("PACMAN_RETCODE=0") self.addrule("!PKG_EXIST=%s" % p1.name) -self.addrule("PKG_EXIST=%s" % p2.name) -self.addrule("PACMAN_OUTPUT=%s optionally requires %s" % (p2.name, p1.name)) +self.addrule("!PKG_EXIST=%s" % p2.name) +self.addrule("PKG_EXIST=%s" % p3.name) +self.addrule("PACMAN_OUTPUT=%s optionally requires %s" % (p3.name, p2.name))