summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS2
-rw-r--r--pod/urpmi.8.pod7
-rw-r--r--pod/urpmi.files.5.pod11
-rw-r--r--pod/urpmq.8.pod13
-rw-r--r--t/data/SPECS/prefer/a.spec14
-rw-r--r--t/data/SPECS/prefer/b.spec14
-rw-r--r--t/data/SPECS/prefer/b_foo.spec14
-rw-r--r--t/data/SPECS/prefer/c.spec14
-rw-r--r--t/data/SPECS/prefer/c_foo.spec14
-rw-r--r--t/superuser--prefer.t72
-rw-r--r--urpm.pm3
-rw-r--r--urpm/args.pm3
-rw-r--r--urpm/select.pm33
-rwxr-xr-xurpmi19
-rw-r--r--urpmi.bash-completion3
-rwxr-xr-xurpmq2
16 files changed, 231 insertions, 7 deletions
diff --git a/NEWS b/NEWS
index 28eab695..9d70d059 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,8 @@
- urpmi
o new option --replacepkgs (same as rpm --replacepkgs) (#16112)
o fix --quiet (regression introduced in 4.9.28)
+ o handle preferred choices (through --prefer, /etc/urpmi/prefer.list
+ and /etc/urpmi/prefer.vendor.list)
- all tools
o new option --wait-lock (#13025)
diff --git a/pod/urpmi.8.pod b/pod/urpmi.8.pod
index a166ddad..a4fef950 100644
--- a/pod/urpmi.8.pod
+++ b/pod/urpmi.8.pod
@@ -359,6 +359,13 @@ You can specify a list of packages which installation should be skipped.
You can also include patterns between //, just like in
F</etc/urpmi/skip.list> (see urpmi.files(5)).
+=item B<--prefer> I<pattern,...>
+
+You can specify a list of packages which installation should be preferred
+(especially useful with B<--auto>).
+You can also include patterns between //, just like in
+F</etc/urpmi/prefer.list> (see urpmi.files(5)).
+
=item B<--more-choices>
When several packages are found, propose more choices than the default.
diff --git a/pod/urpmi.files.5.pod b/pod/urpmi.files.5.pod
index 623ba8bf..502c2703 100644
--- a/pod/urpmi.files.5.pod
+++ b/pod/urpmi.files.5.pod
@@ -69,6 +69,17 @@ the full name of the package, which has the form B<name-version-release.arch>.)
The list of packages that should be installed instead of updated. It has
the same format as the skip.list.
+=item I</etc/urpmi/prefer.list>
+
+The list of packages that should be preferred (useful for choices with
+B<--auto>). It contains one package expression per line; either a package
+name, or a regular expression (if enclosed in slashes B</>) to match the name
+of packages against.
+
+=item I</etc/urpmi/prefer.vendor.list>
+
+Vendor specific version of similar to prefer.list.
+
=item I</etc/urpmi/mirror.config>
This file is optional. If present, it should contain a single line:
diff --git a/pod/urpmq.8.pod b/pod/urpmq.8.pod
index 6557cd17..aba3dbfc 100644
--- a/pod/urpmq.8.pod
+++ b/pod/urpmq.8.pod
@@ -186,6 +186,19 @@ Use hdlist file (to use with --use-distrib).
Use a different environment directly from a bug report to replay a bug.
The argument is the same argument given to B<--bug> option.
+=item B<--skip> I<pattern,...>
+
+You can specify a list of packages which installation should be skipped.
+You can also include patterns between //, just like in
+F</etc/urpmi/skip.list> (see urpmi.files(5)).
+
+=item B<--prefer> I<pattern,...>
+
+You can specify a list of packages which installation should be preferred
+(especially useful with B<--auto>).
+You can also include patterns between //, just like in
+F</etc/urpmi/prefer.list> (see urpmi.files(5)).
+
=item B<--wait-lock>
If the urpmi or rpm db is busy, wait until it is available
diff --git a/t/data/SPECS/prefer/a.spec b/t/data/SPECS/prefer/a.spec
new file mode 100644
index 00000000..30e61f63
--- /dev/null
+++ b/t/data/SPECS/prefer/a.spec
@@ -0,0 +1,14 @@
+Summary: x
+Name: a
+Version: 1
+Release: 1
+License: x
+Group: x
+Url: x
+Requires: virtual1
+BuildRoot: %{_tmppath}/%{name}
+
+%description
+x
+
+%files
diff --git a/t/data/SPECS/prefer/b.spec b/t/data/SPECS/prefer/b.spec
new file mode 100644
index 00000000..e7d79d76
--- /dev/null
+++ b/t/data/SPECS/prefer/b.spec
@@ -0,0 +1,14 @@
+Summary: x
+Name: b
+Version: 1
+Release: 1
+License: x
+Group: x
+Url: x
+Provides: virtual1
+BuildRoot: %{_tmppath}/%{name}
+
+%description
+x
+
+%files
diff --git a/t/data/SPECS/prefer/b_foo.spec b/t/data/SPECS/prefer/b_foo.spec
new file mode 100644
index 00000000..e0cb9d02
--- /dev/null
+++ b/t/data/SPECS/prefer/b_foo.spec
@@ -0,0 +1,14 @@
+Summary: x
+Name: b_foo
+Version: 1
+Release: 1
+License: x
+Group: x
+Url: x
+Provides: virtual1
+BuildRoot: %{_tmppath}/%{name}
+
+%description
+x
+
+%files
diff --git a/t/data/SPECS/prefer/c.spec b/t/data/SPECS/prefer/c.spec
new file mode 100644
index 00000000..88ee35c4
--- /dev/null
+++ b/t/data/SPECS/prefer/c.spec
@@ -0,0 +1,14 @@
+Summary: x
+Name: c
+Version: 1
+Release: 1
+License: x
+Group: x
+Url: x
+Provides: virtual1
+BuildRoot: %{_tmppath}/%{name}
+
+%description
+x
+
+%files
diff --git a/t/data/SPECS/prefer/c_foo.spec b/t/data/SPECS/prefer/c_foo.spec
new file mode 100644
index 00000000..b57f899e
--- /dev/null
+++ b/t/data/SPECS/prefer/c_foo.spec
@@ -0,0 +1,14 @@
+Summary: x
+Name: c_foo
+Version: 1
+Release: 1
+License: x
+Group: x
+Url: x
+Provides: virtual1
+BuildRoot: %{_tmppath}/%{name}
+
+%description
+x
+
+%files
diff --git a/t/superuser--prefer.t b/t/superuser--prefer.t
new file mode 100644
index 00000000..d9b539a9
--- /dev/null
+++ b/t/superuser--prefer.t
@@ -0,0 +1,72 @@
+#!/usr/bin/perl
+
+use strict;
+use lib '.', 't';
+use helper;
+use Expect;
+use urpm::util;
+use Test::More 'no_plan';
+
+need_root_and_prepare();
+
+my $medium_name = 'prefer';
+
+urpmi_addmedia("$medium_name $::pwd/media/$medium_name");
+
+urpmi("--auto --prefer b a");
+check_installed_and_remove('a', 'b');
+
+urpmi("--auto --prefer c a");
+check_installed_and_remove('a', 'c');
+
+test('/foo/', 'foo');
+test('a,a_foo', '^(a|a_foo)$');
+
+
+sub test {
+ my ($prefer, $regexp) = @_;
+
+ my $options = "--prefer '$prefer' a";
+ my @expected = (
+ [ 'What is your choice', "\n" ],
+ [ 'Proceed with the installation of the 2 packages?', "\n" ],
+ );
+
+ if (0) {
+ #- try it interactively for debugging
+ system_(urpm_cmd('urpmi', '-d') . " $options");
+ return;
+ }
+
+ my $cmd = urpmi_cmd() . " $options";
+ print "# $cmd\n";
+ my $expect = Expect->spawn($cmd);
+
+ my $choices;
+ foreach (@expected) {
+ my ($msg, $to_send) = @$_;
+
+ my $ok = $expect->expect(2, # timeout in seconds
+ [ $msg => sub { $choices ||= $expect->before; $expect->send($to_send); } ]);
+ print "$to_send";
+ ok($ok, qq(expecting "$msg"));
+ $ok or return;
+ }
+ my @choices = grep { s/^\s*\d+- (.*?)-.*?:.*/$1/ } split("\n", $choices);
+ is(int(@choices), 4, "4 choices in $choices");
+ my $other = '';
+ foreach (@choices) {
+ if (/$regexp/) {
+ ok(!$other, "line $_ must be before $other line");
+ } else {
+ $other = $_;
+ }
+ }
+
+ $expect->expect(2, [ 'eof' => sub {} ]);
+
+ $expect->soft_close;
+ is($expect->exitstatus, 0, $cmd);
+
+ check_installed_and_remove('a', $choices[0]);
+}
diff --git a/urpm.pm b/urpm.pm
index 602aa0b1..15fcefd6 100644
--- a/urpm.pm
+++ b/urpm.pm
@@ -57,6 +57,9 @@ sub set_files {
config => "$urpmi_root/etc/urpmi/urpmi.cfg",
skiplist => "$urpmi_root/etc/urpmi/skip.list",
instlist => "$urpmi_root/etc/urpmi/inst.list",
+ prefer_list => "$urpmi_root/etc/urpmi/prefer.list",
+ prefer_vendor_list =>
+ "$urpmi_root/etc/urpmi/prefer.vendor.list",
private_netrc => "$urpmi_root/etc/urpmi/netrc",
statedir => "$urpmi_root/var/lib/urpmi",
cachedir => "$urpmi_root/var/cache/urpmi",
diff --git a/urpm/args.pm b/urpm/args.pm
index 80419d78..efe0349e 100644
--- a/urpm/args.pm
+++ b/urpm/args.pm
@@ -133,6 +133,7 @@ my %options_spec = (
'norebuild!' => sub { $urpm->{options}{'build-hdlist-on-error'} = !$_[1] },
'test!' => \$::test,
'skip=s' => \$options{skip},
+ 'prefer=s' => \$options{prefer},
'root=s' => sub {
require File::Spec;
$urpm->{root} = File::Spec->rel2abs($_[1]);
@@ -359,7 +360,7 @@ foreach my $k ("help|h", "version", "no-locales", "test!", "force", "root=s", "u
{
$options_spec{urpme}{$k} = $options_spec{urpmi}{$k};
}
-foreach my $k ("root=s", "nolock", "use-distrib=s", "skip=s")
+foreach my $k ("root=s", "nolock", "use-distrib=s", "skip=s", "prefer=s")
{
$options_spec{urpmq}{$k} = $options_spec{urpmi}{$k};
}
diff --git a/urpm/select.pm b/urpm/select.pm
index 7544e83b..978f88bb 100644
--- a/urpm/select.pm
+++ b/urpm/select.pm
@@ -4,6 +4,7 @@ package urpm::select;
use urpm::msg;
use urpm::util;
+use urpm::sys;
use URPM;
sub _findindeps {
@@ -248,6 +249,38 @@ sub resolve_dependencies {
$need_restart;
}
+sub cooked_prefer {
+ my ($urpm, $cmdline_prefer) = @_;
+
+ $urpm->{prefer_regexps} ||= [
+ map {
+ m!^/(.*)/$! ? "($1)" : '^' . quotemeta($_) . '$';
+ } map { @$_ }
+ urpm::sys::get_packages_list($urpm->{prefer_list}, $cmdline_prefer),
+ urpm::sys::get_packages_list($urpm->{prefer_vendor_list})
+ ];
+ @{$urpm->{prefer_regexps}};
+}
+
+sub sort_choices {
+ my ($urpm, $choices, $cmdline_prefer) = @_;
+
+ my @prefer;
+ my @l = @$choices;
+ foreach my $re (cooked_prefer($urpm, $cmdline_prefer)) {
+ my ($prefer, $other) = partition { $_->name =~ $re } @l;
+ push @prefer, @$prefer;
+ @l = @$other;
+
+ if (@$prefer) {
+ my $prefer_s = join(',', map { $_->name } @$prefer);
+ my $other_s = join(',', map { $_->name } @l);
+ $urpm->{log}("preferring $prefer_s over $other_s");
+ }
+ }
+ (@prefer, @l);
+}
+
#- find packages to remove.
#- options:
#- bundle
diff --git a/urpmi b/urpmi
index 52f268d6..30a42358 100755
--- a/urpmi
+++ b/urpmi
@@ -142,6 +142,7 @@ usage:
") . N(" --noscripts - do not execute package scriptlet(s)
") . N(" --repackage - Re-package the files before erasing
") . N(" --skip - packages which installation should be skipped
+") . N(" --prefer - packages which should be preferred
") . N(" --more-choices - when several packages are found, propose more choices
than the default.
") . N(" --nolock - don't lock rpm db.
@@ -240,7 +241,9 @@ if ($bug) {
? N("Directory [%s] already exists, please use another directory for bug report or delete it", $bug)
: N("Unable to create directory [%s] for bug report", $bug)));
#- copy all synthesis file used, along with configuration of urpmi
- system("cp", "-af", $urpm->{skiplist}, $urpm->{instlist}, $urpm->{config}, $bug)
+ system("cp", "-af", $urpm->{skiplist}, $urpm->{instlist},
+ $urpm->{prefer_list}, $urpm->{prefer_vendor_list},
+ $urpm->{config}, $bug)
and die N("Copying failed");
#- log everything for bug report.
$logfile = "$bug/urpmi.log";
@@ -255,6 +258,8 @@ if ($env) {
$urpm->{config} = "$env/urpmi.cfg";
$urpm->{skiplist} = "$env/skip.list";
$urpm->{instlist} = "$env/inst.list";
+ $urpm->{prefer_list} = "$env/prefer.list";
+ $urpm->{prefer_vendor_list} = "$env/prefer.vendor.list";
$urpm->{statedir} = $env;
} else {
if ($< != 0) {
@@ -423,7 +428,9 @@ if (@src_names) {
sub ask_choice {
my ($urpm, $_db, $_state, $choices, $virtual_pkg_name) = @_;
- my $n = 1; #- default value.
+
+ my @choices = urpm::select::sort_choices($urpm, $choices, $options{prefer});
+
my (@l) = map {
my ($name, $summary) = (scalar($_->fullname), translate($_->summary));
$_->flag_installed ?
@@ -438,7 +445,9 @@ sub ask_choice {
N("%s: %s (to install)", $name, $summary) :
#-PO: here format is "<package_name> (to install)"
N("%s (to install)", $name)) : $name;
- } @$choices;
+ } @choices;
+
+ my $n = 1; #- default value.
if (@l > 1 && !$urpm->{options}{auto}) {
print N("In order to satisfy the '%s' dependency, one of the following packages is needed:", $virtual_pkg_name), "\n";
@@ -447,12 +456,12 @@ sub ask_choice {
$n = message_input(N("What is your choice? (1-%d) ", $i), undef, range_min => 0, range => $i);
defined($n) && $n ne "0" or exit 1; # abort.
if ($n =~ /\D/) {
- my @nn = map { $choices->[$_ - 1] } grep { !/\D/ } split /[, \t]+/, $n;
+ my @nn = map { $choices[$_ - 1] } grep { !/\D/ } split /[, \t]+/, $n;
@nn or exit 1;
return @nn;
}
}
- $choices->[$n - 1];
+ $choices[$n - 1];
}
#- do the resolution of dependencies between requested package (and auto selection if any).
diff --git a/urpmi.bash-completion b/urpmi.bash-completion
index 8c93fd86..90a584d7 100644
--- a/urpmi.bash-completion
+++ b/urpmi.bash-completion
@@ -104,7 +104,7 @@ _urpmi()
--excludedocs --searchmedia --ignoresize --ignorearch \
--strict-arch --wget-options --curl-options \
--prozilla-options --rsync-options --resume --retry \
- --skip --nolock --more-choices"
+ --skip --prefer --nolock --more-choices"
# add dangereous option for everything else as rurpmi
if [[ ${COMP_WORDS[0]} != *rurpmi ]]; then
options="$options --root --use-distrib --env \
@@ -184,6 +184,7 @@ _urpmq()
--src --sources --force --parallel --wget --curl --prozilla \
--changelog --proxy --proxy-user --env --dump-config \
--whatprovides --whatrequires --whatrequires-recursive \
+ --skip --prefer \
--use-distrib --searchmedia --ignorearch" -- $cur))
else
# return available packages (unless it is clearly a file) and rpm files
diff --git a/urpmq b/urpmq
index 271ee92c..3db4cdb1 100755
--- a/urpmq
+++ b/urpmq
@@ -137,6 +137,8 @@ if ($options{env}) {
$urpm->{config} = "$options{env}/urpmi.cfg";
$urpm->{skiplist} = "$options{env}/skip.list";
$urpm->{instlist} = "$options{env}/inst.list";
+ $urpm->{prefer_list} = "$options{env}/prefer.list";
+ $urpm->{prefer_vendor_list} = "$options{env}/prefer.vendor.list";
$urpm->{statedir} = $options{env};
}