From 14abfdf01bfa2e0872a85ea7ce022d44a6e29fb7 Mon Sep 17 00:00:00 2001 From: Pascal Rigaux Date: Sat, 23 Feb 2008 21:31:09 +0000 Subject: - all tools: o handle mirrorlist (need perl-Zone-TimeInfo patched for geolocalisation) --- MANIFEST | 14 ++++ NEWS | 3 + pod/urpmi.addmedia.8.pod | 25 ++++++ pod/urpmi.cfg.5.pod | 10 +++ t/01compile.t | 2 +- urpm.pm | 4 +- urpm/args.pm | 1 + urpm/cfg.pm | 6 +- urpm/media.pm | 85 +++++++++++++++---- urpm/mirrors.pm | 212 +++++++++++++++++++++++++++++++++++++++++++++++ urpmi.addmedia | 23 ++++- urpmq | 4 +- 12 files changed, 369 insertions(+), 20 deletions(-) create mode 100644 urpm/mirrors.pm diff --git a/MANIFEST b/MANIFEST index 289d057a..e8550c32 100644 --- a/MANIFEST +++ b/MANIFEST @@ -125,10 +125,18 @@ t/data/SPECS/file-conflicts/ga.spec t/data/SPECS/file-conflicts/gc.spec t/data/SPECS/file-conflicts/gc_.spec t/data/SPECS/file-conflicts/gd.spec +t/data/SPECS/file-conflicts/h.spec +t/data/SPECS/file-conflicts/i.spec t/data/SPECS/handle-conflict-deps/a-sup.spec t/data/SPECS/handle-conflict-deps/a.spec t/data/SPECS/handle-conflict-deps/b-sub.spec t/data/SPECS/handle-conflict-deps/b.spec +t/data/SPECS/handle-conflict-deps/c.spec +t/data/SPECS/handle-conflict-deps/d.spec +t/data/SPECS/handle-conflict-deps/e.spec +t/data/SPECS/handle-conflict-deps/f.spec +t/data/SPECS/multi-line-macro.spec +t/data/SPECS/multi-line-macro2.spec t/data/SPECS/obsolete-and-conflict/a.spec t/data/SPECS/obsolete-and-conflict/b.spec t/data/SPECS/obsolete-and-conflict/c.spec @@ -199,8 +207,12 @@ t/data/SPECS/split-transactions--promote-2/h.spec t/data/SPECS/split-transactions--strict-require-1/a.spec t/data/SPECS/split-transactions--strict-require-1/b.spec t/data/SPECS/split-transactions--strict-require-1/c.spec +t/data/SPECS/split-transactions--strict-require-1/d.spec +t/data/SPECS/split-transactions--strict-require-1/dd.spec t/data/SPECS/split-transactions--strict-require-2/a.spec t/data/SPECS/split-transactions--strict-require-2/c.spec +t/data/SPECS/split-transactions--strict-require-2/d.spec +t/data/SPECS/split-transactions--strict-require-2/dd.spec t/data/SPECS/split-transactions--strict-require-and-obsolete-1/a.spec t/data/SPECS/split-transactions--strict-require-and-obsolete-1/bb.spec t/data/SPECS/split-transactions--strict-require-and-obsolete-1/c-1.spec @@ -238,6 +250,7 @@ t/superuser--file-conflicts.t t/superuser--handle-conflict-deps.t t/superuser--http.t t/superuser--media_info_dir.t +t/superuser--mirrorlist.t t/superuser--obsolete-and-conflict.t t/superuser--ordering-scriptlets.t t/superuser--prefer.t @@ -266,6 +279,7 @@ urpm/lock.pm urpm/main_loop.pm urpm/md5sum.pm urpm/media.pm +urpm/mirrors.pm urpm/msg.pm urpm/parallel.pm urpm/parallel_ka_run.pm diff --git a/NEWS b/NEWS index ed5a3afd..f5b477b1 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,6 @@ +- all tools: + o handle mirrorlist + (need perl-Zone-TimeInfo patched for geolocalisation) - urpmf o fallback on hdlist when xml-info not found (useful for old distribs) - urpmi handles /etc/urpmi/media.d/*.cfg diff --git a/pod/urpmi.addmedia.8.pod b/pod/urpmi.addmedia.8.pod index efffd9b2..9b99121d 100644 --- a/pod/urpmi.addmedia.8.pod +++ b/pod/urpmi.addmedia.8.pod @@ -16,6 +16,19 @@ must be chosen: =over +=item B [I] --distrib --mirrorlist > + +A mirror list is a special API to describe mirrors available. urpmi will pick +the nearest mirror, and will dynamically handle new mirrors. Example: + + urpmi.addmedia --distrib --mirrorlist '$MIRRORLIST' + +=item B [I] --mirrorlist > > > + +Example: + + urpmi.addmedia --mirrorlist '$MIRRORLIST' backports media/main/backports + =item B [I] > http://>:>@>/> where > is a human-readable name for the new media (e.g. @@ -131,6 +144,14 @@ Use synthesis file. Use rpm files (instead of synthesis). +=item B<--mirrorlist> + +Use the given url as a mirror list. It is quite special, please see examples +at the beginning of this page. + +nb: $MIRRORLIST is a special variable which gives the default URL for the +current distribution/arch + =item B<--distrib> Retrieve a set of media from a distribution. Typically, the URL provided @@ -206,6 +227,10 @@ on a Mandriva cooker system.) The canonical hostname of the machine urpmi runs on. +=item B<$MIRRORLIST> + +The url of the default mirrorlist for the distribution. + =back =head1 SEE ALSO diff --git a/pod/urpmi.cfg.5.pod b/pod/urpmi.cfg.5.pod index dd5826fe..00e8ed9d 100644 --- a/pod/urpmi.cfg.5.pod +++ b/pod/urpmi.cfg.5.pod @@ -123,6 +123,16 @@ Same as B<--limit-rate> for all tools. This option allows to control download speed; there is no limitation by default. The number is given in bytes per second, unless a suffix C or C is added. +=item B + +For mirrorlist, the maximum number of mirrors to try before giving up. (since +sometimes all mirrors have the same problem and it is useless to try more). + +=item B + +After a number of days, urpmi.update will update the list of mirrors (to get +potential new mirrors). + =item B Don't import pubkeys when updating media. diff --git a/t/01compile.t b/t/01compile.t index f4966acf..58ef0907 100644 --- a/t/01compile.t +++ b/t/01compile.t @@ -2,7 +2,7 @@ use strict; use warnings; -use Test::More tests => 23; +use Test::More tests => 24; for my $module (glob("urpm/*.pm")) { $module =~ s,/,::,g; diff --git a/urpm.pm b/urpm.pm index 88f0946c..7a372a93 100644 --- a/urpm.pm +++ b/urpm.pm @@ -12,7 +12,7 @@ use urpm::sys; use urpm::cfg; use urpm::md5sum; -our $VERSION = '5.4'; +our $VERSION = '5.5'; our @ISA = qw(URPM Exporter); our @EXPORT_OK = 'file_from_local_url'; @@ -33,6 +33,8 @@ sub default_options { 'verify-rpm' => 1, 'post-clean' => 1, 'xml-info' => 'on-demand', + 'max-round-robin-tries' => 5, + 'days-between-mirrorlist-update' => 5, }; } diff --git a/urpm/args.pm b/urpm/args.pm index d809ee9d..73665d9d 100644 --- a/urpm/args.pm +++ b/urpm/args.pm @@ -316,6 +316,7 @@ my %options_spec = ( 'xml-info=s' => \$options{'xml-info'}, 'no-probe' => sub { $options{probe_with} = undef }, distrib => sub { $options{distrib} = 1 }, + 'mirrorlist=s' => \$options{mirrorlist}, interactive => sub { $options{interactive} = 1 }, 'all-media' => sub { $options{allmedia} = 1 }, 'from=s' => \$options{mirrors_url}, diff --git a/urpm/cfg.pm b/urpm/cfg.pm index 03175d5f..3283c6e7 100644 --- a/urpm/cfg.pm +++ b/urpm/cfg.pm @@ -140,11 +140,13 @@ sub load_config_raw { $err = N("medium `%s' is defined twice, aborting", $name); return; } - $block = { name => $name, url => $url }; + $block = { name => $name, $url ? (url => $url) : () }; } elsif (/^(hdlist |list |with_hdlist |with_synthesis + |with-dir + |mirrorlist |media_info_dir |removable |md5sum @@ -294,7 +296,7 @@ sub write_ini_config { foreach (@$blocks) { my %h = %$_; my $section = delete $h{'with-dir'} || '_'; - $uniq{$section}++ or die "conflicting with-dir value\n"; + $uniq{$section}++ or die "conflicting with-dir value $section\n"; foreach (difference2([ $cfg->Parameters($section) ], [ keys %h ])) { # remove those options which are no more wanted diff --git a/urpm/media.pm b/urpm/media.pm index 2e91fdd5..c7995b52 100644 --- a/urpm/media.pm +++ b/urpm/media.pm @@ -16,6 +16,7 @@ our @PER_MEDIA_OPT = qw( key-ids list media_info_dir + mirrorlist name no-media-info noreconfigure @@ -56,6 +57,7 @@ sub _only_media_opts_write { my ($m) = @_; my $c = only_media_opts($m); delete $c->{media_info_dir} if $c->{media_info_dir} eq 'media_info'; + delete $c->{url} if $c->{mirrorlist}; $c; } @@ -84,7 +86,7 @@ sub read_config_add_passwords { my ($urpm, $config) = @_; my @netrc = read_private_netrc($urpm) or return; - foreach (@{$config->{media}}) { + foreach (grep { $_->{url} } @{$config->{media}}) { my $u = urpm::download::parse_url_with_login($_->{url}) or next; if (my ($e) = grep { ($_->{default} || $_->{machine} eq $u->{machine}) && $_->{login} eq $u->{login} } @netrc) { $_->{url} = sprintf('%s://%s:%s@%s%s', $u->{proto}, $u->{login}, $e->{password}, $u->{machine}, $u->{dir}); @@ -98,7 +100,7 @@ sub remove_passwords_and_write_private_netrc { my ($urpm, $config) = @_; my @l; - foreach (@{$config->{media}}) { + foreach (grep { $_->{url} } @{$config->{media}}) { my $u = urpm::download::parse_url_with_login($_->{url}) or next; #- check whether a password is visible $u->{password} or next; @@ -149,7 +151,7 @@ sub read_config { foreach my $m (@{$config->{media}}) { my $medium = _only_media_opts_read($m); - if (!$medium->{url}) { + if (!$medium->{url} && !$medium->{mirrorlist}) { #- recover the url the old deprecated way... #- only useful for migration, new urpmi.cfg will use netrc recover_url_from_list($urpm, $medium); @@ -180,7 +182,7 @@ sub check_existing_medium { my ($urpm, $medium) = @_; my $err; - if (!$medium->{url}) { + if (!$medium->{url} && !$medium->{mirrorlist}) { $err = $medium->{virtual} ? N("virtual medium \"%s\" should have a clear url, medium ignored", $medium->{name}) : @@ -602,6 +604,8 @@ sub _parse_media { delete @$_{qw(start end)}; _parse_synthesis_or_ignore($urpm, $_, $options->{callback}); + _pick_mirror_if_needed($urpm, $_, ''); + if ($_->{searchmedia}) { $urpm->{searchmedia} = 1; $urpm->{log}(N("Search start: %s end: %s", $_->{start}, $_->{end})); @@ -644,7 +648,7 @@ sub _compute_flags_for_instlist { #- add a new medium, sync the config file accordingly. #- returns the new medium's name. (might be different from the requested #- name if index_name was specified) -#- options: ignore, index_name, nolock, update, virtual, media_info_dir, xml-info +#- options: ignore, index_name, nolock, update, virtual, media_info_dir, mirrorlist, with-dir, xml-info sub add_medium { my ($urpm, $name, $url, $with_synthesis, %options) = @_; @@ -670,7 +674,7 @@ sub add_medium { url => $url, modified => !$options{ignore}, }; - foreach (qw(downloader update ignore media_info_dir xml-info)) { + foreach (qw(downloader update ignore media_info_dir mirrorlist with-dir xml-info)) { $medium->{$_} = $options{$_} if exists $options{$_}; } @@ -683,6 +687,17 @@ sub add_medium { probe_removable_device($urpm, $medium); } + if (!$medium->{url} && $options{mirrorlist}) { + # forcing the standard media_info_dir if undefined + $medium->{media_info_dir} ||= 'media_info'; + + require urpm::mirrors; + urpm::mirrors::try($urpm, $medium, sub { + # this is a little ugly since MD5SUM will be downloaded again later, but it's small enough... + _download_MD5SUM($urpm, $medium); + }) or return; + } + if ($with_synthesis) { _migrate__with_synthesis($medium, $with_synthesis); } elsif (!$medium->{media_info_dir}) { @@ -719,6 +734,7 @@ sub add_medium { #- - probe_with : force use of rpms instead of using synthesis #- - ask_media : callback to know whether each media should be added #- - only_updates : only add "update" media (used by rpmdrake) +#- - mirrorlist #- other options are passed to add_medium(): ignore, nolock, virtual sub add_distrib_media { my ($urpm, $name, $url, %options) = @_; @@ -728,7 +744,7 @@ sub add_distrib_media { my $distribconf; - if (my $dir = file_from_local_url($url)) { + if (my $dir = $url && file_from_local_url($url)) { urpm::removable::try_mounting($urpm, $dir) or $urpm->{error}(N("unable to mount the distribution medium")), return (); $distribconf = MDV::Distribconf->new($dir, undef); @@ -737,7 +753,15 @@ sub add_distrib_media { } else { unlink "$urpm->{cachedir}/partial/media.cfg"; - $distribconf = _new_distribconf_and_download($urpm, $url); + if ($options{mirrorlist}) { + $url and die "unexpected url $url together with mirrorlist $options{mirrorlist}\n"; + } + + my $m = { mirrorlist => $options{mirrorlist}, url => $url }; + try__maybe_mirrorlist($urpm, $m, sub { + $distribconf = _new_distribconf_and_download($urpm, $m->{url}); + }); + $url = $m->{url}; if ($distribconf) { $distribconf->parse_mediacfg("$urpm->{cachedir}/partial/media.cfg") @@ -795,6 +819,7 @@ sub add_distrib_media { !$use_copied_synthesis && $options{probe_with} ? ($options{probe_with} => 1) : (), index_name => $name ? undef : 0, $add_by_default ? () : (ignore => 1), + $options{mirrorlist} ? ('with-dir' => $distribconf->getpath($media, 'path')) : (), %options, # the following override %options update => $is_update_media ? 1 : undef, @@ -900,6 +925,8 @@ sub _clean_statedir_medium_files { sub _probe_with_try_list { my ($urpm, $medium, $f) = @_; + $medium->{mirrorlist} and die "_probe_with_try_list does not handle mirrorlist\n"; + my @media_info_dirs = ('media_info', '.'); my $base = file_from_local_url($medium->{url}) || $medium->{url}; @@ -919,6 +946,8 @@ sub _probe_with_try_list { sub may_reconfig_urpmi { my ($urpm, $medium) = @_; + $medium->{url} or return; # we should handle mirrorlist? + my $f; if (my $dir = file_from_local_url($medium->{url})) { $f = reduce_pathname("$dir/reconfig.urpmi"); @@ -1116,6 +1145,7 @@ sub get_descriptions_local { $medium->{ignore} = 1; } } +#- not handling different mirrors since the file is not always available sub get_descriptions_remote { my ($urpm, $medium) = @_; @@ -1158,15 +1188,16 @@ sub get_synthesis__local { sub get_synthesis__remote { my ($urpm, $medium, $callback, $quiet) = @_; - if (urpm::download::sync($urpm, $medium, [ _url_with_synthesis($medium) ], + my $ok = try__maybe_mirrorlist($urpm, $medium, sub { + urpm::download::sync($urpm, $medium, [ _url_with_synthesis($medium) ], quiet => $quiet, callback => $callback) && - file_size(cachedir_with_synthesis($urpm, $medium)) >= 20) { - 1; - } else { + file_size(cachedir_with_synthesis($urpm, $medium)) >= 20; + }); + if (!$ok) { chomp(my $err = $@); $urpm->{error}(N("...retrieving failed: %s", $err)); - 0; } + $ok; } #- check copied/downloaded file has right signature. @@ -1425,6 +1456,8 @@ sub _update_medium_ { unlink "$urpm->{cachedir}/partial/$_"; } + _pick_mirror_if_needed($urpm, $medium, 'allow-cache-update'); + #- check for a reconfig.urpmi file (if not already reconfigured) if (!$medium->{noreconfigure}) { may_reconfig_urpmi($urpm, $medium); @@ -1503,7 +1536,7 @@ sub _update_media__handle_some_flags { $medium->{modified} = 0; } elsif ($all) { #- if we're rebuilding all media, mark them as modified (except removable ones) - $medium->{modified} ||= $medium->{url} !~ m!^removable!; + $medium->{modified} ||= !($medium->{url} && $medium->{url} =~ m!^removable!); } } } @@ -1625,6 +1658,30 @@ sub _any_media_info__or_download { $f; } +#- side-effects: +#- + those of urpm::mirrors::pick_one ($urpm->{mirrors_cache}, $medium->{url}) +sub _pick_mirror_if_needed { + my ($urpm, $medium, $allow_cache_update) = @_; + + $medium->{mirrorlist} && !$medium->{url} or return; + + require urpm::mirrors; + urpm::mirrors::pick_one($urpm, $medium, $allow_cache_update); +} + +#- side-effects: +#- + those of urpm::mirrors::try ($urpm->{mirrors_cache}, $medium->{url}) +sub try__maybe_mirrorlist { + my ($urpm, $medium, $try) = @_; + + if ($medium->{mirrorlist}) { + require urpm::mirrors; + urpm::mirrors::try($urpm, $medium, $try); + } else { + $try->(); + } +} + #- clean params and depslist computation zone. sub clean { my ($urpm) = @_; diff --git a/urpm/mirrors.pm b/urpm/mirrors.pm new file mode 100644 index 00000000..17366b38 --- /dev/null +++ b/urpm/mirrors.pm @@ -0,0 +1,212 @@ +package urpm::mirrors; + +# $Id: $ + +use strict; +use urpm::util; +use urpm::msg; +use urpm::download; + + +#- $medium fields used: mirrorlist, with-dir +#- side-effects: $medium->{url} +#- + those of _pick_one ($urpm->{mirrors_cache}) +sub try { + my ($urpm, $medium, $try) = @_; + + for (my $nb = 1; $nb < $urpm->{options}{'max-round-robin-tries'}; $nb++) { + my $url = _pick_one($urpm, $medium->{mirrorlist}, $nb == 1, '') or return; + $urpm->{info}(N("trying again with mirror %s", $url)) if $nb > 1; + $medium->{url} = _add__with_dir($url, $medium->{'with-dir'}); + $try->() and return 1; + black_list($urpm, $medium->{mirrorlist}, $url); + } + 0; +} + +#- side-effects: none +sub _add__with_dir { + my ($url, $with_dir) = @_; + reduce_pathname($url . ($with_dir ? "/$with_dir" : '')); +} + +#- side-effects: $medium->{url} +#- + those of _pick_one ($urpm->{mirrors_cache}) +sub pick_one { + my ($urpm, $medium, $allow_cache_update) = @_; + + my $url = _pick_one($urpm, $medium->{mirrorlist}, 'must_succeed', $allow_cache_update); + $medium->{url} = _add__with_dir($url, $medium->{'with-dir'}); +} + +#- side-effects: $urpm->{mirrors_cache} +sub _pick_one { + my ($urpm, $mirrorlist, $must_succeed, $allow_cache_update) = @_; + my $cache = _cache($urpm, $mirrorlist); + + if ($allow_cache_update && $cache->{time} && + time() > $cache->{time} + 24*60*60 * $urpm->{options}{'days-between-mirrorlist-update'}) { + $urpm->{log}("not using outdated cached mirror list"); + %$cache = (); + } + + if (!$cache->{chosen}) { + if (!$cache->{list}) { + $cache->{list} = [ _list($urpm, $mirrorlist) ]; + $cache->{time} = time(); + } + + $cache->{chosen} = $cache->{list}[0]{url} or do { + $must_succeed and $urpm->{fatal}(10, N("Could not find a mirror from mirrorlist %s", $mirrorlist)); + return; + }; + _save_cache($urpm); + } + if ($cache->{nb_uses}++) { + $urpm->{debug} and $urpm->{debug}("using mirror $cache->{chosen}"); + } else { + $urpm->{log}("using mirror $cache->{chosen}"); + } + + $cache->{chosen}; +} +#- side-effects: $urpm->{mirrors_cache} +sub black_list { + my ($urpm, $mirrorlist, $url) = @_; + my $cache = _cache($urpm, $mirrorlist); + + @{$cache->{list}} = grep { $_->{url} ne $url } @{$cache->{list}}; + delete $cache->{chosen}; +} +#- side-effects: $urpm->{mirrors_cache} +sub _cache { + my ($urpm, $mirrorlist) = @_; + my $full_cache = $urpm->{mirrors_cache} ||= _load_cache($urpm); + $full_cache->{$mirrorlist} ||= {}; +} +sub cache_file { + my ($urpm) = @_; + my $cache_file = "$urpm->{cachedir}/mirrors.cache"; +} +sub _load_cache { + my ($urpm) = @_; + my $cache; + if (-e cache_file($urpm)) { + $urpm->{debug} and $urpm->{debug}("loading mirrors cache"); + $cache = eval(cat_(cache_file($urpm))); + $@ and $urpm->{error}("failed to read " . cache_file($urpm) . ": $@"); + $_->{nb_uses} = 0 foreach values %$cache; + } + $cache || {}; +} +sub _save_cache { + my ($urpm) = @_; + require Data::Dumper; + my $s = Data::Dumper::Dumper($urpm->{mirrors_cache}); + $s =~ s/.*?=//; # get rid of $VAR1 = + output_safe(cache_file($urpm), $s); +} + +#- side-effects: none +sub _list { + my ($urpm, $mirrorlist) = @_; + + # expand the variable + $mirrorlist = _MIRRORLIST() if $mirrorlist eq '$MIRRORLIST'; + + my @mirrors = _mirrors_filtered($urpm, $mirrorlist); + add_proximity_and_sort($urpm, \@mirrors); + @mirrors; +} + +#- side-effects: $mirrors +sub add_proximity_and_sort { + my ($urpm, $mirrors) = @_; + + my ($latitude, $longitude, $country_code); + + require Time::ZoneInfo; + if (my $zone = Time::ZoneInfo->current_zone) { + if (my $zones = Time::ZoneInfo->new) { + if (($latitude, $longitude) = $zones->latitude_longitude_decimal($zone)) { + $country_code = $zones->country($zone); + $urpm->{log}(N("found geolocalisation %s %.2f %.2f from timezone %s", $country_code, $latitude, $longitude, $zone)); + } + } + } + defined $latitude && defined $longitude or return; + + foreach (@$mirrors) { + $_->{latitude} || $_->{longitude} or next; + my $PI = 3.14159265358979; + my $x = $latitude - $_->{latitude}; + my $y = ($longitude - $_->{longitude}) * cos($_->{latitude} / 180 * $PI); + $_->{proximity} = sqrt($x * $x + $y * $y); + } + my ($best) = sort { $a->{proximity} <=> $b->{proximity} } @$mirrors; + + foreach (@$mirrors) { + $_->{proximity_corrected} = $_->{proximity} * _random_correction(); + $_->{proximity_corrected} *= _between_country_correction($country_code, $_->{country}) if $best; + $_->{proximity_corrected} *= _between_continent_correction($best->{continent}, $_->{continent}) if $best; + } + @$mirrors = sort { $a->{proximity_corrected} <=> $b->{proximity_corrected} } @$mirrors; +} + +# add +/- 5% random +sub _random_correction() { + my $correction = 0.05; + 1 + (rand() - 0.5) * $correction * 2; +} + +sub _between_country_correction { + my ($here, $mirror) = @_; + $here && $mirror or return 1; + $here eq $mirror ? 0.5 : 1; +} +sub _between_continent_correction { + my ($here, $mirror) = @_; + $here && $mirror or return 1; + $here eq $mirror ? 0.5 : # favor same continent + $here eq 'SA' && $mirror eq 'NA' ? 0.9 : # favor going "South America" -> "North America" + 1; +} + +sub _mirrors_raw { + my ($urpm, $url) = @_; + + $urpm->{log}(N("getting mirror list from %s", $url)); + my @l = urpm::download::get_content($urpm, $url) or die "mirror list not found"; + @l; +} + +sub _mirrors_filtered { + my ($urpm, $mirrorlist) = @_; + + grep { + $_->{type} eq 'distrib'; # type=updates seems to be history, and type=iso is not interesting here + } map { chomp; parse_LDAP_namespace_structure($_) } _mirrors_raw($urpm, $mirrorlist); +} + +sub _MIRRORLIST() { + my $product_id = parse_LDAP_namespace_structure(cat_('/etc/product.id')); + _mandriva_mirrorlist($product_id); +} +sub _mandriva_mirrorlist { + my ($product_id, $o_arch) = @_; + + #- contact the following URL to retrieve the list of mirrors. + #- http://wiki.mandriva.com/en/Product_id + my $product_type = lc($product_id->{type}); $product_id =~ s/\s//g; + my $arch = $o_arch || $product_id->{arch}; + + "http://api.mandriva.com/mirrors/$product_type.$product_id->{version}.$arch.list"; +} + +sub parse_LDAP_namespace_structure { + my ($s) = @_; + my %h = map { /(.*?)=(.*)/ ? ($1 => $2) : () } split(',', $s); + \%h; +} + +1; diff --git a/urpmi.addmedia b/urpmi.addmedia index c24759a2..3bf79ba2 100755 --- a/urpmi.addmedia +++ b/urpmi.addmedia @@ -41,6 +41,15 @@ where is one of http:/// removable:// +usage: urpmi.addmedia [options] --distrib --mirrorlist +usage: urpmi.addmedia [options] --mirrorlist + +examples: + + urpmi.addmedia --distrib --mirrorlist '\$MIRRORLIST' + urpmi.addmedia --mirrorlist '\$MIRRORLIST' backports media/main/backports + + and [options] are from ") . N(" --help - print this help message. ") . N(" --wget - use wget to retrieve distant files. @@ -94,11 +103,20 @@ if ($options{'xml-info'}) { } our ($name, $url, $with, $relative_synthesis) = our @cmdline; +my $with_dir; $options{quiet} = 1 if $options{verbose} < 0; $url or ($url, $name) = ($name, ''); -$url =~ m,^(([^:]*):/)?/, or die N("bad (for local directory, the path must be absolute)") . "\n"; +if ($options{mirrorlist}) { + if ($options{distrib}) { + $url and die N("no argument needed for --distrib --mirrorlist ") . "\n"; + } else { + ($with_dir, $url) = ($url, undef); + } +} else { + $url =~ m,^(([^:]*):/)?/, or die N("bad (for local directory, the path must be absolute)") . "\n"; +} if ($< != 0) { $urpm->{fatal}(1, N("Only superuser is allowed to add media")); @@ -132,6 +150,7 @@ if ($options{distrib}) { urpm::media::add_distrib_media($urpm, $name, $url, + mirrorlist => $options{mirrorlist}, virtual => $options{virtual}, update => $options{update}, probe_with => $options{probe_with}, @@ -154,6 +173,8 @@ if ($options{distrib}) { urpm::media::add_medium($urpm, $name, $url, $relative_synthesis, + mirrorlist => $options{mirrorlist}, + 'with-dir' => $with_dir, virtual => $options{virtual}, update => $options{update}, ignore => $options{raw}, diff --git a/urpmq b/urpmq index 81f8a71d..448274a9 100755 --- a/urpmq +++ b/urpmq @@ -193,7 +193,9 @@ if ($options{list_aliases}) { foreach (@{$urpm->{media}}) { $_->{update} and print "--update "; $_->{virtual} and print "--virtual "; - print escape_shell($_->{name}), " ", escape_shell($_->{url}), " "; + $_->{mirrorlist} and print "--mirrorlist $_->{mirrorlist} "; + print escape_shell($_->{name}), " "; + print escape_shell($_->{mirrorlist} ? $_->{'with-dir'} : $_->{url}), " " if !$_->{mirrorlist} || $_->{'with-dir'}; $_->{with_synthesis} and print "with " . escape_shell($_->{with_synthesis}); print "\n"; } -- cgit v1.2.1