[pacman-dev] [PATCH] Fix bug 9395 by allowing pacman to remove unresolvable packages from a transaction
Bryan Ischo
bji-keyword-pacman.3644cb at www.ischo.com
Mon Jan 12 14:48:07 EST 2009
Nagy Gabor wrote:
> Hi!
>
> Some comments/suggestions. (Note: First wait for Dan's response, whether
> he can support your concept (behavior change) or not. I would be sad, if
> you did useless work because of me.)
>
> I must repeat some of my earlier suggestions.
>
> We prefer shorter patches. I can fully support in your patch: dropping
> PM_TRANS_CONV_INSTALL_IGNOREPKG, I don't know why we haven't done this
> earlier. But: I think we should give a warning where we asked the user
> earlier. For example, this part could be factorized into a seperate
> patch.
>
>
OK, I can separate that into a different patch if that is required to
get the change in. One reason that I thought it made sense to make
these changes in one patch is that the new prompt I have added to some
degree obsoletes the old prompt: whereas a user used to be asked if they
want to un-ignore packages which have updates, the new prompt doesn't
ask them this but does as them if they want to remove all packages from
the transaction which cannot be updated due to packages being ignored
(although it doesn't explicitly state which packages were ignored -
something I'd like to do, but in a future checkin to improve the
prompt). In both cases, they become aware that some packages are not
going to be updated due to being in the ignore list, but in the prior
code, they were asked whether to let the transaction proceed by
un-ignoring these packages, in the new code they are asked whether to
let the transaction proceed by removing all dependencies on ignored
packages from the transaction. Because both prompts deal with ignore
packages, but in different ways, I thought of the new prompt as a bit of
a "replacement" for the old prompt, and thus include the removal of the
old prompt in this change, rather than doing it in a later change, which
would, in the interim code between the changes, have a "double-prompt".
In terms of a warning, pacman already prints out lines like this:
warning: kernel26: ignoring package upgrade (2.6.27.8-1 => 2.6.27.10-1)
warning: pacman: ignoring package upgrade (3.2.1FIXBUG9395-1 => 3.2.1-2)
warning: pango: ignoring package upgrade (1.22.3-2 => 1.22.4-1)
Is that not sufficient?
>> +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);
>>
>
> ???
> I don't understand this part. (I checked, your earlier patch also had
> this part.) Probably want to do this: If any dependent is needed, then
> this package is also needed, otherwise not.
>
It's more complicated than that. This function might not be very well
named. It's purpose is to determine which packages are to be removed
from the transaction because they either were unresolvable, or were
resolvable but are only in the transaction because they were pulled by a
package that was unresolvable.
This function is run only after the user has been asked about the
top-level packages which were unresolvable (i.e. the packages they
explicitly requested be updated, but which had dependencies which could
not be resolved). If they say that they want these packages removed
from the transaction, then the code has to remove not just those
packages, but also any dependencies which were pulled only to satisfy
dependencies of the packages being removed from the transaction (and so
on recursively).
It determines which packages to be removed using these tests:
- If the package was marked unresolvable, then it must be removed
- Else, if the package was top-level (i.e. not pulled, i.e. explicitly
requested by the user), then it is NOT removed (since it was already
just determined to be resolvable)
- Else, it is a pulled package which was not resolvable. But maybe it
was pulled only to satisfy dependencies of packages which later on
turned out to be unresolvable themselves. Just because the pulled
package has one or more unresolvable "immediate" dependents, does not
mean that it needs to be removed (because some other dependents may be
resolvable and retained in the transaction, thus this package should be
too). And just because the pulled package has all resolvable
"immediate" dependents, does not mean that it should be retained
(because maybe all dependents of its dependents are going to be removed
from the transaction, in which case this package should be too). The
simplest question to ask about such a package is, "is there any path
back through the dependents chain from this package to a top-level
package that will be retained in this transaction". In other words, are
any top-level dependent "ancestors" of this package needed? If so, then
this package is needed too. Otherwise, this package is not needed; we
can visualize this as the entire set of subtrees rooted at the top-level
packages and which include the package that we are testing, as being
unresolvable and thus needing to be removed from the transaction. So
the test we finally do is recursively ask each dependent if it is
needed (which will only recursively stop at the top-level packages), and
if any are, then this package is needed too.
HOWEVER, in writing this very last line, I realize that my final test
should be:
if (is_needed(infolist, findinfo(infolist, deppkg), marker)) {
return(1);
}
This is because we want to consider a package needed if any of its dependent packages are needed. The code as it was was mistakenly considering a package needed only if all of its dependent packages are needed.
Does that make sense?
>> + }
>> +}
>>
>
>
>
>
>> + 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));
>>
>
> 2. The result of this:
> error: cannot resolve dependencies for:
> error: foo
> error: bar
> ...
>
> This is ugly, we use data list for this purpose, the front-end should
> build this message.
>
Please tell me exactly the format you want to see this error message in,
and I will make it so. I don't know exactly what you are expecting so I
am not sure how to fix the problem you are pointing out.
>
>> + if (data) {
>> + alpm_list_t *targ = alpm_list_add(NULL, i->data);
>> + deps = alpm_checkdeps(_alpm_db_get_pkgcache(local), 0, remove, targ);
>>
>
> This is not OK. (If this part existed in your previous patch, sorry for
> missing it.) In the target list we may have a satisfier.
>
I don't understand what you are saying here. A few points:
1. The code already looked like this; I haven't changed how the
dependencies are checked in my patch. So what you are objecting to is,
I think, already the way that this code worked, not a change that I have
made.
2. I think you already talked about this in a previous email, when you said:
> 4. It is not easy to determine which package is unresolvable. If a
> pulled dependency satisfier of foo is unresolvable we may could find an
> other (resolvable) satisfier. But this is not handled in the current
> code neither, so your _alpm_mark_unresolvable() is OK.
3. alpm_checkdeps just returns the list of dependencies for the
package. The very first thing that the code then does with each
dependency is look for it in the target list. Then if it's not found,
it uses _alpm_resolvedep to try to find a satisfier. Here is the code
in question:
Thanks for your comments. I hope that we're getting closer to getting
my changes in :)
Bryan
More information about the pacman-dev
mailing list