Hi, attached is a patch to fix bug 9395, against the current git tree
for pacman, as described in an earlier email to this list. You may find
a description of the changes I made in the Arch bug database for bug
9395. Please let me know if there are any questions.
Thank you, and best wishes,
Bryan
diff -rupN -x '*\.git*' pacman/doc/pacman.8.txt pacman-fixbug9395/doc/pacman.8.txt
--- pacman/doc/pacman.8.txt 2008-12-31 16:45:31.000000000 +1300
+++ pacman-fixbug9395/doc/pacman.8.txt 2008-12-31 17:52:33.000000000 +1300
@@ -152,6 +152,11 @@ Options
If an install scriptlet exists, do not execute it. Do not use this
unless you know what you are doing.
+*\--noignoreprompt*::
+ Do not prompt the user to ask for confirmation that packages listed in
+ IgnorePkg and IgnoreGroup really should be ignored; instead, assume
+ that they should be and silently ignore them.
+
Query Options[[QO]]
-------------------
diff -rupN -x '*\.git*' pacman/lib/libalpm/alpm.h pacman-fixbug9395/lib/libalpm/alpm.h
--- pacman/lib/libalpm/alpm.h 2008-12-31 16:45:31.000000000 +1300
+++ pacman-fixbug9395/lib/libalpm/alpm.h 2008-12-31 17:59:38.000000000 +1300
@@ -377,7 +377,7 @@ typedef enum _pmtransconv_t {
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 -rupN -x '*\.git*' pacman/lib/libalpm/deps.c pacman-fixbug9395/lib/libalpm/deps.c
--- pacman/lib/libalpm/deps.c 2008-12-31 16:45:31.000000000 +1300
+++ pacman-fixbug9395/lib/libalpm/deps.c 2008-12-31 17:52:41.000000000 +1300
@@ -546,17 +546,92 @@ pmpkg_t *_alpm_resolvedep(pmdepend_t *de
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;
+} pkginfo_t;
+
+
+static pkginfo_t *_alpm_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 _alpm_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) {
+ _alpm_mark_unresolvable(list, _alpm_findinfo(list, ((pmpkg_t *) i->data)));
+ }
+}
+
+static void _alpm_info_free(pkginfo_t *info)
+{
+ alpm_list_free(info->dependents);
+ free(info);
+}
+
+
+static int _alpm_is_needed(alpm_list_t *infolist, pkginfo_t *info)
+{
+ /* Obviously if it's already been marked unresolvable, it is not needed */
+ if (info->unresolvable) {
+ return(0);
+ }
+ /* Now, if all of the top-level packages which depend on it are
+ unresolvable, then it is unneeded */
+ else {
+ alpm_list_t *i;
+ for (i = info->dependents; i; i = i->next) {
+ if (!_alpm_is_needed(infolist, _alpm_findinfo(infolist, (pmpkg_t *) i->data))) {
+ 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 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 +640,29 @@ int _alpm_resolvedeps(pmdb_t *local, alp
}
_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;
+ 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 = _alpm_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 +670,122 @@ int _alpm_resolvedeps(pmdb_t *local, alp
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 = _alpm_findinfo(info, spkg);
+ if (sinfo->unresolvable) {
+ _alpm_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 */
+ _alpm_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 (!_alpm_is_needed(info, thisinfo)) {
+ *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 = _alpm_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)_alpm_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 -rupN -x '*\.git*' pacman/lib/libalpm/deps.h pacman-fixbug9395/lib/libalpm/deps.h
--- pacman/lib/libalpm/deps.h 2008-12-31 16:45:31.000000000 +1300
+++ pacman-fixbug9395/lib/libalpm/deps.h 2008-12-31 17:52:41.000000000 +1300
@@ -48,8 +48,8 @@ void _alpm_depmiss_free(pmdepmissing_t *
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 -rupN -x '*\.git*' pacman/lib/libalpm/sync.c pacman-fixbug9395/lib/libalpm/sync.c
--- pacman/lib/libalpm/sync.c 2008-12-31 16:45:31.000000000 +1300
+++ pacman-fixbug9395/lib/libalpm/sync.c 2008-12-31 18:01:17.000000000 +1300
@@ -417,9 +417,10 @@ int _alpm_sync_prepare(pmtrans_t *trans,
}
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,
}
}
- 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 -rupN -x '*\.git*' pacman/src/pacman/callback.c pacman-fixbug9395/src/pacman/callback.c
--- pacman/src/pacman/callback.c 2008-12-31 16:45:31.000000000 +1300
+++ pacman-fixbug9395/src/pacman/callback.c 2008-12-31 18:04:16.000000000 +1300
@@ -248,7 +248,10 @@ void cb_trans_conv(pmtransconv_t event,
{
switch(event) {
case PM_TRANS_CONV_INSTALL_IGNOREPKG:
- if(data2) {
+ if(config->noignoreprompt) {
+ *response = 0;
+ }
+ else 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),
@@ -274,6 +277,31 @@ void cb_trans_conv(pmtransconv_t event,
(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?"),
diff -rupN -x '*\.git*' pacman/src/pacman/conf.c.rej pacman-fixbug9395/src/pacman/conf.c.rej
--- pacman/src/pacman/conf.c.rej 1970-01-01 12:00:00.000000000 +1200
+++ pacman-fixbug9395/src/pacman/conf.c.rej 2008-12-31 17:53:00.000000000 +1300
@@ -0,0 +1,16 @@
+***************
+*** 48,53 ****
+ newconfig->dbpath = NULL;
+ newconfig->logfile = NULL;
+ newconfig->syncfirst = NULL;
+
+ return(newconfig);
+ }
+--- 48,54 ----
+ newconfig->dbpath = NULL;
+ newconfig->logfile = NULL;
+ newconfig->syncfirst = NULL;
++ newconfig->noignoreprompt = 0;
+
+ return(newconfig);
+ }
diff -rupN -x '*\.git*' pacman/src/pacman/conf.h pacman-fixbug9395/src/pacman/conf.h
--- pacman/src/pacman/conf.h 2008-12-31 16:45:31.000000000 +1300
+++ pacman-fixbug9395/src/pacman/conf.h 2008-12-31 18:04:47.000000000 +1300
@@ -69,6 +69,7 @@ typedef struct __config_t {
* downloaded of the total download list */
unsigned short totaldownload;
unsigned short cleanmethod; /* select -Sc behavior */
+ unsigned short noignoreprompt; /* don't ask user to confirm ignored packages */
alpm_list_t *syncfirst;
} config_t;
diff -rupN -x '*\.git*' pacman/src/pacman/pacman.c pacman-fixbug9395/src/pacman/pacman.c
--- pacman/src/pacman/pacman.c 2008-12-31 16:45:31.000000000 +1300
+++ pacman-fixbug9395/src/pacman/pacman.c 2008-12-31 17:53:00.000000000 +1300
@@ -137,15 +137,16 @@ static void usage(int op, const char * c
" ignore a group upgrade (can be used more than once)\n"));
printf(_(" -q, --quiet show less information for query and search\n"));
}
- printf(_(" --config <path> set an alternate configuration file\n"));
- printf(_(" --logfile <path> set an alternate log file\n"));
- printf(_(" --noconfirm do not ask for any confirmation\n"));
- printf(_(" --noprogressbar do not show a progress bar when downloading files\n"));
- printf(_(" --noscriptlet do not execute the install scriptlet if one exists\n"));
- printf(_(" -v, --verbose be verbose\n"));
- printf(_(" -r, --root <path> set an alternate installation root\n"));
- printf(_(" -b, --dbpath <path> set an alternate database location\n"));
- printf(_(" --cachedir <dir> set an alternate package cache location\n"));
+ printf(_(" --config <path> set an alternate configuration file\n"));
+ printf(_(" --logfile <path> set an alternate log file\n"));
+ printf(_(" --noconfirm do not ask for any confirmation\n"));
+ printf(_(" --noprogressbar do not show a progress bar when downloading files\n"));
+ printf(_(" --noscriptlet do not execute the install scriptlet if one exists\n"));
+ printf(_(" --noignoreprompt don't prompt to confirm packages in IngorePkg and IgnoreGroup\n"));
+ printf(_(" -v, --verbose be verbose\n"));
+ printf(_(" -r, --root <path> set an alternate installation root\n"));
+ printf(_(" -b, --dbpath <path> set an alternate database location\n"));
+ printf(_(" --cachedir <dir> set an alternate package cache location\n"));
}
}
@@ -366,6 +367,7 @@ static int parseargs(int argc, char *arg
{"debug", optional_argument, 0, 1003},
{"noprogressbar", no_argument, 0, 1004},
{"noscriptlet", no_argument, 0, 1005},
+ {"noignoreprompt", no_argument, 0, 1006},
{"cachedir", required_argument, 0, 1007},
{"asdeps", no_argument, 0, 1008},
{"logfile", required_argument, 0, 1009},
@@ -422,6 +424,7 @@ static int parseargs(int argc, char *arg
break;
case 1004: config->noprogressbar = 1; break;
case 1005: config->flags |= PM_TRANS_FLAG_NOSCRIPTLET; break;
+ case 1006: config->noignoreprompt = 1; break;
case 1007:
if(alpm_option_add_cachedir(optarg) != 0) {
pm_printf(PM_LOG_ERROR, _("problem adding cachedir '%s' (%s)\n"),
@@ -680,6 +683,9 @@ static int _parseconfig(const char *file
} else if(strcmp(key, "TotalDownload") == 0) {
config->totaldownload = 1;
pm_printf(PM_LOG_DEBUG, "config: totaldownload\n");
+ } else if(strcmp(key, "NoIgnorePrompt") == 0) {
+ config->noignoreprompt = 1;
+ pm_printf(PM_LOG_DEBUG, "config: noignoreprompt\n");
} else {
pm_printf(PM_LOG_ERROR, _("config file %s, line %d: directive '%s' not recognized.\n"),
file, linenum, key);