/[soft]/rpm/urpmi/trunk/gurpmi2
ViewVC logotype

Contents of /rpm/urpmi/trunk/gurpmi2

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3103 - (show annotations) (download)
Mon Feb 27 20:49:33 2012 UTC (12 years, 1 month ago) by tv
File size: 15794 byte(s)
fix urpmi failing silently and with exit status 0 when package
installation fails due to either conflicts (mdv#63072) or to
unselecting package (inspirated by mdv, mdv#63940)
1 #!/usr/bin/perl
2
3 #- Copyright (C) 2005 MandrakeSoft SA
4 #- Copyright (C) 2005-2010 Mandriva SA
5
6 use strict;
7
8 BEGIN { #- set up a safe path and environment
9 $ENV{PATH} = "/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin";
10 delete @ENV{qw(ENV BASH_ENV IFS CDPATH)};
11 }
12
13 use gurpmi;
14 use urpm::install;
15 use urpm::media;
16 use urpm::signature;
17 use urpm::get_pkgs;
18 use urpm::msg;
19 use urpm::util;
20 use urpm::select;
21 use urpm::main_loop;
22 use Gtk2;
23
24 #- default options.
25 our $allow_medium_change = 0;
26 our $auto_select = 0;
27 our $force = 0;
28 our $test = 0;
29 our $use_provides = 1;
30
31 my $progressbar_size = 450;
32
33 #- GUI globals
34 my ($mainw, $mainbox);
35
36 #- Replaces the contents of the main window with the specified box
37 #- (avoids popup multiplication)
38 sub change_mainw {
39 $mainw->remove($mainbox);
40 ($mainbox) = @_;
41 $mainw->add($mainbox);
42 $mainw->show_all;
43 }
44
45 sub sync () {
46 $mainw->show;
47 Gtk2->main_iteration while Gtk2->events_pending;
48 }
49
50 #- sets the window to a please-wait message
51 sub wait_label {
52 my ($o_text) = @_;
53 my $wait_vbox = Gtk2::VBox->new(0, 5);
54 my $wait_label = Gtk2::Label->new($o_text || N("Please wait..."));
55 $wait_label->set_alignment(0.5, 0.5);
56 $wait_vbox->pack_start($wait_label, 1, 1, 0);
57 change_mainw($wait_vbox);
58 sync();
59 }
60
61 my @all_rpms = gurpmi::parse_command_line();
62
63 $> and fatal(N("Must be root"));
64
65 #- Now, the graphical stuff.
66
67 Gtk2->init;
68 Gtk2->croak_execeptions;
69
70 my $title = $::auto_select ? N("Distribution Upgrade") : N("Packages installation");
71
72 #- Create main window
73
74 $mainw = Gtk2::Window->new('toplevel');
75 $::main_window = $mainw;
76 $mainw->set_border_width(12);
77 $mainw->set_title($title);
78 $mainw->signal_connect(destroy => \&quit);
79 $mainw->set_position('center');
80 $mainw->set_default_size($progressbar_size, 60);
81 $mainw->set_type_hint('dialog'); # for matchbox window manager during install
82 $mainw->set_modal(1); # for matchbox window manager during install
83 $mainbox = Gtk2::VBox->new(0, 5);
84 $mainw->add($mainbox);
85
86 #- Performs installation
87
88 my $urpm = configure_urpm();
89 my $state = {};
90 my %requested = $urpm->register_rpms(@all_rpms);
91 if (@gurpmi::names) {
92 urpm::select::search_packages($urpm, \%requested, [ @gurpmi::names ],
93 use_provides => $use_provides,
94 ) || $force or exit 1;
95 }
96
97 wait_label(N("Preparing packages installation..."));
98
99 #- return value is true if program should be restarted (in order to take care of important
100 #- packages being upgraded (problably urpmi and perl-URPM, but maybe rpm too, and glibc also ?).
101 my $restart_itself = urpm::select::resolve_dependencies($urpm,
102 $state,
103 \%requested,
104 callback_choices => \&ask_choice,
105 auto_select => $::auto_select,
106 priority_upgrade => $urpm->{options}{'priority-upgrade'},
107 );
108 my @ask_unselect = urpm::select::unselected_packages($urpm, $state);
109
110 # If there are some unselected packages, designate that we are going to return nonzero code.
111 if (@ask_unselect) {
112 my $unselect_msg = N("Some requested packages cannot be installed:\n%s",
113 urpm::select::translate_why_unselected($urpm, $state, @ask_unselect));
114 $urpm::postponed_msg .= $unselect_msg . "\n";
115 $urpm::postponed_code = 17;
116 }
117
118 @ask_unselect
119 ? ask_continue(N(
120 "Some requested packages cannot be installed:\n%s\nContinue installation anyway?",
121 urpm::select::translate_why_unselected($urpm, $state, @ask_unselect)
122 ), \&do_install)
123 : do_install();
124
125 $mainw->show_all;
126 Gtk2->main;
127
128 my ($rpm_lock, $urpmi_lock);
129
130 #- Creates and configure an urpm object for this application to use.
131 sub configure_urpm() {
132 my $urpm;
133 {
134 local @ARGV = @ARGV;
135 $urpm = urpm->new_parse_cmdline;
136 }
137
138 $urpm->{fatal} = sub {
139 printf STDERR "%s\n", $_[1];
140 Gtk2::MessageDialog->new($mainw, [qw(modal destroy-with-parent)], 'error', 'ok', Locale::gettext::iconv($_[1], undef, 'UTF-8'))->run;
141 quit();
142 exit $_[0];
143 };
144 $urpm->{log} = sub { printf "%s\n", $_[0] };
145 $urpm->{error} = sub {
146 my ($message) = @_;
147 printf STDERR "%s\n", $message;
148
149 if (my $download_errors = delete $urpm->{download_errors}) {
150 $message = join("\n", @$download_errors, $message);
151 }
152 my $nb_lines = $message =~ tr/\n/\n/;
153 my $w;
154 if ($nb_lines > 30) {
155 $w = Gtk2::Dialog->new(N("Warning"), $mainw, [qw(modal destroy-with-parent)], N("Ok"), 'ok');
156 $w->vbox->add(my $f = Gtk2::Frame->new);
157 my $sw = create_scrolled_window(my $text = Gtk2::TextView->new);
158 $sw->set_border_width(2);
159 $f->add($sw);
160 $text->get_buffer->set_text($message);
161 $text->set_editable(0);
162 $_->show foreach $f, $sw, $text;
163 $w->set_size_request(400, 400);
164 $w->set_default_response('ok');
165 } else {
166 $w = Gtk2::MessageDialog->new($mainw, [qw(modal destroy-with-parent)], 'warning', 'ok', $message);
167 }
168 $w->run;
169 $w->destroy;
170 };
171 urpm::select::set_priority_upgrade_option($urpm, $gurpmi::options{previous_priority_upgrade});
172 $rpm_lock = urpm::lock::rpm_db($urpm, 'exclusive');
173 $urpmi_lock = urpm::lock::urpmi_db($urpm);
174 urpm::media::configure($urpm,
175 media => $gurpmi::options{media},
176 searchmedia => $gurpmi::options{searchmedia},
177 update => $::update,
178 );
179 $urpm->{options}{'verify-rpm'} = 0 if $gurpmi::options{'no-verify-rpm'};
180 $urpm;
181 }
182
183 #- Callback for choices
184 sub ask_choice {
185 my (undef, undef, undef, $choices) = @_;
186 return $choices->[0] if $gurpmi::options{auto};
187 my $radio;
188 my @radios = map {
189 $radio = Gtk2::RadioButton->new_with_label(
190 $radio ? $radio->get_group : undef,
191 (scalar $_->fullname) . " : " . $_->summary
192 . ($_->flag_installed ? N(" (to upgrade)") : '')
193 . ($_->flag_upgrade ? N(" (to install)") : '')
194 );
195 } @$choices;
196 my $d = Gtk2::Dialog->new(N("Package choice"), $mainw, [], N("_Cancel") => 0, N("_Ok") => 1);
197 my $label = Gtk2::Label->new(N("One of the following packages is needed:"));
198 $label->set_alignment(0.5, 0.5);
199 $d->vbox->pack_start($label, 1, 1, 0);
200 $d->vbox->pack_start($_, 1, 1, 0) foreach @radios;
201 my $n = 0;
202 $d->signal_connect(response => sub {
203 if ($_[1] == 1) { #- "ok"
204 foreach (@radios) { last if $_->get_active; ++$n }
205 }
206 $d->destroy;
207 exit(1) if $_[1] == 0; #- "cancel"
208 });
209 $radios[0]->set_active(1);
210 $d->set_default_response(1); # defaults to ok
211 $d->show_all;
212 $d->run;
213 $choices->[$n];
214 }
215
216 sub ask_continue {
217 my ($msg, $nextclosure) = @_;
218 my $vbox = Gtk2::VBox->new(0, 5);
219 $vbox->pack_start(new_label($msg), 1, 1, 0);
220 $urpm->{log}($msg);
221 my $continue_button = Gtk2::Button->new(but(N("_Ok")));
222 my $quit_button = Gtk2::Button->new(but(N("_Abort")));
223 $quit_button->signal_connect(clicked => sub { $urpm->{log}("=> cancel"); &quit(); exit 1 });
224 $continue_button->signal_connect(clicked => sub { $urpm->{log}("=> ok"); goto &$nextclosure });
225 add_button_box($vbox, $quit_button, $continue_button);
226 change_mainw($vbox);
227 # default is to continue, but according to some HIG, warning should reverse the choise and defaults to abort
228 $mainw->set_focus($continue_button); # also set_default should be called but it gives a warning!
229 }
230
231 sub ask_continue_if_no_auto {
232 my ($msg, $nextclosure) = @_;
233 if ($gurpmi::options{auto}) {
234 $urpm->{log}($msg);
235 $urpm->{log}("=> ok(auto)");
236 goto &$nextclosure;
237 } else {
238 ask_continue($msg, $nextclosure);
239 }
240 }
241
242 sub ask_continue_blocking {
243 my ($msg) = @_;
244 my $w = Gtk2::MessageDialog->new($mainw, [qw(modal destroy-with-parent)], 'question', 'yes-no', $msg);
245 my $answer = $w->run;
246 $w->destroy;
247 $urpm->{log}($msg . " => " . $answer);
248 exit(1) if $answer eq 'no';
249 1;
250 }
251
252 sub do_install {
253 wait_label();
254 my @ask_remove = urpm::select::removed_packages($urpm, $state);
255 @ask_remove
256 ? ask_continue_if_no_auto(N(
257 "The following packages have to be removed for others to be upgraded:\n%s\nContinue installation anyway?",
258 urpm::select::translate_why_removed($urpm, $state, @ask_remove)
259 ), \&do_install_2)
260 : goto &do_install_2;
261 }
262
263 sub do_install_2 () {
264 my @to_install;
265 my $sum;
266 foreach my $pkg (sort { $a->name cmp $b->name } @{$urpm->{depslist}}[keys %{$state->{selected}}]) {
267 if ($pkg->arch ne 'src') {
268 push @to_install, scalar $pkg->fullname;
269 $sum += $pkg->size;
270 }
271 }
272 $urpm->{nb_install} = @to_install;
273 @to_install > 1
274 ? ask_continue_if_no_auto(
275 (scalar(@to_install) == 1 ?
276 N("To satisfy dependencies, the following package is going to be installed:")
277 : N("To satisfy dependencies, the following packages are going to be installed:"))
278 . join("\n", '', @to_install, '')
279 . P("(%d package, %d MB)", "(%d packages, %d MB)", scalar(@to_install), scalar(@to_install), toMb($sum)),
280 , \&do_install_3)
281 : goto \&do_install_3;
282 }
283
284 sub do_install_3 () {
285 wait_label($title);
286 my ($local_sources, $blists) = urpm::get_pkgs::selected2local_and_blists($urpm, $state->{selected});
287 $local_sources || $blists or $urpm->{fatal}(3, N("unable to get source packages, aborting"));
288 my $vbox = Gtk2::VBox->new(0, 5);
289
290 my $global_label = gtk_new_Label_Left("<b>$title</b>");
291 $global_label->set_use_markup(1);
292 $vbox->pack_start($global_label, 0, 0, 0);
293
294 my $global_progressbar = Gtk2::ProgressBar->new;
295 $vbox->pack_start($global_progressbar, 0, 0, 0);
296
297 my $progress_label = gtk_new_Label_Left('-');
298 $vbox->pack_start($progress_label, 1, 1, 0);
299
300
301 my $progressbar = Gtk2::ProgressBar->new;
302 $progressbar->set_size_request($progressbar_size, -1);
303 $vbox->pack_start($progressbar, 0, 0, 0);
304
305 change_mainw($vbox);
306 my ($progress_nb, $download_nb);
307 my $set_progressbar = sub {
308 my ($local_ratio) = @_;
309 if ($progress_nb || $download_nb) { # this happens when computing transaction
310 $global_progressbar->set_fraction(($download_nb + $progress_nb - 1 + $local_ratio) / 2 / $urpm->{nb_install});
311 }
312 $progressbar->set_fraction($local_ratio);
313 };
314 my $callback_inst = sub {
315 my ($urpm, $type, $id, $subtype, $amount, $total) = @_;
316 my $pkg = defined $id ? $urpm->{depslist}[$id] : undef;
317 if ($subtype eq 'start') {
318 if ($type eq 'trans') {
319 $progress_label->set_label(N("Preparing..."));
320 } elsif ($pkg) {
321 $progress_nb++;
322 $download_nb = max($download_nb, $progress_nb);
323 $set_progressbar->(0);
324 $progress_label->set_label(
325 N("Installing package `%s' (%s/%s)...", $pkg->name, $progress_nb, $urpm->{nb_install})
326 );
327 }
328 } elsif ($subtype eq 'progress') {
329 $set_progressbar->($amount / $total);
330 }
331 sync();
332 };
333
334 my $exit_code = urpm::main_loop::run($urpm, $state, scalar(@gurpmi::names), \@ask_unselect, \%requested, {
335 bad_signature => sub {
336 my ($msg, $msg2) = @_;
337 $urpm->{log}("$msg\n$msg2");
338 ask_continue_blocking("$msg\n$msg2");
339 },
340 copy_removable => sub {
341 #FIXME: use use hal to wait-for/mount cdroms:
342 my $w = Gtk2::MessageDialog->new($mainw, [qw(modal destroy-with-parent)], 'warning', 'ok-cancel',
343 N("Please insert the medium named \"%s\"", $_[0])
344 );
345 my $response = $w->run;
346 $w->destroy;
347 exit 1 if $response eq 'cancel';
348 1;
349 },
350 trans_log => sub {
351 my ($mode, $file, $percent, $_total, $_eta, $_speed) = @_;
352
353 urpm::download::sync_logger(@_);
354
355 if (member($mode, 'start', 'progress')) {
356 $file =~ s|/*\s*$||; $file =~ s|.*/||;
357 $progress_label->set_label(N("Downloading package `%s'...", $file) . "\n" . &urpm::download::progress_text);
358 }
359 if ($mode eq 'start') {
360 $download_nb++;
361 $set_progressbar->(0);
362 select(undef, undef, undef, 0.1); #- hackish
363 } elsif ($mode eq 'progress') {
364 $set_progressbar->($percent / 100);
365 } elsif ($mode eq 'end') {
366 $set_progressbar->(1);
367 } elsif ($mode eq 'error') {
368 #- error is 3rd argument, saved in $percent
369 push @{$urpm->{download_errors}}, N("...retrieving failed: %s", $percent);
370 }
371 sync();
372 },
373 ask_yes_or_no => \&ask_yes_or_no,
374
375 completed => sub {
376 $urpmi_lock->unlock;
377 $rpm_lock->unlock;
378 urpm::removable::try_umounting_removables($urpm);
379 $vbox = Gtk2::VBox->new(0, 5);
380 $progress_label = Gtk2::Label->new('-');
381 return 0 if $gurpmi::options{auto};
382 my $sw = create_scrolled_window($progress_label);
383 $sw->set_size_request(500, 200);
384 $vbox->pack_start($sw, 1, 1, 0);
385 my $quit_button = Gtk2::Button->new(but(N("_Done")));
386 $quit_button->signal_connect(clicked => \&quit);
387 add_button_box($vbox, $quit_button);
388 change_mainw($vbox);
389 $mainw->set_focus($quit_button);
390 },
391 need_restart => sub {
392 return if $gurpmi::options{auto};
393 my ($need_restart_formatted) = @_;
394 my $w = Gtk2::MessageDialog->new($mainw, [qw(modal destroy-with-parent)], 'warning', 'ok',
395 join("\n", values %$need_restart_formatted)
396 );
397 $w->run;
398 $w->destroy;
399 },
400 missing_files_summary => sub {
401 my ($error_sources) = @_;
402 $progress_label->set_label(N("Installation failed, some files are missing:\n%s\nYou may want to update your urpmi database",
403 join("\n", map { s|([^:]*://[^/:\@]*:)[^/:\@]*(\@.*)|$1xxxx$2|; " $_" }
404 values %$error_sources)));
405 },
406 trans_error_summary => sub {
407 my ($_nok, $errors) = @_;
408 $progress_label->set_label(N("Installation failed:") . "\n" . join("\n", map { "\t$_" } @$errors));
409 },
410 # TODO: use urpmi strings:
411 already_installed_or_not_installable => sub {
412 my ($_msg1, $_msg2) = @_;
413 $progress_label->set_label(N("The package(s) are already installed"));
414 },
415 success_summary => sub { $progress_label->set_label(N("Installation finished")) },
416 callback_report_uninst => sub { $progress_label->set_label(N("removing %s", $_[0])) },
417 inst => $callback_inst,
418 trans => $callback_inst,
419 }
420 );
421
422 # Merge postponed exit code to the result of package installation.
423 $exit_code ||= $urpm::postponed_code;
424
425 #- restart gurpmi if needed, keep command line for that.
426 if ($restart_itself && !$exit_code) {
427 print N("restarting urpmi"), "\n";
428 #- it seems to work correctly with exec instead of system, provided
429 #- added --previous-priority-upgrade to allow checking if yet if
430 #- priority-upgrade list has changed. and make sure we don't uselessly restart
431 @ARGV = ('--previous-priority-upgrade=' . $urpm->{options}{'priority-upgrade'},
432 grep { !/^--no-priority-upgrade$|--previous-priority-upgrade=/ } @ARGV);
433 exec $0, @ARGV;
434 }
435
436 # Show postponed message before exiting
437 $urpm->{error}->($urpm::postponed_msg) if $urpm::postponed_code != 0;
438
439 exit $exit_code;
440 }
441
442 sub ask_yes_or_no {
443 my ($_title, $msg) = @_;
444 # MessageDialogs have no titles unless using 'secondary-text'
445 my $w = Gtk2::MessageDialog->new($mainw, [qw(modal destroy-with-parent)], 'warning', 'yes-no', $msg);
446 my $response = $w->run;
447 $w->destroy;
448 $response eq 'yes';
449 }
450
451 sub gtk_new_Label_Left {
452 my ($text) = @_;
453 my $w = Gtk2::Label->new($text);
454 $w->set_alignment(0, 0);
455 $w;
456 }

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.30