1 |
#***************************************************************************** |
2 |
# |
3 |
# Copyright (c) 2002 Guillaume Cottenceau |
4 |
# Copyright (c) 2002-2007 Thierry Vignaud <tvignaud@mandriva.com> |
5 |
# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA |
6 |
# Copyright (c) 2005, 2007 Mandriva SA |
7 |
# |
8 |
# This program is free software; you can redistribute it and/or modify |
9 |
# it under the terms of the GNU General Public License version 2, as |
10 |
# published by the Free Software Foundation. |
11 |
# |
12 |
# This program is distributed in the hope that it will be useful, |
13 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
# GNU General Public License for more details. |
16 |
# |
17 |
# You should have received a copy of the GNU General Public License |
18 |
# along with this program; if not, write to the Free Software |
19 |
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
20 |
# |
21 |
#***************************************************************************** |
22 |
# |
23 |
# $Id: rpmdrake.pm 267936 2010-04-26 16:40:21Z jvictor $ |
24 |
|
25 |
package rpmdrake; |
26 |
|
27 |
use lib qw(/usr/lib/libDrakX); |
28 |
use urpm::download (); |
29 |
use urpm::prompt; |
30 |
use urpm::media; |
31 |
|
32 |
use MDK::Common; |
33 |
use MDK::Common::System; |
34 |
use urpm; |
35 |
use urpm::cfg; |
36 |
use URPM; |
37 |
use URPM::Resolve; |
38 |
use strict; |
39 |
use c; |
40 |
use POSIX qw(_exit); |
41 |
use common; |
42 |
use Locale::gettext; |
43 |
use feature 'state'; |
44 |
|
45 |
our @ISA = qw(Exporter); |
46 |
our $VERSION = '2.27'; |
47 |
our @EXPORT = qw( |
48 |
$changelog_first_config |
49 |
$compute_updates |
50 |
$filter |
51 |
$dont_show_selections |
52 |
$ignore_debug_media |
53 |
$mandrakeupdate_wanted_categories |
54 |
$mandrivaupdate_height |
55 |
$mandrivaupdate_width |
56 |
$max_info_in_descr |
57 |
$mode |
58 |
$NVR_searches |
59 |
$offered_to_add_sources |
60 |
$rpmdrake_height |
61 |
$rpmdrake_width |
62 |
$tree_flat |
63 |
$tree_mode |
64 |
$use_regexp |
65 |
$typical_width |
66 |
$clean_cache |
67 |
$auto_select |
68 |
add_distrib_update_media |
69 |
add_medium_and_check |
70 |
but |
71 |
but_ |
72 |
check_update_media_version |
73 |
choose_mirror |
74 |
distro_type |
75 |
fatal_msg |
76 |
getbanner |
77 |
get_icon |
78 |
interactive_list |
79 |
interactive_list_ |
80 |
interactive_msg |
81 |
interactive_packtable |
82 |
myexit |
83 |
readconf |
84 |
remove_wait_msg |
85 |
run_drakbug |
86 |
show_urpm_progress |
87 |
slow_func |
88 |
slow_func_statusbar |
89 |
statusbar_msg |
90 |
statusbar_msg_remove |
91 |
strip_first_underscore |
92 |
update_sources |
93 |
update_sources_check |
94 |
update_sources_interactive |
95 |
update_sources_noninteractive |
96 |
wait_msg |
97 |
warn_for_network_need |
98 |
writeconf |
99 |
); |
100 |
our $typical_width = 280; |
101 |
|
102 |
our $dont_show_selections; |
103 |
|
104 |
# i18n: IMPORTANT: to get correct namespace (rpmdrake instead of libDrakX) |
105 |
BEGIN { unshift @::textdomains, qw(rpmdrake urpmi rpm-summary-main rpm-summary-contrib rpm-summary-devel rpm-summary-non-free) } |
106 |
|
107 |
use mygtk2 qw(gtknew); |
108 |
use ugtk2 qw(:all); |
109 |
ugtk2::add_icon_path('/usr/share/rpmdrake/icons'); |
110 |
|
111 |
Locale::gettext::bind_textdomain_codeset('rpmdrake', 'UTF8'); |
112 |
|
113 |
our $mandrake_release = cat_( |
114 |
-e '/etc/mandrakelinux-release' ? '/etc/mandrakelinux-release' : '/etc/release' |
115 |
) || ''; |
116 |
chomp $mandrake_release; |
117 |
our ($mdk_version) = $mandrake_release =~ /(\d+\.\d+)/; |
118 |
our ($branded, %distrib); |
119 |
$branded = -f '/etc/sysconfig/oem' |
120 |
and %distrib = MDK::Common::System::distrib(); |
121 |
our $myname_update = $branded ? N("Software Update") : N("Mageia Update"); |
122 |
|
123 |
@rpmdrake::prompt::ISA = 'urpm::prompt'; |
124 |
|
125 |
sub rpmdrake::prompt::prompt { |
126 |
my ($self) = @_; |
127 |
my @answers; |
128 |
my $d = ugtk2->new("", grab => 1, if_($::main_window, transient => $::main_window)); |
129 |
$d->{rwindow}->set_position('center_on_parent'); |
130 |
gtkadd( |
131 |
$d->{window}, |
132 |
gtkpack( |
133 |
Gtk2::VBox->new(0, 5), |
134 |
Gtk2::WrappedLabel->new($self->{title}), |
135 |
(map { gtkpack( |
136 |
Gtk2::HBox->new(0, 5), |
137 |
Gtk2::Label->new($self->{prompts}[$_]), |
138 |
$answers[$_] = gtkset_visibility(gtkentry(), !$self->{hidden}[$_]), |
139 |
) } 0 .. $#{$self->{prompts}}), |
140 |
gtksignal_connect(Gtk2::Button->new(N("Ok")), clicked => sub { Gtk2->main_quit }), |
141 |
), |
142 |
); |
143 |
$d->main; |
144 |
map { $_->get_text } @answers; |
145 |
} |
146 |
|
147 |
$urpm::download::PROMPT_PROXY = new rpmdrake::prompt( |
148 |
N("Please enter your credentials for accessing proxy\n"), |
149 |
[ N("User name:"), N("Password:") ], |
150 |
undef, |
151 |
[ 0, 1 ], |
152 |
); |
153 |
|
154 |
sub myexit { |
155 |
writeconf(); |
156 |
ugtk2::exit(undef, @_); |
157 |
} |
158 |
|
159 |
my ($root) = grep { $_->[2] == 0 } list_passwd(); |
160 |
$ENV{HOME} = $> == 0 ? $root->[7] : $ENV{HOME} || '/root'; |
161 |
$ENV{HOME} = $::env if $::env = $Rpmdrake::init::rpmdrake_options{env}[0]; |
162 |
|
163 |
our $configfile = "$ENV{HOME}/.rpmdrake"; |
164 |
|
165 |
# |
166 |
# Configuration File Options |
167 |
# |
168 |
|
169 |
# clear download cache after successfull installation of packages |
170 |
our $clean_cache; |
171 |
|
172 |
# automatic select dependencies without user intervention |
173 |
our $auto_select; |
174 |
|
175 |
our ($changelog_first_config, $compute_updates, $filter, $max_info_in_descr, $mode, $NVR_searches, $tree_flat, $tree_mode, $use_regexp); |
176 |
our ($mandrakeupdate_wanted_categories, $ignore_debug_media, $offered_to_add_sources, $no_confirmation); |
177 |
our ($rpmdrake_height, $rpmdrake_width, $mandrivaupdate_height, $mandrivaupdate_width); |
178 |
|
179 |
our %config = ( |
180 |
clean_cache => { |
181 |
var => \$clean_cache, |
182 |
default => [ 0 ] |
183 |
}, |
184 |
auto_select => { |
185 |
var => \$auto_select, |
186 |
default => [ 0 ] |
187 |
}, |
188 |
changelog_first_config => { var => \$changelog_first_config, default => [ 0 ] }, |
189 |
compute_updates => { var => \$compute_updates, default => [ 1 ] }, |
190 |
dont_show_selections => { var => \$dont_show_selections, default => [ $> ? 1 : 0 ] }, |
191 |
filter => { var => \$filter, default => [ 'all' ] }, |
192 |
ignore_debug_media => { var => \$ignore_debug_media, default => [ 0 ] }, |
193 |
mandrakeupdate_wanted_categories => { var => \$mandrakeupdate_wanted_categories, default => [ qw(security) ] }, |
194 |
mandrivaupdate_height => { var => \$mandrivaupdate_height, default => [ 0 ] }, |
195 |
mandrivaupdate_width => { var => \$mandrivaupdate_width, default => [ 0 ] }, |
196 |
max_info_in_descr => { var => \$max_info_in_descr, default => [] }, |
197 |
mode => { var => \$mode, default => [ 'by_group' ] }, |
198 |
NVR_searches => { var => \$NVR_searches, default => [ 0 ] }, |
199 |
'no-confirmation' => { var => \$no_confirmation, default => [ 0 ] }, |
200 |
offered_to_add_sources => { var => \$offered_to_add_sources, default => [ 0 ] }, |
201 |
rpmdrake_height => { var => \$rpmdrake_height, default => [ 0 ] }, |
202 |
rpmdrake_width => { var => \$rpmdrake_width, default => [ 0 ] }, |
203 |
tree_flat => { var => \$tree_flat, default => [ 0 ] }, |
204 |
tree_mode => { var => \$tree_mode, default => [ qw(gui_pkgs) ] }, |
205 |
use_regexp => { var => \$use_regexp, default => [ 0 ] }, |
206 |
); |
207 |
|
208 |
sub readconf() { |
209 |
${$config{$_}{var}} = $config{$_}{default} foreach keys %config; |
210 |
foreach my $l (cat_($configfile)) { |
211 |
foreach (keys %config) { |
212 |
${$config{$_}{var}} = [ split ' ', $1 ] if $l =~ /^\Q$_\E(.*)/; |
213 |
} |
214 |
} |
215 |
# special cases: |
216 |
$::rpmdrake_options{'no-confirmation'} = $no_confirmation->[0] if !defined $::rpmdrake_options{'no-confirmation'}; |
217 |
$Rpmdrake::init::default_list_mode = $tree_mode->[0] if ref $tree_mode && !$Rpmdrake::init::overriding_config; |
218 |
} |
219 |
|
220 |
sub writeconf() { |
221 |
return if $::env; |
222 |
unlink $configfile; |
223 |
|
224 |
# special case: |
225 |
$no_confirmation->[0] = $::rpmdrake_options{'no-confirmation'}; |
226 |
|
227 |
output $configfile, map { "$_ " . (ref ${$config{$_}{var}} ? join(' ', @${$config{$_}{var}}) : ()) . "\n" } keys %config; |
228 |
} |
229 |
|
230 |
sub getbanner() { |
231 |
$::MODE or return undef; |
232 |
if (0) { |
233 |
+{ |
234 |
remove => N("Software Packages Removal"), |
235 |
update => N("Software Packages Update"), |
236 |
install => N("Software Packages Installation"), |
237 |
}; |
238 |
} |
239 |
Gtk2::Banner->new($ugtk2::wm_icon, $::MODE eq 'update' ? N("Software Packages Update") : N("Software Management")); |
240 |
} |
241 |
|
242 |
# return value: |
243 |
# - undef if if closed (aka really canceled) |
244 |
# - 0 if if No/Cancel |
245 |
# - 1 if if Yes/Ok |
246 |
sub interactive_msg { |
247 |
my ($title, $contents, %options) = @_; |
248 |
$options{transient} ||= $::main_window if $::main_window; |
249 |
local $::isEmbedded; |
250 |
my $d = ugtk2->new($title, grab => 1, if_(exists $options{transient}, transient => $options{transient})); |
251 |
$d->{rwindow}->set_position($options{transient} ? 'center_on_parent' : 'center_always'); |
252 |
if ($options{scroll}) { |
253 |
$contents = ugtk2::markup_to_TextView_format($contents) if !ref $contents; |
254 |
} else { #- because we'll use a WrappedLabel |
255 |
$contents = formatAlaTeX($contents) if !ref $contents; |
256 |
} |
257 |
my $text_w; |
258 |
my $button_yes; |
259 |
gtkadd( |
260 |
$d->{window}, |
261 |
gtkpack_( |
262 |
Gtk2::VBox->new(0, 5), |
263 |
1, |
264 |
( |
265 |
$options{scroll} ? |
266 |
($text_w = create_scrolled_window(gtktext_insert(Gtk2::TextView->new, $contents))) |
267 |
: ($text_w = gtknew('WrappedLabel', text_markup => $contents)) |
268 |
), |
269 |
if_($options{widget}, 0, $options{widget}), |
270 |
0, |
271 |
gtkpack( |
272 |
create_hbox(), |
273 |
( |
274 |
ref($options{yesno}) eq 'ARRAY' ? map { |
275 |
my $label = $_; |
276 |
gtksignal_connect( |
277 |
$button_yes = Gtk2::Button->new($label), |
278 |
clicked => sub { $d->{retval} = $label; Gtk2->main_quit } |
279 |
); |
280 |
} @{$options{yesno}} |
281 |
: ( |
282 |
$options{yesno} ? ( |
283 |
gtksignal_connect( |
284 |
Gtk2::Button->new($options{text}{no} || N("No")), |
285 |
clicked => sub { $d->{retval} = 0; Gtk2->main_quit } |
286 |
), |
287 |
gtksignal_connect( |
288 |
$button_yes = Gtk2::Button->new($options{text}{yes} || N("Yes")), |
289 |
clicked => sub { $d->{retval} = 1; Gtk2->main_quit } |
290 |
), |
291 |
) |
292 |
: gtksignal_connect( |
293 |
$button_yes = Gtk2::Button->new(N("Ok")), |
294 |
clicked => sub { Gtk2->main_quit } |
295 |
) |
296 |
) |
297 |
) |
298 |
) |
299 |
) |
300 |
); |
301 |
$d->{window}->set_focus($button_yes); |
302 |
$text_w->set_size_request($typical_width*2, $options{scroll} ? 300 : -1); |
303 |
$d->main; |
304 |
return $d->{retval}; |
305 |
} |
306 |
|
307 |
sub interactive_packtable { |
308 |
my ($title, $parent_window, $top_label, $lines, $action_buttons) = @_; |
309 |
|
310 |
my $w = ugtk2->new($title, grab => 1, transient => $parent_window); |
311 |
local $::main_window = $w->{real_window}; |
312 |
$w->{rwindow}->set_position($parent_window ? 'center_on_parent' : 'center'); |
313 |
my $packtable = create_packtable({}, @$lines); |
314 |
|
315 |
gtkadd($w->{window}, |
316 |
gtkpack_(Gtk2::VBox->new(0, 5), |
317 |
if_($top_label, 0, Gtk2::Label->new($top_label)), |
318 |
1, create_scrolled_window($packtable), |
319 |
0, gtkpack__(create_hbox(), @$action_buttons))); |
320 |
my $preq = $packtable->size_request; |
321 |
my ($xpreq, $ypreq) = ($preq->width, $preq->height); |
322 |
my $wreq = $w->{rwindow}->size_request; |
323 |
my ($xwreq, $ywreq) = ($wreq->width, $wreq->height); |
324 |
$w->{rwindow}->set_default_size(max($typical_width, min($typical_width*2.5, $xpreq+$xwreq)), |
325 |
max(200, min(450, $ypreq+$ywreq))); |
326 |
$w->main; |
327 |
} |
328 |
|
329 |
sub interactive_list { |
330 |
my ($title, $contents, $list, $callback, %options) = @_; |
331 |
my $d = ugtk2->new($title, grab => 1, if_(exists $options{transient}, transient => $options{transient})); |
332 |
$d->{rwindow}->set_position($options{transient} ? 'center_on_parent' : 'center_always'); |
333 |
my @radios = gtkradio('', @$list); |
334 |
my $vbradios = $callback ? create_packtable( |
335 |
{}, |
336 |
mapn { |
337 |
my $n = $_[1]; |
338 |
[ $_[0], |
339 |
gtksignal_connect( |
340 |
Gtk2::Button->new(but(N("Info..."))), |
341 |
clicked => sub { $callback->($n) }, |
342 |
) ]; |
343 |
} \@radios, $list, |
344 |
) : gtkpack__(Gtk2::VBox->new(0, 0), @radios); |
345 |
my $choice; |
346 |
my $button_ok; |
347 |
gtkadd( |
348 |
$d->{window}, |
349 |
gtkpack__( |
350 |
Gtk2::VBox->new(0,5), |
351 |
Gtk2::Label->new($contents), |
352 |
int(@$list) > 8 ? gtkset_size_request(create_scrolled_window($vbradios), 250, 320) : $vbradios, |
353 |
gtkpack__( |
354 |
create_hbox(), |
355 |
if_(!$options{nocancel}, |
356 |
gtksignal_connect( |
357 |
Gtk2::Button->new(N("Cancel")), clicked => sub { Gtk2->main_quit }), |
358 |
), |
359 |
gtksignal_connect( |
360 |
$button_ok=Gtk2::Button->new(N("Ok")), clicked => sub { |
361 |
each_index { $_->get_active and $choice = $::i } @radios; |
362 |
Gtk2->main_quit; |
363 |
} |
364 |
) |
365 |
) |
366 |
) |
367 |
); |
368 |
$d->{window}->set_focus($button_ok); |
369 |
$d->main; |
370 |
$choice; |
371 |
} |
372 |
|
373 |
sub interactive_list_ { interactive_list(@_, if_($::main_window, transient => $::main_window)) } |
374 |
|
375 |
sub fatal_msg { |
376 |
interactive_msg @_; |
377 |
myexit -1; |
378 |
} |
379 |
|
380 |
sub wait_msg { |
381 |
my ($msg, %options) = @_; |
382 |
gtkflush(); |
383 |
$options{transient} ||= $::main_window if $::main_window; |
384 |
local $::isEmbedded; |
385 |
my $mainw = ugtk2->new(N("Please wait"), grab => 1, if_(exists $options{transient}, transient => $options{transient})); |
386 |
$mainw->{real_window}->set_position($options{transient} ? 'center_on_parent' : 'center_always'); |
387 |
my $label = ref($msg) =~ /^Gtk/ ? $msg : Gtk2::WrappedLabel->new($msg); |
388 |
gtkadd( |
389 |
$mainw->{window}, |
390 |
gtkpack__( |
391 |
gtkset_border_width(Gtk2::VBox->new(0, 5), 6), |
392 |
$label, |
393 |
if_(exists $options{widgets}, @{$options{widgets}}), |
394 |
) |
395 |
); |
396 |
$mainw->sync; |
397 |
gtkset_mousecursor_wait($mainw->{rwindow}->window) unless $options{no_wait_cursor}; |
398 |
$mainw->flush; |
399 |
$mainw; |
400 |
} |
401 |
|
402 |
sub remove_wait_msg { |
403 |
my $w = shift; |
404 |
gtkset_mousecursor_normal($w->{rwindow}->window); |
405 |
$w->destroy; |
406 |
} |
407 |
|
408 |
sub but { " $_[0] " } |
409 |
sub but_ { " $_[0] " } |
410 |
|
411 |
sub slow_func ($&) { |
412 |
my ($param, $func) = @_; |
413 |
if (ref($param) =~ /^Gtk/) { |
414 |
gtkset_mousecursor_wait($param); |
415 |
ugtk2::flush(); |
416 |
$func->(); |
417 |
gtkset_mousecursor_normal($param); |
418 |
} else { |
419 |
my $w = wait_msg($param); |
420 |
$func->(); |
421 |
remove_wait_msg($w); |
422 |
} |
423 |
} |
424 |
|
425 |
sub statusbar_msg { |
426 |
unless ($::statusbar) { #- fallback if no status bar |
427 |
if (defined &::wait_msg_) { goto &::wait_msg_ } else { goto &wait_msg } |
428 |
} |
429 |
my ($msg, $o_timeout) = @_; |
430 |
#- always use the same context description for now |
431 |
my $cx = $::statusbar->get_context_id("foo"); |
432 |
$::w and $::w->{rwindow} and gtkset_mousecursor_wait($::w->{rwindow}->window); |
433 |
#- returns a msg_id to be passed optionnally to statusbar_msg_remove |
434 |
my $id = $::statusbar->push($cx, $msg); |
435 |
gtkflush(); |
436 |
Glib::Timeout->add(5000, sub { statusbar_msg_remove($id); 0 }) if $o_timeout; |
437 |
$id; |
438 |
} |
439 |
|
440 |
sub statusbar_msg_remove { |
441 |
my ($msg_id) = @_; |
442 |
if (!$::statusbar || ref $msg_id) { #- fallback if no status bar |
443 |
goto &remove_wait_msg; |
444 |
} |
445 |
my $cx = $::statusbar->get_context_id("foo"); |
446 |
if (defined $msg_id) { |
447 |
$::statusbar->remove($cx, $msg_id); |
448 |
} else { |
449 |
$::statusbar->pop($cx); |
450 |
} |
451 |
$::w and $::w->{rwindow} and gtkset_mousecursor_normal($::w->{rwindow}->window); |
452 |
} |
453 |
|
454 |
sub slow_func_statusbar ($$&) { |
455 |
my ($msg, $w, $func) = @_; |
456 |
gtkset_mousecursor_wait($w->window); |
457 |
my $msg_id = statusbar_msg($msg); |
458 |
gtkflush(); |
459 |
$func->(); |
460 |
statusbar_msg_remove($msg_id); |
461 |
gtkset_mousecursor_normal($w->window); |
462 |
} |
463 |
|
464 |
my %u2l = ( |
465 |
at => N_("Austria"), |
466 |
au => N_("Australia"), |
467 |
be => N_("Belgium"), |
468 |
br => N_("Brazil"), |
469 |
ca => N_("Canada"), |
470 |
ch => N_("Switzerland"), |
471 |
cr => N_("Costa Rica"), |
472 |
cz => N_("Czech Republic"), |
473 |
de => N_("Germany"), |
474 |
dk => N_("Danmark"), |
475 |
el => N_("Greece"), |
476 |
es => N_("Spain"), |
477 |
fi => N_("Finland"), |
478 |
fr => N_("France"), |
479 |
gr => N_("Greece"), |
480 |
hu => N_("Hungary"), |
481 |
il => N_("Israel"), |
482 |
it => N_("Italy"), |
483 |
jp => N_("Japan"), |
484 |
ko => N_("Korea"), |
485 |
nl => N_("Netherlands"), |
486 |
no => N_("Norway"), |
487 |
pl => N_("Poland"), |
488 |
pt => N_("Portugal"), |
489 |
ru => N_("Russia"), |
490 |
se => N_("Sweden"), |
491 |
sg => N_("Singapore"), |
492 |
sk => N_("Slovakia"), |
493 |
tw => N_("Taiwan"), |
494 |
uk => N_("United Kingdom"), |
495 |
cn => N_("China"), |
496 |
com => N_("United States"), |
497 |
org => N_("United States"), |
498 |
net => N_("United States"), |
499 |
edu => N_("United States"), |
500 |
); |
501 |
my $us = [ qw(com org net edu) ]; |
502 |
my %t2l = ( |
503 |
'America/\w+' => $us, |
504 |
'Asia/Tel_Aviv' => [ qw(il ru it cz at de fr se) ], |
505 |
'Asia/Tokyo' => [ qw(jp ko tw), @$us ], |
506 |
'Asia/Seoul' => [ qw(ko jp tw), @$us ], |
507 |
'Asia/Taipei' => [ qw(tw jp), @$us ], |
508 |
'Asia/(Shanghai|Beijing)' => [ qw(cn tw sg), @$us ], |
509 |
'Asia/Singapore' => [ qw(cn sg), @$us ], |
510 |
'Atlantic/Reykjavik' => [ qw(uk no se fi dk), @$us, qw(nl de fr at cz it) ], |
511 |
'Australia/\w+' => [ qw(au jp ko tw), @$us ], |
512 |
'Brazil/\w+' => [ 'br', @$us ], |
513 |
'Canada/\w+' => [ 'ca', @$us ], |
514 |
'Europe/Amsterdam' => [ qw(nl be de at cz fr se dk it) ], |
515 |
'Europe/Athens' => [ qw(gr pl cz de it nl at fr) ], |
516 |
'Europe/Berlin' => [ qw(de be at nl cz it fr se) ], |
517 |
'Europe/Brussels' => [ qw(be de nl fr cz at it se) ], |
518 |
'Europe/Budapest' => [ qw(cz it at de fr nl se) ], |
519 |
'Europe/Copenhagen' => [ qw(dk nl de be se at cz it) ], |
520 |
'Europe/Dublin' => [ qw(uk fr be nl dk se cz it) ], |
521 |
'Europe/Helsinki' => [ qw(fi se no nl be de fr at it) ], |
522 |
'Europe/Istanbul' => [ qw(il ru it cz it at de fr nl se) ], |
523 |
'Europe/Lisbon' => [ qw(pt es fr it cz at de se) ], |
524 |
'Europe/London' => [ qw(uk fr be nl de at cz se it) ], |
525 |
'Europe/Madrid' => [ qw(es fr pt it cz at de se) ], |
526 |
'Europe/Moscow' => [ qw(ru de pl cz at se be fr it) ], |
527 |
'Europe/Oslo' => [ qw(no se fi dk de be at cz it) ], |
528 |
'Europe/Paris' => [ qw(fr be de at cz nl it se) ], |
529 |
'Europe/Prague' => [ qw(cz it at de fr nl se) ], |
530 |
'Europe/Rome' => [ qw(it fr cz de at nl se) ], |
531 |
'Europe/Stockholm' => [ qw(se no dk fi nl de at cz fr it) ], |
532 |
'Europe/Vienna' => [ qw(at de cz it fr nl se) ], |
533 |
); |
534 |
|
535 |
#- get distrib release number (2006.0, etc) |
536 |
sub etc_version() { |
537 |
(my $v) = split / /, cat_('/etc/version'); |
538 |
return $v; |
539 |
} |
540 |
|
541 |
#- returns the keyword describing the type of the distribution. |
542 |
#- the parameter indicates whether we want base or update sources |
543 |
sub distro_type { |
544 |
my ($want_base_distro) = @_; |
545 |
return 'cooker' if $mandrake_release =~ /cooker/i; |
546 |
#- we can't use updates for community while official is not out (release ends in ".0") |
547 |
if ($want_base_distro || $mandrake_release =~ /community/i && etc_version() =~ /\.0$/) { |
548 |
return 'official' if $mandrake_release =~ /official|limited/i; |
549 |
return 'community' if $mandrake_release =~ /community/i; |
550 |
#- unknown: fallback to updates |
551 |
} |
552 |
return 'updates'; |
553 |
} |
554 |
|
555 |
sub compat_arch_for_updates($) { |
556 |
# FIXME: We prefer 64-bit packages to update on biarch platforms, |
557 |
# since the system is populated with 64-bit packages anyway. |
558 |
my ($arch) = @_; |
559 |
return $arch =~ /x86_64|amd64/ if arch() eq 'x86_64'; |
560 |
MDK::Common::System::compat_arch($arch); |
561 |
} |
562 |
|
563 |
sub mirrors { |
564 |
my ($urpm, $want_base_distro) = @_; |
565 |
my $cachedir = $urpm->{cachedir} || '/root'; |
566 |
require mirror; |
567 |
mirror::register_downloader( |
568 |
sub { |
569 |
my ($url) = @_; |
570 |
my $file = $url; |
571 |
$file =~ s!.*/!$cachedir/!; |
572 |
unlink $file; # prevent "partial file" errors |
573 |
before_leaving(sub { unlink $file }); |
574 |
|
575 |
my ($gurpm, $id, $canceled); |
576 |
# display a message in statusbar (if availlable): |
577 |
$::statusbar and $id = statusbar_msg( |
578 |
$branded |
579 |
? N("Please wait, downloading mirror addresses.") |
580 |
: N("Please wait, downloading mirror addresses from the Mageia website."), |
581 |
0); |
582 |
my $_clean_guard = before_leaving { |
583 |
undef $gurpm; |
584 |
$id and statusbar_msg_remove($id); |
585 |
}; |
586 |
|
587 |
require Rpmdrake::gurpm; |
588 |
require Rpmdrake::pkg; |
589 |
|
590 |
my $res = urpm::download::sync_url($urpm, $url, |
591 |
dir => $cachedir, |
592 |
callback => sub { |
593 |
$gurpm ||= |
594 |
Rpmdrake::gurpm->new(N("Please wait"), |
595 |
transient => $::main_window); |
596 |
$canceled ||= |
597 |
!Rpmdrake::pkg::download_callback($gurpm, @_); |
598 |
gtkflush(); |
599 |
}, |
600 |
); |
601 |
$res or die N("retrieval of [%s] failed", $file) . "\n"; |
602 |
return $canceled ? () : cat_($file); |
603 |
}); |
604 |
my @mirrors = @{ mirror::list(common::parse_LDAP_namespace_structure(cat_('/etc/product.id')), 'distrib') || [] }; |
605 |
require timezone; |
606 |
my $tz = ${timezone::read()}{timezone}; |
607 |
foreach my $mirror (@mirrors) { |
608 |
my $goodness; |
609 |
each_index { $_ = $u2l{$_} || $_; $_ eq $mirror->{country} and $goodness ||= 100-$::i } (map { if_($tz =~ /^$_$/, @{$t2l{$_}}) } keys %t2l), @$us; |
610 |
$mirror->{goodness} = $goodness + rand(); |
611 |
$mirror->{country} = translate($mirror->{country}); |
612 |
} |
613 |
unless (-x '/usr/bin/rsync') { |
614 |
@mirrors = grep { $_->{url} !~ /^rsync:/ } @mirrors; |
615 |
} |
616 |
return sort { $b->{goodness} <=> $a->{goodness} } @mirrors; |
617 |
} |
618 |
|
619 |
sub warn_for_network_need { |
620 |
my ($message, %options) = @_; |
621 |
$message ||= |
622 |
$branded |
623 |
? N("I need to access internet to get the mirror list. |
624 |
Please check that your network is currently running. |
625 |
|
626 |
Is it ok to continue?") |
627 |
: N("I need to contact the Mageia website to get the mirror list. |
628 |
Please check that your network is currently running. |
629 |
|
630 |
Is it ok to continue?"); |
631 |
interactive_msg(N("Mirror choice"), $message, yesno => 1, %options) or return ''; |
632 |
} |
633 |
|
634 |
sub choose_mirror { |
635 |
my ($urpm, %options) = @_; |
636 |
delete $options{message}; |
637 |
my @transient_options = exists $options{transient} ? (transient => $options{transient}) : (); |
638 |
warn_for_network_need($options{message}, %options) or return; |
639 |
my @mirrors = eval { mirrors($urpm, $options{want_base_distro}) }; |
640 |
my $error = $@; |
641 |
if ($error) { |
642 |
$error = "\n$error\n"; |
643 |
interactive_msg(N("Error during download"), |
644 |
($branded |
645 |
? N("There was an error downloading the mirror list: |
646 |
|
647 |
%s |
648 |
The network, or the website, may be unavailable. |
649 |
Please try again later.", $error) |
650 |
: N("There was an error downloading the mirror list: |
651 |
|
652 |
%s |
653 |
The network, or the Mageia website, may be unavailable. |
654 |
Please try again later.", $error)), %options |
655 |
|
656 |
); |
657 |
return ''; |
658 |
} |
659 |
|
660 |
!@mirrors and interactive_msg(N("No mirror"), |
661 |
($branded |
662 |
? N("I can't find any suitable mirror.") |
663 |
: N("I can't find any suitable mirror. |
664 |
|
665 |
There can be many reasons for this problem; the most frequent is |
666 |
the case when the architecture of your processor is not supported |
667 |
by Mageia Official Updates.")), %options |
668 |
), return ''; |
669 |
|
670 |
my $w = ugtk2->new(N("Mirror choice"), grab => 1, @transient_options); |
671 |
$w->{rwindow}->set_position($options{transient} ? 'center_on_parent' : 'center_always'); |
672 |
my $tree_model = Gtk2::TreeStore->new("Glib::String"); |
673 |
my $tree = Gtk2::TreeView->new_with_model($tree_model); |
674 |
$tree->get_selection->set_mode('browse'); |
675 |
$tree->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, text => 0)); |
676 |
$tree->set_headers_visible(0); |
677 |
|
678 |
gtkadd( |
679 |
$w->{window}, |
680 |
gtkpack_( |
681 |
Gtk2::VBox->new(0,5), |
682 |
0, N("Please choose the desired mirror."), |
683 |
1, create_scrolled_window($tree), |
684 |
0, gtkpack( |
685 |
create_hbox('edge'), |
686 |
map { |
687 |
my $retv = $_->[1]; |
688 |
gtksignal_connect( |
689 |
Gtk2::Button->new(but($_->[0])), |
690 |
clicked => sub { |
691 |
if ($retv) { |
692 |
my ($model, $iter) = $tree->get_selection->get_selected; |
693 |
$model and $w->{retval} = { sel => $model->get($iter, 0) }; |
694 |
} |
695 |
Gtk2->main_quit; |
696 |
}, |
697 |
); |
698 |
} [ N("Cancel"), 0 ], [ N("Ok"), 1 ] |
699 |
), |
700 |
) |
701 |
); |
702 |
my %roots; |
703 |
$tree_model->append_set($roots{$_->{country}} ||= $tree_model->append_set(undef, [ 0 => $_->{country} ]), |
704 |
[ 0 => $_->{url} ]) foreach @mirrors; |
705 |
|
706 |
$w->{window}->set_size_request(500, 400); |
707 |
$w->{rwindow}->show_all; |
708 |
|
709 |
my $path = Gtk2::TreePath->new_first; |
710 |
$tree->expand_row($path, 0); |
711 |
$path->down; |
712 |
$tree->get_selection->select_path($path); |
713 |
|
714 |
$w->main && return grep { $w->{retval}{sel} eq $_->{url} } @mirrors; |
715 |
} |
716 |
|
717 |
sub show_urpm_progress { |
718 |
my ($label, $pb, $mode, $file, $percent, $total, $eta, $speed) = @_; |
719 |
$file =~ s|([^:]*://[^/:\@]*:)[^/:\@]*(\@.*)|$1xxxx$2|; #- if needed... |
720 |
state $medium; |
721 |
if ($mode eq 'copy') { |
722 |
$pb->set_fraction(0); |
723 |
$label->set_label(N("Copying file for medium `%s'...", $file)); |
724 |
} elsif ($mode eq 'parse') { |
725 |
$pb->set_fraction(0); |
726 |
$label->set_label(N("Examining file of medium `%s'...", $file)); |
727 |
} elsif ($mode eq 'retrieve') { |
728 |
$pb->set_fraction(0); |
729 |
$label->set_label(N("Examining remote file of medium `%s'...", $file)); |
730 |
$medium = $file; |
731 |
} elsif ($mode eq 'done') { |
732 |
$pb->set_fraction(1.0); |
733 |
$label->set_label($label->get_label . N(" done.")); |
734 |
$medium = undef; |
735 |
} elsif ($mode eq 'failed') { |
736 |
$pb->set_fraction(1.0); |
737 |
$label->set_label($label->get_label . N(" failed!")); |
738 |
$medium = undef; |
739 |
} else { |
740 |
# FIXME: we're displaying misplaced quotes such as "downloading `foobar from 'medium Main Updates'ยด" |
741 |
$file = $medium && length($file) < 40 ? #-PO: We're downloading the said file from the said medium |
742 |
N("%s from medium %s", basename($file), $medium) |
743 |
: basename($file); |
744 |
if ($mode eq 'start') { |
745 |
$pb->set_fraction(0); |
746 |
$label->set_label(N("Starting download of `%s'...", $file)); |
747 |
} elsif ($mode eq 'progress') { |
748 |
if (defined $total && defined $eta) { |
749 |
$pb->set_fraction($percent/100); |
750 |
$label->set_label(N("Download of `%s'\ntime to go:%s, speed:%s", $file, $eta, $speed)); |
751 |
} else { |
752 |
$pb->set_fraction($percent/100); |
753 |
$label->set_label(N("Download of `%s'\nspeed:%s", $file, $speed)); |
754 |
} |
755 |
} |
756 |
} |
757 |
Gtk2->main_iteration while Gtk2->events_pending; |
758 |
} |
759 |
|
760 |
sub update_sources { |
761 |
my ($urpm, %options) = @_; |
762 |
my $cancel = 0; |
763 |
my $w; my $label; $w = wait_msg( |
764 |
$label = Gtk2::Label->new(N("Please wait, updating media...")), |
765 |
no_wait_cursor => 1, |
766 |
widgets => [ |
767 |
my $pb = gtkset_size_request(Gtk2::ProgressBar->new, 300, -1), |
768 |
gtkpack( |
769 |
create_hbox(), |
770 |
gtksignal_connect( |
771 |
Gtk2::Button->new(N("Cancel")), |
772 |
clicked => sub { |
773 |
$cancel = 1; |
774 |
$urpm->{error}->(N("Canceled")); |
775 |
$w and $w->destroy; |
776 |
}, |
777 |
), |
778 |
), |
779 |
], |
780 |
); |
781 |
my @media; @media = @{$options{medialist}} if ref $options{medialist}; |
782 |
my $outerfatal = $urpm->{fatal}; |
783 |
local $urpm->{fatal} = sub { $w->destroy; $outerfatal->(@_) }; |
784 |
urpm::media::update_those_media($urpm, [ urpm::media::select_media_by_name($urpm, \@media) ], |
785 |
%options, allow_failures => 1, |
786 |
callback => sub { |
787 |
$cancel and goto cancel_update; |
788 |
my ($type, $media) = @_; |
789 |
return if $type !~ /^(?:start|progress|end)$/ && @media && !member($media, @media); |
790 |
if ($type eq 'failed') { |
791 |
$urpm->{fatal}->(N("Error retrieving packages"), |
792 |
N("It's impossible to retrieve the list of new packages from the media |
793 |
`%s'. Either this update media is misconfigured, and in this case |
794 |
you should use the Software Media Manager to remove it and re-add it in order |
795 |
to reconfigure it, either it is currently unreachable and you should retry |
796 |
later.", |
797 |
$media)); |
798 |
} else { |
799 |
show_urpm_progress($label, $pb, @_); |
800 |
} |
801 |
}, |
802 |
); |
803 |
$w->destroy; |
804 |
cancel_update: |
805 |
} |
806 |
|
807 |
sub update_sources_check { |
808 |
my ($urpm, $options, $error_msg, @media) = @_; |
809 |
my @error_msgs; |
810 |
local $urpm->{fatal} = sub { push @error_msgs, $_[1]; goto fatal_error }; |
811 |
local $urpm->{error} = sub { push @error_msgs, $_[0] }; |
812 |
update_sources($urpm, %$options, noclean => 1, medialist => \@media); |
813 |
fatal_error: |
814 |
if (@error_msgs) { |
815 |
interactive_msg(N("Error"), sprintf(translate($error_msg), join("\n", map { formatAlaTeX($_) } @error_msgs)), scroll => 1); |
816 |
return 0; |
817 |
} |
818 |
return 1; |
819 |
} |
820 |
|
821 |
sub update_sources_interactive { |
822 |
my ($urpm, %options) = @_; |
823 |
my $w = ugtk2->new(N("Update media"), grab => 1, center => 1, %options); |
824 |
$w->{rwindow}->set_position($options{transient} ? 'center_on_parent' : 'center_always'); |
825 |
my @buttons; |
826 |
my @media = grep { ! $_->{ignore} } @{$urpm->{media}}; |
827 |
unless (@media) { |
828 |
interactive_msg(N("Warning"), N("No active medium found. You must enable some media to be able to update them.")); |
829 |
return 0; |
830 |
} |
831 |
gtkadd( |
832 |
$w->{window}, |
833 |
gtkpack_( |
834 |
0, Gtk2::VBox->new(0,5), |
835 |
0, Gtk2::Label->new(N("Select the media you wish to update:")), |
836 |
1, gtknew('ScrolledWindow', height => 300, child => |
837 |
# FIXME: using a listview would be just better: |
838 |
gtknew('VBox', spacing => 5, children_tight => [ |
839 |
@buttons = map { |
840 |
Gtk2::CheckButton->new_with_label($_->{name}); |
841 |
} @media |
842 |
]) |
843 |
), |
844 |
0, Gtk2::HSeparator->new, |
845 |
0, gtkpack( |
846 |
create_hbox(), |
847 |
gtksignal_connect( |
848 |
Gtk2::Button->new(N("Cancel")), |
849 |
clicked => sub { $w->{retval} = 0; Gtk2->main_quit }, |
850 |
), |
851 |
gtksignal_connect( |
852 |
Gtk2::Button->new(N("Select all")), |
853 |
clicked => sub { $_->set_active(1) foreach @buttons }, |
854 |
), |
855 |
gtksignal_connect( |
856 |
Gtk2::Button->new(N("Update")), |
857 |
clicked => sub { |
858 |
$w->{retval} = any { $_->get_active } @buttons; |
859 |
# list of media listed in the checkbox panel |
860 |
my @buttonmedia = grep { !$_->{ignore} } @{$urpm->{media}}; |
861 |
@media = map_index { if_($_->get_active, $buttonmedia[$::i]{name}) } @buttons; |
862 |
Gtk2->main_quit; |
863 |
}, |
864 |
), |
865 |
) |
866 |
) |
867 |
); |
868 |
if ($w->main) { |
869 |
return update_sources_noninteractive($urpm, \@media, %options); |
870 |
} |
871 |
return 0; |
872 |
} |
873 |
|
874 |
sub update_sources_noninteractive { |
875 |
my ($urpm, $media, %options) = @_; |
876 |
|
877 |
urpm::media::select_media($urpm, @$media); |
878 |
update_sources_check( |
879 |
$urpm, |
880 |
{}, |
881 |
N_("Unable to update medium; it will be automatically disabled.\n\nErrors:\n%s"), |
882 |
@$media, |
883 |
); |
884 |
return 1; |
885 |
} |
886 |
|
887 |
sub add_medium_and_check { |
888 |
my ($urpm, $options) = splice @_, 0, 2; |
889 |
my @newnames = ($_[0]); #- names of added media |
890 |
my $fatal_msg; |
891 |
my @error_msgs; |
892 |
local $urpm->{fatal} = sub { printf STDERR "Fatal: %s\n", $_[1]; $fatal_msg = $_[1]; goto fatal_error }; |
893 |
local $urpm->{error} = sub { printf STDERR "Error: %s\n", $_[0]; push @error_msgs, $_[0] }; |
894 |
if ($options->{distrib}) { |
895 |
@newnames = urpm::media::add_distrib_media($urpm, @_); |
896 |
} else { |
897 |
urpm::media::add_medium($urpm, @_); |
898 |
} |
899 |
if (@error_msgs) { |
900 |
interactive_msg( |
901 |
N("Error"), |
902 |
N("Unable to add medium, errors reported:\n\n%s", |
903 |
join("\n", map { formatAlaTeX($_) } @error_msgs)) . "\n\n" . N("Medium: ") . "$_[0] ($_[1])", |
904 |
scroll => 1, |
905 |
); |
906 |
return 0; |
907 |
} |
908 |
|
909 |
foreach my $name (@newnames) { |
910 |
urpm::download::set_proxy_config($_, $options->{proxy}{$_}, $name) foreach keys %{$options->{proxy} || {}}; |
911 |
} |
912 |
|
913 |
if (update_sources_check($urpm, $options, N_("Unable to add medium, errors reported:\n\n%s"), @newnames)) { |
914 |
urpm::media::write_config($urpm); |
915 |
$options->{proxy} and urpm::download::dump_proxy_config(); |
916 |
} else { |
917 |
urpm::media::read_config($urpm); |
918 |
return 0; |
919 |
} |
920 |
|
921 |
my %newnames; @newnames{@newnames} = (); |
922 |
if (any { exists $newnames{$_->{name}} } @{$urpm->{media}}) { |
923 |
return 1; |
924 |
} else { |
925 |
interactive_msg(N("Error"), N("Unable to create medium.")); |
926 |
return 0; |
927 |
} |
928 |
|
929 |
fatal_error: |
930 |
interactive_msg(N("Failure when adding medium"), |
931 |
N("There was a problem adding medium:\n\n%s", $fatal_msg)); |
932 |
return 0; |
933 |
} |
934 |
|
935 |
#- Check whether the default update media (added by installation) |
936 |
#- matches the current mdk version |
937 |
sub check_update_media_version { |
938 |
my $urpm = shift; |
939 |
foreach (@_) { |
940 |
if ($_->{name} =~ /(\d+\.\d+).*\bftp\du\b/ && $1 ne $mdk_version) { |
941 |
interactive_msg( |
942 |
N("Warning"), |
943 |
$branded |
944 |
? N("Your medium `%s', used for updates, does not match the version of %s you're running (%s). |
945 |
It will be disabled.", |
946 |
$_->{name}, $distrib{system}, $distrib{product}) |
947 |
: N("Your medium `%s', used for updates, does not match the version of Mageia you're running (%s). |
948 |
It will be disabled.", |
949 |
$_->{name}, $mdk_version) |
950 |
); |
951 |
$_->{ignore} = 1; |
952 |
urpm::media::write_config($urpm) if -w $urpm->{config}; |
953 |
return 0; |
954 |
} |
955 |
} |
956 |
1; |
957 |
} |
958 |
|
959 |
sub add_distrib_update_media { |
960 |
my ($urpm, $mirror, %options) = @_; |
961 |
#- ensure a unique medium name |
962 |
my $medium_name = $rpmdrake::mandrake_release =~ /(\d+\.\d+) \((\w+)\)/ ? $2 . $1 . '-' : 'distrib'; |
963 |
my $initial_number = 1 + max map { $_->{name} =~ /\(\Q$medium_name\E(\d+)\b/ ? $1 : 0 } @{$urpm->{media}}; |
964 |
add_medium_and_check( |
965 |
$urpm, |
966 |
{ nolock => 1, distrib => 1 }, |
967 |
$medium_name, |
968 |
($mirror ? $mirror->{url} : (undef, mirrorlist => '$MIRRORLIST')), |
969 |
probe_with => 'synthesis', initial_number => $initial_number, %options, |
970 |
usedistrib => 1, |
971 |
); |
972 |
} |
973 |
|
974 |
sub open_help { |
975 |
my ($mode) = @_; |
976 |
use run_program; |
977 |
run_program::raw({ detach => 1, as_user => 1 }, 'drakhelp', '--id', $mode ? "software-management-$mode" : 'software-management'); |
978 |
N("Help launched in background"); |
979 |
statusbar_msg(N("The help window has been started, it should appear shortly on your desktop."), 1); |
980 |
} |
981 |
|
982 |
sub run_drakbug { |
983 |
my ($id) = @_; |
984 |
run_program::raw({ detach => 1, as_user => 1 }, 'drakbug', '--report', $id); |
985 |
} |
986 |
|
987 |
mygtk2::add_icon_path('/usr/share/mcc/themes/default/'); |
988 |
sub get_icon { |
989 |
my ($mcc_icon, $fallback_icon) = @_; |
990 |
my $icon = eval { mygtk2::_find_imgfile($mcc_icon) }; |
991 |
$icon ||= eval { mygtk2::_find_imgfile($fallback_icon) }; |
992 |
$icon; |
993 |
} |
994 |
|
995 |
sub strip_first_underscore { join '', map { s/_//; $_ } @_ } |
996 |
|
997 |
1; |