/[soft]/rpm/urpmi/trunk/urpm/get_pkgs.pm
ViewVC logotype

Contents of /rpm/urpmi/trunk/urpm/get_pkgs.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3849 - (show annotations) (download)
Mon Mar 26 20:20:33 2012 UTC (12 years, 1 month ago) by tv
File size: 9106 byte(s)
(selected2local_and_blists) prevent having duplicate packages in blists

(thus fixing downloading twice noarch packages on x86_64 with
--download-all (mga#4867))
1 package urpm::get_pkgs;
2
3 # $Id: get_pkgs.pm 267986 2010-04-28 10:10:27Z cfergeau $
4
5 use strict;
6 use urpm::msg;
7 use urpm::sys;
8 use urpm::util;
9 use urpm::media;
10 use urpm 'file_from_local_url';
11 # perl_checker: require urpm::select
12
13 sub clean_all_cache {
14 my ($urpm) = @_;
15 #- clean download directory, do it here even if this is not the best moment.
16 $urpm->{log}(N("cleaning %s and %s", "$urpm->{cachedir}/partial", "$urpm->{cachedir}/rpms"));
17 urpm::sys::empty_dir("$urpm->{cachedir}/partial");
18 urpm::sys::empty_dir("$urpm->{cachedir}/rpms");
19 }
20
21 sub cachedir_rpms {
22 my ($urpm) = @_;
23
24 #- examine the local repository, which is trusted (no gpg or pgp signature check but md5 is now done).
25 my %fn2file;
26 foreach my $filepath (glob("$urpm->{cachedir}/rpms/*")) {
27 next if -d $filepath;
28
29 if (! -s $filepath) {
30 unlink $filepath; #- this file should be removed or is already empty.
31 } else {
32 my $filename = basename($filepath);
33 my ($fullname) = $filename =~ /(.*)\.rpm$/ or next;
34 $fn2file{$fullname} = $filepath;
35 }
36 }
37 \%fn2file;
38 }
39
40 #- select sources for selected packages,
41 #- according to keys of the packages hash.
42 #- returns a list of lists containing the source description for each rpm,
43 #- matching the exact number of registered media; ignored media being
44 #- associated to a null list.
45 sub _selected2local_and_ids {
46 my ($urpm, $packages, %options) = @_;
47 my (%protected_files, %local_sources, %fullname2id);
48
49 #- build association hash to retrieve id and examine all list files.
50 foreach (keys %$packages) {
51 foreach my $id (split /\|/, $_) {
52 if ($urpm->{source}{$_}) {
53 my $file = $local_sources{$id} = $urpm->{source}{$id};
54 $protected_files{$file} = undef;
55 } else {
56 $fullname2id{$urpm->{depslist}[$id]->fullname} = $id;
57 }
58 }
59 }
60
61 #- examine the local repository, which is trusted (no gpg or pgp signature check but md5 is now done).
62 my $cachedir_rpms = cachedir_rpms($urpm);
63
64 foreach my $fullname (keys %$cachedir_rpms) {
65 my $filepath = $cachedir_rpms->{$fullname};
66
67 if (my $id = delete $fullname2id{$fullname}) {
68 $local_sources{$id} = $filepath;
69 } else {
70 $options{clean_other} && ! exists $protected_files{$filepath} and unlink $filepath;
71 }
72 }
73
74 my %id2ids;
75 foreach my $id (values %fullname2id) {
76 my $pkg = $urpm->{depslist}[$id];
77 my $fullname = $pkg->fullname;
78 my @pkg_ids = $pkg->arch eq 'src' ? do {
79 # packages_by_name can't be used here since $urpm->{provides} doesn't have src.rpm
80 # so a full search is needed
81 my %requested;
82 urpm::select::search_packages($urpm, \%requested, [$pkg->name], src => 1);
83 map { split /\|/ } keys %requested;
84 } : do {
85 map { $_->id } grep {
86 $_->filename !~ /\.delta\.rpm$/ || $urpm->is_delta_installable($_, $urpm->{root});
87 } grep { $fullname eq $_->fullname } $urpm->packages_by_name($pkg->name);
88 };
89
90 $id2ids{$id} = \@pkg_ids;
91 }
92
93 (\%local_sources, \%id2ids);
94 }
95
96 sub selected2local_and_blists {
97 my ($urpm, $selected, %options) = @_;
98
99 my ($local_sources, $id2ids) = _selected2local_and_ids($urpm, $selected, %options);
100
101 # id_map is a remapping of id.
102 # it is needed because @list must be [ { id => pkg } ] where id is one the selected id,
103 # not really the real package id
104 my %id_map;
105 foreach my $id (keys %$id2ids) {
106 $id_map{$_} = $id foreach @{$id2ids->{$id}};
107 }
108
109 my @remaining_ids = sort { $a <=> $b } keys %id_map;
110
111 my %blists;
112 my @blists = map {
113 my $medium = $_;
114 my %pkgs;
115 if (urpm::media::is_valid_medium($medium) && !$medium->{ignore}) {
116 while (@remaining_ids) {
117 my $id = $remaining_ids[0];
118 $medium->{start} <= $id && $id <= $medium->{end} or last;
119 shift @remaining_ids;
120
121 my $maped_id = $id_map{$id};
122 # no duplicate package (especially noarch ones, eg from 32 & 64 bit media):
123 next if $blists{$maped_id};
124 $blists{$maped_id} = 1;
125 my $pkg = $urpm->{depslist}[$id];
126 $pkgs{$maped_id} = $pkg;
127 }
128 }
129 %pkgs ? { medium => $medium, pkgs => \%pkgs } : ();
130 } (@{$urpm->{media} || []});
131
132 if (@remaining_ids) {
133 $urpm->{error}(N("package %s is not found.", $urpm->{depslist}[$_]->fullname)) foreach @remaining_ids;
134 return;
135 }
136
137 ($local_sources, \@blists);
138 }
139
140 #- side-effects: none
141 sub _create_old_list_from_blists {
142 my ($media, $blists) = @_;
143
144 [ map {
145 my $medium = $_;
146 my ($blist) = grep { $_->{medium} == $medium } @$blists;
147
148 { map { $_ => urpm::blist_pkg_to_url($blist, $blist->{pkgs}{$_}) } keys %{$blist->{pkgs}} }
149 } @$media ];
150 }
151
152 # deprecated, use selected2local_and_blists() instead
153 sub selected2list {
154 my ($urpm, $selected, %options) = @_;
155
156 my ($local_sources, $blists) = selected2local_and_blists($urpm, $selected, %options);
157 ($local_sources, _create_old_list_from_blists($urpm->{media}, $blists));
158 }
159
160 sub verify_partial_rpm_and_move {
161 my ($urpm, $cachedir, $filename) = @_;
162
163 URPM::verify_rpm("$cachedir/partial/$filename", nosignatures => 1) or do {
164 unlink "$cachedir/partial/$filename";
165 return;
166 };
167 #- it seems the the file has been downloaded correctly and has been checked to be valid.
168 unlink "$cachedir/rpms/$filename";
169 urpm::sys::move_or_die($urpm, "$cachedir/partial/$filename", "$cachedir/rpms/$filename");
170 "$cachedir/rpms/$filename";
171 }
172
173 # get the filesize of packages to download from remote media.
174 sub get_distant_media_filesize {
175 my (undef, $blists, $sources) = @_;
176
177 my $filesize;
178 #- get back all ftp and http accessible rpm files into the local cache
179 foreach my $blist (@$blists) {
180 #- examine all files to know what can be indexed on multiple media.
181 while (my ($id, $pkg) = each %{$blist->{pkgs}}) {
182 #- the given URL is trusted, so the file can safely be ignored.
183 defined $sources->{$id} and next;
184 if (!urpm::is_local_medium($blist->{medium})) {
185 if (my $n = $pkg->filesize) {
186 $filesize += $n;
187 }
188 }
189 }
190 }
191 $filesize;
192 }
193
194 # download packages listed in $blists,
195 # and put the result in $sources or $error_sources
196 #
197 #- options: quiet, callback,
198 sub download_packages_of_distant_media {
199 my ($urpm, $blists, $sources, $error_sources, %options) = @_;
200
201 my %errors;
202 my %new_sources;
203
204 #- get back all ftp and http accessible rpm files into the local cache
205 foreach my $blist (@$blists) {
206 my %blist_distant = (%$blist, pkgs => {});
207
208 #- examine all files to know what can be indexed on multiple media.
209 while (my ($id, $pkg) = each %{$blist->{pkgs}}) {
210 #- the given URL is trusted, so the file can safely be ignored.
211 if (defined $sources->{$id}) {
212 $new_sources{$id} = [ $pkg->id, $sources->{$id} ];
213 delete $sources->{$id};
214 next;
215 }
216
217 exists $new_sources{$id} and next;
218 if (urpm::is_local_medium($blist->{medium})) {
219 my $local_file = file_from_local_url(urpm::blist_pkg_to_url($blist, $pkg));
220 if (-r $local_file) {
221 $new_sources{$id} = [ $pkg->id, $local_file ];
222 } else {
223 $errors{$id} = [ $local_file, 'missing' ];
224 }
225 } else {
226 $blist_distant{pkgs}{$id} = $pkg;
227 }
228 }
229
230 if (%{$blist_distant{pkgs}}) {
231 my ($remote_sources, $remote_errors) = _download_packages_of_distant_media($urpm, \%blist_distant, %options);
232 put_in_hash(\%new_sources, $remote_sources);
233 put_in_hash(\%errors, $remote_errors);
234 }
235 }
236
237 #- clean failed download which have succeeded.
238 delete @errors{keys %$sources, keys %new_sources};
239
240 foreach (values %new_sources) {
241 my ($id, $local_file) = @$_;
242 $sources->{$id} = $local_file;
243 }
244
245 push @$error_sources, values %errors;
246
247 1;
248 }
249
250 # download packages listed in $blist,
251 # and put the result in $sources or $errors
252 sub _download_packages_of_distant_media {
253 my ($urpm, $blist, %options) = @_;
254
255 my $cachedir = urpm::valid_cachedir($urpm);
256 my (%sources, %errors);
257
258 $urpm->{log}(N("retrieving rpm files from medium \"%s\"...", $blist->{medium}{name}));
259 if (urpm::download::sync_rel($urpm, $blist->{medium}, [ urpm::blist_to_filenames($blist) ],
260 dir => "$cachedir/partial", quiet => $options{quiet},
261 is_versioned => 1,
262 resume => $urpm->{options}{resume},
263 ask_retry => $options{ask_retry},
264 callback => $options{callback})) {
265 $urpm->{log}(N("...retrieving done"));
266 } else {
267 $urpm->{error}(N("...retrieving failed: %s", $@));
268 }
269
270 #- clean files that have not been downloaded, but keep in mind
271 #- there have been problems downloading them at least once, this
272 #- is necessary to keep track of failing downloads in order to
273 #- present the error to the user.
274 foreach my $id (keys %{$blist->{pkgs}}) {
275 my $pkg = $blist->{pkgs}{$id};
276 my $filename = $pkg->filename;
277 my $url = urpm::blist_pkg_to_url($blist, $pkg);
278 if ($filename && -s "$cachedir/partial/$filename") {
279 if (my $rpm = verify_partial_rpm_and_move($urpm, $cachedir, $filename)) {
280 $sources{$id} = [ $pkg->id, $rpm ];
281 } else {
282 $errors{$id} = [ $url, 'bad' ];
283 }
284 } else {
285 $errors{$id} = [ $url, 'missing' ];
286 }
287 }
288 (\%sources, \%errors);
289 }
290
291 1;

  ViewVC Help
Powered by ViewVC 1.1.30