aboutsummaryrefslogtreecommitdiffstats
path: root/URPM/Resolve.pm
diff options
context:
space:
mode:
Diffstat (limited to 'URPM/Resolve.pm')
-rw-r--r--URPM/Resolve.pm121
1 files changed, 88 insertions, 33 deletions
diff --git a/URPM/Resolve.pm b/URPM/Resolve.pm
index ea959fb..0c18f31 100644
--- a/URPM/Resolve.pm
+++ b/URPM/Resolve.pm
@@ -208,7 +208,7 @@ sub backtrack_selected {
$state->{rejected}{$_->fullname}{backtrack} ||=
{ exists $dep->{promote} ? (promote => $dep->{promote}) : @{[]},
exists $dep->{psel} ? (psel => $dep->{psel}) : @{[]},
- required => $dep->{required} };
+ };
#- backtrack callback should return a strictly positive value if the selection of the new
#- package is prefered over the currently selected package.
next;
@@ -235,7 +235,7 @@ sub backtrack_selected {
if (defined $dep->{from}) {
if ($options{nodeps}) {
#- try to keep unsatisfied dependencies in requested.
- if (exists $state->{selected}{$dep->{from}->id}) {
+ if ($dep->{required} && exists $state->{selected}{$dep->{from}->id}) {
push @{$state->{selected}{$dep->{from}->id}{unsatisfied}}, $dep->{required};
}
} else {
@@ -256,19 +256,39 @@ sub backtrack_selected {
}
}
- if (defined $dep->{promote} && defined $dep->{psel}) {
- #- the backtrack need to examine diff_provides promotion on $n.
- $db->traverse_tag('whatrequires', [ $dep->{promote} ], sub {
- my ($p) = @_;
- if (my @l = $urpm->unsatisfied_requires($db, $state, $p, nopromoteepoch => 1, name => $dep->{promote})) {
- #- typically a redo of the diff_provides code should be applied...
- $urpm->resolve_rejected($db, $state, $p,
- removed => 1,
- unsatisfied => \@properties,
- from => scalar $dep->{psel}->fullname,
- why => { unsatisfied => \@l });
- }
- });
+ if (defined $dep->{psel}) {
+ if ($options{keep}) {
+ #- we shouldn't try to remove packages, so psel which leads to this need to be unselected.
+ unless (exists $state->{rejected}{$dep->{psel}->fullname}) {
+ #- package is not currently rejected, compute the closure now.
+ my @l = $options{keep_unrequested_dependencies} ? $urpm->disable_selected($db, $state, $dep->{psel}) :
+ $urpm->disable_selected_unrequested_dependencies($db, $state, $dep->{psel});
+ foreach (@l) {
+ #- disable all these packages in order to avoid selecting them again.
+ $_->fullname eq $dep->{psel}->fullname or
+ $state->{rejected}{$_->fullname}{backtrack}{closure}{$dep->{psel}->fullname} = undef;
+ }
+ }
+ #- the package is already rejected, we assume we can add another reason here!
+ defined $dep->{promote} and push @{$state->{rejected}{$dep->{psel}->fullname}{backtrack}{promote}}, $dep->{promote};
+ #- to simplify, a reference to list or standalone elements may be set in keep.
+ defined $dep->{keep} and push @{$state->{rejected}{$dep->{psel}->fullname}{backtrack}{keep}},
+ ref $dep->{keep} ? @{$dep->{keep}} : $dep->{keep};
+ } else {
+ #- the backtrack need to examine diff_provides promotion on $n.
+ $db->traverse_tag('whatrequires', [ $dep->{promote} ], sub {
+ my ($p) = @_;
+ if (my @l = $urpm->unsatisfied_requires($db, $state, $p,
+ nopromoteepoch => 1, name => $dep->{promote})) {
+ #- typically a redo of the diff_provides code should be applied...
+ $urpm->resolve_rejected($db, $state, $p,
+ removed => 1,
+ unsatisfied => \@properties,
+ from => scalar $dep->{psel}->fullname,
+ why => { unsatisfied => \@l });
+ }
+ });
+ }
}
#- some packages may have been removed because of selection of this one.
@@ -411,11 +431,19 @@ sub resolve_requested {
if (@best == @l) {
push @properties, map { +{ required => $_, promote => $n, psel => $pkg } } @best;
} else {
- $urpm->resolve_rejected($db, $state, $p,
- removed => 1,
- unsatisfied => \@properties,
- from => scalar $pkg->fullname,
- why => { unsatisfied => \@l });
+ if ($options{keep}) {
+ unshift @properties, $urpm->backtrack_selected($db, $state,
+ { keep => scalar $p->fullname,
+ psel => $pkg,
+ },
+ %options);
+ } else {
+ $urpm->resolve_rejected($db, $state, $p,
+ removed => 1,
+ unsatisfied => \@properties,
+ from => scalar $pkg->fullname,
+ why => { unsatisfied => \@l });
+ }
}
}
}
@@ -453,6 +481,9 @@ sub resolve_requested {
#- now do the real work, select the package.
my ($pkg) = @chosen;
+ #- cancel flag if this package should be cancelled but too late (typically keep options).
+ my @keep;
+
!$pkg || exists $state->{selected}{$pkg->id} and next;
if ($pkg->arch eq 'src') {
@@ -577,6 +608,7 @@ sub resolve_requested {
#- examine conflicts, an existing package conflicting with this selection should
#- be upgraded to a new version which will be safe, else it should be removed.
foreach ($pkg->conflicts) {
+ @keep and last;
#- propagate conflicts to avoided.
if (my ($n, $o, $v) = /^([^\s\[]*)(?:\[\*\])?\s*\[?([^\s\]]*)\s*([^\s\]]*)/) {
foreach (keys %{$urpm->{provides}{$n} || {}}) {
@@ -587,14 +619,21 @@ sub resolve_requested {
}
if (my ($file) = /^(\/[^\s\[]*)/) {
$db->traverse_tag('path', [ $file ], sub {
+ @keep and return;
my ($p) = @_;
- #- all these packages should be removed.
- $urpm->resolve_rejected($db, $state, $p,
- removed => 1, unsatisfied => \@properties,
- from => scalar $pkg->fullname, why => { conflicts => $file });
+ if ($options{keep}) {
+ push @keep, scalar $p->fullname;
+ } else {
+ #- all these packages should be removed.
+ $urpm->resolve_rejected($db, $state, $p,
+ removed => 1, unsatisfied => \@properties,
+ from => scalar $pkg->fullname,
+ why => { conflicts => $file });
+ }
});
} elsif (my ($property, $name) = /^(([^\s\[]*).*)/) {
$db->traverse_tag('whatprovides', [ $name ], sub {
+ @keep and return;
my ($p) = @_;
if ($p->provides_overlap($property)) {
#- the existing package will conflicts with selection, check if a newer
@@ -607,12 +646,17 @@ sub resolve_requested {
@{$packages->{$p->name}};
if (length $best) {
- push @properties, { required => $best, promote_conflicts => $name };
+ push @properties, { required => $best, promote_conflicts => $name, };
} else {
- #- no package have been found, we need to remove the package examined.
- $urpm->resolve_rejected($db, $state, $p,
- removed => 1, unsatisfied => \@properties,
- from => scalar $pkg->fullname, why => { conflicts => scalar $pkg->fullname });
+ if ($options{keep}) {
+ push @keep, scalar $p->fullname;
+ } else {
+ #- no package have been found, we need to remove the package examined.
+ $urpm->resolve_rejected($db, $state, $p,
+ removed => 1, unsatisfied => \@properties,
+ from => scalar $pkg->fullname,
+ why => { conflicts => scalar $pkg->fullname });
+ }
}
}
});
@@ -621,16 +665,27 @@ sub resolve_requested {
#- examine if an existing package does not conflicts with this one.
$db->traverse_tag('whatconflicts', [ $pkg->name ], sub {
+ @keep and return;
my ($p) = @_;
foreach my $property ($p->conflicts) {
if ($pkg->provides_overlap($property)) {
- #- all these packages should be removed.
- $urpm->resolve_rejected($db, $state, $p,
- removed => 1, unsatisfied => \@properties,
- from => scalar $pkg->fullname, why => { conflicts => $property });
+ if ($options{keep}) {
+ push @keep, scalar $p->fullname;
+ } else {
+ #- all these packages should be removed.
+ $urpm->resolve_rejected($db, $state, $p,
+ removed => 1, unsatisfied => \@properties,
+ from => scalar $pkg->fullname,
+ why => { conflicts => $property });
+ }
}
}
});
+
+ #- keep existing package and therefore cancel current one.
+ if (@keep) {
+ unshift @properties, $urpm->backtrack_selected($db, $state, +{ keep => \@keep, psel => $pkg }, %options);
+ }
}
#- return what has been selected by this call (not all selected hash which may be not emptry