Hi, forgive me if I'm doing this wrong, I'm new to git and this is the first time I've tried to supply a git patch to this list. My patch is attached to this email - is that the correct way to send it to the list? Some notes on this patch: - It is based on the current git sources instead of the release version of the code as was my previous patch on this same topic - It takes into consideration the following feedback from the list on my previous patch: - Fixed static function names (static void _alpm_xxx -> static void xxx) - Removed the prompt that asks the user if they want to un-ignore packages that have upgrades for the current transaction. The reasoning is that if the user didn't want to ignore the package, they wouldn't have put them in their IgnorePkg list, so why ask them during an upgrade? Instead just expect the user to remove packages from IgnorePkg that they don't actually want to ignore. - Removed the NoIgnorePrompt configuration option that I had previously added since instead I'm just removing that prompt altogether - Fixed the issue where if a top-level package is depended upon by unresolvable top-level packages, it would be removed from the transaction, whereas really it should be retained - Fixed the infinite loop when there are dependency loops - Added a few new test cases to pactest: ignore001,ignore002, and ignore003, which test some new ignore package functionality - Changed the expected results of some existing test cases (provision020, provision022, sync021, sync1008, and sync300) because with the new functionality, pacman succeeds in cases where it used to fail (simply ignoring packages which cannot be upgraded instead of issuing an error) even though the results are the same, and also, because the new behavior means that there is no way to sync a group that has a package that is ignored in it (it used to work if the user said 'yes' to the prompt that I have removed, now there is no such prompt and thus no opportunity to un-ignore the offending package) - And one VERY IMPORTANT note: this change means that the release version of libalpm needs to be increased, so it should be libalpm.so.4 instead of libalpm.so.3. This is because a new callback prompt was added and an old one removed. The latter shouldn't affect existing front-end (they just won't get asked a question that they used to get asked), but the former will likely break any front-end by sending a callback with a new "Transaction Conversation" identifier. Comments welcome! Thanks, Bryan From 4a9236bb54031eb4f447279ce40d86d0c6db7da5 Mon Sep 17 00:00:00 2001 From: Bryan Ischo <bryan@ischo.com> Date: Mon, 12 Jan 2009 17:05:02 +1300 Subject: [PATCH] Changed behavior of transactions to optionally remove packages which cannot be resolved This fixes incident 9395, by providing for a call-out from the transaction resolve step to the front-end, asking the user if they would like to ignore any packages which could not be upgraded due to unresolvable dependencies. In most cases, such dependencies are due to packages in IgnorePkg/IgnoreGroup on which packages to upgrade depend. Simply removing the offending packages from the transaction rather than failing the transaction allows such transactions to proceed and do the work that can be done. This makes managing packages with IgnorePkg/IgnoreGroup much easier. Also removed the prompt which asks the user if they'd like to not ignore packages in IgnorePkg/IgnoreGroup, because this is an unnecessary prompt - if the user wants to do this, they can do it in their /etc/pacman.conf, they don't need pacman to prompt them about it every time they do an upgrade. Finally, changed the expected behavior of some tests, to match the new transaction behavior. Signed-off-by: Bryan Ischo <bryan@ischo.com> --- lib/libalpm/alpm.h | 4 +- lib/libalpm/deps.c | 259 +++++++++++++++++++++++++++++++++++------ lib/libalpm/deps.h | 4 +- lib/libalpm/sync.c | 11 +- pactest/README | 14 +-- pactest/tests/ignore001.py | 17 +++ pactest/tests/ignore002.py | 35 ++++++ pactest/tests/ignore003.py | 35 ++++++ pactest/tests/provision020.py | 2 +- pactest/tests/provision022.py | 2 +- pactest/tests/sync021.py | 4 +- pactest/tests/sync1008.py | 2 +- pactest/tests/sync300.py | 2 +- src/pacman/callback.c | 36 ++++-- 14 files changed, 356 insertions(+), 71 deletions(-) create mode 100644 pactest/tests/ignore001.py create mode 100644 pactest/tests/ignore002.py create mode 100644 pactest/tests/ignore003.py diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index eda35d3..68d99f7 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -372,12 +372,12 @@ typedef enum _pmtransevt_t { /* Transaction Conversations (ie, questions) */ typedef enum _pmtransconv_t { - PM_TRANS_CONV_INSTALL_IGNOREPKG = 0x01, + /* 0x01 is available */ PM_TRANS_CONV_REPLACE_PKG = 0x02, PM_TRANS_CONV_CONFLICT_PKG = 0x04, PM_TRANS_CONV_CORRUPTED_PKG = 0x08, PM_TRANS_CONV_LOCAL_NEWER = 0x10, - /* 0x20 flag can go here */ + PM_TRANS_CONV_REMOVE_PKGS = 0x20, PM_TRANS_CONV_REMOVE_HOLDPKG = 0x40 } pmtransconv_t; diff --git a/lib/libalpm/deps.c b/lib/libalpm/deps.c index 96c971a..3abac06 100644 --- a/lib/libalpm/deps.c +++ b/lib/libalpm/deps.c @@ -513,12 +513,7 @@ pmpkg_t *_alpm_resolvedep(pmdepend_t *dep, alpm_list_t *dbs, alpm_list_t *exclud pmpkg_t *pkg = _alpm_db_get_pkgfromcache(i->data, dep->name); if(pkg && alpm_depcmp(pkg, dep) && !_alpm_pkg_find(excluding, pkg->name)) { if(_alpm_pkg_should_ignore(pkg)) { - int install; - QUESTION(handle->trans, PM_TRANS_CONV_INSTALL_IGNOREPKG, pkg, - tpkg, NULL, &install); - if(!install) { - continue; - } + continue; } return(pkg); } @@ -530,12 +525,7 @@ pmpkg_t *_alpm_resolvedep(pmdepend_t *dep, alpm_list_t *dbs, alpm_list_t *exclud if(alpm_depcmp(pkg, dep) && strcmp(pkg->name, dep->name) && !_alpm_pkg_find(excluding, pkg->name)) { if(_alpm_pkg_should_ignore(pkg)) { - int install; - QUESTION(handle->trans, PM_TRANS_CONV_INSTALL_IGNOREPKG, pkg, - tpkg, NULL, &install); - if(!install) { - continue; - } + continue; } _alpm_log(PM_LOG_WARNING, _("provider package was selected (%s provides %s)\n"), pkg->name, dep->name); @@ -546,17 +536,108 @@ pmpkg_t *_alpm_resolvedep(pmdepend_t *dep, alpm_list_t *dbs, alpm_list_t *exclud return(NULL); } +typedef struct __pkginfo_t +{ + /* The package for which this info is being kept */ + pmpkg_t *pkg; + /* 0 if this package has been determined to be unresolvable, meaning that + it has dependencies that cannot be resolved, nonzero otherwise */ + int unresolvable; + /* 0 if this package was not pulled, nonzero if this package was pulled */ + int pulled; + /* Packages that are immediately dependent on this package. */ + alpm_list_t *dependents; + /* This marker is used to detect when a dependency cycle exists */ + int marker; +} pkginfo_t; + + +static pkginfo_t *findinfo(alpm_list_t *list, pmpkg_t *pkg) +{ + alpm_list_t *i; + + for (i = list; i; i = i->next) { + pkginfo_t *info = (pkginfo_t *) i->data; + if (info->pkg == pkg) { + return info; + } + } + + return NULL; +} + + +static void mark_unresolvable(alpm_list_t *list, pkginfo_t *info) +{ + alpm_list_t *i; + + if (info->unresolvable) { + return; + } + + info->unresolvable = 1; + + for (i = info->dependents; i; i = i->next) { + mark_unresolvable(list, findinfo(list, ((pmpkg_t *) i->data))); + } +} + +static void info_free(pkginfo_t *info) +{ + alpm_list_free(info->dependents); + free(info); +} + + +static int is_needed(alpm_list_t *infolist, pkginfo_t *info, int marker) +{ + if (info->unresolvable) { + /* Obviously if it's already been marked unresolvable, it is not + needed */ + return(0); + } else if (!info->pulled) { + /* If it's top-level (not pulled), then it's needed */ + return(1); + } else { + /* Now, if all of the top-level packages which depend on it are + unresolvable, then it is unneeded */ + alpm_list_t *i; + for (i = info->dependents; i; i = i->next) { + pmpkg_t *deppkg = (pmpkg_t *) i->data; + if (info->marker == marker) { + /* This means that a dependency loop has been detected; we've + already marked this package meaning that it's already been + seen this time through. So ignore this dependency. */ + continue; + } + + info->marker = marker; + + if (!is_needed(infolist, findinfo(infolist, deppkg), marker)) { + return(0); + } + } + + return(1); + } +} + + /* populates list with packages that need to be installed to satisfy all * dependencies of packages in list * * @param remove contains packages elected for removal */ -int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, alpm_list_t *list, - alpm_list_t *remove, alpm_list_t **data) +int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, alpm_list_t **list, + alpm_list_t **pulled, alpm_list_t *remove, alpm_list_t **data) { + int marker = 0; + int ret = 0; alpm_list_t *i, *j; alpm_list_t *targ; alpm_list_t *deps = NULL; + alpm_list_t *info = NULL; + alpm_list_t *unresolvable = NULL; ALPM_LOG_FUNC; @@ -565,8 +646,30 @@ int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, alpm_list_t *list, } _alpm_log(PM_LOG_DEBUG, "started resolving dependencies\n"); - for(i = list; i; i = i->next) { + + /* Build up a list of pkginfo_t structures describing the root level + packages */ + for(i = *list; i; i = i->next) { + pkginfo_t *thisinfo; + thisinfo = (pkginfo_t *) malloc(sizeof(pkginfo_t)); + if (thisinfo == NULL) { + pm_errno = PM_ERR_MEMORY; + ret = -1; + goto cleanup; + } + thisinfo->pkg = i->data; + thisinfo->unresolvable = 0; + thisinfo->pulled = 0; + thisinfo->dependents = NULL; + thisinfo->marker = 0; + info = alpm_list_add(info, thisinfo); + } + + /* Now resolve */ + for(i = *list; i; i = i->next) { pmpkg_t *tpkg = i->data; + /* Find the info for tpkg */ + pkginfo_t *tinfo = findinfo(info, tpkg); targ = alpm_list_add(NULL, tpkg); deps = alpm_checkdeps(_alpm_db_get_pkgcache(local), 0, remove, targ); alpm_list_free(targ); @@ -574,38 +677,122 @@ int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, alpm_list_t *list, pmdepmissing_t *miss = j->data; pmdepend_t *missdep = alpm_miss_get_dep(miss); /* check if one of the packages in list already satisfies this dependency */ - if(_alpm_find_dep_satisfier(list, missdep)) { + pmpkg_t *spkg = _alpm_find_dep_satisfier(*list, missdep); + if(spkg != NULL) { + /* Check spkg to make sure that it was not unresolvable; if it is, mark tpkg as + unresolvable also */ + pkginfo_t *sinfo = findinfo(info, spkg); + if (sinfo->unresolvable) { + mark_unresolvable(info, tinfo); + /* No need to do any further dependency + checking for tpkg, even if it has other + dependencies, tpkg will not be installed + because it is not resolvable */ + break; + } + sinfo->dependents = alpm_list_add(sinfo->dependents, tpkg); continue; } /* find a satisfier package in the given repositories */ - pmpkg_t *spkg = _alpm_resolvedep(missdep, dbs_sync, list, tpkg); - if(!spkg) { - pm_errno = PM_ERR_UNSATISFIED_DEPS; - char *missdepstring = alpm_dep_get_string(missdep); - _alpm_log(PM_LOG_ERROR, _("cannot resolve \"%s\", a dependency of \"%s\"\n"), - missdepstring, tpkg->name); - free(missdepstring); - if(data) { - pmdepmissing_t *missd = _alpm_depmiss_new(miss->target, - miss->depend, miss->causingpkg); - if(missd) { - *data = alpm_list_add(*data, missd); - } - } - alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_depmiss_free); - alpm_list_free(deps); - return(-1); - } else { + spkg = _alpm_resolvedep(missdep, dbs_sync, *list, tpkg); + if(spkg != NULL) { _alpm_log(PM_LOG_DEBUG, "pulling dependency %s (needed by %s)\n", alpm_pkg_get_name(spkg), alpm_pkg_get_name(tpkg)); - list = alpm_list_add(list, spkg); + *list = alpm_list_add(*list, spkg); + pkginfo_t *sinfo; + sinfo = (pkginfo_t *) malloc(sizeof(pkginfo_t)); + if (sinfo == NULL) { + pm_errno = PM_ERR_MEMORY; + ret = -1; + goto cleanup; + } + sinfo->pkg = spkg; + sinfo->unresolvable = 0; + sinfo->pulled = 1; + sinfo->dependents = alpm_list_add(NULL, tpkg); + info = alpm_list_add(info, sinfo); + } else { + /* tpkg is not resolvable, so mark it and all of + its dependents as such */ + mark_unresolvable(info, tinfo); } } alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_depmiss_free); alpm_list_free(deps); + deps = NULL; } + + /* Build up a list of unresolvable top-level packages, so that they + can be queried about */ + for(i = info; i; i = i->next) { + pkginfo_t *info = (pkginfo_t *) i->data; + if (info->unresolvable && !info->pulled) { + unresolvable = alpm_list_add(unresolvable, info->pkg); + } + } + + /* If there were unresolvable packages, query the user to see if they + should be removed from the transaction */ + if(unresolvable != NULL) { + int remove_unresolved = 0; + QUESTION(handle->trans, PM_TRANS_CONV_REMOVE_PKGS, unresolvable, NULL, NULL, &remove_unresolved); + if (remove_unresolved) { + /* Need to remove all packages which are: + - unresolvable, OR + - are pulled elements whose entire list of top-level + dependents are unresolvable */ + for (i = info; i; i = i->next) { + pkginfo_t *thisinfo = (pkginfo_t *) i->data; + if (!is_needed(info, thisinfo, ++marker)) { + *list = alpm_list_remove(*list, thisinfo->pkg, _alpm_pkg_cmp, NULL); + } + } + } else { + alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_depmiss_free); + alpm_list_free(deps); + deps = NULL; + pm_errno = PM_ERR_UNSATISFIED_DEPS; + _alpm_log(PM_LOG_ERROR, _("cannot resolve dependencies for:\n")); + for (i = unresolvable; i; i = i->next) { + _alpm_log(PM_LOG_ERROR, _("\t%s\n"), alpm_pkg_get_name((pmpkg_t *) i->data)); + if (data) { + alpm_list_t *targ = alpm_list_add(NULL, i->data); + deps = alpm_checkdeps(_alpm_db_get_pkgcache(local), 0, remove, targ); + alpm_list_free(targ); + } + } + for(i = deps; i; i = i->next) { + pmdepmissing_t *miss = i->data; + pmdepmissing_t *missd = _alpm_depmiss_new(miss->target, miss->depend, miss->causingpkg); + if(missd) { + *data = alpm_list_add(*data, missd); + } + } + ret = -1; + } + } + + /* Set pulled to be the last top-level item in the list */ + *pulled = NULL; + for(i = *list; i; i = i->next) { + pkginfo_t *thisinfo = findinfo(info, i->data); + if (thisinfo->pulled) { + *pulled = i; + break; + } + } + + cleanup: + + alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_depmiss_free); + alpm_list_free(deps); + alpm_list_free_inner(info, (alpm_list_fn_free)info_free); + alpm_list_free(info); + alpm_list_free(unresolvable); + _alpm_log(PM_LOG_DEBUG, "finished resolving dependencies\n"); - return(0); + + return(ret); } /* Does pkg1 depend on pkg2, ie. does pkg2 satisfy a dependency of pkg1? */ diff --git a/lib/libalpm/deps.h b/lib/libalpm/deps.h index 2f3c450..f281452 100644 --- a/lib/libalpm/deps.h +++ b/lib/libalpm/deps.h @@ -48,8 +48,8 @@ void _alpm_depmiss_free(pmdepmissing_t *miss); alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, int reverse); void _alpm_recursedeps(pmdb_t *db, alpm_list_t *targs, int include_explicit); pmpkg_t *_alpm_resolvedep(pmdepend_t *dep, alpm_list_t *dbs, alpm_list_t *excluding, pmpkg_t *tpkg); -int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, alpm_list_t *list, - alpm_list_t *remove, alpm_list_t **data); +int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, alpm_list_t **list, + alpm_list_t **pulled, alpm_list_t *remove, alpm_list_t **data); int _alpm_dep_edge(pmpkg_t *pkg1, pmpkg_t *pkg2); pmdepend_t *_alpm_splitdep(const char *depstring); pmpkg_t *_alpm_find_dep_satisfier(alpm_list_t *pkgs, pmdepend_t *dep); diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index b458874..5741262 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -417,9 +417,10 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync } if(!(trans->flags & PM_TRANS_FLAG_NODEPS)) { - /* store a pointer to the last original target so we can tell what was - * pulled by resolvedeps */ - alpm_list_t *pulled = alpm_list_last(list); + /* resolvedeps returns a pointer to the first element of the + * list which is a pulled element, and all elements after that + * are pulled as well */ + alpm_list_t *pulled; /* Resolve targets dependencies */ EVENT(trans, PM_TRANS_EVT_RESOLVEDEPS_START, NULL, NULL); _alpm_log(PM_LOG_DEBUG, "resolving target's dependencies\n"); @@ -432,13 +433,13 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync } } - if(_alpm_resolvedeps(db_local, dbs_sync, list, remove, data) == -1) { + if(_alpm_resolvedeps(db_local, dbs_sync, &list, &pulled, remove, data) == -1) { /* pm_errno is set by resolvedeps */ ret = -1; goto cleanup; } - for(i = pulled->next; i; i = i->next) { + for(i = pulled; i; i = i->next) { pmpkg_t *spkg = i->data; pmsyncpkg_t *sync = _alpm_sync_new(PM_PKG_REASON_DEPEND, spkg, NULL); if(sync == NULL) { diff --git a/pactest/README b/pactest/README index 5d4e47f..c7d00f7 100644 --- a/pactest/README +++ b/pactest/README @@ -70,12 +70,12 @@ Usage pactest will run the suite of tests defined by the "--test" parameter. Example: - ./pactest.py --test=test/* + ./pactest.py --test tests/*.py -This example will run tests from the "test" directory. +This example will run all tests from the "tests" directory. Note: several "--test" options can be passed to pactest. -Use the ""help" option to get the full list of parameters: +Use the "help" option to get the full list of parameters: ./pactest.py --help @@ -103,15 +103,11 @@ Example: ------ A dictionary that holds the data used in the pacman configuration file. -It has 3 keys, each one of them pointing at a list of strings: - - noupgrade - - noextract - - ignorepkg Examples: - self.option["noupgrade"] = ["etc/X11/xorg.conf", + self.option["NoUpgrade"] = ["etc/X11/xorg.conf", "etc/pacman.conf"] - self.option["noextract"] = ["etc/lilo.conf"] + self.option["NoExtract"] = ["etc/lilo.conf"] filesystem ---------- diff --git a/pactest/tests/ignore001.py b/pactest/tests/ignore001.py new file mode 100644 index 0000000..bf8e8c6 --- /dev/null +++ b/pactest/tests/ignore001.py @@ -0,0 +1,17 @@ +self.description = "Sync with irrelevent ignored packages" + +package1 = pmpkg("package1") +self.addpkg2db("local", package1) + +package2 = pmpkg("package2") +self.addpkg2db("local", package2) + +package2up = pmpkg("package2", "2.0-1") +self.addpkg2db("sync", package2up) + +self.option["IgnorePkg"] = ["irrelevent"] +self.args = "-Su" + +self.addrule("PACMAN_RETCODE=0") +self.addrule("PKG_VERSION=package1|1.0-1") +self.addrule("PKG_VERSION=package2|2.0-1") diff --git a/pactest/tests/ignore002.py b/pactest/tests/ignore002.py new file mode 100644 index 0000000..b64b70a --- /dev/null +++ b/pactest/tests/ignore002.py @@ -0,0 +1,35 @@ +self.description = "Sync with relevent ignored packages" + +package1 = pmpkg("package1") +self.addpkg2db("local", package1) + +package2 = pmpkg("package2") +self.addpkg2db("local", package2) + +package3 = pmpkg("package3") +package3.depends = ["package2=1.0-1"] +self.addpkg2db("local", package3) + +package4 = pmpkg("package4") +package4.depends = ["package3=1.0-1"] +self.addpkg2db("local", package4) + +package2up = pmpkg("package2", "2.0-1") +self.addpkg2db("sync", package2up) + +package3up = pmpkg("package3", "2.0-1") +package3up.depends = ["package2=2.0-1"] +self.addpkg2db("sync", package3up) + +package4up = pmpkg("package4", "2.0-1") +package4up.depends = ["package3=2.0-1"] +self.addpkg2db("sync", package4up) + +self.option["IgnorePkg"] = ["package2"] +self.args = "-Su" + +self.addrule("PACMAN_RETCODE=0") +self.addrule("PKG_VERSION=package1|1.0-1") +self.addrule("PKG_VERSION=package2|1.0-1") +self.addrule("PKG_VERSION=package3|1.0-1") +self.addrule("PKG_VERSION=package4|1.0-1") diff --git a/pactest/tests/ignore003.py b/pactest/tests/ignore003.py new file mode 100644 index 0000000..f7c1658 --- /dev/null +++ b/pactest/tests/ignore003.py @@ -0,0 +1,35 @@ +self.description = "Sync with relevent ignored packages and dependency loop" + +package1 = pmpkg("package1") +self.addpkg2db("local", package1) + +package2 = pmpkg("package2") +self.addpkg2db("local", package2) + +package3 = pmpkg("package3") +package3.depends = ["package2=1.0-1"] +self.addpkg2db("local", package3) + +package4 = pmpkg("package4") +package4.depends = ["package3=1.0-1"] +self.addpkg2db("local", package4) + +package2up = pmpkg("package2", "2.0-1") +self.addpkg2db("sync", package2up) + +package3up = pmpkg("package3", "2.0-1") +package3up.depends = ["package2=2.0-1", "package4=2.0-1"] +self.addpkg2db("sync", package3up) + +package4up = pmpkg("package4", "2.0-1") +package4up.depends = ["package3=2.0-1"] +self.addpkg2db("sync", package4up) + +self.option["IgnorePkg"] = ["package2"] +self.args = "-Su" + +self.addrule("PACMAN_RETCODE=0") +self.addrule("PKG_VERSION=package1|1.0-1") +self.addrule("PKG_VERSION=package2|1.0-1") +self.addrule("PKG_VERSION=package3|1.0-1") +self.addrule("PKG_VERSION=package4|1.0-1") diff --git a/pactest/tests/provision020.py b/pactest/tests/provision020.py index 7cb0a01..c9c0ac3 100644 --- a/pactest/tests/provision020.py +++ b/pactest/tests/provision020.py @@ -10,6 +10,6 @@ self.args = "-S %s" % p.name -self.addrule("PACMAN_RETCODE=1") +self.addrule("PACMAN_RETCODE=0") self.addrule("!PKG_EXIST=pkg1") self.addrule("PKG_EXIST=pkg2") diff --git a/pactest/tests/provision022.py b/pactest/tests/provision022.py index 4883d42..190a8b6 100644 --- a/pactest/tests/provision022.py +++ b/pactest/tests/provision022.py @@ -10,6 +10,6 @@ self.args = "-S %s" % p.name -self.addrule("PACMAN_RETCODE=1") +self.addrule("PACMAN_RETCODE=0") self.addrule("!PKG_EXIST=pkg1") self.addrule("PKG_EXIST=pkg2") diff --git a/pactest/tests/sync021.py b/pactest/tests/sync021.py index 4c664d8..bb1c277 100644 --- a/pactest/tests/sync021.py +++ b/pactest/tests/sync021.py @@ -16,6 +16,6 @@ self.args = "-S grp" -self.addrule("PACMAN_RETCODE=0") +self.addrule("!PACMAN_RETCODE=0") for p in sp1, sp2, sp3: - self.addrule("PKG_EXIST=%s" % p.name) + self.addrule("!PKG_EXIST=%s" % p.name) diff --git a/pactest/tests/sync1008.py b/pactest/tests/sync1008.py index a606459..90c61df 100644 --- a/pactest/tests/sync1008.py +++ b/pactest/tests/sync1008.py @@ -14,6 +14,6 @@ self.args = "-S pkg" -self.addrule("PACMAN_RETCODE=1") +self.addrule("PACMAN_RETCODE=0") self.addrule("!PKG_EXIST=pkg") self.addrule("!PKG_EXIST=cpkg") diff --git a/pactest/tests/sync300.py b/pactest/tests/sync300.py index 31b520a..36d6758 100644 --- a/pactest/tests/sync300.py +++ b/pactest/tests/sync300.py @@ -9,6 +9,6 @@ self.args = "-S %s" % sp1.name -self.addrule("PACMAN_RETCODE=1") +self.addrule("PACMAN_RETCODE=0") self.addrule("!PKG_EXIST=pkg1") self.addrule("!PKG_EXIST=pkg2") diff --git a/src/pacman/callback.c b/src/pacman/callback.c index 9f1cca8..e478bf5 100644 --- a/src/pacman/callback.c +++ b/src/pacman/callback.c @@ -247,17 +247,6 @@ void cb_trans_conv(pmtransconv_t event, void *data1, void *data2, void *data3, int *response) { switch(event) { - case PM_TRANS_CONV_INSTALL_IGNOREPKG: - if(data2) { - /* TODO we take this route based on data2 being not null? WTF */ - *response = yesno(_(":: %s requires installing %s from IgnorePkg/IgnoreGroup. Install anyway?"), - alpm_pkg_get_name(data2), - alpm_pkg_get_name(data1)); - } else { - *response = yesno(_(":: %s is in IgnorePkg/IgnoreGroup. Install anyway?"), - alpm_pkg_get_name(data1)); - } - break; case PM_TRANS_CONV_REMOVE_HOLDPKG: *response = yesno(_(":: %s is designated as a HoldPkg. Remove anyway?"), alpm_pkg_get_name(data1)); @@ -274,6 +263,31 @@ void cb_trans_conv(pmtransconv_t event, void *data1, void *data2, (char *)data2, (char *)data2); break; + case PM_TRANS_CONV_REMOVE_PKGS: + { + /* Allocate a buffer big enough to hold all of the + package names */ + char *packagenames; + alpm_list_t *unresolved = (alpm_list_t *) data1; + alpm_list_t *i; + int len = 1, /* for trailing \0 */ where = 0, count = 0; + for (i = unresolved; i; i = i->next) { + count += 1; + len += 3 /* for \t, comma, and \n */ + + strlen(alpm_pkg_get_name(i->data)); + } + packagenames = (char *) malloc(len); + for (i = unresolved; i; i = i->next) { + where += snprintf(&(packagenames[where]), len - where, "\t%s%s\n", + alpm_pkg_get_name(i->data), (i->next) ? "," : ""); + } + *response = yesno(_(":: the following package%s cannot be upgraded due to unresolvable " + "dependencies:\n%s\nDo you want to skip %s package%s for this upgrade?"), + (count > 1) ? "s" : "", packagenames, (count > 1) ? "these" : "this", + (count > 1) ? "s" : ""); + free(packagenames); + } + break; case PM_TRANS_CONV_LOCAL_NEWER: if(!config->op_s_downloadonly) { *response = yesno(_(":: %s-%s: local version is newer. Upgrade anyway?"), -- 1.6.1