From 871705259637a1b980f74fe118c5a23a0674b283 Mon Sep 17 00:00:00 2001 From: Pascal Rigaux Date: Tue, 21 Nov 2006 17:43:37 +0000 Subject: move many functions from urpm.pm to urpm/media.pm --- gurpmi2 | 3 +- urpm.pm | 1827 +--------------------------------------------------- urpm/bug_report.pm | 4 +- urpm/download.pm | 105 ++- urpm/ldap.pm | 18 +- urpm/md5sum.pm | 4 +- urpm/media.pm | 1800 +++++++++++++++++++++++++++++++++++++++++++++++++++ urpm/parallel.pm | 4 +- urpme | 3 +- urpmf | 3 +- urpmi | 7 +- urpmi.addmedia | 21 +- urpmi.removemedia | 9 +- urpmi.update | 11 +- urpmq | 7 +- 15 files changed, 1970 insertions(+), 1856 deletions(-) create mode 100644 urpm/media.pm diff --git a/gurpmi2 b/gurpmi2 index 44cfcd25..0fe865b1 100755 --- a/gurpmi2 +++ b/gurpmi2 @@ -13,6 +13,7 @@ BEGIN { #- set up a safe path and environment use gurpmi; use urpm::install; +use urpm::media; use Gtk2; #- GUI globals @@ -117,7 +118,7 @@ sub configure_urpm() { }; urpm::sys::lock_rpm_db($urpm, 'exclusive'); urpm::sys::lock_urpmi_db($urpm); - $urpm->configure( + urpm::media::configure($urpm, root => $gurpmi::options{root}, media => $gurpmi::options{media}, searchmedia => $gurpmi::options{searchmedia}, diff --git a/urpm.pm b/urpm.pm index 16177d4f..1750d9a1 100644 --- a/urpm.pm +++ b/urpm.pm @@ -14,7 +14,8 @@ use urpm::md5sum; use MDV::Distribconf; our $VERSION = '4.8.29'; -our @ISA = qw(URPM); +our @ISA = qw(URPM Exporter); +our @EXPORT_OK = 'file_from_local_url'; use URPM; use URPM::Resolve; @@ -54,1115 +55,19 @@ sub new { $self; } -our @PER_MEDIA_OPT = qw( - downloader - hdlist - ignore - key-ids - list - md5sum - noreconfigure - priority - priority-upgrade - removable - static - synthesis - update - url - verify-rpm - virtual - with_hdlist -); - -sub read_private_netrc { - my ($urpm) = @_; - - my @words = split(/\s+/, scalar cat_($urpm->{private_netrc})); - my @l; - my $e; - while (@words) { - my $keyword = shift @words; - if ($keyword eq 'machine') { - push @l, $e = { machine => shift(@words) }; - } elsif ($keyword eq 'default') { - push @l, $e = { default => '' }; - } elsif ($keyword eq 'login' || $keyword eq 'password' || $keyword eq 'account') { - $e->{$keyword} = shift(@words); - } else { - $urpm->{error}("unknown netrc command $keyword"); - } - } - @l; -} - -sub parse_url_with_login { - my ($url) = @_; - $url =~ m!([^:]*)://([^/:\@]*)(:([^/:\@]*))?\@([^/]*)(.*)! && - { proto => $1, login => $2, password => $4, machine => $5, dir => $6 }; -} - -sub read_config_add_passwords { - my ($urpm, $config) = @_; - - my @netrc = read_private_netrc($urpm) or return; - foreach (values %$config) { - my $u = 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}); - } else { - $urpm->{log}("no password found for $u->{login}@$u->{machine}"); - } - } -} - -sub remove_passwords_and_write_private_netrc { - my ($urpm, $config) = @_; - - my @l; - foreach (values %$config) { - my $u = parse_url_with_login($_->{url}) or next; - #- check whether a password is visible - $u->{password} or next; - - push @l, $u; - $_->{url} = sprintf('%s://%s@%s%s', $u->{proto}, $u->{login}, $u->{machine}, $u->{dir}); - } - { - my $fh = urpm::sys::open_safe($urpm, '>', $urpm->{private_netrc}) or return; - foreach my $u (@l) { - printf $fh "machine %s login %s password %s\n", $u->{machine}, $u->{login}, $u->{password}; - } - } - chmod 0600, $urpm->{private_netrc}; -} - -#- handle deprecated way of saving passwords -sub recover_url_from_list { - my ($urpm, $medium) = @_; - - #- /./ is end of url marker in list file (typically generated by a - #- find . -name "*.rpm" > list - #- for exportable list file. - if (my @probe = map { m!^(.*)/\./! || m!^(.*)/[^/]*$! } cat_(statedir_list($urpm, $medium))) { - ($medium->{url}) = sort { length($a) <=> length($b) } @probe; - $urpm->{modified} = 1; #- ensure urpmi.cfg is handled using only partially hidden url + netrc, since file list won't be generated anymore - } -} - -#- Loads /etc/urpmi/urpmi.cfg and performs basic checks. -#- Does not handle old format: [with ] -#- options : -#- - nocheck_access : don't check presence of hdlist and other files -sub read_config { - my ($urpm, $b_nocheck_access) = @_; - return if $urpm->{media}; #- media already loaded - $urpm->{media} = []; - my $config = urpm::cfg::load_config($urpm->{config}) - or $urpm->{fatal}(6, $urpm::cfg::err); - - #- global options - if (my $global = $config->{''}) { - foreach my $opt (keys %$global) { - if (defined $global->{$opt} && !exists $urpm->{options}{$opt}) { - $urpm->{options}{$opt} = $global->{$opt}; - } - } - } - - #- per-media options - - read_config_add_passwords($urpm, $config); - - foreach my $m (grep { $_ ne '' } keys %$config) { - my $medium = { name => $m }; - foreach my $opt (@PER_MEDIA_OPT) { - defined $config->{$m}{$opt} and $medium->{$opt} = $config->{$m}{$opt}; - } - - if (!$medium->{url}) { - #- recover the url the old deprecated way... - #- only useful for migration, new urpmi.cfg will use netrc - recover_url_from_list($urpm, $medium); - $medium->{url} or $urpm->{error}("unable to find url in list file $medium->{name}, medium ignored"); - } - - $urpm->add_existing_medium($medium, $b_nocheck_access); - } - - eval { require urpm::ldap; urpm::ldap::load_ldap_media($urpm) }; - - #- load default values - foreach (qw(post-clean verify-rpm)) { - exists $urpm->{options}{$_} or $urpm->{options}{$_} = 1; - } - - $urpm->{media} = [ sort { $a->{priority} <=> $b->{priority} } @{$urpm->{media}} ]; - - #- read MD5 sums (usually not in urpmi.cfg but in a separate file) - foreach (@{$urpm->{media}}) { - if (my $md5sum = urpm::md5sum::from_MD5SUM("$urpm->{statedir}/MD5SUM", statedir_hdlist_or_synthesis($urpm, $_))) { - $_->{md5sum} = $md5sum; - } - } - - #- remember global options for write_config - $urpm->{global_config} = $config->{''}; -} - -#- if invalid, set {ignore} -sub check_existing_medium { - my ($urpm, $medium, $b_nocheck_access) = @_; - - if ($medium->{virtual}) { - #- a virtual medium needs to have an url available without using a list file. - if ($medium->{hdlist} || $medium->{list}) { - $medium->{ignore} = 1; - $urpm->{error}(N("virtual medium \"%s\" should not have defined hdlist or list file, medium ignored", - $medium->{name})); - } - unless ($medium->{url}) { - $medium->{ignore} = 1; - $urpm->{error}(N("virtual medium \"%s\" should have a clear url, medium ignored", - $medium->{name})); - } - } else { - if ($medium->{hdlist}) { - #- is this check really needed? keeping just in case - $medium->{hdlist} ne 'list' && $medium->{hdlist} ne 'pubkey' or - $medium->{ignore} = 1, - $urpm->{error}(N("invalid hdlist name")); - } - if (!$medium->{ignore} && !$medium->{hdlist}) { - $medium->{hdlist} = "hdlist.$medium->{name}.cz"; - -e statedir_hdlist($urpm, $medium) or - $medium->{ignore} = 1, - $urpm->{error}(N("unable to find hdlist file for \"%s\", medium ignored", $medium->{name})); - } - if (!$medium->{ignore} && !$medium->{list}) { - unless (defined $medium->{url}) { - $medium->{list} = "list.$medium->{name}"; - unless (-e statedir_list($urpm, $medium)) { - $medium->{ignore} = 1, - $urpm->{error}(N("unable to find list file for \"%s\", medium ignored", $medium->{name})); - } - } - } - } - - - #- check the presence of hdlist and list files if necessary. - if (!$b_nocheck_access && !$medium->{ignore}) { - if ($medium->{virtual} && -r hdlist_or_synthesis_for_virtual_medium($medium)) {} - elsif (-r statedir_hdlist($urpm, $medium)) {} - elsif ($medium->{synthesis} && -r statedir_synthesis($urpm, $medium)) {} - else { - $medium->{ignore} = 1; - $urpm->{error}(N("unable to access hdlist file of \"%s\", medium ignored", $medium->{name})); - } - if ($medium->{list} && -r statedir_list($urpm, $medium)) {} - elsif ($medium->{url}) {} - else { - $medium->{ignore} = 1; - $urpm->{error}(N("unable to access list file of \"%s\", medium ignored", $medium->{name})); - } - } - - foreach my $field ('hdlist', 'list') { - $medium->{$field} or next; - if (grep { $_->{$field} eq $medium->{$field} } @{$urpm->{media}}) { - $medium->{ignore} = 1; - $urpm->{error}( - $field eq 'hdlist' - ? N("medium \"%s\" trying to use an already used hdlist, medium ignored", $medium->{name}) - : N("medium \"%s\" trying to use an already used list, medium ignored", $medium->{name})); - } - } -} - -#- probe medium to be used, take old medium into account too. -sub add_existing_medium { - my ($urpm, $medium, $b_nocheck_access) = @_; - - if (name2medium($urpm, $medium->{name})) { - $urpm->{error}(N("trying to override existing medium \"%s\", skipping", $medium->{name})); - return; - } - - check_existing_medium($urpm, $medium, $b_nocheck_access); - - #- probe removable device. - $urpm->probe_removable_device($medium); - - #- clear URLs for trailing /es. - $medium->{url} and $medium->{url} =~ s|(.*?)/*$|$1|; - - push @{$urpm->{media}}, $medium; -} - -#- returns the removable device name if it corresponds to an iso image, '' otherwise -sub is_iso { - my ($removable_dev) = @_; - $removable_dev && $removable_dev =~ /\.iso$/i; -} - -sub protocol_from_url { - my ($url) = @_; - $url =~ m!^([^:_]*)[^:]*:! && $1; -} -sub file_from_local_url { - my ($url) = @_; - $url =~ m!^(?:removable[^:]*:/|file:/)?(/.*)! && $1; -} -sub file_from_file_url { - my ($url) = @_; - $url =~ m!^(?:file:/)?(/.*)! && $1; -} - -sub _hdlist_dir { - my ($medium) = @_; - my $base = file_from_file_url($medium->{url}) || $medium->{url}; - $medium->{with_hdlist} && reduce_pathname("$base/$medium->{with_hdlist}/.."); -} -sub _url_with_hdlist { - my ($medium) = @_; - - my $base = file_from_file_url($medium->{url}) || $medium->{url}; - $medium->{with_hdlist} && reduce_pathname("$base/$medium->{with_hdlist}"); -} -sub hdlist_or_synthesis_for_virtual_medium { - my ($medium) = @_; - file_from_file_url($medium->{url}) && _url_with_hdlist($medium); -} - -sub statedir_hdlist_or_synthesis { - my ($urpm, $medium) = @_; - $medium->{hdlist} && "$urpm->{statedir}/" . ($medium->{synthesis} ? 'synthesis.' : '') . $medium->{hdlist}; -} -sub statedir_hdlist { - my ($urpm, $medium) = @_; - $medium->{hdlist} && "$urpm->{statedir}/$medium->{hdlist}"; -} -sub statedir_synthesis { - my ($urpm, $medium) = @_; - $medium->{hdlist} && "$urpm->{statedir}/synthesis.$medium->{hdlist}"; -} -sub statedir_list { - my ($urpm, $medium) = @_; - $medium->{list} && "$urpm->{statedir}/$medium->{list}"; -} -sub statedir_descriptions { - my ($urpm, $medium) = @_; - $medium->{name} && "$urpm->{statedir}/descriptions.$medium->{name}"; -} -sub statedir_names { - my ($urpm, $medium) = @_; - $medium->{name} && "$urpm->{statedir}/names.$medium->{name}"; -} -sub cachedir_hdlist { - my ($urpm, $medium) = @_; - $medium->{hdlist} && "$urpm->{cachedir}/partial/$medium->{hdlist}"; -} -sub cachedir_list { - my ($urpm, $medium) = @_; - $medium->{list} && "$urpm->{cachedir}/partial/$medium->{list}"; -} - -sub name2medium { - my ($urpm, $name) = @_; - my ($medium) = grep { $_->{name} eq $name } @{$urpm->{media}}; - $medium; -} - -#- probe device associated with a removable device. -sub probe_removable_device { - my ($urpm, $medium) = @_; - - if ($medium->{url} && $medium->{url} =~ /^removable/) { - #- try to find device name in url scheme, this is deprecated, use medium option "removable" instead - if ($medium->{url} =~ /^removable_?([^_:]*)/) { - $medium->{removable} ||= $1 && "/dev/$1"; - } - } else { - delete $medium->{removable}; - return; - } - - #- try to find device to open/close for removable medium. - if (my $dir = file_from_local_url($medium->{url})) { - my %infos; - my @mntpoints = urpm::sys::find_mntpoints($dir, \%infos); - if (@mntpoints > 1) { #- return value is suitable for an hash. - $urpm->{log}(N("too many mount points for removable medium \"%s\"", $medium->{name})); - $urpm->{log}(N("taking removable device as \"%s\"", join ',', map { $infos{$_}{device} } @mntpoints)); - } - if (is_iso($medium->{removable})) { - $urpm->{log}(N("Medium \"%s\" is an ISO image, will be mounted on-the-fly", $medium->{name})); - } elsif (@mntpoints) { - if ($medium->{removable} && $medium->{removable} ne $infos{$mntpoints[-1]}{device}) { - $urpm->{log}(N("using different removable device [%s] for \"%s\"", - $infos{$mntpoints[-1]}{device}, $medium->{name})); - } - $medium->{removable} = $infos{$mntpoints[-1]}{device}; - } else { - $urpm->{error}(N("unable to retrieve pathname for removable medium \"%s\"", $medium->{name})); - } - } else { - $urpm->{error}(N("unable to retrieve pathname for removable medium \"%s\"", $medium->{name})); - } -} - - -sub write_MD5SUM { - my ($urpm) = @_; - - #- write MD5SUM file - my $fh = urpm::sys::open_safe($urpm, '>', "$urpm->{statedir}/MD5SUM") or return 0; - foreach my $medium (grep { $_->{md5sum} } @{$urpm->{media}}) { - my $s = basename(statedir_hdlist_or_synthesis($urpm, $medium)); - print $fh "$medium->{md5sum} $s\n"; - } - - $urpm->{log}(N("wrote %s", "$urpm->{statedir}/MD5SUM")); - - delete $urpm->{md5sum_modified}; -} - -#- Writes the urpmi.cfg file. -sub write_urpmi_cfg { - my ($urpm) = @_; - - #- avoid trashing exiting configuration if it wasn't loaded - $urpm->{media} or return; - - my $config = { - #- global config options found in the config file, without the ones - #- set from the command-line - '' => $urpm->{global_config}, - }; - foreach my $medium (@{$urpm->{media}}) { - next if $medium->{external}; - my $medium_name = $medium->{name}; - - foreach (@PER_MEDIA_OPT) { - defined $medium->{$_} and $config->{$medium_name}{$_} = $medium->{$_}; - } - } - remove_passwords_and_write_private_netrc($urpm, $config); - - urpm::cfg::dump_config($urpm->{config}, $config) - or $urpm->{fatal}(6, N("unable to write config file [%s]", $urpm->{config})); - - $urpm->{log}(N("wrote config file [%s]", $urpm->{config})); - - #- everything should be synced now. - delete $urpm->{modified}; -} - -sub write_config { - my ($urpm) = @_; - - write_urpmi_cfg($urpm); - write_MD5SUM($urpm); -} - -#- read urpmi.cfg file as well as necessary synthesis files -#- options : -#- root -#- cmdline_skiplist -#- nocheck_access (used by read_config) -#- -#- callback (urpmf) -#- need_hdlist (for urpmf: to be able to have info not available in synthesis) -#- nodepslist (for urpmq: we don't need the hdlist/synthesis) -#- no_skiplist (urpmf) -#- -#- synthesis (use this synthesis file, and only this synthesis file) -#- -#- usedistrib (otherwise uses urpmi.cfg) -#- parallel -#- media -#- excludemedia -#- sortmedia -#- -#- update -#- searchmedia -sub configure { - my ($urpm, %options) = @_; - - $urpm->clean; - - $options{parallel} && $options{usedistrib} and $urpm->{fatal}(1, N("Can't use parallel mode with use-distrib mode")); - - if ($options{parallel}) { - require urpm::parallel; - urpm::parallel::configure($urpm, $options{parallel}); - - if (!$options{media} && $urpm->{parallel_handler}{media}) { - $options{media} = $urpm->{parallel_handler}{media}; - $urpm->{log}->(N("using associated media for parallel mode: %s", $options{media})); - } - } else { - #- nb: can't have both parallel and root - $urpm->{root} = $options{root}; - } - - $urpm->{root} && ! -c "$urpm->{root}/dev/null" - and $urpm->{error}(N("there doesn't seem to be devices in the chroot in \"%s\"", $urpm->{root})); - - if ($options{synthesis}) { - if ($options{synthesis} ne 'none') { - #- synthesis take precedence over media, update options. - $options{media} || $options{excludemedia} || $options{sortmedia} || $options{update} || $options{usedistrib} || $options{parallel} and - $urpm->{fatal}(1, N("--synthesis cannot be used with --media, --excludemedia, --sortmedia, --update, --use-distrib or --parallel")); - $urpm->parse_synthesis($options{synthesis}); - #- synthesis disables the split of transaction (too risky and not useful). - $urpm->{options}{'split-length'} = 0; - } - } else { - if ($options{usedistrib}) { - $urpm->{media} = []; - $urpm->add_distrib_media("Virtual", $options{usedistrib}, %options, 'virtual' => 1); - } else { - $urpm->read_config($options{nocheck_access}); - if (!$options{media} && $urpm->{options}{'default-media'}) { - $options{media} = $urpm->{options}{'default-media'}; - } - } - if ($options{media}) { - delete $_->{modified} foreach @{$urpm->{media} || []}; - $urpm->select_media(split /,/, $options{media}); - foreach (grep { !$_->{modified} } @{$urpm->{media} || []}) { - #- this is only a local ignore that will not be saved. - $_->{tempignore} = $_->{ignore} = 1; - } - } - if ($options{searchmedia}) { - $urpm->select_media($options{searchmedia}); #- Ensure this media has been selected - if (my $medium = name2medium($urpm, $options{searchmedia})) { - $medium->{ignore} and $urpm->{fatal}("searchmedia is ignored"); - $medium->{searchmedia} = 1; - } - } - if ($options{excludemedia}) { - delete $_->{modified} foreach @{$urpm->{media} || []}; - foreach (select_media_by_name($urpm, [ split /,/, $options{excludemedia} ])) { - $_->{modified} = 1; - #- this is only a local ignore that will not be saved. - $_->{tempignore} = $_->{ignore} = 1; - } - } - if ($options{sortmedia}) { - my @sorted_media = map { select_media_by_name($urpm, [$_]) } split(/,/, $options{sortmedia}); - my @remaining = difference2($urpm->{media}, \@sorted_media); - $urpm->{media} = [ @sorted_media, @remaining ]; - } - _parse_media($urpm, 0, \%options) if !$options{nodepslist}; - } - #- determine package to withdraw (from skip.list file) only if something should be withdrawn. - if (!$options{nodepslist}) { - _compute_flags_for_skiplist($urpm, $options{cmdline_skiplist}) if !$options{no_skiplist}; - _compute_flags_for_instlist($urpm); - } -} - -sub _parse_media { - my ($urpm, $second_pass, $options) = @_; - - foreach (grep { !$_->{ignore} && (!$options->{update} || $_->{update}) } @{$urpm->{media} || []}) { - our $currentmedia = $_; #- hack for urpmf - delete @$_{qw(start end)}; - if ($_->{virtual}) { - if (file_from_file_url($_->{url})) { - if ($_->{synthesis}) { - _parse_synthesis($urpm, $_, - hdlist_or_synthesis_for_virtual_medium($_), $options->{callback}); - } else { - #- we'll need a second pass - $second_pass++; - _parse_hdlist($urpm, $_, - hdlist_or_synthesis_for_virtual_medium($_), - $second_pass > 1 ? undef : $options->{callback}, - ); - } - } else { - $urpm->{error}(N("virtual medium \"%s\" is not local, medium ignored", $_->{name})); - $_->{ignore} = 1; - } - } else { - if ($options->{need_hdlist} && file_size(statedir_hdlist($urpm, $_)) > 32) { - _parse_hdlist($urpm, $_, statedir_hdlist($urpm, $_), $options->{callback}); - } else { - if (!_parse_synthesis($urpm, $_, - statedir_synthesis($urpm, $_), - $options->{callback})) { - _parse_hdlist($urpm, $_, statedir_hdlist($urpm, $_), $options->{callback}); - } - } - } - unless ($_->{ignore}) { - _check_after_reading_hdlist_or_synthesis($urpm, $_); - } - unless ($_->{ignore}) { - if ($_->{searchmedia}) { - ($urpm->{searchmedia}{start}, $urpm->{searchmedia}{end}) = ($_->{start}, $_->{end}); - $urpm->{log}(N("Search start: %s end: %s", - $urpm->{searchmedia}{start}, $urpm->{searchmedia}{end})); - delete $_->{searchmedia}; - } - } - } - - if ($second_pass == 1) { - require URPM::Build; - $urpm->{log}(N("performing second pass to compute dependencies\n")); - $urpm->unresolved_provides_clean; - _parse_media($urpm, 1, $options); - } -} - -sub _compute_flags_for_skiplist { - my ($urpm, $cmdline_skiplist) = @_; - my %uniq; - $urpm->compute_flags( - get_packages_list($urpm->{skiplist}, $cmdline_skiplist), - skip => 1, - callback => sub { - my ($urpm, $pkg) = @_; - $pkg->is_arch_compat && ! exists $uniq{$pkg->fullname} or return; - $uniq{$pkg->fullname} = undef; - $urpm->{log}(N("skipping package %s", scalar($pkg->fullname))); - }, - ); -} - -sub _compute_flags_for_instlist { - my ($urpm) = @_; - - my %uniq; - $urpm->compute_flags( - get_packages_list($urpm->{instlist}), - disable_obsolete => 1, - callback => sub { - my ($urpm, $pkg) = @_; - $pkg->is_arch_compat && ! exists $uniq{$pkg->fullname} or return; - $uniq{$pkg->fullname} = undef; - $urpm->{log}(N("would install instead of upgrade package %s", scalar($pkg->fullname))); - }, - ); - -} - -#- 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 -sub add_medium { - my ($urpm, $name, $url, $with_hdlist, %options) = @_; - - #- make sure configuration has been read. - $urpm->{media} or die "caller should have used ->read_config or ->configure first"; - urpm::sys::lock_urpmi_db($urpm, 'exclusive') if !$options{nolock}; - - #- if a medium with that name has already been found, we have to exit now - my $medium; - if (defined $options{index_name}) { - my $i = $options{index_name}; - do { - ++$i; - $medium = name2medium($urpm, $name . $i); - } while $medium; - $name .= $i; - } else { - $medium = name2medium($urpm, $name); - } - $medium and $urpm->{fatal}(5, N("medium \"%s\" already exists", $medium->{name})); - - $url =~ s,/*$,,; #- clear URLs for trailing /es. - - #- creating the medium info. - $medium = { name => $name, url => $url, update => $options{update}, modified => 1, ignore => $options{ignore} }; - if ($options{virtual}) { - file_from_file_url($url) or $urpm->{fatal}(1, N("virtual medium needs to be local")); - $medium->{virtual} = 1; - } else { - $medium->{hdlist} = "hdlist.$name.cz"; - $urpm->probe_removable_device($medium); - } - - #- local media have priority, other are added at the end. - if (file_from_file_url($url)) { - $medium->{priority} = 0.5; - } else { - $medium->{priority} = 1 + @{$urpm->{media}}; - } - - $with_hdlist and $medium->{with_hdlist} = $with_hdlist; - - #- create an entry in media list. - push @{$urpm->{media}}, $medium; - - $urpm->{log}(N("added medium %s", $name)); - $urpm->{modified} = 1; - - $options{nolock} or urpm::sys::unlock_urpmi_db($urpm); - $name; -} - -#- add distribution media, according to url given. -#- returns the list of names of added media. -#- options : -#- - initial_number : when adding several numbered media, start with this number -#- - probe_with : if eq 'synthesis', use synthesis instead of hdlists -#- - ask_media : callback to know whether each media should be added -#- other options are passed to add_medium(): ignore, nolock, virtual -sub add_distrib_media { - my ($urpm, $name, $url, %options) = @_; - - #- make sure configuration has been read. - $urpm->{media} or die "caller should have used ->read_config or ->configure first"; - - my $distribconf; - - if (my $dir = file_from_local_url($url)) { - $urpm->try_mounting($dir) - or $urpm->{error}(N("unable to mount the distribution medium")), return (); - $distribconf = MDV::Distribconf->new($dir, undef); - $distribconf->load - or $urpm->{error}(N("this location doesn't seem to contain any distribution")), return (); - } else { - unlink "$urpm->{cachedir}/partial/media.cfg"; - - $distribconf = MDV::Distribconf->new($url, undef); - $distribconf->settree('mandriva'); - - $urpm->{log}(N("retrieving media.cfg file...")); - if (urpm::download::sync($urpm, undef, - [ reduce_pathname($distribconf->getfullpath(undef, 'infodir') . '/media.cfg') ], - quiet => 1)) { - $urpm->{log}(N("...retrieving done")); - $distribconf->parse_mediacfg("$urpm->{cachedir}/partial/media.cfg") - or $urpm->{error}(N("unable to parse media.cfg")), return(); - } else { - $urpm->{error}(N("...retrieving failed: %s", $@)); - $urpm->{error}(N("unable to access the distribution medium (no media.cfg file found)")); - return (); - } - } - - #- cosmetic update of name if it contains spaces. - $name =~ /\s/ and $name .= ' '; - - my @newnames; - #- at this point, we have found a media.cfg file, so parse it - #- and create all necessary media according to it. - my $medium = $options{initial_number} || 1; - - foreach my $media ($distribconf->listmedia) { - my $skip = 0; - # if one of those values is set, by default, we skip adding the media - foreach (qw(noauto)) { - $distribconf->getvalue($media, $_) and do { - $skip = 1; - last; - }; - } - if ($options{ask_media}) { - if ($options{ask_media}->( - $distribconf->getvalue($media, 'name'), - !$skip, - )) { - $skip = 0; - } else { - $skip = 1; - } - } - $skip and next; - - my $media_name = $distribconf->getvalue($media, 'name') || ''; - my $is_update_media = $distribconf->getvalue($media, 'updates_for'); - - push @newnames, $urpm->add_medium( - $name ? "$media_name ($name$medium)" : $media_name, - reduce_pathname($distribconf->getfullpath($media, 'path')), - offset_pathname( - $url, - $distribconf->getpath($media, 'path'), - ) . '/' . $distribconf->getpath($media, $options{probe_with} eq 'synthesis' ? 'synthesis' : 'hdlist'), - index_name => $name ? undef : 0, - %options, - # the following override %options - update => $is_update_media ? 1 : undef, - ); - ++$medium; - } - return @newnames; -} - -#- deprecated, use select_media_by_name instead -sub select_media { - my $urpm = shift; - my $options = {}; - if (ref $_[0]) { $options = shift } - foreach (select_media_by_name($urpm, [ @_ ], $options->{strict_match})) { - #- select medium by setting the modified flag, do not check ignore. - $_->{modified} = 1; - } -} - -sub select_media_by_name { - my ($urpm, $names, $b_strict_match) = @_; - - my %wanted = map { $_ => 1 } @$names; - - #- first the exact matches - my @l = grep { delete $wanted{$_->{name}} } @{$urpm->{media}}; - - #- check if some arguments don't correspond to the medium name. - #- in such case, try to find the unique medium (or list candidate - #- media found). - foreach (keys %wanted) { - my $q = quotemeta; - my (@found, @foundi); - my $regex = $b_strict_match ? qr/^$q$/ : qr/$q/; - my $regexi = $b_strict_match ? qr/^$q$/i : qr/$q/i; - foreach my $medium (@{$urpm->{media}}) { - $medium->{name} =~ $regex and push @found, $medium; - $medium->{name} =~ $regexi and push @foundi, $medium; - } - @found = @foundi if !@found; - - if (@found == 0) { - $urpm->{error}(N("trying to select nonexistent medium \"%s\"", $_)); - } else { - if (@found > 1) { - $urpm->{log}(N("selecting multiple media: %s", join(", ", map { qq("$_->{name}") } @found))); - } - #- changed behaviour to select all occurences by default. - push @l, @found; - } - } - @l; -} - -#- deprecated, use remove_media instead -sub remove_selected_media { - my ($urpm) = @_; - - remove_media($urpm, [ grep { $_->{modified} } @{$urpm->{media}} ]); -} - -sub remove_media { - my ($urpm, $to_remove) = @_; - - foreach my $medium (@$to_remove) { - $urpm->{log}(N("removing medium \"%s\"", $medium->{name})); - - #- mark to re-write configuration. - $urpm->{modified} = 1; - - #- remove files associated with this medium. - unlink grep { $_ } map { $_->($urpm, $medium) } \&statedir_hdlist, \&statedir_list, \&statedir_synthesis, \&statedir_descriptions, \&statedir_names; - - #- remove proxy settings for this media - urpm::download::remove_proxy_media($medium->{name}); - } - - $urpm->{media} = [ difference2($urpm->{media}, $to_remove) ]; -} - -#- return list of synthesis or hdlist reference to probe. -sub _probe_with_try_list { - my ($probe_with) = @_; - - my @probe_synthesis = ( - "media_info/synthesis.hdlist.cz", - "synthesis.hdlist.cz", - ); - my @probe_hdlist = ( - "media_info/hdlist.cz", - "hdlist.cz", - ); - $probe_with =~ /synthesis/ - ? (@probe_synthesis, @probe_hdlist) - : (@probe_hdlist, @probe_synthesis); -} - -sub may_reconfig_urpmi { - my ($urpm, $medium) = @_; - - my $f; - if (my $dir = file_from_file_url($medium->{url})) { - $f = reduce_pathname("$dir/reconfig.urpmi"); - } else { - unlink($f = "$urpm->{cachedir}/partial/reconfig.urpmi"); - urpm::download::sync($urpm, $medium, [ reduce_pathname("$medium->{url}/reconfig.urpmi") ], quiet => 1); - } - if (-s $f) { - reconfig_urpmi($urpm, $f, $medium->{name}); - } - unlink $f if !file_from_file_url($medium->{url}); -} - -#- read a reconfiguration file for urpmi, and reconfigure media accordingly -#- $rfile is the reconfiguration file (local), $name is the media name -#- -#- the format is similar to the RewriteRule of mod_rewrite, so: -#- PATTERN REPLACEMENT [FLAG] -#- where FLAG can be L or N -#- -#- example of reconfig.urpmi: -#- # this is an urpmi reconfiguration file -#- /cooker /cooker/$ARCH -sub reconfig_urpmi { - my ($urpm, $rfile, $name) = @_; - -r $rfile or return; - - $urpm->{log}(N("reconfiguring urpmi for media \"%s\"", $name)); - - my ($magic, @lines) = cat_($rfile); - #- the first line of reconfig.urpmi must be magic, to be sure it's not an error file - $magic =~ /^# this is an urpmi reconfiguration file/ or return undef; - - my @replacements; - foreach (@lines) { - chomp; - s/^\s*//; s/#.*$//; s/\s*$//; - $_ or next; - my ($p, $r, $f) = split /\s+/, $_, 3; - push @replacements, [ quotemeta $p, $r, $f || 1 ]; - } - - my $reconfigured = 0; - my @reconfigurable = qw(url with_hdlist); - - my $medium = name2medium($urpm, $name) or return; - my %orig = %$medium; - - URLS: - foreach my $k (@reconfigurable) { - foreach my $r (@replacements) { - if ($medium->{$k} =~ s/$r->[0]/$r->[1]/) { - $reconfigured = 1; - #- Flags stolen from mod_rewrite: L(ast), N(ext) - if ($r->[2] =~ /L/) { - last; - } elsif ($r->[2] =~ /N/) { #- dangerous option - redo URLS; - } - } - } - #- check that the new url exists before committing changes (local mirrors) - my $file = file_from_local_url($medium->{$k}); - if ($file && !-e $file) { - %$medium = %orig; - $reconfigured = 0; - $urpm->{log}(N("...reconfiguration failed")); - return; - } - } - - if ($reconfigured) { - $urpm->{log}(N("reconfiguration done")); - $urpm->write_config; - } - $reconfigured; -} - -sub _guess_hdlist_suffix { - my ($url) = @_; - $url =~ m!\bmedia/(\w+)/*\Z! && $1; -} - -sub _hdlist_suffix { - my ($medium) = @_; - $medium->{with_hdlist} =~ /hdlist(.*?)(?:\.src)?\.cz$/ ? $1 : ''; -} - -sub _parse_hdlist_or_synthesis__when_not_modified { - my ($urpm, $medium) = @_; - - delete @$medium{qw(start end)}; - if ($medium->{virtual}) { - if (file_from_file_url($medium->{url})) { - _parse_maybe_hdlist_or_synthesis($urpm, $medium, hdlist_or_synthesis_for_virtual_medium($medium)); - } else { - $urpm->{error}(N("virtual medium \"%s\" is not local, medium ignored", $medium->{name})); - $medium->{ignore} = 1; - } - } else { - if (!_parse_synthesis($urpm, $medium, statedir_synthesis($urpm, $medium))) { - _parse_hdlist($urpm, $medium, statedir_hdlist($urpm, $medium)); - } - } - unless ($medium->{ignore}) { - _check_after_reading_hdlist_or_synthesis($urpm, $medium); - } -} - -sub _parse_hdlist_or_synthesis__virtual { - my ($urpm, $medium) = @_; - - if (my $hdlist_or = hdlist_or_synthesis_for_virtual_medium($medium)) { - delete $medium->{modified}; - $medium->{really_modified} = 1; - $urpm->{md5sum_modified} = 1; - _parse_maybe_hdlist_or_synthesis($urpm, $medium, $hdlist_or); - _check_after_reading_hdlist_or_synthesis($urpm, $medium); - } else { - $urpm->{error}(N("virtual medium \"%s\" should have valid source hdlist or synthesis, medium ignored", - $medium->{name})); - $medium->{ignore} = 1; - } -} - -#- names. is used by external progs (namely for bash-completion) -sub generate_medium_names { - my ($urpm, $medium) = @_; - - unlink statedir_names($urpm, $medium); - - if (my $fh = urpm::sys::open_safe($urpm, ">", statedir_names($urpm, $medium))) { - foreach ($medium->{start} .. $medium->{end}) { - if (defined $urpm->{depslist}[$_]) { - print $fh $urpm->{depslist}[$_]->name . "\n"; - } else { - $urpm->{error}(N("Error generating names file: dependency %d not found", $_)); - } - } - } else { - $urpm->{error}(N("Error generating names file: Can't write to file (%s)", $!)); - } -} - - -sub _read_existing_synthesis_and_hdlist_if_same_time_and_msize { - my ($urpm, $medium, $basename) = @_; - - same_size_and_mtime("$urpm->{cachedir}/partial/$basename", - statedir_hdlist($urpm, $medium)) or return; - - unlink "$urpm->{cachedir}/partial/$basename"; - - _read_existing_synthesis_and_hdlist($urpm, $medium); - - 1; -} - -sub _read_existing_synthesis_and_hdlist_if_same_md5sum { - my ($urpm, $medium, $retrieved_md5sum) = @_; - - #- if an existing hdlist or synthesis file has the same md5sum, we assume the - #- files are the same. - #- if local md5sum is the same as distant md5sum, this means there is no need to - #- download hdlist or synthesis file again. - $retrieved_md5sum && $medium->{md5sum} eq $retrieved_md5sum or return; - - unlink "$urpm->{cachedir}/partial/" . basename($medium->{with_hdlist}); - - _read_existing_synthesis_and_hdlist($urpm, $medium); - - 1; -} - -sub _read_existing_synthesis_and_hdlist { - my ($urpm, $medium) = @_; - - $urpm->{log}(N("medium \"%s\" is up-to-date", $medium->{name})); - - #- the medium is now considered not modified. - $medium->{modified} = 0; - #- XXX we could link the new hdlist to the old one. - #- (However links need to be managed. see bug #12391.) - #- as previously done, just read synthesis file here, this is enough. - if (!_parse_synthesis($urpm, $medium, statedir_synthesis($urpm, $medium))) { - _parse_hdlist($urpm, $medium, statedir_hdlist($urpm, $medium)); - _check_after_reading_hdlist_or_synthesis($urpm, $medium); - } - - 1; -} - -sub _parse_hdlist { - my ($urpm, $medium, $hdlist_file, $o_callback) = @_; - - $urpm->{log}(N("examining hdlist file [%s]", $hdlist_file)); - ($medium->{start}, $medium->{end}) = - $urpm->parse_hdlist($hdlist_file, packing => 1, $o_callback ? (callback => $o_callback) : @{[]}); -} - -sub _parse_synthesis { - my ($urpm, $medium, $synthesis_file, $o_callback) = @_; - - $urpm->{log}(N("examining synthesis file [%s]", $synthesis_file)); - ($medium->{start}, $medium->{end}) = - $urpm->parse_synthesis($synthesis_file, $o_callback ? (callback => $o_callback) : @{[]}); -} -sub _parse_maybe_hdlist_or_synthesis { - my ($urpm, $medium, $hdlist_or) = @_; - - if ($medium->{synthesis}) { - if (_parse_synthesis($urpm, $medium, $hdlist_or)) { - $medium->{synthesis} = 1; - } elsif (_parse_hdlist($urpm, $medium, $hdlist_or)) { - delete $medium->{synthesis}; - } else { - return; - } - } else { - if (_parse_hdlist($urpm, $medium, $hdlist_or)) { - delete $medium->{synthesis}; - } elsif (_parse_synthesis($urpm, $medium, $hdlist_or)) { - $medium->{synthesis} = 1; - } else { - return; - } - } - 1; -} - -sub _build_hdlist_using_rpm_headers { - my ($urpm, $medium) = @_; - - $urpm->{log}(N("building hdlist [%s]", statedir_hdlist($urpm, $medium))); - #- finish building operation of hdlist. - $urpm->build_hdlist(start => $medium->{start}, - end => $medium->{end}, - dir => "$urpm->{cachedir}/headers", - hdlist => statedir_hdlist($urpm, $medium), - ); -} - -sub _build_synthesis { - my ($urpm, $medium) = @_; - - eval { $urpm->build_synthesis( - start => $medium->{start}, - end => $medium->{end}, - synthesis => statedir_synthesis($urpm, $medium), - ) }; - if ($@) { - $urpm->{error}(N("Unable to build synthesis file for medium \"%s\". Your hdlist file may be corrupted.", $medium->{name})); - $urpm->{error}($@); - unlink statedir_synthesis($urpm, $medium); - } else { - $urpm->{log}(N("built hdlist synthesis file for medium \"%s\"", $medium->{name})); - } - #- keep in mind we have a modified database, sure at this point. - $urpm->{md5sum_modified} = 1; +#- returns the removable device name if it corresponds to an iso image, '' otherwise +sub is_iso { + my ($removable_dev) = @_; + $removable_dev && $removable_dev =~ /\.iso$/i; } -sub is_valid_medium { - my ($medium) = @_; - defined $medium->{start} && defined $medium->{end}; +sub protocol_from_url { + my ($url) = @_; + $url =~ m!^([^:_]*)[^:]*:! && $1; } - -sub _check_after_reading_hdlist_or_synthesis { - my ($urpm, $medium) = @_; - - if (!is_valid_medium($medium)) { - $urpm->{error}(N("problem reading hdlist or synthesis file of medium \"%s\"", $medium->{name})); - $medium->{ignore} = 1; - } +sub file_from_local_url { + my ($url) = @_; + $url =~ m!^(?:removable[^:]*:/|file:/)?(/.*)! && $1; } sub db_open_or_die { @@ -1174,37 +79,6 @@ sub db_open_or_die { $db; } -sub _get_list_or_pubkey__local { - my ($urpm, $medium, $name) = @_; - - my $path = _hdlist_dir($medium) . "/$name" . _hdlist_suffix($medium); - -e $path or $path = file_from_local_url($medium->{url}) . "/$name"; - if (-e $path) { - copy_and_own($path, "$urpm->{cachedir}/partial/$name") - or $urpm->{error}(N("...copying failed")), return; - } - 1; -} - -sub _get_list_or_pubkey__remote { - my ($urpm, $medium, $name) = @_; - - my $found; - if (_hdlist_suffix($medium)) { - my $local_name = $name . _hdlist_suffix($medium); - - if (urpm::download::sync($urpm, $medium, [_hdlist_dir($medium) . "/$local_name"], - quiet => 1)) { - rename("$urpm->{cachedir}/partial/$local_name", "$urpm->{cachedir}/partial/$name"); - $found = 1; - } - } - if (!$found) { - urpm::download::sync($urpm, $medium, [reduce_pathname("$medium->{url}/$name")], quiet => 1) - or unlink "$urpm->{cachedir}/partial/$name"; - } -} - sub clean_dir { my ($dir) = @_; @@ -1213,542 +87,6 @@ sub clean_dir { mkdir $dir, 0755; } -sub get_descriptions_local { - my ($urpm, $medium) = @_; - - unlink statedir_descriptions($urpm, $medium); - - my $dir = file_from_local_url($medium->{url}); - my $description_file = "$dir/media_info/descriptions"; #- new default location - -e $description_file or $description_file = "$dir/../descriptions"; - -e $description_file or return; - - $urpm->{log}(N("copying description file of \"%s\"...", $medium->{name})); - if (copy_and_own($description_file, statedir_descriptions($urpm, $medium))) { - $urpm->{log}(N("...copying done")); - } else { - $urpm->{error}(N("...copying failed")); - $medium->{ignore} = 1; - } -} -sub get_descriptions_remote { - my ($urpm, $medium) = @_; - - unlink "$urpm->{cachedir}/partial/descriptions"; - - if (-e statedir_descriptions($urpm, $medium)) { - urpm::util::move(statedir_descriptions($urpm, $medium), "$urpm->{cachedir}/partial/descriptions"); - } - urpm::download::sync($urpm, $medium, [ reduce_pathname("$medium->{url}/media_info/descriptions") ], quiet => 1) - or #- try older location - urpm::download::sync($urpm, $medium, [ reduce_pathname("$medium->{url}/../descriptions") ], quiet => 1); - - if (-e "$urpm->{cachedir}/partial/descriptions") { - urpm::util::move("$urpm->{cachedir}/partial/descriptions", statedir_descriptions($urpm, $medium)); - } -} -sub get_hdlist_or_synthesis__local { - my ($urpm, $medium, $callback) = @_; - - unlink cachedir_hdlist($urpm, $medium); - $urpm->{log}(N("copying source hdlist (or synthesis) of \"%s\"...", $medium->{name})); - $callback and $callback->('copy', $medium->{name}); - if (copy_and_own(_url_with_hdlist($medium), cachedir_hdlist($urpm, $medium))) { - $callback and $callback->('done', $medium->{name}); - $urpm->{log}(N("...copying done")); - if (file_size(cachedir_hdlist($urpm, $medium)) < 20) { - $urpm->{error}(N("copy of [%s] failed (file is suspiciously small)", cachedir_hdlist($urpm, $medium))); - 0; - } else { - 1; - } - } else { - $callback and $callback->('failed', $medium->{name}); - #- force error, reported afterwards - unlink cachedir_hdlist($urpm, $medium); - 0; - } -} - -sub get_hdlist_or_synthesis_and_check_md5sum__local { - my ($urpm, $medium, $retrieved_md5sum, $callback) = @_; - - get_hdlist_or_synthesis__local($urpm, $medium, $callback) or return; - - #- keep checking md5sum of file just copied ! (especially on nfs or removable device). - if ($retrieved_md5sum) { - $urpm->{log}(N("computing md5sum of copied source hdlist (or synthesis)")); - urpm::md5sum::compute(cachedir_hdlist($urpm, $medium)) eq $retrieved_md5sum or - $urpm->{error}(N("copy of [%s] failed (md5sum mismatch)", _url_with_hdlist($medium))), return; - } - - 1; -} - -sub _read_rpms_from_dir { - my ($urpm, $medium, $second_pass, $clean_cache) = @_; - - my $dir = file_from_local_url($medium->{url}); - - $medium->{rpm_files} = [ glob("$dir/*.rpm") ]; - - #- check files contains something good! - if (!@{$medium->{rpm_files}}) { - $urpm->{error}(N("no rpm files found from [%s]", $dir)); - $medium->{ignore} = 1; - return; - } - - #- we need to rebuild from rpm files the hdlist. - - $urpm->{log}(N("reading rpm files from [%s]", $dir)); - my @unresolved_before = grep { - ! defined $urpm->{provides}{$_}; - } keys %{$urpm->{provides} || {}}; - $medium->{start} = @{$urpm->{depslist}}; - - eval { - $medium->{headers} = [ $urpm->parse_rpms_build_headers( - dir => "$urpm->{cachedir}/headers", - rpms => $medium->{rpm_files}, - clean => $$clean_cache, - packing => 1, - ) ]; - }; - if ($@) { - $urpm->{error}(N("unable to read rpm files from [%s]: %s", $dir, $@)); - delete $medium->{headers}; #- do not propagate these. - return; - } - - $medium->{end} = $#{$urpm->{depslist}}; - if ($medium->{start} > $medium->{end}) { - #- an error occured (provided there are files in input.) - delete $medium->{start}; - delete $medium->{end}; - $urpm->{fatal}(9, N("no rpms read")); - } - - #- make sure the headers will not be removed for another media. - $$clean_cache = 0; - my @unresolved = grep { - ! defined $urpm->{provides}{$_}; - } keys %{$urpm->{provides} || {}}; - @unresolved_before == @unresolved or $$second_pass = 1; - - delete $medium->{synthesis}; #- when building hdlist by ourself, drop synthesis property. - 1; -} - -#- options: callback, force, force_building_hdlist, nomd5sum, nopubkey, probe_with -sub _update_medium__parse_if_unmodified__local { - my ($urpm, $medium, $second_pass, $clean_cache, $options) = @_; - - my $dir = file_from_local_url($medium->{url}); - - if (!-d $dir) { - #- the directory given does not exist and may be accessible - #- by mounting some other directory. Try to figure it out and mount - #- everything that might be necessary. - $urpm->try_mounting( - !$options->{force_building_hdlist} && $medium->{with_hdlist} - ? _hdlist_dir($medium) : $dir, - #- in case of an iso image, pass its name - is_iso($medium->{removable}) && $medium->{removable}, - ) or $urpm->{error}(N("unable to access medium \"%s\", -this could happen if you mounted manually the directory when creating the medium.", $medium->{name})), return 'unmodified'; - } - - #- try to probe for possible with_hdlist parameter, unless - #- it is already defined (and valid). - if ($options->{probe_with} && !$medium->{with_hdlist}) { - foreach (_probe_with_try_list($options->{probe_with})) { - -e "$dir/$_" or next; - if (file_size("$dir/$_") >= 20) { - $medium->{with_hdlist} = $_; - last; - } else { - $urpm->{error}(N("invalid hdlist file %s for medium \"%s\"", "$dir/$_", $medium->{name})); - return; - } - } - } - - if ($medium->{virtual}) { - #- syncing a virtual medium is very simple, just try to read the file in order to - #- determine its type, once a with_hdlist has been found (but is mandatory). - _parse_hdlist_or_synthesis__virtual($urpm, $medium); - } - - #- examine if a distant MD5SUM file is available. - #- this will only be done if $with_hdlist is not empty in order to use - #- an existing hdlist or synthesis file, and to check if download was good. - #- if no MD5SUM is available, do it as before... - #- we can assume at this point a basename is existing, but it needs - #- to be checked for being valid, nothing can be deduced if no MD5SUM - #- file is present. - - unless ($medium->{virtual}) { - if ($medium->{with_hdlist}) { - my ($retrieved_md5sum); - - if (!$options->{nomd5sum} && file_size(_hdlist_dir($medium) . '/MD5SUM') > 32) { - $retrieved_md5sum = urpm::md5sum::from_MD5SUM__or_warn($urpm, _hdlist_dir($medium) . '/MD5SUM', basename($medium->{with_hdlist})); - if (urpm::md5sum::on_local_medium($urpm, $medium, $options->{force})) { - _read_existing_synthesis_and_hdlist_if_same_md5sum($urpm, $medium, $retrieved_md5sum) - and return 'unmodified'; - } - } - - #- if the source hdlist is present and we are not forcing using rpm files - if (!$options->{force_building_hdlist} && -e _url_with_hdlist($medium)) { - if (get_hdlist_or_synthesis_and_check_md5sum__local($urpm, $medium, $retrieved_md5sum, $options->{callback})) { - - $medium->{md5sum} = $retrieved_md5sum if $retrieved_md5sum; - - #- check if the files are equal... and no force copy... - if (!$options->{force}) { - _read_existing_synthesis_and_hdlist_if_same_time_and_msize($urpm, $medium, $medium->{hdlist}) - and return 'unmodified'; - } - } else { - #- if copying hdlist has failed, try to build it directly. - if ($urpm->{options}{'build-hdlist-on-error'}) { - $options->{force_building_hdlist} = 1; - } else { - $urpm->{error}(N("unable to access hdlist file of \"%s\", medium ignored", $medium->{name})); - $medium->{ignore} = 1; - return; - } - } - } - } else { - #- no available hdlist/synthesis, try to build it from rpms - $options->{force_building_hdlist} = 1; - } - - if ($options->{force_building_hdlist}) { - _read_rpms_from_dir($urpm, $medium, $second_pass, $clean_cache) or return; - } - } - - 1; -} - -#- options: callback, force, nomd5sum, nopubkey, probe_with, quiet -sub _update_medium__parse_if_unmodified__remote { - my ($urpm, $medium, $options) = @_; - my ($retrieved_md5sum, $basename); - - #- examine if a distant MD5SUM file is available. - #- this will only be done if $with_hdlist is not empty in order to use - #- an existing hdlist or synthesis file, and to check if download was good. - #- if no MD5SUM is available, do it as before... - if ($medium->{with_hdlist}) { - #- we can assume at this point a basename is existing, but it needs - #- to be checked for being valid, nothing can be deduced if no MD5SUM - #- file is present. - $basename = basename($medium->{with_hdlist}); - - unlink "$urpm->{cachedir}/partial/MD5SUM"; - if (!$options->{nomd5sum} && - urpm::download::sync($urpm, $medium, - [ reduce_pathname(_hdlist_dir($medium) . '/MD5SUM') ], - quiet => 1) && file_size("$urpm->{cachedir}/partial/MD5SUM") > 32) { - if (urpm::md5sum::on_local_medium($urpm, $medium, $options->{force} >= 2)) { - $retrieved_md5sum = urpm::md5sum::from_MD5SUM__or_warn($urpm, "$urpm->{cachedir}/partial/MD5SUM", $basename); - _read_existing_synthesis_and_hdlist_if_same_md5sum($urpm, $medium, $retrieved_md5sum) - and return 'unmodified'; - } - } else { - #- at this point, we don't if a basename exists and is valid, let probe it later. - $basename = undef; - } - } - - #- try to probe for possible with_hdlist parameter, unless - #- it is already defined (and valid). - $urpm->{log}(N("retrieving source hdlist (or synthesis) of \"%s\"...", $medium->{name})); - $options->{callback} and $options->{callback}('retrieve', $medium->{name}); - if ($options->{probe_with} && !$medium->{with_hdlist}) { - foreach my $with_hdlist (_probe_with_try_list($options->{probe_with})) { - $basename = basename($with_hdlist) or next; - $options->{force} and unlink "$urpm->{cachedir}/partial/$basename"; - if (urpm::download::sync($urpm, $medium, [ reduce_pathname("$medium->{url}/$with_hdlist") ], - quiet => $options->{quiet}, callback => $options->{callback}) && file_size("$urpm->{cachedir}/partial/$basename") >= 20) { - $urpm->{log}(N("...retrieving done")); - $medium->{with_hdlist} = $with_hdlist; - $urpm->{log}(N("found probed hdlist (or synthesis) as %s", $medium->{with_hdlist})); - last; #- found a suitable with_hdlist in the list above. - } - } - } else { - $basename = basename($medium->{with_hdlist}); - - if ($options->{force}) { - unlink "$urpm->{cachedir}/partial/$basename"; - } else { - #- try to sync (copy if needed) local copy after restored the previous one. - #- this is useful for rsync (?) - if (-e statedir_hdlist_or_synthesis($urpm, $medium)) { - copy_and_own( - statedir_hdlist_or_synthesis($urpm, $medium), - "$urpm->{cachedir}/partial/$basename", - ) or $urpm->{error}(N("...copying failed")), return; - } - } - if (urpm::download::sync($urpm, $medium, [ _url_with_hdlist($medium) ], - quiet => $options->{quiet}, callback => $options->{callback})) { - $urpm->{log}(N("...retrieving done")); - } else { - $urpm->{error}(N("...retrieving failed: %s", $@)); - unlink "$urpm->{cachedir}/partial/$basename"; - } - } - - #- check downloaded file has right signature. - if (file_size("$urpm->{cachedir}/partial/$basename") >= 20 && $retrieved_md5sum) { - $urpm->{log}(N("computing md5sum of retrieved source hdlist (or synthesis)")); - unless (urpm::md5sum::compute("$urpm->{cachedir}/partial/$basename") eq $retrieved_md5sum) { - $urpm->{error}(N("...retrieving failed: md5sum mismatch")); - unlink "$urpm->{cachedir}/partial/$basename"; - } - } - - if (file_size("$urpm->{cachedir}/partial/$basename") >= 20) { - $options->{callback} and $options->{callback}('done', $medium->{name}); - - unless ($options->{force}) { - _read_existing_synthesis_and_hdlist_if_same_time_and_msize($urpm, $medium, $basename) - and return 'unmodified'; - } - - #- the files are different, update local copy. - rename("$urpm->{cachedir}/partial/$basename", cachedir_hdlist($urpm, $medium)); - } else { - $options->{callback} and $options->{callback}('failed', $medium->{name}); - $urpm->{error}(N("retrieval of source hdlist (or synthesis) failed")); - return; - } - $urpm->{md5sum} = $retrieved_md5sum if $retrieved_md5sum; - 1; -} - -sub _get_pubkey_and_descriptions { - my ($urpm, $medium, $nopubkey) = @_; - - my $local = file_from_local_url($medium->{url}); - - ($local ? \&get_descriptions_local : \&get_descriptions_remote)->($urpm, $medium); - - #- examine if a pubkey file is available. - if (!$nopubkey && !$medium->{'key-ids'}) { - ($local ? \&_get_list_or_pubkey__local : \&_get_list_or_pubkey__remote)->($urpm, $medium, 'pubkey'); - } -} - -sub _read_cachedir_pubkey { - my ($urpm, $medium) = @_; - -s "$urpm->{cachedir}/partial/pubkey" or return; - - $urpm->{log}(N("examining pubkey file of \"%s\"...", $medium->{name})); - - my %key_ids; - $urpm->import_needed_pubkeys( - [ $urpm->parse_armored_file("$urpm->{cachedir}/partial/pubkey") ], - root => $urpm->{root}, - callback => sub { - my (undef, undef, $_k, $id, $imported) = @_; - if ($id) { - $key_ids{$id} = undef; - $imported and $urpm->{log}(N("...imported key %s from pubkey file of \"%s\"", - $id, $medium->{name})); - } else { - $urpm->{error}(N("unable to import pubkey file of \"%s\"", $medium->{name})); - } - }); - if (keys(%key_ids)) { - $medium->{'key-ids'} = join(',', keys %key_ids); - } -} - -sub _write_rpm_list { - my ($urpm, $medium) = @_; - - @{$medium->{rpm_files} || []} or return; - - $medium->{list} ||= "list.$medium->{name}"; - - #- write list file. - $urpm->{log}(N("writing list file for medium \"%s\"", $medium->{name})); - my $listfh = urpm::sys::open_safe($urpm, '>', cachedir_list($urpm, $medium)) or return; - print $listfh basename($_), "\n" foreach @{$medium->{rpm_files}}; - 1; -} - -#- options: callback, force, force_building_hdlist, nomd5sum, probe_with, quiet -#- (from _update_medium__parse_if_unmodified__local and _update_medium__parse_if_unmodified__remote) -sub _update_medium_first_pass { - my ($urpm, $medium, $second_pass, $clean_cache, %options) = @_; - - #- we should create the associated synthesis file if it does not already exist... - file_size(statedir_synthesis($urpm, $medium)) >= 20 - or $medium->{must_build_synthesis} = 1; - - unless ($medium->{modified}) { - #- the medium is not modified, but to compute dependencies, - #- we still need to read it and all synthesis will be written if - #- an unresolved provides is found. - #- to speed up the process, we only read the synthesis at the beginning. - _parse_hdlist_or_synthesis__when_not_modified($urpm, $medium); - return 1; - } - - #- always delete a remaining list file or pubkey file in cache. - foreach (qw(list pubkey)) { - unlink "$urpm->{cachedir}/partial/$_"; - } - - #- check for a reconfig.urpmi file (if not already reconfigured) - if (!$medium->{noreconfigure}) { - may_reconfig_urpmi($urpm, $medium); - } - - { - my $rc = - file_from_local_url($medium->{url}) - ? _update_medium__parse_if_unmodified__local($urpm, $medium, $second_pass, $clean_cache, \%options) - : _update_medium__parse_if_unmodified__remote($urpm, $medium, \%options); - - if (!$rc || $rc eq 'unmodified') { - return $rc; - } - } - - #- build list file according to hdlist. - if (!$medium->{headers} && !$medium->{virtual} && file_size(cachedir_hdlist($urpm, $medium)) < 20) { - $urpm->{error}(N("no hdlist file found for medium \"%s\"", $medium->{name})); - return; - } - - if (!$medium->{virtual}) { - if ($medium->{headers}) { - _write_rpm_list($urpm, $medium) or return; - } else { - #- read first pass hdlist or synthesis, try to open as synthesis, if file - #- is larger than 1MB, this is probably an hdlist else a synthesis. - #- anyway, if one tries fails, try another mode. - $options{callback} and $options{callback}('parse', $medium->{name}); - my @unresolved_before = grep { ! defined $urpm->{provides}{$_} } keys %{$urpm->{provides} || {}}; - - #- if it looks like a hdlist, try to parse as hdlist first - delete $medium->{synthesis} if file_size(cachedir_hdlist($urpm, $medium)) > 262144; - _parse_maybe_hdlist_or_synthesis($urpm, $medium, cachedir_hdlist($urpm, $medium)); - - if (is_valid_medium($medium)) { - $options{callback} && $options{callback}('done', $medium->{name}); - } else { - $urpm->{error}(N("unable to parse hdlist file of \"%s\"", $medium->{name})); - $options{callback} and $options{callback}('failed', $medium->{name}); - delete $medium->{md5sum}; - - #- we have to read back the current synthesis file unmodified. - if (!_parse_synthesis($urpm, $medium, statedir_synthesis($urpm, $medium))) { - $urpm->{error}(N("problem reading synthesis file of medium \"%s\"", $medium->{name})); - $medium->{ignore} = 1; - } - return; - } - delete $medium->{list}; - - { - my @unresolved_after = grep { ! defined $urpm->{provides}{$_} } keys %{$urpm->{provides} || {}}; - @unresolved_before == @unresolved_after or $$second_pass = 1; - } - } - } - - unless ($medium->{virtual}) { - #- make sure to rebuild base files and clear medium modified state. - $medium->{modified} = 0; - $medium->{really_modified} = 1; - $urpm->{md5sum_modified} = 1; - - #- but use newly created file. - unlink statedir_hdlist($urpm, $medium); - $medium->{synthesis} and unlink statedir_synthesis($urpm, $medium); - $medium->{list} and unlink statedir_list($urpm, $medium); - unless ($medium->{headers}) { - unlink statedir_synthesis($urpm, $medium); - unlink statedir_hdlist($urpm, $medium); - urpm::util::move(cachedir_hdlist($urpm, $medium), - statedir_hdlist_or_synthesis($urpm, $medium)); - } - if ($medium->{list}) { - urpm::util::move(cachedir_list($urpm, $medium), statedir_list($urpm, $medium)); - } - - #- and create synthesis file associated. - $medium->{must_build_synthesis} = !$medium->{synthesis}; - } - 1; -} - -sub _update_medium_first_pass_failed { - my ($urpm, $medium) = @_; - - !$medium->{virtual} or return; - - #- an error has occured for updating the medium, we have to remove temporary files. - unlink(glob("$urpm->{cachedir}/partial/*")); -} - -#- take care of modified medium only, or all if all have to be recomputed. -sub _update_medium_second_pass { - my ($urpm, $medium, $callback) = @_; - - $callback and $callback->('parse', $medium->{name}); - - #- a modified medium is an invalid medium, we have to read back the previous hdlist - #- or synthesis which has not been modified by first pass above. - - if ($medium->{headers} && !$medium->{modified}) { - $urpm->{log}(N("reading headers from medium \"%s\"", $medium->{name})); - ($medium->{start}, $medium->{end}) = $urpm->parse_headers(dir => "$urpm->{cachedir}/headers", - headers => $medium->{headers}, - ); - } elsif ($medium->{synthesis}) { - if ($medium->{virtual}) { - if (file_from_file_url($medium->{url})) { - _parse_synthesis($urpm, $medium, hdlist_or_synthesis_for_virtual_medium($medium)); - } - } else { - _parse_synthesis($urpm, $medium, statedir_synthesis($urpm, $medium)); - } - } else { - _parse_hdlist($urpm, $medium, statedir_hdlist($urpm, $medium)); - $medium->{must_build_synthesis} ||= 1; - } - - $callback && $callback->('done', $medium->{name}); -} - -sub _build_hdlist_synthesis { - my ($urpm, $medium) = @_; - - if ($medium->{headers} && !$medium->{modified}) { - _build_hdlist_using_rpm_headers($urpm, $medium); - #- synthesis needs to be created, since the medium has been built from rpm files. - _build_synthesis($urpm, $medium); - } elsif ($medium->{synthesis}) { - } else { - #- check if the synthesis file can be built. - if ($medium->{must_build_synthesis} && !$medium->{modified} && !$medium->{virtual}) { - _build_synthesis($urpm, $medium); - } - } -} - sub remove_obsolete_headers_in_cache { my ($urpm) = @_; my %headers; @@ -1770,117 +108,6 @@ sub remove_obsolete_headers_in_cache { } } -sub _update_media__handle_some_flags { - my ($urpm, $forcekey, $all) = @_; - - foreach my $medium (grep { !$_->{ignore} } @{$urpm->{media}}) { - $forcekey and delete $medium->{'key-ids'}; - - if ($medium->{static}) { - #- don't ever update static media - $medium->{modified} = 0; - } elsif ($all) { - #- if we're rebuilding all media, mark them as modified (except removable ones) - $medium->{modified} ||= $medium->{url} !~ m!^removable!; - } - } -} - -#- Update the urpmi database w.r.t. the current configuration. -#- Takes care of modifications, and tries some tricks to bypass -#- the recomputation of base files. -#- Recognized options : -#- all : all medias are being rebuilt -#- callback : UI callback -#- forcekey : force retrieval of pubkey -#- force : try to force rebuilding base files -#- force_building_hdlist -#- noclean : keep old files in the header cache directory -#- nolock : don't lock the urpmi database -#- nomd5sum : don't verify MD5SUM of retrieved files -#- nopubkey : don't use rpm pubkeys -#- probe_with : probe synthesis or hdlist (or none) -#- quiet : download hdlists quietly -sub update_media { - my ($urpm, %options) = @_; - - $urpm->{media} or return; # verify that configuration has been read - - $options{nopubkey} ||= $urpm->{options}{nopubkey}; - #- get gpg-pubkey signature. - if (!$options{nopubkey}) { - urpm::sys::lock_rpm_db($urpm, 'exclusive'); - $urpm->{keys} or $urpm->parse_pubkeys(root => $urpm->{root}); - } - #- lock database if allowed. - urpm::sys::lock_urpmi_db($urpm, 'exclusive') if !$options{nolock}; - - #- examine each medium to see if one of them needs to be updated. - #- if this is the case and if not forced, try to use a pre-calculated - #- hdlist file, else build it from rpm files. - $urpm->clean; - - _update_media__handle_some_flags($urpm, $options{forcekey}, $options{all}); - - my $clean_cache = !$options{noclean}; - my $second_pass; - foreach my $medium (grep { !$_->{ignore} } @{$urpm->{media}}) { - _update_medium_first_pass($urpm, $medium, \$second_pass, \$clean_cache, %options) - or _update_medium_first_pass_failed($urpm, $medium); - } - - #- some unresolved provides may force to rebuild all synthesis, - #- a second pass will be necessary. - if ($second_pass) { - $urpm->{log}(N("performing second pass to compute dependencies\n")); - $urpm->unresolved_provides_clean; - } - - foreach my $medium (grep { !$_->{ignore} } @{$urpm->{media}}) { - if ($second_pass) { - #- second pass consists in reading again synthesis or hdlists. - _update_medium_second_pass($urpm, $medium, $options{callback}); - } - _build_hdlist_synthesis($urpm, $medium); - - if ($medium->{really_modified}) { - _get_pubkey_and_descriptions($urpm, $medium, $options{nopubkey}); - _read_cachedir_pubkey($urpm, $medium); - generate_medium_names($urpm, $medium); - } - } - - if ($urpm->{modified}) { - if ($options{noclean}) { - #- clean headers cache directory to remove everything that is no longer - #- useful according to the depslist. - remove_obsolete_headers_in_cache($urpm); - } - #- write config files in any case - $urpm->write_config; - dump_proxy_config(); - } elsif ($urpm->{md5sum_modified}) { - #- NB: in case of $urpm->{modified}, write_MD5SUM is called in write_config above - write_MD5SUM($urpm); - } - - $options{nolock} or urpm::sys::unlock_urpmi_db($urpm); - $options{nopubkey} or urpm::sys::unlock_rpm_db($urpm); -} - -#- clean params and depslist computation zone. -sub clean { - my ($urpm) = @_; - - $urpm->{depslist} = []; - $urpm->{provides} = {}; - - foreach (@{$urpm->{media} || []}) { - delete $_->{start}; - delete $_->{end}; - } -} - sub try_mounting { my ($urpm, $dir, $o_removable) = @_; my %infos; @@ -2210,20 +437,6 @@ sub resolve_dependencies { $need_restart; } -#- get the list of packages that should not be upgraded or installed, -#- typically from the inst.list or skip.list files. -sub get_packages_list { - my ($file, $o_extra) = @_; - my $val = []; - open(my $f, '<', $file) or return []; - foreach (<$f>, split /,/, $o_extra || '') { - chomp; s/#.*$//; s/^\s*//; s/\s*$//; - next if $_ eq ''; - push @$val, $_; - } - $val; -} - #- select sources for selected packages, #- according to keys of the packages hash. #- returns a list of lists containing the source description for each rpm, @@ -2287,11 +500,11 @@ sub get_source_packages { foreach my $medium (@{$urpm->{media} || []}) { my (%sources, %list_examined, $list_warning); - if (is_valid_medium($medium) && !$medium->{ignore}) { + if (urpm::media::is_valid_medium($medium) && !$medium->{ignore}) { #- always prefer a list file if available. if ($medium->{list}) { - if (-r statedir_list($urpm, $medium)) { - foreach (cat_(statedir_list($urpm, $medium))) { + if (-r urpm::media::statedir_list($urpm, $medium)) { + foreach (cat_(urpm::media::statedir_list($urpm, $medium))) { chomp; if (my ($filename) = m!([^/]*\.rpm)$!) { if (keys(%{$file2fullnames{$filename} || {}}) > 1) { @@ -2309,7 +522,7 @@ sub get_source_packages { } else { chomp; $error = 1; - $urpm->{error}(N("unable to correctly parse [%s] on value \"%s\"", statedir_list($urpm, $medium), $_)); + $urpm->{error}(N("unable to correctly parse [%s] on value \"%s\"", urpm::media::statedir_list($urpm, $medium), $_)); last; } } @@ -2341,7 +554,7 @@ sub get_source_packages { } } } - $list_warning && $medium->{list} && -r statedir_list($urpm, $medium) && -f _ + $list_warning && $medium->{list} && -r urpm::media::statedir_list($urpm, $medium) && -f _ and $urpm->{error}(N("medium \"%s\" uses an invalid list file: mirror is probably not up-to-date, trying to use alternate method", $medium->{name})); } elsif (!%list_examined) { @@ -2844,12 +1057,12 @@ sub _check_sources_signatures { $verif =~ s/\n//g; $invalid_sources{$filepath} = N("Invalid signature (%s)", $verif); } else { - unless ($medium && is_valid_medium($medium) && + unless ($medium && urpm::media::is_valid_medium($medium) && $medium->{start} <= $id && $id <= $medium->{end}) { $medium = undef; foreach (@{$urpm->{media}}) { - is_valid_medium($_) && $_->{start} <= $id && $id <= $_->{end} + urpm::media::is_valid_medium($_) && $_->{start} <= $id && $id <= $_->{end} and $medium = $_, last; } } @@ -2900,7 +1113,7 @@ sub get_updates_description { @update_medias or @update_medias = grep { !$_->{ignore} && $_->{update} } @{$urpm->{media}}; - foreach (map { cat_(statedir_descriptions($urpm, $_)), '%package dummy' } @update_medias) { + foreach (map { cat_(urpm::media::statedir_descriptions($urpm, $_)), '%package dummy' } @update_medias) { /^%package (.+)/ and do { if (exists $cur->{importance} && $cur->{importance} ne "security" && $cur->{importance} ne "bugfix") { $cur->{importance} = 'normal'; diff --git a/urpm/bug_report.pm b/urpm/bug_report.pm index e9666d13..eb1258a4 100644 --- a/urpm/bug_report.pm +++ b/urpm/bug_report.pm @@ -32,14 +32,14 @@ sub write_urpmdb { #- take care of virtual medium this way. $_->{hdlist} ||= "hdlist.$_->{name}.cz"; #- now build directly synthesis file, this is by far the simplest method. - if (urpm::is_valid_medium($_)) { + if (urpm::media::is_valid_medium($_)) { $urpm->build_synthesis(start => $_->{start}, end => $_->{end}, synthesis => "$bug_report_dir/synthesis.$_->{hdlist}"); $urpm->{log}(N("built hdlist synthesis file for medium \"%s\"", $_->{name})); } } #- fake configuration written to convert virtual media on the fly. local $urpm->{config} = "$bug_report_dir/urpmi.cfg"; - $urpm->write_config; + urpm::media::write_config($urpm); } sub copy_requested { diff --git a/urpm/download.pm b/urpm/download.pm index 2a60a4eb..0b6b94e9 100644 --- a/urpm/download.pm +++ b/urpm/download.pm @@ -11,7 +11,7 @@ use Exporter; our @ISA = 'Exporter'; our @EXPORT = qw(get_proxy propagate_sync_callback - sync_file sync_prozilla sync_wget sync_curl sync_rsync sync_ssh + sync_file sync_rsync sync_ssh set_proxy_config dump_proxy_config ); @@ -24,6 +24,20 @@ my $proxy_config; #- Timeout for curl connection and wget operations our $CONNECT_TIMEOUT = 60; #- (in seconds) + + +sub ftp_http_downloaders() { qw(curl wget prozilla) } + +sub available_ftp_http_downloaders() { + my %binaries = ( + curl => 'curl', + wget => 'wget', + prozilla => 'proz', + ); + grep { -x "/usr/bin/$binaries{$_}" || -x "/bin/$binaries{$_}" } ftp_http_downloaders(); +} + + #- parses proxy.cfg (private) sub load_proxy_config () { return if defined $proxy_config; @@ -294,7 +308,7 @@ sub sync_curl { eval { require Date::Manip }; #- prepare to get back size and time stamp of each file. - open my $curl, join(" ", map { "'$_'" } "/usr/bin/curl", + my $cmd = join(" ", map { "'$_'" } "/usr/bin/curl", "-q", # don't read .curlrc; some toggle options might interfer ($options->{limit_rate} ? ("--limit-rate", $options->{limit_rate}) : ()), ($options->{proxy} ? set_proxy({ type => "curl", proxy => $options->{proxy} }) : ()), @@ -305,7 +319,8 @@ sub sync_curl { "-s", "-I", "--anyauth", (defined $options->{'curl-options'} ? split /\s+/, $options->{'curl-options'} : ()), - @ftp_files) . " |"; + @ftp_files); + open my $curl, "$cmd |"; while (<$curl>) { if (/Content-Length:\s*(\d+)/) { !$cur_ftp_file || exists($ftp_files_info{$cur_ftp_file}{size}) @@ -353,7 +368,7 @@ sub sync_curl { { my @l = (@ftp_files, @other_files); my ($buf, $file); $buf = ''; - my $curl_pid = open my $curl, join(" ", map { "'$_'" } "/usr/bin/curl", + my $cmd = join(" ", map { "'$_'" } "/usr/bin/curl", "-q", # don't read .curlrc; some toggle options might interfer ($options->{limit_rate} ? ("--limit-rate", $options->{limit_rate}) : ()), ($options->{resume} ? ("--continue-at", "-") : ()), @@ -369,7 +384,8 @@ sub sync_curl { "--anyauth", (defined $options->{'curl-options'} ? split /\s+/, $options->{'curl-options'} : ()), "--stderr", "-", # redirect everything to stdout - @all_files) . " |"; + @all_files); + my $curl_pid = open(my $curl, "$cmd |"); local $/ = \1; #- read input by only one char, this is slow but very nice (and it works!). local $_; while (<$curl>) { @@ -581,6 +597,85 @@ sub sync_logger { } } + +sub requested_ftp_http_downloader { + my ($urpm, $media_name) = @_; + + $urpm->{options}{downloader} || #- cmd-line switch + $media_name && do { + #- per-media config + require urpm::media; #- help perl_checker + my $m = urpm::media::name2medium($urpm, $media_name); + $m && $m->{downloader}; + } || $urpm->{global_config}{downloader}; +} + +#- $medium can be undef +#- known options: quiet, resume, callback +sub sync { + my ($urpm, $medium, $files, %options) = @_; + + my %all_options = ( + dir => "$urpm->{cachedir}/partial", + proxy => get_proxy($medium), + $medium ? (media => $medium->{name}) : (), + %options, + ); + foreach my $cpt (qw(compress limit_rate retry wget-options curl-options rsync-options prozilla-options)) { + $all_options{$cpt} = $urpm->{options}{$cpt} if defined $urpm->{options}{$cpt}; + } + + eval { _sync_webfetch_raw($urpm, $files, \%all_options); 1 }; +} + +#- syncing algorithms. +sub _sync_webfetch_raw { + my ($urpm, $files, $options) = @_; + + my %files; + #- currently ftp and http protocols are managed by curl or wget, + #- ssh and rsync protocols are managed by rsync *AND* ssh. + foreach (@$files) { + my $proto = urpm::protocol_from_url($_) or die N("unknown protocol defined for %s", $_); + push @{$files{$proto}}, $_; + } + if ($files{removable} || $files{file}) { + my @l = map { urpm::file_from_local_url($_) } @{$files{removable} || []}, @{$files{file} || []}; + eval { sync_file($options, @l) }; + $urpm->{fatal}(10, $@) if $@; + delete @files{qw(removable file)}; + } + if ($files{ftp} || $files{http} || $files{https}) { + my @available = urpm::download::available_ftp_http_downloaders(); + + #- use user default downloader if provided and available + my $requested_downloader = requested_ftp_http_downloader($urpm, $options->{media}); + my ($preferred) = grep { $_ eq $requested_downloader } @available; + if (!$preferred) { + #- else first downloader of @available is the default one + $preferred = $available[0]; + if ($requested_downloader && !our $webfetch_not_available) { + $urpm->{log}(N("%s is not available, falling back on %s", $requested_downloader, $preferred)); + $webfetch_not_available = 1; + } + } + my $sync = $urpm::download::{"sync_$preferred"} or die N("no webfetch found, supported webfetch are: %s\n", join(", ", urpm::download::ftp_http_downloaders())); + $sync->($options, @{$files{ftp} || []}, @{$files{http} || []}, @{$files{https} || []}); + + delete @files{qw(ftp http https)}; + } + if ($files{rsync}) { + sync_rsync($options, @{$files{rsync}}); + delete $files{rsync}; + } + if ($files{ssh}) { + my @ssh_files = map { m!^ssh://([^/]*)(.*)! ? "$1:$2" : () } @{$files{ssh}}; + sync_ssh($options, @ssh_files); + delete $files{ssh}; + } + %files and die N("unable to handle protocol: %s", join ', ', keys %files); +} + 1; __END__ diff --git a/urpm/ldap.pm b/urpm/ldap.pm index 6298f422..5c4d636f 100644 --- a/urpm/ldap.pm +++ b/urpm/ldap.pm @@ -38,7 +38,7 @@ therefore, caching is useless if server is up. Checks if the ldap medium has all required attributes. -=item read_ldap_cache($urpm, %options) +=item read_ldap_cache($urpm) Reads the cache created by the C function. Should be called if the ldap server doesn't answer (upgrade, network problem, mobile user, etc.) @@ -47,7 +47,7 @@ if the ldap server doesn't answer (upgrade, network problem, mobile user, etc.) Cleans the ldap cache, removes all files in the directory. -=item load_ldap_media($urpm, %options) +=item load_ldap_media($urpm) Loads urpmi media configuration from ldap. @@ -97,13 +97,13 @@ sub get_vars_from_sh { %l; } -sub read_ldap_cache($%) { - my ($urpm, %options) = @_; +sub read_ldap_cache { + my ($urpm) = @_; foreach (glob("$urpm->{cachedir}/ldap/*")) { ! -f $_ and next; my %medium = get_vars_from_sh($_); next if !check_ldap_medium(\%medium); - $urpm->probe_medium(\%medium, %options) and push @{$urpm->{media}}, \%medium; + urpm::media::add_existing_medium($urpm, \%medium); } } @@ -146,8 +146,8 @@ my %ldap_changed_attributes = ( 'ftp-proxy' => 'ftp_proxy', ); -sub load_ldap_media($%) { - my ($urpm, %options) = @_; +sub load_ldap_media { + my ($urpm) = @_; my $config = get_ldap_config() or return; @@ -205,13 +205,13 @@ sub load_ldap_media($%) { $medium->{ldap} = 1; $medium->{priority} = $priority++; next if !check_ldap_medium($medium); - $urpm->probe_medium($medium, %options) and push @{$urpm->{media}}, $medium; + urpm::media::add_existing_medium($urpm, $medium); write_ldap_cache($urpm,$medium); } }; if ($@) { $urpm->{log}($@); - read_ldap_cache($urpm, %options); + read_ldap_cache($urpm); } } diff --git a/urpm/md5sum.pm b/urpm/md5sum.pm index 829e0dfd..f5295190 100644 --- a/urpm/md5sum.pm +++ b/urpm/md5sum.pm @@ -40,8 +40,8 @@ sub on_local_medium { sub compute_on_local_medium { my ($urpm, $medium) = @_; - require urpm; #- help perl_checker - my $f = urpm::statedir_hdlist_or_synthesis($urpm, $medium); + require urpm::media; #- help perl_checker + my $f = urpm::media::statedir_hdlist_or_synthesis($urpm, $medium); $urpm->{log}(N("computing md5sum of existing source hdlist (or synthesis) [%s]", $f)); -e $f && compute($f); } diff --git a/urpm/media.pm b/urpm/media.pm new file mode 100644 index 00000000..e32ae406 --- /dev/null +++ b/urpm/media.pm @@ -0,0 +1,1800 @@ +package urpm::media; + +# $Id$ + +use urpm 'file_from_local_url'; +use urpm::msg; +use urpm::util; + + +our @PER_MEDIA_OPT = qw( + downloader + hdlist + ignore + key-ids + list + md5sum + noreconfigure + priority + priority-upgrade + removable + static + synthesis + update + url + verify-rpm + virtual + with_hdlist +); + +sub read_private_netrc { + my ($urpm) = @_; + + my @words = split(/\s+/, scalar cat_($urpm->{private_netrc})); + my @l; + my $e; + while (@words) { + my $keyword = shift @words; + if ($keyword eq 'machine') { + push @l, $e = { machine => shift(@words) }; + } elsif ($keyword eq 'default') { + push @l, $e = { default => '' }; + } elsif ($keyword eq 'login' || $keyword eq 'password' || $keyword eq 'account') { + $e->{$keyword} = shift(@words); + } else { + $urpm->{error}("unknown netrc command $keyword"); + } + } + @l; +} + +sub parse_url_with_login { + my ($url) = @_; + $url =~ m!([^:]*)://([^/:\@]*)(:([^/:\@]*))?\@([^/]*)(.*)! && + { proto => $1, login => $2, password => $4, machine => $5, dir => $6 }; +} + +sub read_config_add_passwords { + my ($urpm, $config) = @_; + + my @netrc = read_private_netrc($urpm) or return; + foreach (values %$config) { + my $u = 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}); + } else { + $urpm->{log}("no password found for $u->{login}@$u->{machine}"); + } + } +} + +sub remove_passwords_and_write_private_netrc { + my ($urpm, $config) = @_; + + my @l; + foreach (values %$config) { + my $u = parse_url_with_login($_->{url}) or next; + #- check whether a password is visible + $u->{password} or next; + + push @l, $u; + $_->{url} = sprintf('%s://%s@%s%s', $u->{proto}, $u->{login}, $u->{machine}, $u->{dir}); + } + { + my $fh = urpm::sys::open_safe($urpm, '>', $urpm->{private_netrc}) or return; + foreach my $u (@l) { + printf $fh "machine %s login %s password %s\n", $u->{machine}, $u->{login}, $u->{password}; + } + } + chmod 0600, $urpm->{private_netrc}; +} + +#- handle deprecated way of saving passwords +sub recover_url_from_list { + my ($urpm, $medium) = @_; + + #- /./ is end of url marker in list file (typically generated by a + #- find . -name "*.rpm" > list + #- for exportable list file. + if (my @probe = map { m!^(.*)/\./! || m!^(.*)/[^/]*$! } cat_(statedir_list($urpm, $medium))) { + ($medium->{url}) = sort { length($a) <=> length($b) } @probe; + $urpm->{modified} = 1; #- ensure urpmi.cfg is handled using only partially hidden url + netrc, since file list won't be generated anymore + } +} + +#- Loads /etc/urpmi/urpmi.cfg and performs basic checks. +#- Does not handle old format: [with ] +#- options : +#- - nocheck_access : don't check presence of hdlist and other files +sub read_config { + my ($urpm, $b_nocheck_access) = @_; + return if $urpm->{media}; #- media already loaded + $urpm->{media} = []; + my $config = urpm::cfg::load_config($urpm->{config}) + or $urpm->{fatal}(6, $urpm::cfg::err); + + #- global options + if (my $global = $config->{''}) { + foreach my $opt (keys %$global) { + if (defined $global->{$opt} && !exists $urpm->{options}{$opt}) { + $urpm->{options}{$opt} = $global->{$opt}; + } + } + } + + #- per-media options + + read_config_add_passwords($urpm, $config); + + foreach my $m (grep { $_ ne '' } keys %$config) { + my $medium = { name => $m }; + foreach my $opt (@PER_MEDIA_OPT) { + defined $config->{$m}{$opt} and $medium->{$opt} = $config->{$m}{$opt}; + } + + if (!$medium->{url}) { + #- recover the url the old deprecated way... + #- only useful for migration, new urpmi.cfg will use netrc + recover_url_from_list($urpm, $medium); + $medium->{url} or $urpm->{error}("unable to find url in list file $medium->{name}, medium ignored"); + } + + add_existing_medium($urpm, $medium, $b_nocheck_access); + } + + eval { require urpm::ldap; urpm::ldap::load_ldap_media($urpm) }; + + #- load default values + foreach (qw(post-clean verify-rpm)) { + exists $urpm->{options}{$_} or $urpm->{options}{$_} = 1; + } + + $urpm->{media} = [ sort { $a->{priority} <=> $b->{priority} } @{$urpm->{media}} ]; + + #- read MD5 sums (usually not in urpmi.cfg but in a separate file) + foreach (@{$urpm->{media}}) { + if (my $md5sum = urpm::md5sum::from_MD5SUM("$urpm->{statedir}/MD5SUM", statedir_hdlist_or_synthesis($urpm, $_))) { + $_->{md5sum} = $md5sum; + } + } + + #- remember global options for write_config + $urpm->{global_config} = $config->{''}; +} + +#- if invalid, set {ignore} +sub check_existing_medium { + my ($urpm, $medium, $b_nocheck_access) = @_; + + if ($medium->{virtual}) { + #- a virtual medium needs to have an url available without using a list file. + if ($medium->{hdlist} || $medium->{list}) { + $medium->{ignore} = 1; + $urpm->{error}(N("virtual medium \"%s\" should not have defined hdlist or list file, medium ignored", + $medium->{name})); + } + unless ($medium->{url}) { + $medium->{ignore} = 1; + $urpm->{error}(N("virtual medium \"%s\" should have a clear url, medium ignored", + $medium->{name})); + } + } else { + if ($medium->{hdlist}) { + #- is this check really needed? keeping just in case + $medium->{hdlist} ne 'list' && $medium->{hdlist} ne 'pubkey' or + $medium->{ignore} = 1, + $urpm->{error}(N("invalid hdlist name")); + } + if (!$medium->{ignore} && !$medium->{hdlist}) { + $medium->{hdlist} = "hdlist.$medium->{name}.cz"; + -e statedir_hdlist($urpm, $medium) or + $medium->{ignore} = 1, + $urpm->{error}(N("unable to find hdlist file for \"%s\", medium ignored", $medium->{name})); + } + if (!$medium->{ignore} && !$medium->{list}) { + unless (defined $medium->{url}) { + $medium->{list} = "list.$medium->{name}"; + unless (-e statedir_list($urpm, $medium)) { + $medium->{ignore} = 1, + $urpm->{error}(N("unable to find list file for \"%s\", medium ignored", $medium->{name})); + } + } + } + } + + + #- check the presence of hdlist and list files if necessary. + if (!$b_nocheck_access && !$medium->{ignore}) { + if ($medium->{virtual} && -r hdlist_or_synthesis_for_virtual_medium($medium)) {} + elsif (-r statedir_hdlist($urpm, $medium)) {} + elsif ($medium->{synthesis} && -r statedir_synthesis($urpm, $medium)) {} + else { + $medium->{ignore} = 1; + $urpm->{error}(N("unable to access hdlist file of \"%s\", medium ignored", $medium->{name})); + } + if ($medium->{list} && -r statedir_list($urpm, $medium)) {} + elsif ($medium->{url}) {} + else { + $medium->{ignore} = 1; + $urpm->{error}(N("unable to access list file of \"%s\", medium ignored", $medium->{name})); + } + } + + foreach my $field ('hdlist', 'list') { + $medium->{$field} or next; + if (grep { $_->{$field} eq $medium->{$field} } @{$urpm->{media}}) { + $medium->{ignore} = 1; + $urpm->{error}( + $field eq 'hdlist' + ? N("medium \"%s\" trying to use an already used hdlist, medium ignored", $medium->{name}) + : N("medium \"%s\" trying to use an already used list, medium ignored", $medium->{name})); + } + } +} + +#- probe medium to be used, take old medium into account too. +sub add_existing_medium { + my ($urpm, $medium, $b_nocheck_access) = @_; + + if (name2medium($urpm, $medium->{name})) { + $urpm->{error}(N("trying to override existing medium \"%s\", skipping", $medium->{name})); + return; + } + + check_existing_medium($urpm, $medium, $b_nocheck_access); + + #- probe removable device. + probe_removable_device($urpm, $medium); + + #- clear URLs for trailing /es. + $medium->{url} and $medium->{url} =~ s|(.*?)/*$|$1|; + + push @{$urpm->{media}}, $medium; +} + +sub file_from_file_url { + my ($url) = @_; + $url =~ m!^(?:file:/)?(/.*)! && $1; +} + +sub _hdlist_dir { + my ($medium) = @_; + my $base = file_from_file_url($medium->{url}) || $medium->{url}; + $medium->{with_hdlist} && reduce_pathname("$base/$medium->{with_hdlist}/.."); +} +sub _url_with_hdlist { + my ($medium) = @_; + + my $base = file_from_file_url($medium->{url}) || $medium->{url}; + $medium->{with_hdlist} && reduce_pathname("$base/$medium->{with_hdlist}"); +} +sub hdlist_or_synthesis_for_virtual_medium { + my ($medium) = @_; + file_from_file_url($medium->{url}) && _url_with_hdlist($medium); +} + +sub statedir_hdlist_or_synthesis { + my ($urpm, $medium) = @_; + $medium->{hdlist} && "$urpm->{statedir}/" . ($medium->{synthesis} ? 'synthesis.' : '') . $medium->{hdlist}; +} +sub statedir_hdlist { + my ($urpm, $medium) = @_; + $medium->{hdlist} && "$urpm->{statedir}/$medium->{hdlist}"; +} +sub statedir_synthesis { + my ($urpm, $medium) = @_; + $medium->{hdlist} && "$urpm->{statedir}/synthesis.$medium->{hdlist}"; +} +sub statedir_list { + my ($urpm, $medium) = @_; + $medium->{list} && "$urpm->{statedir}/$medium->{list}"; +} +sub statedir_descriptions { + my ($urpm, $medium) = @_; + $medium->{name} && "$urpm->{statedir}/descriptions.$medium->{name}"; +} +sub statedir_names { + my ($urpm, $medium) = @_; + $medium->{name} && "$urpm->{statedir}/names.$medium->{name}"; +} +sub cachedir_hdlist { + my ($urpm, $medium) = @_; + $medium->{hdlist} && "$urpm->{cachedir}/partial/$medium->{hdlist}"; +} +sub cachedir_list { + my ($urpm, $medium) = @_; + $medium->{list} && "$urpm->{cachedir}/partial/$medium->{list}"; +} + +sub name2medium { + my ($urpm, $name) = @_; + my ($medium) = grep { $_->{name} eq $name } @{$urpm->{media}}; + $medium; +} + +#- probe device associated with a removable device. +sub probe_removable_device { + my ($urpm, $medium) = @_; + + if ($medium->{url} && $medium->{url} =~ /^removable/) { + #- try to find device name in url scheme, this is deprecated, use medium option "removable" instead + if ($medium->{url} =~ /^removable_?([^_:]*)/) { + $medium->{removable} ||= $1 && "/dev/$1"; + } + } else { + delete $medium->{removable}; + return; + } + + #- try to find device to open/close for removable medium. + if (my $dir = file_from_local_url($medium->{url})) { + my %infos; + my @mntpoints = urpm::sys::find_mntpoints($dir, \%infos); + if (@mntpoints > 1) { #- return value is suitable for an hash. + $urpm->{log}(N("too many mount points for removable medium \"%s\"", $medium->{name})); + $urpm->{log}(N("taking removable device as \"%s\"", join ',', map { $infos{$_}{device} } @mntpoints)); + } + if (urpm::is_iso($medium->{removable})) { + $urpm->{log}(N("Medium \"%s\" is an ISO image, will be mounted on-the-fly", $medium->{name})); + } elsif (@mntpoints) { + if ($medium->{removable} && $medium->{removable} ne $infos{$mntpoints[-1]}{device}) { + $urpm->{log}(N("using different removable device [%s] for \"%s\"", + $infos{$mntpoints[-1]}{device}, $medium->{name})); + } + $medium->{removable} = $infos{$mntpoints[-1]}{device}; + } else { + $urpm->{error}(N("unable to retrieve pathname for removable medium \"%s\"", $medium->{name})); + } + } else { + $urpm->{error}(N("unable to retrieve pathname for removable medium \"%s\"", $medium->{name})); + } +} + + +sub write_MD5SUM { + my ($urpm) = @_; + + #- write MD5SUM file + my $fh = urpm::sys::open_safe($urpm, '>', "$urpm->{statedir}/MD5SUM") or return 0; + foreach my $medium (grep { $_->{md5sum} } @{$urpm->{media}}) { + my $s = basename(statedir_hdlist_or_synthesis($urpm, $medium)); + print $fh "$medium->{md5sum} $s\n"; + } + + $urpm->{log}(N("wrote %s", "$urpm->{statedir}/MD5SUM")); + + delete $urpm->{md5sum_modified}; +} + +#- Writes the urpmi.cfg file. +sub write_urpmi_cfg { + my ($urpm) = @_; + + #- avoid trashing exiting configuration if it wasn't loaded + $urpm->{media} or return; + + my $config = { + #- global config options found in the config file, without the ones + #- set from the command-line + '' => $urpm->{global_config}, + }; + foreach my $medium (@{$urpm->{media}}) { + next if $medium->{external}; + my $medium_name = $medium->{name}; + + foreach (@PER_MEDIA_OPT) { + defined $medium->{$_} and $config->{$medium_name}{$_} = $medium->{$_}; + } + } + remove_passwords_and_write_private_netrc($urpm, $config); + + urpm::cfg::dump_config($urpm->{config}, $config) + or $urpm->{fatal}(6, N("unable to write config file [%s]", $urpm->{config})); + + $urpm->{log}(N("wrote config file [%s]", $urpm->{config})); + + #- everything should be synced now. + delete $urpm->{modified}; +} + +sub write_config { + my ($urpm) = @_; + + write_urpmi_cfg($urpm); + write_MD5SUM($urpm); +} + +#- read urpmi.cfg file as well as necessary synthesis files +#- options : +#- root +#- cmdline_skiplist +#- nocheck_access (used by read_config) +#- +#- callback (urpmf) +#- need_hdlist (for urpmf: to be able to have info not available in synthesis) +#- nodepslist (for urpmq: we don't need the hdlist/synthesis) +#- no_skiplist (urpmf) +#- +#- synthesis (use this synthesis file, and only this synthesis file) +#- +#- usedistrib (otherwise uses urpmi.cfg) +#- parallel +#- media +#- excludemedia +#- sortmedia +#- +#- update +#- searchmedia +sub configure { + my ($urpm, %options) = @_; + + clean($urpm); + + $options{parallel} && $options{usedistrib} and $urpm->{fatal}(1, N("Can't use parallel mode with use-distrib mode")); + + if ($options{parallel}) { + require urpm::parallel; + urpm::parallel::configure($urpm, $options{parallel}); + + if (!$options{media} && $urpm->{parallel_handler}{media}) { + $options{media} = $urpm->{parallel_handler}{media}; + $urpm->{log}->(N("using associated media for parallel mode: %s", $options{media})); + } + } else { + #- nb: can't have both parallel and root + $urpm->{root} = $options{root}; + } + + $urpm->{root} && ! -c "$urpm->{root}/dev/null" + and $urpm->{error}(N("there doesn't seem to be devices in the chroot in \"%s\"", $urpm->{root})); + + if ($options{synthesis}) { + if ($options{synthesis} ne 'none') { + #- synthesis take precedence over media, update options. + $options{media} || $options{excludemedia} || $options{sortmedia} || $options{update} || $options{usedistrib} || $options{parallel} and + $urpm->{fatal}(1, N("--synthesis cannot be used with --media, --excludemedia, --sortmedia, --update, --use-distrib or --parallel")); + $urpm->parse_synthesis($options{synthesis}); + #- synthesis disables the split of transaction (too risky and not useful). + $urpm->{options}{'split-length'} = 0; + } + } else { + if ($options{usedistrib}) { + $urpm->{media} = []; + add_distrib_media($urpm, "Virtual", $options{usedistrib}, %options, 'virtual' => 1); + } else { + read_config($urpm, $options{nocheck_access}); + if (!$options{media} && $urpm->{options}{'default-media'}) { + $options{media} = $urpm->{options}{'default-media'}; + } + } + if ($options{media}) { + delete $_->{modified} foreach @{$urpm->{media} || []}; + select_media($urpm, split /,/, $options{media}); + foreach (grep { !$_->{modified} } @{$urpm->{media} || []}) { + #- this is only a local ignore that will not be saved. + $_->{tempignore} = $_->{ignore} = 1; + } + } + if ($options{searchmedia}) { + select_media($urpm, $options{searchmedia}); #- Ensure this media has been selected + if (my $medium = name2medium($urpm, $options{searchmedia})) { + $medium->{ignore} and $urpm->{fatal}("searchmedia is ignored"); + $medium->{searchmedia} = 1; + } + } + if ($options{excludemedia}) { + delete $_->{modified} foreach @{$urpm->{media} || []}; + foreach (select_media_by_name($urpm, [ split /,/, $options{excludemedia} ])) { + $_->{modified} = 1; + #- this is only a local ignore that will not be saved. + $_->{tempignore} = $_->{ignore} = 1; + } + } + if ($options{sortmedia}) { + my @sorted_media = map { select_media_by_name($urpm, [$_]) } split(/,/, $options{sortmedia}); + my @remaining = difference2($urpm->{media}, \@sorted_media); + $urpm->{media} = [ @sorted_media, @remaining ]; + } + _parse_media($urpm, 0, \%options) if !$options{nodepslist}; + } + #- determine package to withdraw (from skip.list file) only if something should be withdrawn. + if (!$options{nodepslist}) { + _compute_flags_for_skiplist($urpm, $options{cmdline_skiplist}) if !$options{no_skiplist}; + _compute_flags_for_instlist($urpm); + } +} + +sub _parse_media { + my ($urpm, $second_pass, $options) = @_; + + foreach (grep { !$_->{ignore} && (!$options->{update} || $_->{update}) } @{$urpm->{media} || []}) { + our $currentmedia = $_; #- hack for urpmf + delete @$_{qw(start end)}; + if ($_->{virtual}) { + if (file_from_file_url($_->{url})) { + if ($_->{synthesis}) { + _parse_synthesis($urpm, $_, + hdlist_or_synthesis_for_virtual_medium($_), $options->{callback}); + } else { + #- we'll need a second pass + $second_pass++; + _parse_hdlist($urpm, $_, + hdlist_or_synthesis_for_virtual_medium($_), + $second_pass > 1 ? undef : $options->{callback}, + ); + } + } else { + $urpm->{error}(N("virtual medium \"%s\" is not local, medium ignored", $_->{name})); + $_->{ignore} = 1; + } + } else { + if ($options->{need_hdlist} && file_size(statedir_hdlist($urpm, $_)) > 32) { + _parse_hdlist($urpm, $_, statedir_hdlist($urpm, $_), $options->{callback}); + } else { + if (!_parse_synthesis($urpm, $_, + statedir_synthesis($urpm, $_), + $options->{callback})) { + _parse_hdlist($urpm, $_, statedir_hdlist($urpm, $_), $options->{callback}); + } + } + } + unless ($_->{ignore}) { + _check_after_reading_hdlist_or_synthesis($urpm, $_); + } + unless ($_->{ignore}) { + if ($_->{searchmedia}) { + ($urpm->{searchmedia}{start}, $urpm->{searchmedia}{end}) = ($_->{start}, $_->{end}); + $urpm->{log}(N("Search start: %s end: %s", + $urpm->{searchmedia}{start}, $urpm->{searchmedia}{end})); + delete $_->{searchmedia}; + } + } + } + + if ($second_pass == 1) { + require URPM::Build; + $urpm->{log}(N("performing second pass to compute dependencies\n")); + $urpm->unresolved_provides_clean; + _parse_media($urpm, 1, $options); + } +} + +sub _compute_flags_for_skiplist { + my ($urpm, $cmdline_skiplist) = @_; + my %uniq; + $urpm->compute_flags( + get_packages_list($urpm->{skiplist}, $cmdline_skiplist), + skip => 1, + callback => sub { + my ($urpm, $pkg) = @_; + $pkg->is_arch_compat && ! exists $uniq{$pkg->fullname} or return; + $uniq{$pkg->fullname} = undef; + $urpm->{log}(N("skipping package %s", scalar($pkg->fullname))); + }, + ); +} + +sub _compute_flags_for_instlist { + my ($urpm) = @_; + + my %uniq; + $urpm->compute_flags( + get_packages_list($urpm->{instlist}), + disable_obsolete => 1, + callback => sub { + my ($urpm, $pkg) = @_; + $pkg->is_arch_compat && ! exists $uniq{$pkg->fullname} or return; + $uniq{$pkg->fullname} = undef; + $urpm->{log}(N("would install instead of upgrade package %s", scalar($pkg->fullname))); + }, + ); + +} + +#- 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 +sub add_medium { + my ($urpm, $name, $url, $with_hdlist, %options) = @_; + + #- make sure configuration has been read. + $urpm->{media} or die "caller should have used ->read_config or ->configure first"; + urpm::sys::lock_urpmi_db($urpm, 'exclusive') if !$options{nolock}; + + #- if a medium with that name has already been found, we have to exit now + my $medium; + if (defined $options{index_name}) { + my $i = $options{index_name}; + do { + ++$i; + $medium = name2medium($urpm, $name . $i); + } while $medium; + $name .= $i; + } else { + $medium = name2medium($urpm, $name); + } + $medium and $urpm->{fatal}(5, N("medium \"%s\" already exists", $medium->{name})); + + $url =~ s,/*$,,; #- clear URLs for trailing /es. + + #- creating the medium info. + $medium = { name => $name, url => $url, update => $options{update}, modified => 1, ignore => $options{ignore} }; + if ($options{virtual}) { + file_from_file_url($url) or $urpm->{fatal}(1, N("virtual medium needs to be local")); + $medium->{virtual} = 1; + } else { + $medium->{hdlist} = "hdlist.$name.cz"; + probe_removable_device($urpm, $medium); + } + + #- local media have priority, other are added at the end. + if (file_from_file_url($url)) { + $medium->{priority} = 0.5; + } else { + $medium->{priority} = 1 + @{$urpm->{media}}; + } + + $with_hdlist and $medium->{with_hdlist} = $with_hdlist; + + #- create an entry in media list. + push @{$urpm->{media}}, $medium; + + $urpm->{log}(N("added medium %s", $name)); + $urpm->{modified} = 1; + + $options{nolock} or urpm::sys::unlock_urpmi_db($urpm); + $name; +} + +#- add distribution media, according to url given. +#- returns the list of names of added media. +#- options : +#- - initial_number : when adding several numbered media, start with this number +#- - probe_with : if eq 'synthesis', use synthesis instead of hdlists +#- - ask_media : callback to know whether each media should be added +#- other options are passed to add_medium(): ignore, nolock, virtual +sub add_distrib_media { + my ($urpm, $name, $url, %options) = @_; + + #- make sure configuration has been read. + $urpm->{media} or die "caller should have used ->read_config or ->configure first"; + + my $distribconf; + + if (my $dir = file_from_local_url($url)) { + $urpm->try_mounting($dir) + or $urpm->{error}(N("unable to mount the distribution medium")), return (); + $distribconf = MDV::Distribconf->new($dir, undef); + $distribconf->load + or $urpm->{error}(N("this location doesn't seem to contain any distribution")), return (); + } else { + unlink "$urpm->{cachedir}/partial/media.cfg"; + + $distribconf = MDV::Distribconf->new($url, undef); + $distribconf->settree('mandriva'); + + $urpm->{log}(N("retrieving media.cfg file...")); + if (urpm::download::sync($urpm, undef, + [ reduce_pathname($distribconf->getfullpath(undef, 'infodir') . '/media.cfg') ], + quiet => 1)) { + $urpm->{log}(N("...retrieving done")); + $distribconf->parse_mediacfg("$urpm->{cachedir}/partial/media.cfg") + or $urpm->{error}(N("unable to parse media.cfg")), return(); + } else { + $urpm->{error}(N("...retrieving failed: %s", $@)); + $urpm->{error}(N("unable to access the distribution medium (no media.cfg file found)")); + return (); + } + } + + #- cosmetic update of name if it contains spaces. + $name =~ /\s/ and $name .= ' '; + + my @newnames; + #- at this point, we have found a media.cfg file, so parse it + #- and create all necessary media according to it. + my $medium = $options{initial_number} || 1; + + foreach my $media ($distribconf->listmedia) { + my $skip = 0; + # if one of those values is set, by default, we skip adding the media + foreach (qw(noauto)) { + $distribconf->getvalue($media, $_) and do { + $skip = 1; + last; + }; + } + if ($options{ask_media}) { + if ($options{ask_media}->( + $distribconf->getvalue($media, 'name'), + !$skip, + )) { + $skip = 0; + } else { + $skip = 1; + } + } + $skip and next; + + my $media_name = $distribconf->getvalue($media, 'name') || ''; + my $is_update_media = $distribconf->getvalue($media, 'updates_for'); + + push @newnames, add_medium($urpm, + $name ? "$media_name ($name$medium)" : $media_name, + reduce_pathname($distribconf->getfullpath($media, 'path')), + offset_pathname( + $url, + $distribconf->getpath($media, 'path'), + ) . '/' . $distribconf->getpath($media, $options{probe_with} eq 'synthesis' ? 'synthesis' : 'hdlist'), + index_name => $name ? undef : 0, + %options, + # the following override %options + update => $is_update_media ? 1 : undef, + ); + ++$medium; + } + return @newnames; +} + +#- deprecated, use select_media_by_name instead +sub select_media { + my $urpm = shift; + my $options = {}; + if (ref $_[0]) { $options = shift } + foreach (select_media_by_name($urpm, [ @_ ], $options->{strict_match})) { + #- select medium by setting the modified flag, do not check ignore. + $_->{modified} = 1; + } +} + +sub select_media_by_name { + my ($urpm, $names, $b_strict_match) = @_; + + my %wanted = map { $_ => 1 } @$names; + + #- first the exact matches + my @l = grep { delete $wanted{$_->{name}} } @{$urpm->{media}}; + + #- check if some arguments don't correspond to the medium name. + #- in such case, try to find the unique medium (or list candidate + #- media found). + foreach (keys %wanted) { + my $q = quotemeta; + my (@found, @foundi); + my $regex = $b_strict_match ? qr/^$q$/ : qr/$q/; + my $regexi = $b_strict_match ? qr/^$q$/i : qr/$q/i; + foreach my $medium (@{$urpm->{media}}) { + $medium->{name} =~ $regex and push @found, $medium; + $medium->{name} =~ $regexi and push @foundi, $medium; + } + @found = @foundi if !@found; + + if (@found == 0) { + $urpm->{error}(N("trying to select nonexistent medium \"%s\"", $_)); + } else { + if (@found > 1) { + $urpm->{log}(N("selecting multiple media: %s", join(", ", map { qq("$_->{name}") } @found))); + } + #- changed behaviour to select all occurences by default. + push @l, @found; + } + } + @l; +} + +#- deprecated, use remove_media instead +sub remove_selected_media { + my ($urpm) = @_; + + remove_media($urpm, [ grep { $_->{modified} } @{$urpm->{media}} ]); +} + +sub remove_media { + my ($urpm, $to_remove) = @_; + + foreach my $medium (@$to_remove) { + $urpm->{log}(N("removing medium \"%s\"", $medium->{name})); + + #- mark to re-write configuration. + $urpm->{modified} = 1; + + #- remove files associated with this medium. + unlink grep { $_ } map { $_->($urpm, $medium) } \&statedir_hdlist, \&statedir_list, \&statedir_synthesis, \&statedir_descriptions, \&statedir_names; + + #- remove proxy settings for this media + urpm::download::remove_proxy_media($medium->{name}); + } + + $urpm->{media} = [ difference2($urpm->{media}, $to_remove) ]; +} + +#- return list of synthesis or hdlist reference to probe. +sub _probe_with_try_list { + my ($probe_with) = @_; + + my @probe_synthesis = ( + "media_info/synthesis.hdlist.cz", + "synthesis.hdlist.cz", + ); + my @probe_hdlist = ( + "media_info/hdlist.cz", + "hdlist.cz", + ); + $probe_with =~ /synthesis/ + ? (@probe_synthesis, @probe_hdlist) + : (@probe_hdlist, @probe_synthesis); +} + +sub may_reconfig_urpmi { + my ($urpm, $medium) = @_; + + my $f; + if (my $dir = file_from_file_url($medium->{url})) { + $f = reduce_pathname("$dir/reconfig.urpmi"); + } else { + unlink($f = "$urpm->{cachedir}/partial/reconfig.urpmi"); + urpm::download::sync($urpm, $medium, [ reduce_pathname("$medium->{url}/reconfig.urpmi") ], quiet => 1); + } + if (-s $f) { + reconfig_urpmi($urpm, $f, $medium->{name}); + } + unlink $f if !file_from_file_url($medium->{url}); +} + +#- read a reconfiguration file for urpmi, and reconfigure media accordingly +#- $rfile is the reconfiguration file (local), $name is the media name +#- +#- the format is similar to the RewriteRule of mod_rewrite, so: +#- PATTERN REPLACEMENT [FLAG] +#- where FLAG can be L or N +#- +#- example of reconfig.urpmi: +#- # this is an urpmi reconfiguration file +#- /cooker /cooker/$ARCH +sub reconfig_urpmi { + my ($urpm, $rfile, $name) = @_; + -r $rfile or return; + + $urpm->{log}(N("reconfiguring urpmi for media \"%s\"", $name)); + + my ($magic, @lines) = cat_($rfile); + #- the first line of reconfig.urpmi must be magic, to be sure it's not an error file + $magic =~ /^# this is an urpmi reconfiguration file/ or return undef; + + my @replacements; + foreach (@lines) { + chomp; + s/^\s*//; s/#.*$//; s/\s*$//; + $_ or next; + my ($p, $r, $f) = split /\s+/, $_, 3; + push @replacements, [ quotemeta $p, $r, $f || 1 ]; + } + + my $reconfigured = 0; + my @reconfigurable = qw(url with_hdlist); + + my $medium = name2medium($urpm, $name) or return; + my %orig = %$medium; + + URLS: + foreach my $k (@reconfigurable) { + foreach my $r (@replacements) { + if ($medium->{$k} =~ s/$r->[0]/$r->[1]/) { + $reconfigured = 1; + #- Flags stolen from mod_rewrite: L(ast), N(ext) + if ($r->[2] =~ /L/) { + last; + } elsif ($r->[2] =~ /N/) { #- dangerous option + redo URLS; + } + } + } + #- check that the new url exists before committing changes (local mirrors) + my $file = file_from_local_url($medium->{$k}); + if ($file && !-e $file) { + %$medium = %orig; + $reconfigured = 0; + $urpm->{log}(N("...reconfiguration failed")); + return; + } + } + + if ($reconfigured) { + $urpm->{log}(N("reconfiguration done")); + write_config($urpm); + } + $reconfigured; +} + +sub _guess_hdlist_suffix { + my ($url) = @_; + $url =~ m!\bmedia/(\w+)/*\Z! && $1; +} + +sub _hdlist_suffix { + my ($medium) = @_; + $medium->{with_hdlist} =~ /hdlist(.*?)(?:\.src)?\.cz$/ ? $1 : ''; +} + +sub _parse_hdlist_or_synthesis__when_not_modified { + my ($urpm, $medium) = @_; + + delete @$medium{qw(start end)}; + if ($medium->{virtual}) { + if (file_from_file_url($medium->{url})) { + _parse_maybe_hdlist_or_synthesis($urpm, $medium, hdlist_or_synthesis_for_virtual_medium($medium)); + } else { + $urpm->{error}(N("virtual medium \"%s\" is not local, medium ignored", $medium->{name})); + $medium->{ignore} = 1; + } + } else { + if (!_parse_synthesis($urpm, $medium, statedir_synthesis($urpm, $medium))) { + _parse_hdlist($urpm, $medium, statedir_hdlist($urpm, $medium)); + } + } + unless ($medium->{ignore}) { + _check_after_reading_hdlist_or_synthesis($urpm, $medium); + } +} + +sub _parse_hdlist_or_synthesis__virtual { + my ($urpm, $medium) = @_; + + if (my $hdlist_or = hdlist_or_synthesis_for_virtual_medium($medium)) { + delete $medium->{modified}; + $medium->{really_modified} = 1; + $urpm->{md5sum_modified} = 1; + _parse_maybe_hdlist_or_synthesis($urpm, $medium, $hdlist_or); + _check_after_reading_hdlist_or_synthesis($urpm, $medium); + } else { + $urpm->{error}(N("virtual medium \"%s\" should have valid source hdlist or synthesis, medium ignored", + $medium->{name})); + $medium->{ignore} = 1; + } +} + +#- names. is used by external progs (namely for bash-completion) +sub generate_medium_names { + my ($urpm, $medium) = @_; + + unlink statedir_names($urpm, $medium); + + if (my $fh = urpm::sys::open_safe($urpm, ">", statedir_names($urpm, $medium))) { + foreach ($medium->{start} .. $medium->{end}) { + if (defined $urpm->{depslist}[$_]) { + print $fh $urpm->{depslist}[$_]->name . "\n"; + } else { + $urpm->{error}(N("Error generating names file: dependency %d not found", $_)); + } + } + } else { + $urpm->{error}(N("Error generating names file: Can't write to file (%s)", $!)); + } +} + + +sub _read_existing_synthesis_and_hdlist_if_same_time_and_msize { + my ($urpm, $medium, $basename) = @_; + + same_size_and_mtime("$urpm->{cachedir}/partial/$basename", + statedir_hdlist($urpm, $medium)) or return; + + unlink "$urpm->{cachedir}/partial/$basename"; + + _read_existing_synthesis_and_hdlist($urpm, $medium); + + 1; +} + +sub _read_existing_synthesis_and_hdlist_if_same_md5sum { + my ($urpm, $medium, $retrieved_md5sum) = @_; + + #- if an existing hdlist or synthesis file has the same md5sum, we assume the + #- files are the same. + #- if local md5sum is the same as distant md5sum, this means there is no need to + #- download hdlist or synthesis file again. + $retrieved_md5sum && $medium->{md5sum} eq $retrieved_md5sum or return; + + unlink "$urpm->{cachedir}/partial/" . basename($medium->{with_hdlist}); + + _read_existing_synthesis_and_hdlist($urpm, $medium); + + 1; +} + +sub _read_existing_synthesis_and_hdlist { + my ($urpm, $medium) = @_; + + $urpm->{log}(N("medium \"%s\" is up-to-date", $medium->{name})); + + #- the medium is now considered not modified. + $medium->{modified} = 0; + #- XXX we could link the new hdlist to the old one. + #- (However links need to be managed. see bug #12391.) + #- as previously done, just read synthesis file here, this is enough. + if (!_parse_synthesis($urpm, $medium, statedir_synthesis($urpm, $medium))) { + _parse_hdlist($urpm, $medium, statedir_hdlist($urpm, $medium)); + _check_after_reading_hdlist_or_synthesis($urpm, $medium); + } + + 1; +} + +sub _parse_hdlist { + my ($urpm, $medium, $hdlist_file, $o_callback) = @_; + + $urpm->{log}(N("examining hdlist file [%s]", $hdlist_file)); + ($medium->{start}, $medium->{end}) = + $urpm->parse_hdlist($hdlist_file, packing => 1, $o_callback ? (callback => $o_callback) : @{[]}); +} + +sub _parse_synthesis { + my ($urpm, $medium, $synthesis_file, $o_callback) = @_; + + $urpm->{log}(N("examining synthesis file [%s]", $synthesis_file)); + ($medium->{start}, $medium->{end}) = + $urpm->parse_synthesis($synthesis_file, $o_callback ? (callback => $o_callback) : @{[]}); +} +sub _parse_maybe_hdlist_or_synthesis { + my ($urpm, $medium, $hdlist_or) = @_; + + if ($medium->{synthesis}) { + if (_parse_synthesis($urpm, $medium, $hdlist_or)) { + $medium->{synthesis} = 1; + } elsif (_parse_hdlist($urpm, $medium, $hdlist_or)) { + delete $medium->{synthesis}; + } else { + return; + } + } else { + if (_parse_hdlist($urpm, $medium, $hdlist_or)) { + delete $medium->{synthesis}; + } elsif (_parse_synthesis($urpm, $medium, $hdlist_or)) { + $medium->{synthesis} = 1; + } else { + return; + } + } + 1; +} + +sub _build_hdlist_using_rpm_headers { + my ($urpm, $medium) = @_; + + $urpm->{log}(N("building hdlist [%s]", statedir_hdlist($urpm, $medium))); + #- finish building operation of hdlist. + $urpm->build_hdlist(start => $medium->{start}, + end => $medium->{end}, + dir => "$urpm->{cachedir}/headers", + hdlist => statedir_hdlist($urpm, $medium), + ); +} + +sub _build_synthesis { + my ($urpm, $medium) = @_; + + eval { $urpm->build_synthesis( + start => $medium->{start}, + end => $medium->{end}, + synthesis => statedir_synthesis($urpm, $medium), + ) }; + if ($@) { + $urpm->{error}(N("Unable to build synthesis file for medium \"%s\". Your hdlist file may be corrupted.", $medium->{name})); + $urpm->{error}($@); + unlink statedir_synthesis($urpm, $medium); + } else { + $urpm->{log}(N("built hdlist synthesis file for medium \"%s\"", $medium->{name})); + } + #- keep in mind we have a modified database, sure at this point. + $urpm->{md5sum_modified} = 1; +} + +sub is_valid_medium { + my ($medium) = @_; + defined $medium->{start} && defined $medium->{end}; +} + +sub _check_after_reading_hdlist_or_synthesis { + my ($urpm, $medium) = @_; + + if (!is_valid_medium($medium)) { + $urpm->{error}(N("problem reading hdlist or synthesis file of medium \"%s\"", $medium->{name})); + $medium->{ignore} = 1; + } +} + +sub _get_list_or_pubkey__local { + my ($urpm, $medium, $name) = @_; + + my $path = _hdlist_dir($medium) . "/$name" . _hdlist_suffix($medium); + -e $path or $path = file_from_local_url($medium->{url}) . "/$name"; + if (-e $path) { + copy_and_own($path, "$urpm->{cachedir}/partial/$name") + or $urpm->{error}(N("...copying failed")), return; + } + 1; +} + +sub _get_list_or_pubkey__remote { + my ($urpm, $medium, $name) = @_; + + my $found; + if (_hdlist_suffix($medium)) { + my $local_name = $name . _hdlist_suffix($medium); + + if (urpm::download::sync($urpm, $medium, [_hdlist_dir($medium) . "/$local_name"], + quiet => 1)) { + rename("$urpm->{cachedir}/partial/$local_name", "$urpm->{cachedir}/partial/$name"); + $found = 1; + } + } + if (!$found) { + urpm::download::sync($urpm, $medium, [reduce_pathname("$medium->{url}/$name")], quiet => 1) + or unlink "$urpm->{cachedir}/partial/$name"; + } +} + +sub get_descriptions_local { + my ($urpm, $medium) = @_; + + unlink statedir_descriptions($urpm, $medium); + + my $dir = file_from_local_url($medium->{url}); + my $description_file = "$dir/media_info/descriptions"; #- new default location + -e $description_file or $description_file = "$dir/../descriptions"; + -e $description_file or return; + + $urpm->{log}(N("copying description file of \"%s\"...", $medium->{name})); + if (copy_and_own($description_file, statedir_descriptions($urpm, $medium))) { + $urpm->{log}(N("...copying done")); + } else { + $urpm->{error}(N("...copying failed")); + $medium->{ignore} = 1; + } +} +sub get_descriptions_remote { + my ($urpm, $medium) = @_; + + unlink "$urpm->{cachedir}/partial/descriptions"; + + if (-e statedir_descriptions($urpm, $medium)) { + urpm::util::move(statedir_descriptions($urpm, $medium), "$urpm->{cachedir}/partial/descriptions"); + } + urpm::download::sync($urpm, $medium, [ reduce_pathname("$medium->{url}/media_info/descriptions") ], quiet => 1) + or #- try older location + urpm::download::sync($urpm, $medium, [ reduce_pathname("$medium->{url}/../descriptions") ], quiet => 1); + + if (-e "$urpm->{cachedir}/partial/descriptions") { + urpm::util::move("$urpm->{cachedir}/partial/descriptions", statedir_descriptions($urpm, $medium)); + } +} +sub get_hdlist_or_synthesis__local { + my ($urpm, $medium, $callback) = @_; + + unlink cachedir_hdlist($urpm, $medium); + $urpm->{log}(N("copying source hdlist (or synthesis) of \"%s\"...", $medium->{name})); + $callback and $callback->('copy', $medium->{name}); + if (copy_and_own(_url_with_hdlist($medium), cachedir_hdlist($urpm, $medium))) { + $callback and $callback->('done', $medium->{name}); + $urpm->{log}(N("...copying done")); + if (file_size(cachedir_hdlist($urpm, $medium)) < 20) { + $urpm->{error}(N("copy of [%s] failed (file is suspiciously small)", cachedir_hdlist($urpm, $medium))); + 0; + } else { + 1; + } + } else { + $callback and $callback->('failed', $medium->{name}); + #- force error, reported afterwards + unlink cachedir_hdlist($urpm, $medium); + 0; + } +} + +sub get_hdlist_or_synthesis_and_check_md5sum__local { + my ($urpm, $medium, $retrieved_md5sum, $callback) = @_; + + get_hdlist_or_synthesis__local($urpm, $medium, $callback) or return; + + #- keep checking md5sum of file just copied ! (especially on nfs or removable device). + if ($retrieved_md5sum) { + $urpm->{log}(N("computing md5sum of copied source hdlist (or synthesis)")); + urpm::md5sum::compute(cachedir_hdlist($urpm, $medium)) eq $retrieved_md5sum or + $urpm->{error}(N("copy of [%s] failed (md5sum mismatch)", _url_with_hdlist($medium))), return; + } + + 1; +} + +sub _read_rpms_from_dir { + my ($urpm, $medium, $second_pass, $clean_cache) = @_; + + my $dir = file_from_local_url($medium->{url}); + + $medium->{rpm_files} = [ glob("$dir/*.rpm") ]; + + #- check files contains something good! + if (!@{$medium->{rpm_files}}) { + $urpm->{error}(N("no rpm files found from [%s]", $dir)); + $medium->{ignore} = 1; + return; + } + + #- we need to rebuild from rpm files the hdlist. + + $urpm->{log}(N("reading rpm files from [%s]", $dir)); + my @unresolved_before = grep { + ! defined $urpm->{provides}{$_}; + } keys %{$urpm->{provides} || {}}; + $medium->{start} = @{$urpm->{depslist}}; + + eval { + $medium->{headers} = [ $urpm->parse_rpms_build_headers( + dir => "$urpm->{cachedir}/headers", + rpms => $medium->{rpm_files}, + clean => $$clean_cache, + packing => 1, + ) ]; + }; + if ($@) { + $urpm->{error}(N("unable to read rpm files from [%s]: %s", $dir, $@)); + delete $medium->{headers}; #- do not propagate these. + return; + } + + $medium->{end} = $#{$urpm->{depslist}}; + if ($medium->{start} > $medium->{end}) { + #- an error occured (provided there are files in input.) + delete $medium->{start}; + delete $medium->{end}; + $urpm->{fatal}(9, N("no rpms read")); + } + + #- make sure the headers will not be removed for another media. + $$clean_cache = 0; + my @unresolved = grep { + ! defined $urpm->{provides}{$_}; + } keys %{$urpm->{provides} || {}}; + @unresolved_before == @unresolved or $$second_pass = 1; + + delete $medium->{synthesis}; #- when building hdlist by ourself, drop synthesis property. + 1; +} + +#- options: callback, force, force_building_hdlist, nomd5sum, nopubkey, probe_with +sub _update_medium__parse_if_unmodified__local { + my ($urpm, $medium, $second_pass, $clean_cache, $options) = @_; + + my $dir = file_from_local_url($medium->{url}); + + if (!-d $dir) { + #- the directory given does not exist and may be accessible + #- by mounting some other directory. Try to figure it out and mount + #- everything that might be necessary. + $urpm->try_mounting( + !$options->{force_building_hdlist} && $medium->{with_hdlist} + ? _hdlist_dir($medium) : $dir, + #- in case of an iso image, pass its name + urpm::is_iso($medium->{removable}) && $medium->{removable}, + ) or $urpm->{error}(N("unable to access medium \"%s\", +this could happen if you mounted manually the directory when creating the medium.", $medium->{name})), return 'unmodified'; + } + + #- try to probe for possible with_hdlist parameter, unless + #- it is already defined (and valid). + if ($options->{probe_with} && !$medium->{with_hdlist}) { + foreach (_probe_with_try_list($options->{probe_with})) { + -e "$dir/$_" or next; + if (file_size("$dir/$_") >= 20) { + $medium->{with_hdlist} = $_; + last; + } else { + $urpm->{error}(N("invalid hdlist file %s for medium \"%s\"", "$dir/$_", $medium->{name})); + return; + } + } + } + + if ($medium->{virtual}) { + #- syncing a virtual medium is very simple, just try to read the file in order to + #- determine its type, once a with_hdlist has been found (but is mandatory). + _parse_hdlist_or_synthesis__virtual($urpm, $medium); + } + + #- examine if a distant MD5SUM file is available. + #- this will only be done if $with_hdlist is not empty in order to use + #- an existing hdlist or synthesis file, and to check if download was good. + #- if no MD5SUM is available, do it as before... + #- we can assume at this point a basename is existing, but it needs + #- to be checked for being valid, nothing can be deduced if no MD5SUM + #- file is present. + + unless ($medium->{virtual}) { + if ($medium->{with_hdlist}) { + my ($retrieved_md5sum); + + if (!$options->{nomd5sum} && file_size(_hdlist_dir($medium) . '/MD5SUM') > 32) { + $retrieved_md5sum = urpm::md5sum::from_MD5SUM__or_warn($urpm, _hdlist_dir($medium) . '/MD5SUM', basename($medium->{with_hdlist})); + if (urpm::md5sum::on_local_medium($urpm, $medium, $options->{force})) { + _read_existing_synthesis_and_hdlist_if_same_md5sum($urpm, $medium, $retrieved_md5sum) + and return 'unmodified'; + } + } + + #- if the source hdlist is present and we are not forcing using rpm files + if (!$options->{force_building_hdlist} && -e _url_with_hdlist($medium)) { + if (get_hdlist_or_synthesis_and_check_md5sum__local($urpm, $medium, $retrieved_md5sum, $options->{callback})) { + + $medium->{md5sum} = $retrieved_md5sum if $retrieved_md5sum; + + #- check if the files are equal... and no force copy... + if (!$options->{force}) { + _read_existing_synthesis_and_hdlist_if_same_time_and_msize($urpm, $medium, $medium->{hdlist}) + and return 'unmodified'; + } + } else { + #- if copying hdlist has failed, try to build it directly. + if ($urpm->{options}{'build-hdlist-on-error'}) { + $options->{force_building_hdlist} = 1; + } else { + $urpm->{error}(N("unable to access hdlist file of \"%s\", medium ignored", $medium->{name})); + $medium->{ignore} = 1; + return; + } + } + } + } else { + #- no available hdlist/synthesis, try to build it from rpms + $options->{force_building_hdlist} = 1; + } + + if ($options->{force_building_hdlist}) { + _read_rpms_from_dir($urpm, $medium, $second_pass, $clean_cache) or return; + } + } + + 1; +} + +#- options: callback, force, nomd5sum, nopubkey, probe_with, quiet +sub _update_medium__parse_if_unmodified__remote { + my ($urpm, $medium, $options) = @_; + my ($retrieved_md5sum, $basename); + + #- examine if a distant MD5SUM file is available. + #- this will only be done if $with_hdlist is not empty in order to use + #- an existing hdlist or synthesis file, and to check if download was good. + #- if no MD5SUM is available, do it as before... + if ($medium->{with_hdlist}) { + #- we can assume at this point a basename is existing, but it needs + #- to be checked for being valid, nothing can be deduced if no MD5SUM + #- file is present. + $basename = basename($medium->{with_hdlist}); + + unlink "$urpm->{cachedir}/partial/MD5SUM"; + if (!$options->{nomd5sum} && + urpm::download::sync($urpm, $medium, + [ reduce_pathname(_hdlist_dir($medium) . '/MD5SUM') ], + quiet => 1) && file_size("$urpm->{cachedir}/partial/MD5SUM") > 32) { + if (urpm::md5sum::on_local_medium($urpm, $medium, $options->{force} >= 2)) { + $retrieved_md5sum = urpm::md5sum::from_MD5SUM__or_warn($urpm, "$urpm->{cachedir}/partial/MD5SUM", $basename); + _read_existing_synthesis_and_hdlist_if_same_md5sum($urpm, $medium, $retrieved_md5sum) + and return 'unmodified'; + } + } else { + #- at this point, we don't if a basename exists and is valid, let probe it later. + $basename = undef; + } + } + + #- try to probe for possible with_hdlist parameter, unless + #- it is already defined (and valid). + $urpm->{log}(N("retrieving source hdlist (or synthesis) of \"%s\"...", $medium->{name})); + $options->{callback} and $options->{callback}('retrieve', $medium->{name}); + if ($options->{probe_with} && !$medium->{with_hdlist}) { + foreach my $with_hdlist (_probe_with_try_list($options->{probe_with})) { + $basename = basename($with_hdlist) or next; + $options->{force} and unlink "$urpm->{cachedir}/partial/$basename"; + if (urpm::download::sync($urpm, $medium, [ reduce_pathname("$medium->{url}/$with_hdlist") ], + quiet => $options->{quiet}, callback => $options->{callback}) && file_size("$urpm->{cachedir}/partial/$basename") >= 20) { + $urpm->{log}(N("...retrieving done")); + $medium->{with_hdlist} = $with_hdlist; + $urpm->{log}(N("found probed hdlist (or synthesis) as %s", $medium->{with_hdlist})); + last; #- found a suitable with_hdlist in the list above. + } + } + } else { + $basename = basename($medium->{with_hdlist}); + + if ($options->{force}) { + unlink "$urpm->{cachedir}/partial/$basename"; + } else { + #- try to sync (copy if needed) local copy after restored the previous one. + #- this is useful for rsync (?) + if (-e statedir_hdlist_or_synthesis($urpm, $medium)) { + copy_and_own( + statedir_hdlist_or_synthesis($urpm, $medium), + "$urpm->{cachedir}/partial/$basename", + ) or $urpm->{error}(N("...copying failed")), return; + } + } + if (urpm::download::sync($urpm, $medium, [ _url_with_hdlist($medium) ], + quiet => $options->{quiet}, callback => $options->{callback})) { + $urpm->{log}(N("...retrieving done")); + } else { + $urpm->{error}(N("...retrieving failed: %s", $@)); + unlink "$urpm->{cachedir}/partial/$basename"; + } + } + + #- check downloaded file has right signature. + if (file_size("$urpm->{cachedir}/partial/$basename") >= 20 && $retrieved_md5sum) { + $urpm->{log}(N("computing md5sum of retrieved source hdlist (or synthesis)")); + unless (urpm::md5sum::compute("$urpm->{cachedir}/partial/$basename") eq $retrieved_md5sum) { + $urpm->{error}(N("...retrieving failed: md5sum mismatch")); + unlink "$urpm->{cachedir}/partial/$basename"; + } + } + + if (file_size("$urpm->{cachedir}/partial/$basename") >= 20) { + $options->{callback} and $options->{callback}('done', $medium->{name}); + + unless ($options->{force}) { + _read_existing_synthesis_and_hdlist_if_same_time_and_msize($urpm, $medium, $basename) + and return 'unmodified'; + } + + #- the files are different, update local copy. + rename("$urpm->{cachedir}/partial/$basename", cachedir_hdlist($urpm, $medium)); + } else { + $options->{callback} and $options->{callback}('failed', $medium->{name}); + $urpm->{error}(N("retrieval of source hdlist (or synthesis) failed")); + return; + } + $urpm->{md5sum} = $retrieved_md5sum if $retrieved_md5sum; + 1; +} + +sub _get_pubkey_and_descriptions { + my ($urpm, $medium, $nopubkey) = @_; + + my $local = file_from_local_url($medium->{url}); + + ($local ? \&get_descriptions_local : \&get_descriptions_remote)->($urpm, $medium); + + #- examine if a pubkey file is available. + if (!$nopubkey && !$medium->{'key-ids'}) { + ($local ? \&_get_list_or_pubkey__local : \&_get_list_or_pubkey__remote)->($urpm, $medium, 'pubkey'); + } +} + +sub _read_cachedir_pubkey { + my ($urpm, $medium) = @_; + -s "$urpm->{cachedir}/partial/pubkey" or return; + + $urpm->{log}(N("examining pubkey file of \"%s\"...", $medium->{name})); + + my %key_ids; + $urpm->import_needed_pubkeys( + [ $urpm->parse_armored_file("$urpm->{cachedir}/partial/pubkey") ], + root => $urpm->{root}, + callback => sub { + my (undef, undef, $_k, $id, $imported) = @_; + if ($id) { + $key_ids{$id} = undef; + $imported and $urpm->{log}(N("...imported key %s from pubkey file of \"%s\"", + $id, $medium->{name})); + } else { + $urpm->{error}(N("unable to import pubkey file of \"%s\"", $medium->{name})); + } + }); + if (keys(%key_ids)) { + $medium->{'key-ids'} = join(',', keys %key_ids); + } +} + +sub _write_rpm_list { + my ($urpm, $medium) = @_; + + @{$medium->{rpm_files} || []} or return; + + $medium->{list} ||= "list.$medium->{name}"; + + #- write list file. + $urpm->{log}(N("writing list file for medium \"%s\"", $medium->{name})); + my $listfh = urpm::sys::open_safe($urpm, '>', cachedir_list($urpm, $medium)) or return; + print $listfh basename($_), "\n" foreach @{$medium->{rpm_files}}; + 1; +} + +#- options: callback, force, force_building_hdlist, nomd5sum, probe_with, quiet +#- (from _update_medium__parse_if_unmodified__local and _update_medium__parse_if_unmodified__remote) +sub _update_medium_first_pass { + my ($urpm, $medium, $second_pass, $clean_cache, %options) = @_; + + #- we should create the associated synthesis file if it does not already exist... + file_size(statedir_synthesis($urpm, $medium)) >= 20 + or $medium->{must_build_synthesis} = 1; + + unless ($medium->{modified}) { + #- the medium is not modified, but to compute dependencies, + #- we still need to read it and all synthesis will be written if + #- an unresolved provides is found. + #- to speed up the process, we only read the synthesis at the beginning. + _parse_hdlist_or_synthesis__when_not_modified($urpm, $medium); + return 1; + } + + #- always delete a remaining list file or pubkey file in cache. + foreach (qw(list pubkey)) { + unlink "$urpm->{cachedir}/partial/$_"; + } + + #- check for a reconfig.urpmi file (if not already reconfigured) + if (!$medium->{noreconfigure}) { + may_reconfig_urpmi($urpm, $medium); + } + + { + my $rc = + file_from_local_url($medium->{url}) + ? _update_medium__parse_if_unmodified__local($urpm, $medium, $second_pass, $clean_cache, \%options) + : _update_medium__parse_if_unmodified__remote($urpm, $medium, \%options); + + if (!$rc || $rc eq 'unmodified') { + return $rc; + } + } + + #- build list file according to hdlist. + if (!$medium->{headers} && !$medium->{virtual} && file_size(cachedir_hdlist($urpm, $medium)) < 20) { + $urpm->{error}(N("no hdlist file found for medium \"%s\"", $medium->{name})); + return; + } + + if (!$medium->{virtual}) { + if ($medium->{headers}) { + _write_rpm_list($urpm, $medium) or return; + } else { + #- read first pass hdlist or synthesis, try to open as synthesis, if file + #- is larger than 1MB, this is probably an hdlist else a synthesis. + #- anyway, if one tries fails, try another mode. + $options{callback} and $options{callback}('parse', $medium->{name}); + my @unresolved_before = grep { ! defined $urpm->{provides}{$_} } keys %{$urpm->{provides} || {}}; + + #- if it looks like a hdlist, try to parse as hdlist first + delete $medium->{synthesis} if file_size(cachedir_hdlist($urpm, $medium)) > 262144; + _parse_maybe_hdlist_or_synthesis($urpm, $medium, cachedir_hdlist($urpm, $medium)); + + if (is_valid_medium($medium)) { + $options{callback} && $options{callback}('done', $medium->{name}); + } else { + $urpm->{error}(N("unable to parse hdlist file of \"%s\"", $medium->{name})); + $options{callback} and $options{callback}('failed', $medium->{name}); + delete $medium->{md5sum}; + + #- we have to read back the current synthesis file unmodified. + if (!_parse_synthesis($urpm, $medium, statedir_synthesis($urpm, $medium))) { + $urpm->{error}(N("problem reading synthesis file of medium \"%s\"", $medium->{name})); + $medium->{ignore} = 1; + } + return; + } + delete $medium->{list}; + + { + my @unresolved_after = grep { ! defined $urpm->{provides}{$_} } keys %{$urpm->{provides} || {}}; + @unresolved_before == @unresolved_after or $$second_pass = 1; + } + } + } + + unless ($medium->{virtual}) { + #- make sure to rebuild base files and clear medium modified state. + $medium->{modified} = 0; + $medium->{really_modified} = 1; + $urpm->{md5sum_modified} = 1; + + #- but use newly created file. + unlink statedir_hdlist($urpm, $medium); + $medium->{synthesis} and unlink statedir_synthesis($urpm, $medium); + $medium->{list} and unlink statedir_list($urpm, $medium); + unless ($medium->{headers}) { + unlink statedir_synthesis($urpm, $medium); + unlink statedir_hdlist($urpm, $medium); + urpm::util::move(cachedir_hdlist($urpm, $medium), + statedir_hdlist_or_synthesis($urpm, $medium)); + } + if ($medium->{list}) { + urpm::util::move(cachedir_list($urpm, $medium), statedir_list($urpm, $medium)); + } + + #- and create synthesis file associated. + $medium->{must_build_synthesis} = !$medium->{synthesis}; + } + 1; +} + +sub _update_medium_first_pass_failed { + my ($urpm, $medium) = @_; + + !$medium->{virtual} or return; + + #- an error has occured for updating the medium, we have to remove temporary files. + unlink(glob("$urpm->{cachedir}/partial/*")); +} + +#- take care of modified medium only, or all if all have to be recomputed. +sub _update_medium_second_pass { + my ($urpm, $medium, $callback) = @_; + + $callback and $callback->('parse', $medium->{name}); + + #- a modified medium is an invalid medium, we have to read back the previous hdlist + #- or synthesis which has not been modified by first pass above. + + if ($medium->{headers} && !$medium->{modified}) { + $urpm->{log}(N("reading headers from medium \"%s\"", $medium->{name})); + ($medium->{start}, $medium->{end}) = $urpm->parse_headers(dir => "$urpm->{cachedir}/headers", + headers => $medium->{headers}, + ); + } elsif ($medium->{synthesis}) { + if ($medium->{virtual}) { + if (file_from_file_url($medium->{url})) { + _parse_synthesis($urpm, $medium, hdlist_or_synthesis_for_virtual_medium($medium)); + } + } else { + _parse_synthesis($urpm, $medium, statedir_synthesis($urpm, $medium)); + } + } else { + _parse_hdlist($urpm, $medium, statedir_hdlist($urpm, $medium)); + $medium->{must_build_synthesis} ||= 1; + } + + $callback && $callback->('done', $medium->{name}); +} + +sub _build_hdlist_synthesis { + my ($urpm, $medium) = @_; + + if ($medium->{headers} && !$medium->{modified}) { + _build_hdlist_using_rpm_headers($urpm, $medium); + #- synthesis needs to be created, since the medium has been built from rpm files. + _build_synthesis($urpm, $medium); + } elsif ($medium->{synthesis}) { + } else { + #- check if the synthesis file can be built. + if ($medium->{must_build_synthesis} && !$medium->{modified} && !$medium->{virtual}) { + _build_synthesis($urpm, $medium); + } + } +} + +sub _update_media__handle_some_flags { + my ($urpm, $forcekey, $all) = @_; + + foreach my $medium (grep { !$_->{ignore} } @{$urpm->{media}}) { + $forcekey and delete $medium->{'key-ids'}; + + if ($medium->{static}) { + #- don't ever update static media + $medium->{modified} = 0; + } elsif ($all) { + #- if we're rebuilding all media, mark them as modified (except removable ones) + $medium->{modified} ||= $medium->{url} !~ m!^removable!; + } + } +} + +#- Update the urpmi database w.r.t. the current configuration. +#- Takes care of modifications, and tries some tricks to bypass +#- the recomputation of base files. +#- Recognized options : +#- all : all medias are being rebuilt +#- callback : UI callback +#- forcekey : force retrieval of pubkey +#- force : try to force rebuilding base files +#- force_building_hdlist +#- noclean : keep old files in the header cache directory +#- nolock : don't lock the urpmi database +#- nomd5sum : don't verify MD5SUM of retrieved files +#- nopubkey : don't use rpm pubkeys +#- probe_with : probe synthesis or hdlist (or none) +#- quiet : download hdlists quietly +sub update_media { + my ($urpm, %options) = @_; + + $urpm->{media} or return; # verify that configuration has been read + + $options{nopubkey} ||= $urpm->{options}{nopubkey}; + #- get gpg-pubkey signature. + if (!$options{nopubkey}) { + urpm::sys::lock_rpm_db($urpm, 'exclusive'); + $urpm->{keys} or $urpm->parse_pubkeys(root => $urpm->{root}); + } + #- lock database if allowed. + urpm::sys::lock_urpmi_db($urpm, 'exclusive') if !$options{nolock}; + + #- examine each medium to see if one of them needs to be updated. + #- if this is the case and if not forced, try to use a pre-calculated + #- hdlist file, else build it from rpm files. + clean($urpm); + + _update_media__handle_some_flags($urpm, $options{forcekey}, $options{all}); + + my $clean_cache = !$options{noclean}; + my $second_pass; + foreach my $medium (grep { !$_->{ignore} } @{$urpm->{media}}) { + _update_medium_first_pass($urpm, $medium, \$second_pass, \$clean_cache, %options) + or _update_medium_first_pass_failed($urpm, $medium); + } + + #- some unresolved provides may force to rebuild all synthesis, + #- a second pass will be necessary. + if ($second_pass) { + $urpm->{log}(N("performing second pass to compute dependencies\n")); + $urpm->unresolved_provides_clean; + } + + foreach my $medium (grep { !$_->{ignore} } @{$urpm->{media}}) { + if ($second_pass) { + #- second pass consists in reading again synthesis or hdlists. + _update_medium_second_pass($urpm, $medium, $options{callback}); + } + _build_hdlist_synthesis($urpm, $medium); + + if ($medium->{really_modified}) { + _get_pubkey_and_descriptions($urpm, $medium, $options{nopubkey}); + _read_cachedir_pubkey($urpm, $medium); + generate_medium_names($urpm, $medium); + } + } + + if ($urpm->{modified}) { + if ($options{noclean}) { + #- clean headers cache directory to remove everything that is no longer + #- useful according to the depslist. + urpm::remove_obsolete_headers_in_cache($urpm); + } + #- write config files in any case + write_config($urpm); + urpm::download::dump_proxy_config(); + } elsif ($urpm->{md5sum_modified}) { + #- NB: in case of $urpm->{modified}, write_MD5SUM is called in write_config above + write_MD5SUM($urpm); + } + + $options{nolock} or urpm::sys::unlock_urpmi_db($urpm); + $options{nopubkey} or urpm::sys::unlock_rpm_db($urpm); +} + +#- clean params and depslist computation zone. +sub clean { + my ($urpm) = @_; + + $urpm->{depslist} = []; + $urpm->{provides} = {}; + + foreach (@{$urpm->{media} || []}) { + delete $_->{start}; + delete $_->{end}; + } +} + + +#- get the list of packages that should not be upgraded or installed, +#- typically from the inst.list or skip.list files. +sub get_packages_list { + my ($file, $o_extra) = @_; + my $val = []; + open(my $f, '<', $file) or return []; + foreach (<$f>, split /,/, $o_extra || '') { + chomp; s/#.*$//; s/^\s*//; s/\s*$//; + next if $_ eq ''; + push @$val, $_; + } + $val; +} + +1; diff --git a/urpm/parallel.pm b/urpm/parallel.pm index 2e0fc70a..fc8f6020 100644 --- a/urpm/parallel.pm +++ b/urpm/parallel.pm @@ -46,8 +46,8 @@ sub resolve_dependencies { my $file = "$urpm->{cachedir}/partial/parallel.cz"; unlink $file; foreach (@{$urpm->{media}}) { - urpm::is_valid_medium($_) or next; - my $f = urpm::statedir_synthesis($urpm, $_); + urpm::media::is_valid_medium($_) or next; + my $f = urpm::media::statedir_synthesis($urpm, $_); system "cat '$f' >> '$file'"; } #- let each node determine what is requested, according to handler given. diff --git a/urpme b/urpme index 6cd94f03..9658f2a4 100644 --- a/urpme +++ b/urpme @@ -24,6 +24,7 @@ use urpm; use urpm::args; use urpm::msg; use urpm::install; +use urpm::media; $ENV{PATH} = "/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin"; delete @ENV{qw(ENV BASH_ENV IFS CDPATH)}; @@ -79,7 +80,7 @@ unless ($test) { } #- just configure parallel mode if available. -$urpm->configure( +urpm::media::configure($urpm, synthesis => ($parallel ? 'none' : ''), root => $root, parallel => $parallel, diff --git a/urpmf b/urpmf index 8b42bc4c..2ca63804 100755 --- a/urpmf +++ b/urpmf @@ -23,6 +23,7 @@ use strict; use urpm; use urpm::args; use urpm::msg; +use urpm::media; sub usage() { print N("urpmf version %s @@ -207,7 +208,7 @@ my $need_hdlist = grep { $usedtags{$_} } qw( url vendor ); -$urpm->configure( +urpm::media::configure($urpm, nocheck_access => 1, no_skiplist => 1, media => $media, diff --git a/urpmi b/urpmi index f966401f..01da1045 100755 --- a/urpmi +++ b/urpmi @@ -24,6 +24,7 @@ use urpm; use urpm::args; use urpm::msg; use urpm::install; +use urpm::media; use urpm::util qw(untaint difference2 member); #- contains informations to parse installed system. @@ -359,8 +360,8 @@ if ($auto_update && !$bug && !$env) { #- FIXME we need to configure it twice; otherwise #- some settings are lost (like the skiplist) for #- some reason. - $urpm->configure(%config_hash); - $urpm->update_media( + urpm::media::configure($urpm, %config_hash); + urpm::media::update_media($urpm, all => 1, callback => \&urpm::download::sync_logger, noclean => $noclean, @@ -373,7 +374,7 @@ if ($auto_update && !$bug && !$env) { } } -$urpm->configure(%config_hash); +urpm::media::configure($urpm, %config_hash); if ($bug) { require urpm::bug_report; diff --git a/urpmi.addmedia b/urpmi.addmedia index 3db52574..04b6fe71 100755 --- a/urpmi.addmedia +++ b/urpmi.addmedia @@ -25,6 +25,7 @@ use urpm::args; use urpm::msg; use urpm::download (); use urpm::cfg; +use urpm::media; sub usage { my $m = shift; @@ -83,8 +84,8 @@ sub remove_failed { if (@media) { print STDERR join("\n", map { N("unable to update medium \"%s\"\n", $_->{name}) } @media); local $urpm->{log} = sub {}; - $urpm->remove_selected_media; - $urpm->update_media(%options, callback => $sync_logger); + urpm::media::remove_selected_media($urpm); + urpm::media::update_media($urpm, %options, callback => $sync_logger); exit(1); } } @@ -122,7 +123,7 @@ if (!-e $urpm->{config}) { $urpm->{error}(N("Will create config file [%s]", $urpm->{config})); open my $_f, '>', $urpm->{config} or $urpm->{fatal}(6, N("Can't create config file [%s]", $urpm->{config})); } -$urpm->read_config; +urpm::media::read_config($urpm); if ($options{distrib}) { $with || $relative_hdlist @@ -143,7 +144,7 @@ if ($options{distrib}) { 1; } : undef; - $urpm->add_distrib_media( + urpm::media::add_distrib_media($urpm, $name, $url, virtual => $options{virtual}, @@ -156,7 +157,7 @@ if ($options{distrib}) { remove_failed($urpm, grep { $_->{modified} } @{$urpm->{media}}); exit(1); }; - $urpm->update_media(%options, callback => $sync_logger); + urpm::media::update_media($urpm, %options, callback => $sync_logger); remove_failed($urpm, grep { $_->{modified} } @{$urpm->{media}}); } else { @@ -168,7 +169,7 @@ if ($options{distrib}) { $options{probe_with} or usage N("`with' missing for network media\n"); } - $urpm->add_medium( + urpm::media::add_medium($urpm, $name, $url, $relative_hdlist, virtual => $options{virtual}, update => $options{update}, @@ -177,16 +178,16 @@ if ($options{distrib}) { ); urpm::download::copy_cmd_line_proxy($name); if ($options{raw}) { - $urpm->write_config; + urpm::media::write_config($urpm); } else { local $SIG{INT} = sub { - my $medium = urpm::name2medium($urpm, $name); + my $medium = urpm::media::name2medium($urpm, $name); remove_failed($urpm, $medium) if $medium && $medium->{modified}; exit(1); }; - $urpm->update_media(%options, callback => $sync_logger); + urpm::media::update_media($urpm, %options, callback => $sync_logger); #- check creation of media - my $medium = urpm::name2medium($urpm, $name) or die N("unable to create medium \"%s\"\n", $name); + my $medium = urpm::media::name2medium($urpm, $name) or die N("unable to create medium \"%s\"\n", $name); remove_failed($urpm, $medium) if $medium->{modified}; } } diff --git a/urpmi.removemedia b/urpmi.removemedia index dfc7ea3f..25e43ab6 100755 --- a/urpmi.removemedia +++ b/urpmi.removemedia @@ -25,6 +25,7 @@ use strict; use urpm; use urpm::msg; use urpm::download; +use urpm::media; $ENV{PATH} = "/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin"; delete @ENV{qw(ENV BASH_ENV IFS CDPATH)}; @@ -72,7 +73,7 @@ if ($< != 0) { $options{verbose} > 0 or $urpm->{log} = sub {}; -$urpm->read_config; +urpm::media::read_config($urpm); urpm::download::set_cmdline_proxy(); my @entries = map { $_->{name} } @{$urpm->{media}}; @@ -82,15 +83,15 @@ if ($options{all}) { @toremove or die N("the entry to remove is missing\n(one of %s)\n", join(", ", @entries)); } -my @selected = $urpm->select_media_by_name(\@toremove, $options{strict_match}) +my @selected = urpm::media::select_media_by_name($urpm, \@toremove, $options{strict_match}) or exit 1; -$urpm->remove_media(\@selected); +urpm::media::remove_media($urpm, \@selected); if ($options{noclean}) { #- FIXME: AFAIK it is broken because function below use {depslist} which we don't clean here urpm::remove_obsolete_headers_in_cache($urpm); } -$urpm->write_urpmi_cfg; +urpm::media::write_urpmi_cfg($urpm); exit(0); diff --git a/urpmi.update b/urpmi.update index 6abca159..0ed9d6c4 100755 --- a/urpmi.update +++ b/urpmi.update @@ -24,6 +24,7 @@ use urpm; use urpm::args; use urpm::msg; use urpm::download (); +use urpm::media; sub usage() { print N("usage: urpmi.update [options] ... @@ -40,7 +41,6 @@ where is a medium name to update. ") . N(" --update - update only update media. ") . N(" --no-md5sum - disable MD5SUM file checking. ") . N(" --force-key - force update of gpg key. -") . N(" --norebuild - don't try to rebuild hdlist if not readable. ") . N(" --ignore - don't update, mark the media as ignored. ") . N(" --no-ignore - don't update, mark the media as enabled. ") . N(" -a - select all non-removable media. @@ -68,8 +68,7 @@ $options{verbose} > 0 or $urpm->{log} = sub {}; if ($< != 0) { $urpm->{fatal}(1, N("Only superuser is allowed to update media")); } -$urpm->read_config; -exists $options{limit_rate} or $options{limit_rate} = $urpm->{options}{'limit-rate'}; +urpm::media::read_config($urpm); my @entries = map { $_->{name} } @{$urpm->{media}}; @@ -77,7 +76,7 @@ if ($options{all} && !defined $options{ignore}) { @entries == 0 and die N("nothing to update (use urpmi.addmedia to add a media)\n"); } else { if ($options{all}) { @toupdates = '' } #- select all - $urpm->select_media(@toupdates); + urpm::media::select_media($urpm, @toupdates); my $something_todo = 0; foreach (@{$urpm->{media}}) { $options{update} && $_->{update} and $_->{modified} = 1; @@ -98,9 +97,9 @@ if ($options{all} && !defined $options{ignore}) { if (defined $options{ignore}) { my $str = join(", ", map { N("\"%s\"", $_->{name}) } grep { $_->{modified} } @{$urpm->{media}}); $urpm->{log}($options{ignore} ? N("ignoring media %s", $str) : N("enabling media %s", $str)); - $urpm->write_config; + urpm::media::write_config($urpm); } else { - $urpm->update_media(%options, callback => \&urpm::download::sync_logger); + urpm::media::update_media($urpm, %options, callback => \&urpm::download::sync_logger); #- try to umount removable device which may have been mounted. $urpm->try_umounting_removables; } diff --git a/urpmq b/urpmq index 1fc76dc9..d63ab0e1 100755 --- a/urpmq +++ b/urpmq @@ -27,6 +27,7 @@ use urpm; use urpm::args; use urpm::msg; use urpm::sys; +use urpm::media; #- default options. $urpm::args::options = { use_provides => 1 }; @@ -138,7 +139,7 @@ if ($urpm::args::options{ignorearch}) { urpm::shunt_ignorearch() } $urpm::args::options{upgrade} && !$urpm::args::options{env} && !$urpm::args::options{nolock} and urpm::sys::lock_rpm_db($urpm); urpm::sys::lock_urpmi_db($urpm) if !$urpm::args::options{nolock}; -$urpm->configure( +urpm::media::configure($urpm, nocheck_access => 1, nodepslist => $urpm::args::options{nodepslist}, media => $urpm::args::options{media}, @@ -331,8 +332,8 @@ if ($urpm::args::options{list_aliases}) { { my %h = map { $_ => 1 } @headers; @headers = keys %h; my $hdlist_path = $medium->{virtual} - ? urpm::hdlist_or_synthesis_for_virtual_medium($medium) - : urpm::statedir_hdlist($urpm, $medium); + ? urpm::media::hdlist_or_synthesis_for_virtual_medium($medium) + : urpm::media::statedir_hdlist($urpm, $medium); if (-s $hdlist_path) { require MDV::Packdrakeng; my $packer = MDV::Packdrakeng->open(archive => $hdlist_path, quiet => 1); -- cgit v1.2.1