From 57ce115d84224fe8dd75f19490f788fe8acf198c Mon Sep 17 00:00:00 2001 From: Pascal Rigaux Date: Sat, 11 Aug 2007 16:25:18 +0000 Subject: - urpmi o handle preferred choices (through --prefer, /etc/urpmi/prefer.list and /etc/urpmi/prefer.vendor.list) --- NEWS | 2 ++ pod/urpmi.8.pod | 7 ++++ pod/urpmi.files.5.pod | 11 +++++++ pod/urpmq.8.pod | 13 ++++++++ t/data/SPECS/prefer/a.spec | 14 ++++++++ t/data/SPECS/prefer/b.spec | 14 ++++++++ t/data/SPECS/prefer/b_foo.spec | 14 ++++++++ t/data/SPECS/prefer/c.spec | 14 ++++++++ t/data/SPECS/prefer/c_foo.spec | 14 ++++++++ t/superuser--prefer.t | 72 ++++++++++++++++++++++++++++++++++++++++++ urpm.pm | 3 ++ urpm/args.pm | 3 +- urpm/select.pm | 33 +++++++++++++++++++ urpmi | 19 ++++++++--- urpmi.bash-completion | 3 +- urpmq | 2 ++ 16 files changed, 231 insertions(+), 7 deletions(-) create mode 100644 t/data/SPECS/prefer/a.spec create mode 100644 t/data/SPECS/prefer/b.spec create mode 100644 t/data/SPECS/prefer/b_foo.spec create mode 100644 t/data/SPECS/prefer/c.spec create mode 100644 t/data/SPECS/prefer/c_foo.spec create mode 100644 t/superuser--prefer.t 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 (see urpmi.files(5)). +=item B<--prefer> I + +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 (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.) The list of packages that should be installed instead of updated. It has the same format as the skip.list. +=item I + +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 + +Vendor specific version of similar to prefer.list. + =item I 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 + +You can specify a list of packages which installation should be skipped. +You can also include patterns between //, just like in +F (see urpmi.files(5)). + +=item B<--prefer> I + +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 (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 " (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}; } -- cgit v1.2.1