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);