/[soft]/rpmdrake/trunk/Rpmdrake/pkg.pm
ViewVC logotype

Contents of /rpmdrake/trunk/Rpmdrake/pkg.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1948 - (show annotations) (download)
Sat Sep 17 10:32:15 2011 UTC (12 years, 7 months ago) by tv
File size: 40456 byte(s)
(perform_installation,perform_removal) better message for orphans (#902)
(needs urpmi > 6.40)
1 package Rpmdrake::pkg;
2 #*****************************************************************************
3 #
4 # Copyright (c) 2002 Guillaume Cottenceau
5 # Copyright (c) 2002-2007 Thierry Vignaud <tvignaud@mandriva.com>
6 # Copyright (c) 2003, 2004, 2005 MandrakeSoft SA
7 # Copyright (c) 2005-2007 Mandriva SA
8 #
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License version 2, as
11 # published by the Free Software Foundation.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 #
22 #*****************************************************************************
23 #
24 # $Id: pkg.pm 270160 2010-06-22 19:55:40Z jvictor $
25
26 use strict;
27 use MDK::Common::Func 'any';
28 use lib qw(/usr/lib/libDrakX);
29 use common;
30 use POSIX qw(_exit);
31 use URPM;
32 use utf8;
33 use Rpmdrake::open_db;
34 use Rpmdrake::gurpm;
35 use Rpmdrake::formatting;
36 use Rpmdrake::rpmnew;
37
38 use rpmdrake;
39 use urpm;
40 use urpm::lock;
41 use urpm::install;
42 use urpm::signature;
43 use urpm::get_pkgs;
44 use urpm::select;
45 use urpm::main_loop;
46 use urpm::args qw();
47
48
49 use Exporter;
50 our @ISA = qw(Exporter);
51 our @EXPORT = qw(
52 $priority_up_alread_warned
53 download_callback
54 extract_header
55 find_installed_version
56 get_pkgs
57 perform_installation
58 perform_removal
59 run_rpm);
60
61 use mygtk2 qw(gtknew);
62 use ugtk2 qw(:all);
63
64 our $priority_up_alread_warned;
65
66
67 sub run_rpm {
68 foreach (qw(LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT LC_IDENTIFICATION LC_ALL)) {
69 local $ENV{$_} = $ENV{$_} . '.UTF-8' if $ENV{$_} && $ENV{$_} !~ /UTF-8/;
70 }
71 my @l = map { ensure_utf8($_) } run_program::get_stdout(@_);
72 wantarray() ? @l : join('', @l);
73 }
74
75
76 sub extract_header {
77 my ($pkg, $urpm, $xml_info, $o_installed_version) = @_;
78 my %fields = (
79 info => 'description',
80 files => 'files',
81 changelog => 'changelog',
82 );
83 # already extracted:
84 return if $pkg->{$fields{$xml_info}};
85
86 my $p = $pkg->{pkg};
87
88 if (!$p) {
89 warn ">> ghost package '$pkg' has no URPM object!!!\n";
90 return;
91 }
92
93 my $name = urpm_name($p);
94 # fix extracting info for SRPMS and RPM GPG keys:
95 $name =~ s!\.src!!;
96
97 if ($p->flag_installed && !$p->flag_upgrade) {
98 my @files = map { chomp_($_) } run_rpm("rpm -ql $name");
99 add2hash($pkg, { files => [ @files ? @files : N("(none)") ],
100 description => rpm_description(scalar(run_rpm("rpm -q --qf '%{description}' $name"))),
101 changelog => format_changelog_string($o_installed_version, scalar(run_rpm("rpm -q --changelog $name"))) });
102 } else {
103 my $medium = pkg2medium($p, $urpm);
104 my ($local_source, %xml_info_pkgs, $bar_id);
105 my $_statusbar_clean_guard = before_leaving { $bar_id and statusbar_msg_remove($bar_id) };
106 my $dir = urpm::file_from_local_url($medium->{url});
107 if ($dir) {
108 $local_source = "$dir/" . $p->filename;
109 }
110 if (-e $local_source) {
111 $bar_id = statusbar_msg(N("Getting information from XML meta-data from %s...", $dir), 0);
112 $urpm->{log}("getting information from rpms from $dir");
113 } else {
114 my $gurpm;
115 $bar_id = statusbar_msg(N("Getting '%s' from XML meta-data...", $xml_info), 0);
116 my $_gurpm_clean_guard = before_leaving { undef $gurpm };
117 if (my $xml_info_file = eval { urpm::media::any_xml_info($urpm, $medium, $xml_info, undef, sub {
118 $gurpm ||= Rpmdrake::gurpm->new(N("Please wait"),
119 '', # FIXME: add a real string after cooker
120 transient => $::main_window);
121 download_callback($gurpm, @_)
122 or goto header_non_available;
123 }) }) {
124 require urpm::xml_info;
125 require urpm::xml_info_pkg;
126 $urpm->{log}("getting information from $xml_info_file");
127 my %nodes = eval { urpm::xml_info::get_nodes($xml_info, $xml_info_file, [ $name ]) };
128 goto header_non_available if $@;
129 put_in_hash($xml_info_pkgs{$name} ||= {}, $nodes{$name});
130 } else {
131 if ($xml_info eq 'info') {
132 $urpm->{info}(N("No xml info for medium \"%s\", only partial result for package %s", $medium->{name}, $name));
133 } else {
134 $urpm->{error}(N("No xml info for medium \"%s\", unable to return any result for package %s", $medium->{name}, $name));
135 }
136 }
137 }
138
139 #- even if non-root, search for a header in the global cachedir
140 my $file = $local_source;
141 if (-s $file) {
142 $p->update_header($file) or do {
143 warn "Warning, could not extract header for $name from $medium!";
144 goto header_non_available;
145 };
146 add2hash($pkg, { description => rpm_description($p->description),
147 files => scalar($p->files) ? [ $p->files ] : [ N("(none)") ],
148 url => $p->url,
149 changelog => format_changelog_changelogs($o_installed_version, $p->changelogs) });
150 $p->pack_header; # needed in order to call methods on objects outside ->traverse
151 } elsif ($xml_info_pkgs{$name}) {
152 if ($xml_info eq 'info') {
153 add2hash($pkg, { description => rpm_description($xml_info_pkgs{$name}{description}),
154 url => $xml_info_pkgs{$name}{url}
155 });
156 } elsif ($xml_info eq 'files') {
157 my @files = map { chomp_(to_utf8($_)) } split("\n", $xml_info_pkgs{$name}{files});
158 add2hash($pkg, { files => [ @files ? @files : N("(none)") ] });
159 } elsif ($xml_info eq 'changelog') {
160 add2hash($pkg, {
161 changelog => format_changelog_changelogs($o_installed_version,
162 @{$xml_info_pkgs{$name}{changelogs}})
163 });
164 }
165 $p->pack_header; # needed in order to call methods on objects outside ->traverse
166 } else {
167 goto header_non_available;
168 }
169 return;
170 header_non_available:
171 add2hash($pkg, { summary => $p->summary || N("(Not available)"), description => undef });
172 }
173 }
174
175 sub find_installed_version {
176 my ($p) = @_;
177 my @version;
178 open_rpm_db()->traverse_tag('name', [ $p->name ], sub { push @version, $_[0]->version . '-' . $_[0]->release });
179 @version ? join(',', sort @version) : N("(none)");
180 }
181
182 my $canceled;
183 sub download_callback {
184 my ($gurpm, $mode, $file, $percent, $total, $eta, $speed) = @_;
185 $canceled = 0;
186 if ($mode eq 'start') {
187 $gurpm->label(N("Downloading package `%s'...", basename($file)));
188 $gurpm->validate_cancel(but(N("Cancel")), sub { $canceled = 1 });
189 } elsif ($mode eq 'progress') {
190 $gurpm->label(
191 join("\n",
192 N("Downloading package `%s'...", basename($file)),
193 (defined $total && defined $eta ?
194 N(" %s%% of %s completed, ETA = %s, speed = %s", $percent, $total, $eta, $speed)
195 : N(" %s%% completed, speed = %s", $percent, $speed)
196 ) =~ /^\s*(.*)/
197 ),
198 );
199 $gurpm->progress($percent/100);
200 } elsif ($mode eq 'end') {
201 $gurpm->progress(1);
202 $gurpm->invalidate_cancel;
203 }
204 !$canceled;
205 }
206
207
208 # -=-=-=---=-=-=---=-=-=-- install packages -=-=-=---=-=-=---=-=-=-
209
210 my (@update_medias, $is_update_media_already_asked);
211
212 sub warn_about_media {
213 my ($w, $opts) = @_;
214
215 return if $::MODE ne 'update';
216 return if $::rpmdrake_options{'no-media-update'};
217
218 # we use our own instance of the urpmi db in order not to mess up with skip-list managment (#31092):
219 # and no need to fully configure urpmi since we may have to do it again anyway because of new media:
220 my $urpm = fast_open_urpmi_db();
221
222 my $_lock = urpm::lock::urpmi_db($urpm, undef, wait => $urpm->{options}{wait_lock});
223
224 # build media list:
225 @update_medias = get_update_medias($urpm);
226
227 # do not update again media after installing/removing some packages:
228 $::rpmdrake_options{'no-media-update'} ||= 1;
229
230 if (@update_medias > 0) {
231 if (!$opts->{skip_updating_mu} && !$is_update_media_already_asked) {
232 $is_update_media_already_asked = 1;
233 $::rpmdrake_options{'no-confirmation'} or interactive_msg(N("Confirmation"),
234 N("I need to contact the mirror to get latest update packages.
235 Please check that your network is currently running.
236
237 Is it ok to continue?"), yesno => 1,
238 widget => gtknew('CheckButton', text => N("Do not ask me next time"),
239 active_ref => \$::rpmdrake_options{'no-confirmation'}
240 )) or myexit(-1);
241 writeconf();
242 urpm::media::select_media($urpm, map { $_->{name} } @update_medias);
243 update_sources($urpm, noclean => 1, medialist => [ map { $_->{name} } @update_medias ]);
244 }
245 } else {
246 if (any { $_->{update} } @{$urpm->{media}}) {
247 interactive_msg(N("Already existing update media"),
248 N("You already have at least one update medium configured, but
249 all of them are currently disabled. You should run the Software
250 Media Manager to enable at least one (check it in the \"%s\"
251 column).
252
253 Then, restart \"%s\".", N("Enabled"), $rpmdrake::myname_update));
254 myexit(-1);
255 }
256 my ($mirror) = choose_mirror($urpm, transient => $w->{real_window} || $::main_window,
257 message => join("\n\n",
258 N("You have no configured update media. MageiaUpdate cannot operate without any update media."),
259 N("I need to contact the Mageia website to get the mirror list.
260 Please check that your network is currently running.
261
262 Is it ok to continue?"),
263 ),
264 );
265 my $m = ref($mirror) ? $mirror->{url} : '';
266 $m or interactive_msg(N("How to choose manually your mirror"),
267 N("You may also choose your desired mirror manually: to do so,
268 launch the Software Media Manager, and then add a `Security
269 updates' medium.
270
271 Then, restart %s.", $rpmdrake::myname_update)), myexit(-1);
272 add_distrib_update_media($urpm, $mirror, only_updates => 1);
273 }
274 }
275
276
277 sub get_parallel_group() {
278 $::rpmdrake_options{parallel} ? $::rpmdrake_options{parallel}[0] : undef;
279 }
280
281 my ($count, $level, $limit, $new_stage, $prev_stage, $total);
282
283 sub init_progress_bar {
284 my ($urpm) = @_;
285 undef $_ foreach $count, $prev_stage, $new_stage, $limit;
286 $level = 0.05;
287 $total = @{$urpm->{depslist}};
288 }
289
290 sub reset_pbar_count {
291 undef $prev_stage;
292 $count = 0;
293 $limit = $_[0];
294 }
295
296 sub update_pbar {
297 my ($gurpm) = @_;
298 return if !$total; # don't die if there's no source
299 $count++;
300 $new_stage = $level+($limit-$level)*$count/$total;
301 if ($prev_stage + 0.01 < $new_stage) {
302 $prev_stage = $new_stage;
303 $gurpm->progress($new_stage);
304 }
305 }
306
307
308 sub get_installed_packages {
309 my ($urpm, $db, $all_pkgs, $gurpm) = @_;
310
311 my @base = ("basesystem", split /,\s*/, $urpm->{global_config}{'prohibit-remove'});
312 my (%base, %basepackages, @installed_pkgs, @processed_base);
313 reset_pbar_count(0.33);
314 while (defined(local $_ = shift @base)) {
315 exists $basepackages{$_} and next;
316 $db->traverse_tag(m|^/| ? 'path' : 'whatprovides', [ $_ ], sub {
317 update_pbar($gurpm);
318 my $name = urpm_name($_[0]);
319 # workaround looping in URPM:
320 return if member($name, @processed_base);
321 push @processed_base, $name;
322 push @{$basepackages{$_}}, $name;
323 push @base, $_[0]->requires_nosense;
324 });
325 }
326 foreach (values %basepackages) {
327 my $n = @$_; #- count number of times it's provided
328 foreach (@$_) {
329 $base{$_} = \$n;
330 }
331 }
332 # costly:
333 $db->traverse(sub {
334 my ($pkg) = @_;
335 update_pbar($gurpm);
336 my $fullname = urpm_name($pkg);
337 return if $fullname =~ /@/;
338 $all_pkgs->{$fullname} = {
339 selected => 0, pkg => $pkg, urpm_name => urpm_name($pkg),
340 } if !($all_pkgs->{$fullname} && $all_pkgs->{$fullname}{description});
341 if (my $name = $base{$fullname}) {
342 $all_pkgs->{$fullname}{base} = \$name;
343 $pkg->set_flag_base(1) if $$name == 1;
344 }
345 push @installed_pkgs, $fullname;
346 $pkg->set_flag_installed;
347 $pkg->pack_header; # needed in order to call methods on objects outside ->traverse
348 });
349 @installed_pkgs;
350 }
351
352 urpm::select::add_packages_to_priority_upgrade_list('rpmdrake');
353
354 my ($priority_state, $priority_requested);
355 our $need_restart;
356
357 our $probe_only_for_updates;
358
359 sub get_updates_list {
360 my ($urpm, $db, $state, $requested, $requested_list, $requested_strict, $all_pkgs) = @_;
361
362 $urpm->request_packages_to_upgrade(
363 $db,
364 $state,
365 $requested,
366 );
367
368 my %common_opts = (
369 callback_choices => \&Rpmdrake::gui::callback_choices,
370 priority_upgrade => $urpm->{options}{'priority-upgrade'},
371 );
372
373 if ($urpm->{options}{'priority-upgrade'}) {
374 $need_restart =
375 urpm::select::resolve_priority_upgrades_after_auto_select($urpm, $db, $state,
376 $requested, %common_opts);
377 }
378
379 # list of updates (including those matching /etc/urpmi/skip.list):
380 @$requested_list = sort map {
381 my $name = urpm_name($_);
382 $all_pkgs->{$name} = { pkg => $_ };
383 $name;
384 } @{$urpm->{depslist}}[keys %$requested];
385
386 # list of pure updates (w/o those matching /etc/urpmi/skip.list but with their deps):
387 if ($probe_only_for_updates && !$need_restart) {
388 @$requested_strict = sort map {
389 urpm_name($_);
390 } $urpm->resolve_requested($db, $state, $requested, callback_choices => \&Rpmdrake::gui::callback_choices);
391
392 if (my @l = grep { $state->{selected}{$_->id} }
393 urpm::select::_priority_upgrade_pkgs($urpm, $urpm->{options}{'priority-upgrade'})) {
394 if (!$need_restart) {
395 $need_restart =
396 urpm::select::_resolve_priority_upgrades($urpm, $db, $state, $state->{selected},
397 \@l, %common_opts);
398 }
399 }
400 }
401
402 if ($need_restart) {
403 $requested_strict = [ map { scalar $_->fullname } @{$urpm->{depslist}}[keys %{$state->{selected}}] ];
404 # drop non priority updates:
405 @$requested_list = ();
406 }
407
408 # list updates including skiped ones + their deps in MageiaUpdate:
409 @$requested_list = uniq(@$requested_list, @$requested_strict);
410
411 # do not pre select updates in rpmdrake:
412 @$requested_strict = () if !$probe_only_for_updates;
413 }
414
415 sub get_pkgs {
416 my ($opts) = @_;
417 my $w = $::main_window;
418
419 my $gurpm = Rpmdrake::gurpm->new(1 ? N("Please wait") : N("Package installation..."), N("Initializing..."), transient => $::main_window);
420 my $_gurpm_clean_guard = before_leaving { undef $gurpm };
421 #my $_flush_guard = Gtk2::GUI_Update_Guard->new;
422
423 warn_about_media($w, $opts);
424
425 my $urpm = open_urpmi_db(update => $probe_only_for_updates && !is_it_a_devel_distro());
426
427 my $_drop_lock = before_leaving { undef $urpm->{lock} };
428
429 $priority_up_alread_warned = 0;
430
431 # update media list in case warn_about_media() added some:
432 @update_medias = get_update_medias($urpm);
433
434 $gurpm->label(N("Reading updates description"));
435 $gurpm->progress(0.05);
436
437 #- parse the description file
438 my $update_descr = urpm::get_updates_description($urpm, @update_medias);
439
440 my $_unused = N("Please wait, finding available packages...");
441
442 # find out installed packages:
443
444 init_progress_bar($urpm);
445
446 $gurpm->label(N("Please wait, listing base packages..."));
447 $gurpm->progress($level);
448
449 my $db = eval { open_rpm_db() };
450 if (my $err = $@) {
451 interactive_msg(N("Error"), N("A fatal error occurred: %s.", $err));
452 return;
453 }
454
455 my $sig_handler = sub { undef $db; exit 3 };
456 local $SIG{INT} = $sig_handler;
457 local $SIG{QUIT} = $sig_handler;
458
459 $gurpm->label(N("Please wait, finding installed packages..."));
460 $gurpm->progress($level = 0.33);
461 reset_pbar_count(0.66);
462 my (@installed_pkgs, %all_pkgs);
463 if (!$probe_only_for_updates) {
464 @installed_pkgs = get_installed_packages($urpm, $db, \%all_pkgs, $gurpm);
465 }
466
467 if (my $group = get_parallel_group()) {
468 urpm::media::configure($urpm, parallel => $group);
469 }
470
471 # find out availlable packages:
472
473 $urpm->{state} = {};
474 my (@installable_pkgs, @updates);
475
476 $gurpm->label(N("Please wait, finding available packages..."));
477 $gurpm->progress($level = 0.66);
478
479 check_update_media_version($urpm, @update_medias);
480
481 my $requested = {};
482 my $state = {};
483 my (@requested, @requested_strict);
484
485 if ($compute_updates->[0] || $::MODE eq 'update') {
486 get_updates_list($urpm, $db, $state, $requested, \@requested, \@requested_strict, \%all_pkgs);
487 }
488
489 $priority_state = $need_restart ? $state : undef;
490 $priority_requested = $need_restart ? $requested : undef;
491
492 if (!$probe_only_for_updates) {
493 $urpm->compute_installed_flags($db); # TODO/FIXME: not for updates
494 $urpm->{depslist}[$_]->set_flag_installed foreach keys %$requested; #- pretend it's installed
495 }
496 $urpm->{rpmdrake_state} = $state; #- Don't forget it
497 $gurpm->progress($level = 0.7);
498
499 reset_pbar_count(1);
500 foreach my $pkg (@{$urpm->{depslist}}) {
501 update_pbar($gurpm);
502 $pkg->flag_upgrade or next;
503 my $name = urpm_name($pkg);
504 push @installable_pkgs, $name;
505 $all_pkgs{$name} = { pkg => $pkg };
506 }
507
508 my @inactive_backports;
509 my @active_backports;
510 my @backport_medias = get_backport_media($urpm);
511
512 foreach my $medium (@backport_medias) {
513 update_pbar($gurpm);
514
515 # The 'searchmedia' flag differentiates inactive backport medias
516 # (because that option was passed to urpm::media::configure to
517 # temporarily enable them)
518
519 my $backports =
520 $medium->{searchmedia} ? \@inactive_backports : \@active_backports;
521
522 foreach my $pkg_id ($medium->{start} .. $medium->{end}) {
523 next if !$pkg_id;
524 my $pkg = $urpm->{depslist}[$pkg_id];
525 $pkg->flag_upgrade or next;
526 my $name = urpm_name($pkg);
527 push @$backports, $name;
528 $all_pkgs{$name} = { pkg => $pkg };
529 }
530 }
531 @updates = @requested;
532 # selecting updates by default but skipped ones (MageiaUpdate only):
533 foreach (@requested_strict) {
534 $all_pkgs{$_}{selected} = 1;
535 }
536
537 # urpmi only care about the first medium where it found the package,
538 # so there's no need to list the same package several time:
539 @installable_pkgs = uniq(difference2(\@installable_pkgs, \@updates));
540
541 my @meta_pkgs = grep { /^task-|^basesystem/ } keys %all_pkgs;
542
543 my @gui_pkgs = map { chomp; $_ } cat_('/usr/share/rpmdrake/gui.lst');
544 # add meta packages to GUI packages list (which expect basic names not fullnames):
545 push @gui_pkgs, map { (split_fullname($_))[0] } @meta_pkgs;
546
547 +{ urpm => $urpm,
548 all_pkgs => \%all_pkgs,
549 installed => \@installed_pkgs,
550 installable => \@installable_pkgs,
551 updates => \@updates,
552 meta_pkgs => \@meta_pkgs,
553 gui_pkgs => [ grep { member(($all_pkgs{$_}{pkg}->fullname)[0], @gui_pkgs) } keys %all_pkgs ],
554 update_descr => $update_descr,
555 backports => [ @inactive_backports, @active_backports ],
556 inactive_backports => \@inactive_backports
557 };
558 }
559
560 sub display_READMEs_if_needed {
561 my ($urpm, $w) = @_;
562 return if !$urpm->{readmes};
563 my %Readmes = %{$urpm->{readmes}};
564 if (keys %Readmes) { #- display the README*.urpmi files
565 interactive_packtable(
566 N("Upgrade information"),
567 $w,
568 N("These packages come with upgrade information"),
569 [ map {
570 my $fullname = $_;
571 [ gtkpack__(
572 gtknew('HBox'),
573 gtkset_selectable(gtknew('Label', text => $Readmes{$fullname}),1),
574 ),
575 gtksignal_connect(
576 gtknew('Button', text => N("Upgrade information about this package")),
577 clicked => sub {
578 interactive_msg(
579 N("Upgrade information about package %s", $Readmes{$fullname}),
580 (join '' => formatAlaTeX(scalar cat_($fullname))),
581 scroll => 1,
582 );
583 },
584 ),
585 ] } keys %Readmes ],
586 [ gtknew('Button', text => N("Ok"), clicked => sub { Gtk2->main_quit }) ]
587 );
588 }
589 }
590
591 sub perform_parallel_install {
592 my ($urpm, $group, $w, $statusbar_msg_id) = @_;
593 my @pkgs = map { if_($_->flag_requested, urpm_name($_)) } @{$urpm->{depslist}};
594
595 my @error_msgs;
596 my $res = !run_program::run('urpmi', '2>', \@error_msgs, '-v', '--X', '--parallel', $group, @pkgs);
597
598 if ($res) {
599 $$statusbar_msg_id = statusbar_msg(
600 #N("Everything installed successfully"),
601 N("All requested packages were installed successfully."),
602 );
603 } else {
604 interactive_msg(
605 N("Problem during installation"),
606 N("There was a problem during the installation:\n\n%s", join("\n", @error_msgs)),
607 scroll => 1,
608 );
609 }
610 open_rpm_db('force_sync');
611 $w->set_sensitive(1);
612 return 0;
613 }
614
615 sub perform_installation { #- (partially) duplicated from /usr/sbin/urpmi :-(
616 my ($urpm, $pkgs) = @_;
617
618 my @error_msgs;
619 my $statusbar_msg_id;
620 my $gurpm;
621 local $urpm->{fatal} = sub {
622 my $fatal_msg = $_[1];
623 printf STDERR "Fatal: %s\n", $fatal_msg;
624 undef $gurpm;
625 interactive_msg(N("Installation failed"),
626 N("There was a problem during the installation:\n\n%s", $fatal_msg));
627 goto return_with_exit_code;
628 };
629 local $urpm->{error} = sub { printf STDERR "Error: %s\n", $_[0]; push @error_msgs, $_[0] };
630
631 my $w = $::main_window;
632 $w->set_sensitive(0);
633 my $_restore_sensitive = before_leaving { $w->set_sensitive(1) };
634
635 my $_flush_guard = Gtk2::GUI_Update_Guard->new;
636
637 if (my $group = get_parallel_group()) {
638 return perform_parallel_install($urpm, $group, $w, \$statusbar_msg_id);
639 }
640
641 my $lock = urpm::lock::urpmi_db($urpm, undef, wait => $urpm->{options}{wait_lock}) if !$::env;
642 my $rpm_lock = urpm::lock::rpm_db($urpm, 'exclusive') if !$::env;
643 my $state = $priority_state || $probe_only_for_updates ? { } : $urpm->{rpmdrake_state};
644
645 my $bar_id = statusbar_msg(N("Checking validity of requested packages..."), 0);
646
647 # FIXME: THIS SET flag_requested on all packages!!!!
648 # select packages to install / enssure selected pkg set is consistant:
649 my %saved_flags;
650 my $requested = { map {
651 $saved_flags{$_->id} = $_->flag_requested;
652 $_->id => undef;
653 } grep { $_->flag_selected } @{$urpm->{depslist}} };
654 urpm::select::resolve_dependencies(
655 $urpm, $state, $requested,
656 rpmdb => $::env && "$::env/rpmdb.cz",
657 callback_choices => \&Rpmdrake::gui::callback_choices,
658 );
659 statusbar_msg_remove($bar_id);
660
661 my ($local_sources, $blist) = urpm::get_pkgs::selected2local_and_blists($urpm,
662 $state->{selected},
663 );
664 if (!$local_sources && (!$blist || !@$blist)) {
665 interactive_msg(
666 N("Unable to get source packages."),
667 N("Unable to get source packages, sorry. %s",
668 @error_msgs ? N("\n\nError(s) reported:\n%s", join("\n", @error_msgs)) : ''),
669 scroll => 1,
670 );
671 goto return_with_exit_code;
672 }
673
674 my @to_install = @{$urpm->{depslist}}[keys %{$state->{selected}}];
675 my @pkgs = map { scalar($_->fullname) } sort(grep { $_->flag_selected } @to_install);
676
677 @{$urpm->{ask_remove}} = sort(urpm::select::removed_packages($urpm, $urpm->{state}));
678 my @to_remove = map { if_($pkgs->{$_}{selected} && !$pkgs->{$_}{pkg}->flag_upgrade, $pkgs->{$_}{urpm_name}) } keys %$pkgs;
679
680 my $r = format_list(map { scalar(urpm::select::translate_why_removed_one($urpm, $urpm->{state}, $_)) } @to_remove);
681
682 my ($size, $filesize) = $urpm->selected_size_filesize($state);
683 my $install_count = int(@pkgs);
684 my $to_install = $install_count == 0 ? '' :
685 ($priority_state ? '<b>' . N("Rpmdrake or one of its priority dependencies needs to be updated first. Rpmdrake will then restart.") . '</b>' . "\n\n" : '') .
686 (P("The following package is going to be installed:", "The following %d packages are going to be installed:", $install_count, $install_count)
687 . "\n\n" . format_list(map { s!.*/!!; $_ } @pkgs));
688 my $remove_count = scalar(@to_remove);
689 interactive_msg(($to_install ? N("Confirmation") : N("Some packages need to be removed")),
690 join("\n\n",
691 ($r ?
692 (!$to_install ? (P("Remove one package?", "Remove %d packages?", $remove_count, $remove_count), $r) :
693 (($remove_count == 1 ?
694 N("The following package has to be removed for others to be upgraded:")
695 : N("The following packages have to be removed for others to be upgraded:")), $r), if_($to_install, $to_install))
696 : $to_install),
697 format_size($size),
698 $filesize ? N("%s of packages will be retrieved.", formatXiB($filesize))
699 : (),
700 N("Is it ok to continue?")),
701 scroll => 1,
702 yesno => 1) or return 1;
703
704 my $_umount_guard = before_leaving { urpm::removable::try_umounting_removables($urpm) };
705
706 # select packages to uninstall for !update mode:
707 perform_removal($urpm, { map { $_ => $pkgs->{$_} } @to_remove }) if !$probe_only_for_updates;
708
709 $gurpm = Rpmdrake::gurpm->new(1 ? N("Please wait") : N("Package installation..."), N("Initializing..."), transient => $::main_window);
710 my $_gurpm_clean_guard = before_leaving { undef $gurpm };
711 my $something_installed;
712
713 if (@to_install && $::rpmdrake_options{auto_orphans}) {
714 urpm::orphans::compute_future_unrequested_orphans($urpm, $state);
715 if (my @orphans = map { scalar $_->fullname } @{$state->{orphans_to_remove}}) {
716 interactive_msg(N("Orphan packages"), P("The following orphan package will be removed.",
717 "The following orphan packages will be removed.", scalar(@orphans))
718 . "\n" . urpm::orphans::add_leading_spaces(join("\n", @orphans) . "\n"), scroll => 1);
719 }
720 }
721
722 urpm::orphans::mark_as_requested($urpm, $state);
723
724 my ($progress, $total, @rpms_upgrade);
725 my $transaction;
726 my ($progress_nb, $transaction_progress_nb, $remaining, $done);
727 my $callback_inst = sub {
728 my ($urpm, $type, $id, $subtype, $amount, $total) = @_;
729 my $pkg = defined $id ? $urpm->{depslist}[$id] : undef;
730 if ($subtype eq 'start') {
731 if ($type eq 'trans') {
732 $gurpm->label(1 ? N("Preparing package installation...") : N("Preparing package installation transaction..."));
733 } elsif (defined $pkg) {
734 $something_installed = 1;
735 $gurpm->label(N("Installing package `%s' (%s/%s)...", $pkg->name, ++$transaction_progress_nb, scalar(@{$transaction->{upgrade}}))
736 . "\n" . N("Total: %s/%s", ++$progress_nb, $install_count));
737 }
738 } elsif ($subtype eq 'progress') {
739 $gurpm->progress($total ? $amount/$total : 1);
740 }
741 };
742
743 # FIXME: sometimes state is lost:
744 my @ask_unselect = urpm::select::unselected_packages($urpm, $state);
745
746 # fix flags for orphan computing:
747 foreach (keys %{$state->{selected}}) {
748 my $pkg = $urpm->{depslist}[$_];
749 $pkg->set_flag_requested($saved_flags{$pkg->id});
750 }
751 my $exit_code =
752 urpm::main_loop::run($urpm, $state, 1, \@ask_unselect, $requested,
753 {
754 completed => sub {
755 # explicitly destroy the progress window when it's over; we may
756 # have sg to display before returning (errors, rpmnew/rpmsave, ...):
757 undef $gurpm;
758
759 undef $lock;
760 undef $rpm_lock;
761 },
762 inst => $callback_inst,
763 trans => $callback_inst,
764 ask_yes_or_no => sub {
765 # handle 'allow-force' and 'allow-nodeps' options:
766 my ($title, $msg) = @_;
767 local $::main_window = $gurpm->{real_window};
768 interactive_msg($title, $msg, yesno => 1, scroll => 1,
769 );
770 },
771 message => sub {
772 my ($title, $message) = @_;
773 interactive_msg($title, $message, scroll => 1);
774 },
775 # cancel installation when 'cancel' button is pressed:
776 trans_log => sub { download_callback($gurpm, @_) or goto return_with_exit_code },
777 post_extract => sub {
778 my ($set, $transaction_sources, $transaction_sources_install) = @_;
779 $transaction = $set;
780 $transaction_progress_nb = 0;
781 $done += grep { !/\.src\.rpm$/ } values %$transaction_sources; #updates
782 $total = keys(%$transaction_sources_install) + keys %$transaction_sources;
783 push @rpms_upgrade, grep { !/\.src\.rpm$/ } values %$transaction_sources;
784 $done += grep { !/\.src\.rpm$/ } values %$transaction_sources_install; # installs
785 },
786 pre_removable => sub {
787 # Gtk2::GUI_Update_Guard->new use of alarm() kill us when
788 # running system(), thus making DVD being ejected and printing
789 # wrong error messages (#30463)
790
791 local $SIG{ALRM} = sub { die "ALARM" };
792 $remaining = alarm(0);
793 },
794
795 post_removable => sub { alarm $remaining },
796 copy_removable => sub {
797 my ($medium) = @_;
798 interactive_msg(
799 N("Change medium"),
800 N("Please insert the medium named \"%s\"", $medium),
801 yesno => 1, text => { no => N("Cancel"), yes => N("Ok") },
802 );
803 },
804 pre_check_sig => sub { $gurpm->label(N("Verifying package signatures...")) },
805 check_sig => sub { $gurpm->progress(++$progress/$total) },
806 bad_signature => sub {
807 my ($msg, $msg2) = @_;
808 local $::main_window = $gurpm->{real_window};
809 $msg =~ s/:$/\n\n/m; # FIXME: to be fixed in urpmi after 2008.0
810 interactive_msg(
811 N("Warning"), "$msg\n\n$msg2", yesno => 1, if_(10 < ($msg =~ tr/\n/\n/), scroll => 1),
812 );
813 },
814 post_download => sub {
815 $canceled and goto return_with_exit_code;
816 $gurpm->invalidate_cancel_forever;
817 },
818 need_restart => sub {
819 my ($need_restart_formatted) = @_;
820 # FIXME: offer to restart the system
821 interactive_msg(N("Warning"), join("\n", values %$need_restart_formatted), scroll => 1);
822 },
823 trans_error_summary => sub {
824 my ($nok, $errors) = @_;
825 interactive_msg(
826 N("Problem during installation"),
827 if_($nok, N("%d installation transactions failed", $nok) . "\n\n") .
828 N("There was a problem during the installation:\n\n%s",
829 join("\n\n", @$errors, @error_msgs)),
830 scroll => 1,
831 );
832 },
833 need_restart => sub {
834 my ($need_restart_formatted) = @_;
835 interactive_msg(N("Warning"),
836 join("\n\n", values %$need_restart_formatted));
837 },
838 success_summary => sub {
839 if (!($done || @to_remove)) {
840 interactive_msg(N("Error"),
841 N("Unrecoverable error: no package found for installation, sorry."));
842 return;
843 }
844 my $id = statusbar_msg(N("Inspecting configuration files..."), 0);
845 my %pkg2rpmnew;
846 foreach my $u (@rpms_upgrade) {
847 $u =~ m|/([^/]+-[^-]+-[^-]+)\.[^\./]+\.rpm$|
848 and $pkg2rpmnew{$1} = [ grep { m|^/etc| && (-r "$_.rpmnew" || -r "$_.rpmsave") }
849 map { chomp_($_) } run_rpm("rpm -ql $1") ];
850 }
851 statusbar_msg_remove($id);
852 dialog_rpmnew(N("The installation is finished; everything was installed correctly.
853
854 Some configuration files were created as `.rpmnew' or `.rpmsave',
855 you may now inspect some in order to take actions:"),
856 %pkg2rpmnew)
857 and statusbar_msg(N("All requested packages were installed successfully."), 1);
858 statusbar_msg(N("Looking for \"README\" files..."), 1);
859 display_READMEs_if_needed($urpm, $w);
860 },
861 already_installed_or_not_installable => sub {
862 my ($msg1, $msg2) = @_;
863 my $msg = join("\n", @$msg1, @$msg2);
864 return if !$msg; # workaround missing state
865 interactive_msg(N("Error"), $msg);
866 },
867 },
868 );
869
870 #- restart rpmdrake if needed, keep command line for that.
871 if ($need_restart && !$exit_code && $something_installed) {
872 log::explanations("restarting rpmdrake");
873 #- it seems to work correctly with exec instead of system, provided we stop timers
874 #- added --previous-priority-upgrade to allow checking if yet if
875 #- priority-upgrade list has changed. and make sure we don't uselessly restart
876 my @argv = ('--previous-priority-upgrade=' . $urpm->{options}{'priority-upgrade'},
877 grep { !/^--no-priority-upgrade$|--previous-priority-upgrade=/ } @Rpmdrake::init::ARGV_copy);
878 # remove "--emmbedded <id>" from argv:
879 my $i = 0;
880 foreach (@argv) {
881 splice @argv, $i, 2 if /^--embedded$/;
882 $i++;
883 }
884 alarm(0);
885 # remember not to ask again questions and the like:
886 writeconf();
887 exec($0, @argv);
888 exit(0);
889 }
890
891 N("RPM transaction %d/%d");
892 N("Unselect all");
893 N("Details");
894
895 statusbar_msg_remove($statusbar_msg_id); #- XXX maybe remove this
896
897 if ($exit_code == 0 && !$::rpmdrake_options{auto_orphans}) {
898 if (urpm::orphans::check_unrequested_orphans_after_auto_select($urpm)) {
899 if (my $msg = urpm::orphans::get_now_orphans_gui_msg($urpm)) {
900 interactive_msg(N("Orphan packages"), $msg, scroll => 1);
901 }
902 }
903 }
904
905 return_with_exit_code:
906 return !($something_installed || scalar(@to_remove));
907 }
908
909
910 # -=-=-=---=-=-=---=-=-=-- remove packages -=-=-=---=-=-=---=-=-=-
911
912 sub perform_removal {
913 my ($urpm, $pkgs) = @_;
914 my @toremove = map { if_($pkgs->{$_}{selected}, $pkgs->{$_}{urpm_name}) } keys %$pkgs;
915 return if !@toremove;
916 my $gurpm = Rpmdrake::gurpm->new(1 ? N("Please wait") : N("Please wait, removing packages..."), N("Initializing..."), transient => $::main_window);
917 my $_gurpm_clean_guard = before_leaving { undef $gurpm };
918
919 my $may_be_orphans = 1;
920 urpm::orphans::unrequested_orphans_after_remove($urpm, \@toremove)
921 or $may_be_orphans = 0;
922
923 my $progress = -1;
924 local $urpm->{log} = sub {
925 my $str = $_[0];
926 print $str;
927 $progress++;
928 return if $progress <= 0; # skip first "creating transaction..." message
929 $gurpm->label($str); # display "removing package %s"
930 $gurpm->progress(min(0.99, scalar($progress/@toremove)));
931 gtkflush();
932 };
933
934 my @results;
935 slow_func_statusbar(
936 N("Please wait, removing packages..."),
937 $::main_window,
938 sub {
939 @results = $::rpmdrake_options{parallel}
940 ? urpm::parallel::remove($urpm, \@toremove)
941 : urpm::install::install($urpm, \@toremove, {}, {},
942 callback_report_uninst => sub { $gurpm->label($_[0]) },
943 );
944 open_rpm_db('force_sync');
945 },
946 );
947 if (@results) {
948 interactive_msg(
949 N("Problem during removal"),
950 N("There was a problem during the removal of packages:\n\n%s", join("\n", @results)),
951 if_(@results > 1, scroll => 1),
952 );
953 return 1;
954 } else {
955 if ($may_be_orphans && !$::rpmdrake_options{auto_orphans}) {
956 if (my $msg = urpm::orphans::get_now_orphans_gui_msg($urpm)) {
957 interactive_msg(N("Information"), $msg, scroll => 1);
958 }
959 }
960 return 0;
961 }
962 }
963
964 1;

  ViewVC Help
Powered by ViewVC 1.1.30