aboutsummaryrefslogtreecommitdiffstats
path: root/AdminPanel
diff options
context:
space:
mode:
authorMatteo Pasotti <matteo@mageia.org>2013-01-07 17:17:05 +0000
committerMatteo Pasotti <matteo@mageia.org>2013-01-07 17:17:05 +0000
commit7ff32d873460c70bc158a8cc38c04132926e5791 (patch)
tree687ddd2060e10fc9cf530870f46c96442b623566 /AdminPanel
parent80b79c965d0fa811d8c6433fd999bfaebe48d2f2 (diff)
downloadcolin-keep-7ff32d873460c70bc158a8cc38c04132926e5791.tar
colin-keep-7ff32d873460c70bc158a8cc38c04132926e5791.tar.gz
colin-keep-7ff32d873460c70bc158a8cc38c04132926e5791.tar.bz2
colin-keep-7ff32d873460c70bc158a8cc38c04132926e5791.tar.xz
colin-keep-7ff32d873460c70bc158a8cc38c04132926e5791.zip
- imported rpmdragora module (still under development)
Diffstat (limited to 'AdminPanel')
-rw-r--r--AdminPanel/Rpmdragora/.perl_checker1
-rw-r--r--AdminPanel/Rpmdragora/edit_urpm_sources.pm1215
-rw-r--r--AdminPanel/Rpmdragora/formatting.pm177
-rw-r--r--AdminPanel/Rpmdragora/gui.pm1105
-rw-r--r--AdminPanel/Rpmdragora/gurpm.pm133
-rw-r--r--AdminPanel/Rpmdragora/icon.pm231
-rw-r--r--AdminPanel/Rpmdragora/init.pm168
-rw-r--r--AdminPanel/Rpmdragora/open_db.pm161
-rw-r--r--AdminPanel/Rpmdragora/pkg.pm990
-rw-r--r--AdminPanel/Rpmdragora/rpmnew.pm204
-rw-r--r--AdminPanel/Rpmdragora/widgets.pm51
-rw-r--r--AdminPanel/Shared.pm4
-rw-r--r--AdminPanel/rpmdragora.pm989
13 files changed, 5427 insertions, 2 deletions
diff --git a/AdminPanel/Rpmdragora/.perl_checker b/AdminPanel/Rpmdragora/.perl_checker
new file mode 100644
index 0000000..202e053
--- /dev/null
+++ b/AdminPanel/Rpmdragora/.perl_checker
@@ -0,0 +1 @@
+Basedir ..
diff --git a/AdminPanel/Rpmdragora/edit_urpm_sources.pm b/AdminPanel/Rpmdragora/edit_urpm_sources.pm
new file mode 100644
index 0000000..7f8a254
--- /dev/null
+++ b/AdminPanel/Rpmdragora/edit_urpm_sources.pm
@@ -0,0 +1,1215 @@
+package AdminPanel::Rpmdragora::edit_urpm_sources;
+#*****************************************************************************
+#
+# Copyright (c) 2002 Guillaume Cottenceau
+# Copyright (c) 2002-2007 Thierry Vignaud <tvignaud@mandriva.com>
+# Copyright (c) 2002-2007 Mandriva Linux
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2, as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#*****************************************************************************
+#
+# $Id: edit_urpm_sources.pm 266598 2010-03-03 12:00:58Z tv $
+
+
+use strict;
+use lib qw(/usr/lib/libDrakX);
+use common;
+use AdminPanel::rpmdragora;
+use AdminPanel::Rpmdragora::open_db;
+use AdminPanel::Rpmdragora::formatting;
+use URPM::Signature;
+use MDK::Common::Math qw(max);
+use urpm::media;
+use urpm::download;
+use urpm::lock;
+
+use Exporter;
+our @ISA = qw(Exporter);
+our @EXPORT = qw(run);
+
+#use mygtk2 qw(gtknew gtkset);
+#use ugtk2 qw(:all);
+
+my $urpm;
+my ($mainw, $list_tv, $something_changed);
+
+my %col = (
+ mainw => {
+ is_enabled => 0,
+ is_update => 1,
+ type => 2,
+ name => 3,
+ activatable => 4
+ },
+);
+
+
+sub get_medium_type {
+ my ($medium) = @_;
+ my %medium_type = (
+ cdrom => N("CD-ROM"),
+ ftp => N("FTP"),
+ file => N("Local"),
+ http => N("HTTP"),
+ https => N("HTTPS"),
+ nfs => N("NFS"),
+ removable => N("Removable"),
+ rsync => N("rsync"),
+ ssh => N("NFS"),
+ );
+ return N("Mirror list") if $medium->{mirrorlist};
+ return $medium_type{$1} if $medium->{url} =~ m!^([^:]*)://!;
+ return N("Local");
+}
+
+sub selrow {
+ my ($o_list_tv) = @_;
+ defined $o_list_tv or $o_list_tv = $list_tv;
+ my ($model, $iter) = $o_list_tv->get_selection->get_selected;
+ $model && $iter or return -1;
+ my $path = $model->get_path($iter);
+ my $row = $path->to_string;
+ return $row;
+}
+
+sub selected_rows {
+ my ($o_list_tv) = @_;
+ defined $o_list_tv or $o_list_tv = $list_tv;
+ my (@rows) = $o_list_tv->get_selection->get_selected_rows;
+ return -1 if @rows == 0;
+ map { $_->to_string } @rows;
+}
+
+sub remove_row {
+ my ($model, $path_str) = @_;
+ my $iter = $model->get_iter_from_string($path_str);
+ $iter or return;
+ $model->remove($iter);
+}
+
+sub remove_from_list {
+ my ($list, $list_ref, $model) = @_;
+ my $row = selrow($list);
+ if ($row != -1) {
+ splice @$list_ref, $row, 1;
+ remove_row($model, $row);
+ }
+
+}
+
+sub _want_base_distro() {
+ distro_type(0) eq 'updates' ? interactive_msg(
+ N("Choose media type"),
+N("In order to keep your system secure and stable, you must at a minimum set up
+sources for official security and stability updates. You can also choose to set
+up a fuller set of sources which includes the complete official Mageia
+repositories, giving you access to more software than can fit on the Mageia
+discs. Please choose whether to configure update sources only, or the full set
+of sources."),
+ transient => $::main_window,
+ yesno => 1, text => { yes => N("Full set of sources"), no => N("Update sources only") },
+ ) : 1;
+}
+
+sub easy_add_callback_with_mirror() {
+ # when called on early init by rpmdragora
+ $urpm ||= fast_open_urpmi_db();
+
+ #- cooker and community don't have update sources
+ my $want_base_distro = _want_base_distro();
+ defined $want_base_distro or return;
+ my $distro = $rpmdragora::mandrake_release;
+ my ($mirror) = choose_mirror($urpm, message =>
+N("This will attempt to install all official sources corresponding to your
+distribution (%s).
+
+I need to contact the Mageia website to get the mirror list.
+Please check that your network is currently running.
+
+Is it ok to continue?", $distro),
+ transient => $::main_window,
+ ) or return 0;
+ ref $mirror or return;
+ my $wait = wait_msg(N("Please wait, adding media..."));
+ add_distrib_update_media($urpm, $mirror, if_(!$want_base_distro, only_updates => 1));
+ $offered_to_add_sources->[0] = 1;
+ remove_wait_msg($wait);
+ return 1;
+}
+
+sub easy_add_callback() {
+ # when called on early init by rpmdragora
+ $urpm ||= fast_open_urpmi_db();
+
+ #- cooker and community don't have update sources
+ my $want_base_distro = _want_base_distro();
+ defined $want_base_distro or return;
+ warn_for_network_need(undef, transient => $::main_window) or return;
+ my $wait = wait_msg(N("Please wait, adding media..."));
+ add_distrib_update_media($urpm, undef, if_(!$want_base_distro, only_updates => 1));
+ $offered_to_add_sources->[0] = 1;
+ remove_wait_msg($wait);
+ return 1;
+}
+
+sub add_callback() {
+ my $w = ugtk2->new(N("Add a medium"), grab => 1, center => 1, transient => $::main_window);
+ my $prev_main_window = $::main_window;
+ local $::main_window = $w->{real_window};
+ my %radios_infos = (
+ local => { name => N("Local files"), url => N("Medium path:"), dirsel => 1 },
+ ftp => { name => N("FTP server"), url => N("URL:"), loginpass => 1 },
+ rsync => { name => N("RSYNC server"), url => N("URL:") },
+ http => { name => N("HTTP server"), url => N("URL:") },
+ removable => { name => N("Removable device (CD-ROM, DVD, ...)"), url => N("Path or mount point:"), dirsel => 1 },
+ );
+ my @radios_names_ordered = qw(local ftp rsync http removable);
+ # TODO: replace NoteBook by sensitive widgets and Label->set()
+ my $notebook = gtknew('Notebook');
+ $notebook->set_show_tabs(0); $notebook->set_show_border(0);
+ my ($count_nbs, %pages);
+ my $size_group = Gtk2::SizeGroup->new('horizontal');
+ my ($cb1, $cb2);
+ foreach (@radios_names_ordered) {
+ my $info = $radios_infos{$_};
+ my $url_entry = sub {
+ gtkpack_(
+ gtknew('HBox'),
+ 1, $info->{url_entry} = gtkentry(),
+ if_(
+ $info->{dirsel},
+ 0, gtksignal_connect(
+ gtknew('Button', text => but(N("Browse..."))),
+ clicked => sub { $info->{url_entry}->set_text(ask_dir()) },
+ )
+ ),
+ );
+ };
+ my $checkbut_entry = sub {
+ my ($name, $label, $visibility, $callback, $tip) = @_;
+ my $w = [ gtksignal_connect(
+ $info->{$name . '_check'} = gtkset(gtknew('CheckButton', text => $label), tip => $tip),
+ clicked => sub {
+ $info->{$name . '_entry'}->set_sensitive($_[0]->get_active);
+ $callback and $callback->(@_);
+ },
+ ),
+ gtkset_visibility(gtkset_sensitive($info->{$name . '_entry'} = gtkentry(), 0), $visibility) ];
+ $size_group->add_widget($info->{$name . '_check'});
+ $w;
+ };
+ my $loginpass_entries = sub {
+ map {
+ $checkbut_entry->(
+ @$_, sub {
+ $info->{pass_check}->set_active($_[0]->get_active);
+ $info->{login_check}->set_active($_[0]->get_active);
+ }
+ );
+ } ([ 'login', N("Login:"), 1 ], [ 'pass', N("Password:"), 0 ]);
+ };
+ $pages{$info->{name}} = $count_nbs++;
+ $notebook->append_page(
+ gtkshow(create_packtable(
+ { xpadding => 0, ypadding => 0 },
+ [ gtkset_alignment(gtknew('Label', text => N("Medium name:")), 0, 0.5),
+ $info->{name_entry} = gtkentry('') ],
+ [ gtkset_alignment(gtknew('Label', text => $info->{url}), 0, 0.5),
+ $url_entry->() ],
+ if_($info->{loginpass}, $loginpass_entries->()),
+ sub {
+ [ $info->{distrib_check} = $cb1 = gtknew('CheckButton', text => N("Create media for a whole distribution"),
+ toggled => sub {
+ return if !$cb2;
+ my ($w) = @_;
+ $info->{update_check}->set_sensitive(!$w->get_active);
+ })
+ ];
+ }->(),
+ sub {
+ [ $info->{update_check} = $cb2 = gtknew('CheckButton', text => N("Tag this medium as an update medium")) ];
+ }->(),
+ ))
+ );
+ }
+ $size_group->add_widget($_) foreach $cb1, $cb2;
+
+ my $checkok = sub {
+ my $info = $radios_infos{$radios_names_ordered[$notebook->get_current_page]};
+ my ($name, $url) = map { $info->{$_ . '_entry'}->get_text } qw(name url);
+ $name eq '' || $url eq '' and interactive_msg('rpmdragora', N("You need to fill up at least the two first entries.")), return 0;
+ if (member($name, map { $_->{name} } @{$urpm->{media}})) {
+ $info->{name_entry}->select_region(0, -1);
+ interactive_msg('rpmdragora',
+N("There is already a medium by that name, do you
+really want to replace it?"), yesno => 1) or return 0;
+ }
+ 1;
+ };
+
+ my $type = 'local';
+ my (%i, %make_url);
+ gtkadd(
+ $w->{window},
+ gtkpack(
+ gtknew('VBox', spacing => 5),
+ gtknew('Title2', label => N("Adding a medium:")),
+ gtknew('HBox', children_tight => [
+ Gtk2::Label->new(but(N("Type of medium:"))),
+ gtknew('ComboBox', text_ref => \$type,
+ list => \@radios_names_ordered,
+ format => sub { $radios_infos{$_[0]}{name} },
+ changed => sub { $notebook->set_current_page($pages{$_[0]->get_text}) })
+ ]),
+ $notebook,
+ gtknew('HSeparator'),
+ gtkpack(
+ gtknew('HButtonBox'),
+ gtknew('Button', text => N("Cancel"), clicked => sub { $w->{retval} = 0; Gtk2->main_quit }),
+ gtksignal_connect(
+ gtknew('Button', text => N("Ok")), clicked => sub {
+ if ($checkok->()) {
+ $w->{retval} = { nb => $notebook->get_current_page };
+ my $info = $radios_infos{$type};
+ %i = (
+ name => $info->{name_entry}->get_text,
+ url => $info->{url_entry}->get_text,
+ distrib => $info->{distrib_check} ? $info->{distrib_check}->get_active : 0,
+ update => $info->{update_check}->get_active ? 1 : undef,
+ );
+ %make_url = (
+ local => "file:/$i{url}",
+ http => $i{url},
+ rsync => $i{url},
+ removable => "removable:/$i{url}",
+ );
+ $i{url} =~ s|^ftp://||;
+ $make_url{ftp} = sprintf "ftp://%s%s",
+ $info->{login_check}->get_active
+ ? ($info->{login_entry}->get_text . ':' . $info->{pass_entry}->get_text . '@')
+ : '',
+ $i{url};
+ Gtk2->main_quit;
+ }
+ },
+ ),
+ ),
+ ),
+ );
+
+ if ($w->main) {
+ $::main_window = $prev_main_window;
+ if ($i{distrib}) {
+ add_medium_and_check(
+ $urpm,
+ { nolock => 1, distrib => 1 },
+ $i{name}, $make_url{$type}, probe_with => 'synthesis', update => $i{update},
+ );
+ } else {
+ if (member($i{name}, map { $_->{name} } @{$urpm->{media}})) {
+ urpm::media::select_media($urpm, $i{name});
+ urpm::media::remove_selected_media($urpm);
+ }
+ add_medium_and_check(
+ $urpm,
+ { nolock => 1 },
+ $i{name}, $make_url{$type}, $i{hdlist}, update => $i{update},
+ );
+ }
+ return 1;
+ }
+ return 0;
+}
+
+sub options_callback() {
+ my $w = ugtk2->new(N("Global options for package installation"), grab => 1, center => 1, transient => $::main_window);
+ local $::main_window = $w->{real_window};
+ my %verif = (0 => N("never"), 1 => N("always"));
+ my $verify_rpm = $urpm->{global_config}{'verify-rpm'};
+ my @avail_downloaders = urpm::download::available_ftp_http_downloaders();
+ my $downloader = $urpm->{global_config}{downloader} || $avail_downloaders[0];
+ my %xml_info_policies = (
+ 'never' => N("Never"),
+ 'on-demand' => N("On-demand"),
+ 'update-only' => N("Update-only"),
+ 'always' => N("Always"),
+ );
+ my $xml_info_policy = $urpm->{global_config}{'xml-info'};
+
+ gtkadd(
+ $w->{window},
+ gtkpack(
+ gtknew('VBox', spacing => 5),
+ gtknew('HBox', children_loose => [ gtknew('Label', text => N("Verify RPMs to be installed:")),
+ gtknew('ComboBox', list => [ keys %verif ], text_ref => \$verify_rpm,
+ format => sub { $verif{$_[0]} || $_[0] },
+ )
+ ]),
+ gtknew('HBox', children_loose => [ gtknew('Label', text => N("Download program to use:")),
+ gtknew('ComboBox', list => \@avail_downloaders, text_ref => \$downloader,
+ format => sub { $verif{$_[0]} || $_[0] },
+ )
+ ]),
+ gtknew('HBox',
+ children_loose =>
+ [ gtknew('Label', text => N("XML meta-data download policy:")),
+ gtknew('ComboBox',
+ list => [ keys %xml_info_policies ], text_ref => \$xml_info_policy,
+
+ format => sub { $xml_info_policies{$_[0]} || $_[0] },
+ tip =>
+ join("\n",
+ N("For remote media, specify when XML meta-data (file lists, changelogs & information) are downloaded."),
+ '',
+ N("Never"),
+ N("For remote media, XML meta-data are never downloaded."),
+ '',
+ N("On-demand"),
+ N("(This is the default)"),
+ N("The specific XML info file is downloaded when clicking on package."),
+ '',
+ N("Update-only"),
+ N("Updating media implies updating XML info files already required at least once."),
+ '',
+ N("Always"),
+ N("All XML info files are downloaded when adding or updating media."),
+ ),
+ ),
+ ]),
+
+ gtkpack(
+ gtknew('HButtonBox'),
+ gtknew('Button', text => N("Cancel"), clicked => sub { Gtk2->main_quit }),
+ gtksignal_connect(
+ gtknew('Button', text => N("Ok")), clicked => sub {
+ $urpm->{global_config}{'verify-rpm'} = $verify_rpm;
+ $urpm->{global_config}{downloader} = $downloader;
+ $urpm->{global_config}{'xml-info'} = $xml_info_policy;
+ $something_changed = 1;
+ urpm::media::write_config($urpm);
+ $urpm = fast_open_urpmi_db();
+ Gtk2->main_quit;
+ },
+ ),
+ ),
+ ),
+ );
+ $w->main;
+}
+
+sub remove_callback() {
+ my @rows = selected_rows();
+ @rows == 0 and return;
+ interactive_msg(
+ N("Source Removal"),
+ @rows == 1 ?
+ N("Are you sure you want to remove source \"%s\"?", $urpm->{media}[$rows[0]]{name}) :
+ N("Are you sure you want to remove the following sources?") . "\n\n" .
+ format_list(map { $urpm->{media}[$_]{name} } @rows),
+ yesno => 1, scroll => 1,
+ transient => $::main_window,
+ ) or return;
+
+ my $wait = wait_msg(N("Please wait, removing medium..."));
+ foreach my $row (reverse(@rows)) {
+ $something_changed = 1;
+ urpm::media::remove_media($urpm, [ $urpm->{media}[$row] ]);
+ urpm::media::write_urpmi_cfg($urpm);
+ remove_wait_msg($wait);
+ }
+ return 1;
+}
+
+sub renum_media ($$$) {
+ my ($model, @iters) = @_;
+ my @rows = map { $model->get_path($_)->to_string } @iters;
+ my @media = map { $urpm->{media}[$_] } @rows;
+ $urpm->{media}[$rows[$_]] = $media[1 - $_] foreach 0, 1;
+ $model->swap(@iters);
+ $something_changed = 1;
+ urpm::media::write_config($urpm);
+ $urpm = fast_open_urpmi_db();
+}
+
+sub upwards_callback() {
+ my @rows = selected_rows();
+ @rows == 0 and return;
+ my $model = $list_tv->get_model;
+ my $prev = $model->get_iter_from_string($rows[0] - 1);
+ defined $prev and renum_media($model, $model->get_iter_from_string($rows[0]), $prev);
+ $list_tv->get_selection->signal_emit('changed');
+}
+
+sub downwards_callback() {
+ my @rows = selected_rows();
+ @rows == 0 and return;
+ my $model = $list_tv->get_model;
+ my $iter = $model->get_iter_from_string($rows[0]);
+ my $next = $model->iter_next($iter);
+ defined $next and renum_media($model, $iter, $next);
+ $list_tv->get_selection->signal_emit('changed');
+}
+
+#- returns the name of the media for which edition failed, or undef on success
+sub edit_callback() {
+ my ($row) = selected_rows();
+ $row == -1 and return;
+ my $medium = $urpm->{media}[$row];
+ my $config = urpm::cfg::load_config_raw($urpm->{config}, 1);
+ my ($verbatim_medium) = grep { $medium->{name} eq $_->{name} } @$config;
+ my $old_main_window = $::main_window;
+ my $w = ugtk2->new(N("Edit a medium"), grab => 1, center => 1, transient => $::main_window);
+ local $::main_window = $w->{real_window};
+ my ($url_entry, $downloader_entry, $url, $downloader);
+ gtkadd(
+ $w->{window},
+ gtkpack_(
+ gtknew('VBox', spacing => 5),
+ 0, gtknew('Title2', label => N("Editing medium \"%s\":", $medium->{name})),
+ 0, create_packtable(
+ {},
+ [ gtknew('Label_Left', text => N("URL:")), $url_entry = gtkentry($verbatim_medium->{url} || $verbatim_medium->{mirrorlist}) ],
+ [ gtknew('Label_Left', text => N("Downloader:")),
+ my $download_combo = Gtk2::ComboBox->new_with_strings([ urpm::download::available_ftp_http_downloaders() ],
+ $verbatim_medium->{downloader} || '') ],
+ ),
+ 0, gtknew('HSeparator'),
+ 0, gtkpack(
+ gtknew('HButtonBox'),
+ gtksignal_connect(
+ gtknew('Button', text => N("Cancel")),
+ clicked => sub { $w->{retval} = 0; Gtk2->main_quit },
+ ),
+ gtksignal_connect(
+ gtknew('Button', text => N("Save changes")),
+ clicked => sub {
+ $w->{retval} = 1;
+ $url = $url_entry->get_text;
+ $downloader = $downloader_entry->get_text;
+ Gtk2->main_quit;
+ },
+ ),
+ gtksignal_connect(
+ gtknew('Button', text => N("Proxy...")),
+ clicked => sub { proxy_callback($medium) },
+ ),
+ )
+ )
+ );
+ $downloader_entry = $download_combo->entry;
+ $w->{rwindow}->set_size_request(600, -1);
+ if ($w->main) {
+ my ($name, $update) = map { $medium->{$_} } qw(name update);
+ $url =~ m|^removable://| and (
+ interactive_msg(
+ N("You need to insert the medium to continue"),
+ N("In order to save the changes, you need to insert the medium in the drive."),
+ yesno => 1, text => { yes => N("Ok"), no => N("Cancel") }
+ ) or return 0
+ );
+ my $saved_proxy = urpm::download::get_proxy($name);
+ undef $saved_proxy if !defined $saved_proxy->{http_proxy} && !defined $saved_proxy->{ftp_proxy};
+ urpm::media::select_media($urpm, $name);
+ if (my ($media) = grep { $_->{name} eq $name } @{$urpm->{media}}) {
+ put_in_hash($media, {
+ ($verbatim_medium->{mirrorlist} ? 'mirrorlist' : 'url') => $url,
+ name => $name,
+ if_($update ne $media->{update} || $update, update => $update),
+ if_($saved_proxy ne $media->{proxy} || $saved_proxy, proxy => $saved_proxy),
+ if_($downloader ne $media->{downloader} || $downloader, downloader => $downloader),
+ modified => 1,
+ });
+ urpm::media::write_config($urpm);
+ local $::main_window = $old_main_window;
+ update_sources_noninteractive($urpm, [ $name ], transient => $::main_window, nolock => 1);
+ } else {
+ urpm::media::remove_selected_media($urpm);
+ add_medium_and_check($urpm, { nolock => 1, proxy => $saved_proxy }, $name, $url, undef, update => $update, if_($downloader, downloader => $downloader));
+ }
+ return $name;
+ }
+ return undef;
+}
+
+sub update_callback() {
+ update_sources_interactive($urpm, transient => $::main_window, nolock => 1);
+}
+
+sub proxy_callback {
+ my ($medium) = @_;
+ my $medium_name = $medium ? $medium->{name} : '';
+ my $w = ugtk2->new(N("Configure proxies"), grab => 1, center => 1, transient => $::main_window);
+ local $::main_window = $w->{real_window};
+ require curl_download;
+ my ($proxy, $proxy_user) = curl_download::readproxy($medium_name);
+ my ($user, $pass) = $proxy_user =~ /^([^:]*):(.*)$/;
+ my ($proxybutton, $proxyentry, $proxyuserbutton, $proxyuserentry, $proxypasswordentry);
+ my $sg = Gtk2::SizeGroup->new('horizontal');
+ gtkadd(
+ $w->{window},
+ gtkpack__(
+ gtknew('VBox', spacing => 5),
+ gtknew('Title2', label =>
+ $medium_name
+ ? N("Proxy settings for media \"%s\"", $medium_name)
+ : N("Global proxy settings")
+ ),
+ gtknew('Label_Left', text => N("If you need a proxy, enter the hostname and an optional port (syntax: <proxyhost[:port]>):")),
+ gtkpack_(
+ gtknew('HBox', spacing => 10),
+ 1, gtkset_active($proxybutton = gtknew('CheckButton', text => N("Proxy hostname:")), to_bool($proxy)),
+ 0, gtkadd_widget($sg, gtkset_sensitive($proxyentry = gtkentry($proxy), to_bool($proxy))),
+ ),
+ gtkset_active($proxyuserbutton = gtknew('CheckButton', text => N("You may specify a username/password for the proxy authentication:")), to_bool($proxy_user)),
+ gtkpack_(
+ my $hb_user = gtknew('HBox', spacing => 10, sensitive => to_bool($proxy_user)),
+ 1, gtknew('Label_Left', text => N("User:")),
+ 0, gtkadd_widget($sg, $proxyuserentry = gtkentry($user)),
+ ),
+ gtkpack_(
+ my $hb_pswd = gtknew('HBox', spacing => 10, sensitive => to_bool($proxy_user)),
+ 1, gtknew('Label_Left', text => N("Password:")),
+ 0, gtkadd_widget($sg, gtkset_visibility($proxypasswordentry = gtkentry($pass), 0)),
+ ),
+ gtknew('HSeparator'),
+ gtkpack(
+ gtknew('HButtonBox'),
+ gtksignal_connect(
+ gtknew('Button', text => N("Ok")),
+ clicked => sub {
+ $w->{retval} = 1;
+ $proxy = $proxybutton->get_active ? $proxyentry->get_text : '';
+ $proxy_user = $proxyuserbutton->get_active
+ ? ($proxyuserentry->get_text . ':' . $proxypasswordentry->get_text) : '';
+ Gtk2->main_quit;
+ },
+ ),
+ gtksignal_connect(
+ gtknew('Button', text => N("Cancel")),
+ clicked => sub { $w->{retval} = 0; Gtk2->main_quit },
+ )
+ )
+ )
+ );
+ $sg->add_widget($_) foreach $proxyentry, $proxyuserentry, $proxypasswordentry;
+ $proxybutton->signal_connect(
+ clicked => sub {
+ $proxyentry->set_sensitive($_[0]->get_active);
+ $_[0]->get_active and return;
+ $proxyuserbutton->set_active(0);
+ $hb_user->set_sensitive(0);
+ $hb_pswd->set_sensitive(0);
+ }
+ );
+ $proxyuserbutton->signal_connect(clicked => sub { $_->set_sensitive($_[0]->get_active) foreach $hb_user, $hb_pswd;
+ $proxypasswordentry->set_sensitive($_[0]->get_active) });
+
+ $w->main and do {
+ $something_changed = 1;
+ curl_download::writeproxy($proxy, $proxy_user, $medium_name);
+ };
+}
+
+sub parallel_read_sysconf() {
+ my @conf;
+ foreach (cat_('/etc/urpmi/parallel.cfg')) {
+ my ($name, $protocol, $command) = /([^:]+):([^:]+):(.*)/ or print STDERR "Warning, unrecognized line in /etc/urpmi/parallel.cfg:\n$_";
+ my $medias = $protocol =~ s/\(([^\)]+)\)$// ? [ split /,/, $1 ] : [];
+ push @conf, { name => $name, protocol => $protocol, medias => $medias, command => $command };
+ }
+ \@conf;
+}
+
+sub parallel_write_sysconf {
+ my ($conf) = @_;
+ output '/etc/urpmi/parallel.cfg',
+ map { my $m = @{$_->{medias}} ? '(' . join(',', @{$_->{medias}}) . ')' : '';
+ "$_->{name}:$_->{protocol}$m:$_->{command}\n" } @$conf;
+}
+
+sub remove_parallel {
+ my ($num, $conf) = @_;
+ if ($num != -1) {
+ splice @$conf, $num, 1;
+ parallel_write_sysconf($conf);
+ }
+}
+
+sub add_callback_ {
+ my ($title, $label, $mainw, $widget, $get_value, $check) = @_;
+ my $w = ugtk2->new($title, grab => 1, transient => $mainw->{real_window});
+ local $::main_window = $w->{real_window};
+ gtkadd(
+ $w->{window},
+ gtkpack__(
+ gtknew('VBox', spacing => 5),
+ gtknew('Label', text => $label),
+ $widget,
+ gtknew('HSeparator'),
+ gtkpack(
+ gtknew('HButtonBox'),
+ gtknew('Button', text => N("Ok"), clicked => sub { $w->{retval} = 1; $get_value->(); Gtk2->main_quit }),
+ gtknew('Button', text => N("Cancel"), clicked => sub { $w->{retval} = 0; Gtk2->main_quit })
+ )
+ )
+ );
+ $check->() if $w->main;
+}
+
+sub edit_parallel {
+ my ($num, $conf) = @_;
+ my $edited = $num == -1 ? {} : $conf->[$num];
+ my $w = ugtk2->new($num == -1 ? N("Add a parallel group") : N("Edit a parallel group"), grab => 1, center => 1, transient => $::main_window);
+ local $::main_window = $w->{real_window};
+ my $name_entry;
+
+ my ($medias_ls, $hosts_ls) = (Gtk2::ListStore->new("Glib::String"), Gtk2::ListStore->new("Glib::String"));
+
+ my ($medias, $hosts) = map {
+ my $list = Gtk2::TreeView->new_with_model($_);
+ $list->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, 'text' => 0));
+ $list->set_headers_visible(0);
+ $list->get_selection->set_mode('browse');
+ $list;
+ } $medias_ls, $hosts_ls;
+
+ $medias_ls->append_set([ 0 => $_ ]) foreach @{$edited->{medias}};
+
+ my $add_media = sub {
+ my $medias_list_ls = Gtk2::ListStore->new("Glib::String");
+ my $medias_list = Gtk2::TreeView->new_with_model($medias_list_ls);
+ $medias_list->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, 'text' => 0));
+ $medias_list->set_headers_visible(0);
+ $medias_list->get_selection->set_mode('browse');
+ $medias_list_ls->append_set([ 0 => $_->{name} ]) foreach @{$urpm->{media}};
+ my $sel;
+ add_callback_(N("Add a medium limit"), N("Choose a medium to add to the media limit:"),
+ $w, $medias_list, sub { $sel = selrow($medias_list) },
+ sub {
+ return if $sel == -1;
+ my $media = ${$urpm->{media}}[$sel]{name};
+ $medias_ls->append_set([ 0 => $media ]);
+ push @{$edited->{medias}}, $media;
+ }
+ );
+ };
+
+ my $hosts_list;
+ if ($edited->{protocol} eq 'ssh') { $hosts_list = [ split /:/, $edited->{command} ] }
+ elsif ($edited->{protocol} eq 'ka-run') { push @$hosts_list, $1 while $edited->{command} =~ /-m (\S+)/g }
+ $hosts_ls->append_set([ 0 => $_ ]) foreach @$hosts_list;
+ my $add_host = sub {
+ my ($entry, $value);
+ add_callback_(N("Add a host"), N("Type in the hostname or IP address of the host to add:"),
+ $mainw, $entry = gtkentry(), sub { $value = $entry->get_text },
+ sub { $hosts_ls->append_set([ 0 => $value ]); push @$hosts_list, $value }
+ );
+ };
+
+ my @protocols_names = qw(ka-run ssh);
+ my @protocols;
+ gtkadd(
+ $w->{window},
+ gtkpack_(
+ gtknew('VBox', spacing => 5),
+ if_(
+ $num != -1,
+ 0, gtknew('Label', text => N("Editing parallel group \"%s\":", $edited->{name}))
+ ),
+ 1, create_packtable(
+ {},
+ [ N("Group name:"), $name_entry = gtkentry($edited->{name}) ],
+ [ N("Protocol:"), gtknew('HBox', children_tight => [
+ @protocols = gtkradio($edited->{protocol}, @protocols_names) ]) ],
+ [ N("Media limit:"),
+ gtknew('HBox', spacing => 5, children => [
+ 1, gtknew('Frame', shadow_type => 'in', child =>
+ gtknew('ScrolledWindow', h_policy => 'never', child => $medias)),
+ 0, gtknew('VBox', children_tight => [
+ gtksignal_connect(Gtk2::Button->new(but(N("Add"))), clicked => sub { $add_media->() }),
+ gtksignal_connect(Gtk2::Button->new(but(N("Remove"))), clicked => sub {
+ remove_from_list($medias, $edited->{medias}, $medias_ls);
+ }) ]) ]) ],
+ [ N("Hosts:"),
+ gtknew('HBox', spacing => 5, children => [
+ 1, gtknew('Frame', shadow_type => 'in', child =>
+ gtknew('ScrolledWindow', h_policy => 'never', child => $hosts)),
+ 0, gtknew('VBox', children_tight => [
+ gtksignal_connect(Gtk2::Button->new(but(N("Add"))), clicked => sub { $add_host->() }),
+ gtksignal_connect(Gtk2::Button->new(but(N("Remove"))), clicked => sub {
+ remove_from_list($hosts, $hosts_list, $hosts_ls);
+ }) ]) ]) ]
+ ),
+ 0, gtknew('HSeparator'),
+ 0, gtkpack(
+ gtknew('HButtonBox'),
+ gtksignal_connect(
+ gtknew('Button', text => N("Ok")), clicked => sub {
+ $w->{retval} = 1;
+ $edited->{name} = $name_entry->get_text;
+ mapn { $_[0]->get_active and $edited->{protocol} = $_[1] } \@protocols, \@protocols_names;
+ Gtk2->main_quit;
+ }
+ ),
+ gtknew('Button', text => N("Cancel"), clicked => sub { $w->{retval} = 0; Gtk2->main_quit }))
+ )
+ );
+ $w->{rwindow}->set_size_request(600, -1);
+ if ($w->main) {
+ $num == -1 and push @$conf, $edited;
+ if ($edited->{protocol} eq 'ssh') { $edited->{command} = join(':', @$hosts_list) }
+ if ($edited->{protocol} eq 'ka-run') { $edited->{command} = "-c ssh " . join(' ', map { "-m $_" } @$hosts_list) }
+ parallel_write_sysconf($conf);
+ return 1;
+ }
+ return 0;
+}
+
+sub parallel_callback() {
+ my $w = ugtk2->new(N("Configure parallel urpmi (distributed execution of urpmi)"), grab => 1, center => 1, transient => $mainw->{real_window});
+ local $::main_window = $w->{real_window};
+ my $list_ls = Gtk2::ListStore->new("Glib::String", "Glib::String", "Glib::String", "Glib::String");
+ my $list = Gtk2::TreeView->new_with_model($list_ls);
+ each_index { $list->append_column(Gtk2::TreeViewColumn->new_with_attributes($_, Gtk2::CellRendererText->new, 'text' => $::i)) } N("Group"), N("Protocol"), N("Media limit");
+ $list->append_column(my $commandcol = Gtk2::TreeViewColumn->new_with_attributes(N("Command"), Gtk2::CellRendererText->new, 'text' => 3));
+ $commandcol->set_max_width(200);
+
+ my $conf;
+ my $reread = sub {
+ $list_ls->clear;
+ $conf = parallel_read_sysconf();
+ foreach (@$conf) {
+ $list_ls->append_set([ 0 => $_->{name},
+ 1 => $_->{protocol},
+ 2 => @{$_->{medias}} ? join(', ', @{$_->{medias}}) : N("(none)"),
+ 3 => $_->{command} ]);
+ }
+ };
+ $reread->();
+
+ gtkadd(
+ $w->{window},
+ gtkpack_(
+ gtknew('VBox', spacing => 5),
+ 1, gtkpack_(
+ gtknew('HBox', spacing => 10),
+ 1, $list,
+ 0, gtkpack__(
+ gtknew('VBox', spacing => 5),
+ gtksignal_connect(
+ Gtk2::Button->new(but(N("Remove"))),
+ clicked => sub { remove_parallel(selrow($list), $conf); $reread->() },
+ ),
+ gtksignal_connect(
+ Gtk2::Button->new(but(N("Edit..."))),
+ clicked => sub {
+ my $row = selrow($list);
+ $row != -1 and edit_parallel($row, $conf);
+ $reread->();
+ },
+ ),
+ gtksignal_connect(
+ Gtk2::Button->new(but(N("Add..."))),
+ clicked => sub { edit_parallel(-1, $conf) and $reread->() },
+ )
+ )
+ ),
+ 0, gtknew('HSeparator'),
+ 0, gtkpack(
+ gtknew('HButtonBox'),
+ gtknew('Button', text => N("Ok"), clicked => sub { Gtk2->main_quit })
+ )
+ )
+ );
+ $w->main;
+}
+
+sub keys_callback() {
+ my $w = ugtk2->new(N("Manage keys for digital signatures of packages"), grab => 1, center => 1, transient => $mainw->{real_window});
+ local $::main_window = $w->{real_window};
+ $w->{real_window}->set_size_request(600, 300);
+
+ my $media_list_ls = Gtk2::ListStore->new("Glib::String");
+ my $media_list = Gtk2::TreeView->new_with_model($media_list_ls);
+ $media_list->append_column(Gtk2::TreeViewColumn->new_with_attributes(N("Medium"), Gtk2::CellRendererText->new, 'text' => 0));
+ $media_list->get_selection->set_mode('browse');
+
+ my $key_col_size = 200;
+ my $keys_list_ls = Gtk2::ListStore->new("Glib::String", "Glib::String");
+ my $keys_list = Gtk2::TreeView->new_with_model($keys_list_ls);
+ $keys_list->set_rules_hint(1);
+ $keys_list->append_column(my $col = Gtk2::TreeViewColumn->new_with_attributes(N("_:cryptographic keys\nKeys"), my $renderer = Gtk2::CellRendererText->new, 'text' => 0));
+ $col->set_sizing('fixed');
+ $col->set_fixed_width($key_col_size);
+ $renderer->set_property('width' => 1);
+ $renderer->set_property('wrap-width', $key_col_size);
+ $keys_list->get_selection->set_mode('browse');
+
+ my ($current_medium, $current_medium_nb, @keys);
+
+ my $read_conf = sub {
+ $urpm->parse_pubkeys(root => $urpm->{root});
+ @keys = map { [ split /[,\s]+/, $_->{'key-ids'} ] } @{$urpm->{media}};
+ };
+ my $write = sub {
+ $something_changed = 1;
+ urpm::media::write_config($urpm);
+ $urpm = fast_open_urpmi_db();
+ $read_conf->();
+ $media_list->get_selection->signal_emit('changed');
+ };
+ $read_conf->();
+ my $key_name = sub {
+ exists $urpm->{keys}{$_[0]} ? $urpm->{keys}{$_[0]}{name}
+ : N("no name found, key doesn't exist in rpm keyring!");
+ };
+ $media_list_ls->append_set([ 0 => $_->{name} ]) foreach @{$urpm->{media}};
+ $media_list->get_selection->signal_connect(changed => sub {
+ my ($model, $iter) = $_[0]->get_selected;
+ $model && $iter or return;
+ $current_medium = $model->get($iter, 0);
+ $current_medium_nb = $model->get_path($iter)->to_string;
+ $keys_list_ls->clear;
+ $keys_list_ls->append_set([ 0 => sprintf("%s (%s)", $_, $key_name->($_)), 1 => $_ ]) foreach @{$keys[$current_medium_nb]};
+ });
+
+ my $add_key = sub {
+ my $available_keyz_ls = Gtk2::ListStore->new("Glib::String", "Glib::String");
+ my $available_keyz = Gtk2::TreeView->new_with_model($available_keyz_ls);
+ $available_keyz->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, 'text' => 0));
+ $available_keyz->set_headers_visible(0);
+ $available_keyz->get_selection->set_mode('browse');
+ $available_keyz_ls->append_set([ 0 => sprintf("%s (%s)", $_, $key_name->($_)), 1 => $_ ]) foreach keys %{$urpm->{keys}};
+ my $key;
+ add_callback_(N("Add a key"), N("Choose a key to add to the medium %s", $current_medium), $w, $available_keyz,
+ sub {
+ my ($model, $iter) = $available_keyz->get_selection->get_selected;
+ $model && $iter and $key = $model->get($iter, 1);
+ },
+ sub {
+ return if !defined $key;
+ $urpm->{media}[$current_medium_nb]{'key-ids'} = join(',', sort(uniq(@{$keys[$current_medium_nb]}, $key)));
+ $write->();
+ }
+ );
+
+
+ };
+
+ my $remove_key = sub {
+ my ($model, $iter) = $keys_list->get_selection->get_selected;
+ $model && $iter or return;
+ my $key = $model->get($iter, 1);
+ interactive_msg(N("Remove a key"),
+ N("Are you sure you want to remove the key %s from medium %s?\n(name of the key: %s)",
+ $key, $current_medium, $key_name->($key)),
+ yesno => 1, transient => $w->{real_window}) or return;
+ $urpm->{media}[$current_medium_nb]{'key-ids'} = join(',', difference2(\@{$keys[$current_medium_nb]}, [ $key ]));
+ $write->();
+ };
+
+ gtkadd(
+ $w->{window},
+ gtkpack_(
+ gtknew('VBox', spacing => 5),
+ 1, gtkpack_(
+ gtknew('HBox', spacing => 10),
+ 1, create_scrolled_window($media_list),
+ 1, create_scrolled_window($keys_list),
+ 0, gtkpack__(
+ gtknew('VBox', spacing => 5),
+ gtksignal_connect(
+ Gtk2::Button->new(but(N("Add"))),
+ clicked => \&$add_key,
+ ),
+ gtksignal_connect(
+ Gtk2::Button->new(but(N("Remove"))),
+ clicked => \&$remove_key,
+ )
+ )
+ ),
+ 0, gtknew('HSeparator'),
+ 0, gtkpack(
+ gtknew('HButtonBox'),
+ gtknew('Button', text => N("Ok"), clicked => sub { Gtk2->main_quit })
+ ),
+ ),
+ );
+ $w->main;
+}
+
+sub mainwindow() {
+ undef $something_changed;
+ $mainw = ugtk2->new(N("Configure media"), center => 1, transient => $::main_window, modal => 1);
+ local $::main_window = $mainw->{real_window};
+
+ my $reread_media;
+
+ my ($menu, $_factory) = create_factory_menu(
+ $mainw->{real_window},
+ [ N("/_File"), undef, undef, undef, '<Branch>' ],
+ [ N("/_File") . N("/_Update"), N("<control>U"), sub { update_callback() and $reread_media->() }, undef, '<Item>', ],
+ [ N("/_File") . N("/Add a specific _media mirror"), N("<control>M"), sub { easy_add_callback_with_mirror() and $reread_media->() }, undef, '<Item>' ],
+ [ N("/_File") . N("/_Add a custom medium"), N("<control>A"), sub { add_callback() and $reread_media->() }, undef, '<Item>' ],
+ [ N("/_File") . N("/Close"), N("<control>W"), sub { Gtk2->main_quit }, undef, '<Item>', ],
+ [ N("/_Options"), undef, undef, undef, '<Branch>' ],
+ [ N("/_Options") . N("/_Global options"), N("<control>G"), \&options_callback, undef, '<Item>' ],
+ [ N("/_Options") . N("/Manage _keys"), N("<control>K"), \&keys_callback, undef, '<Item>' ],
+ [ N("/_Options") . N("/_Parallel"), N("<control>P"), \&parallel_callback, undef, '<Item>' ],
+ [ N("/_Options") . N("/P_roxy"), N("<control>R"), \&proxy_callback, undef, '<Item>' ],
+ if_($0 =~ /edit-urpm-sources/,
+ [ N("/_Help"), undef, undef, undef, '<Branch>' ],
+ [ N("/_Help") . N("/_Report Bug"), undef, sub { run_drakbug('edit-urpm-sources.pl') }, undef, '<Item>' ],
+ [ N("/_Help") . N("/_Help"), undef, sub { rpmdragora::open_help('sources') }, undef, '<Item>' ],
+ [ N("/_Help") . N("/_About..."), undef, sub {
+ my $license = formatAlaTeX(translate($::license));
+ $license =~ s/\n/\n\n/sg; # nicer formatting
+ my $w = gtknew('AboutDialog', name => N("Rpmdragora"),
+ version => $rpmdragora::distro_version,
+ copyright => N("Copyright (C) %s by Mandriva", '2002-2008'),
+ license => $license, wrap_license => 1,
+ comments => N("Rpmdragora is the Mageia package management tool."),
+ website => 'http://www.mageia.org/',
+ website_label => N("Mageia"),
+ authors => 'Thierry Vignaud <vignaud@mandriva.com>',
+ artists => 'Hรฉlรจne Durosini <ln@mandriva.com>',
+ translator_credits =>
+ #-PO: put here name(s) and email(s) of translator(s) (eg: "John Smith <jsmith@nowhere.com>")
+ N("_: Translator(s) name(s) & email(s)\n"),
+ transient_for => $::main_window, modal => 1, position_policy => 'center-on-parent',
+ );
+ $w->show_all;
+ $w->run;
+ }, undef, '<Item>'
+ ]
+ ),
+ );
+
+ my $list = Gtk2::ListStore->new("Glib::Boolean", "Glib::Boolean", "Glib::String", "Glib::String", "Glib::Boolean");
+ $list_tv = Gtk2::TreeView->new_with_model($list);
+ $list_tv->get_selection->set_mode('multiple');
+ my ($dw_button, $edit_button, $remove_button, $up_button);
+ $list_tv->get_selection->signal_connect(changed => sub {
+ my ($selection) = @_;
+ my @rows = $selection->get_selected_rows;
+ my $model = $list;
+ # we can delete several medium at a time:
+ $remove_button and $remove_button->set_sensitive($#rows != -1);
+ # we can only edit/move one item at a time:
+ $_ and $_->set_sensitive(@rows == 1) foreach $up_button, $dw_button, $edit_button;
+
+ # we can only up/down one item if not at begin/end:
+ return if @rows != 1;
+
+ my $curr_path = $rows[0];
+ my $first_path = $model->get_path($model->get_iter_first);
+ $up_button->set_sensitive($first_path && $first_path->compare($curr_path));
+
+ $curr_path->next;
+ my $next_item = $model->get_iter($curr_path);
+ $dw_button->set_sensitive($next_item); # && !$model->get($next_item, 0)
+ });
+
+ $list_tv->set_rules_hint(1);
+ $list_tv->set_reorderable(1);
+
+ my $reorder_ok = 1;
+ $list->signal_connect(
+ row_deleted => sub {
+ $reorder_ok or return;
+ my ($model) = @_;
+ my @media;
+ $model->foreach(
+ sub {
+ my (undef, undef, $iter) = @_;
+ my $name = $model->get($iter, $col{mainw}{name});
+ push @media, urpm::media::name2medium($urpm, $name);
+ 0;
+ }, undef);
+ @{$urpm->{media}} = @media;
+ },
+ );
+
+ $list_tv->append_column(Gtk2::TreeViewColumn->new_with_attributes(N("Enabled"),
+ my $tr = Gtk2::CellRendererToggle->new,
+ 'active' => $col{mainw}{is_enabled}));
+ $list_tv->append_column(Gtk2::TreeViewColumn->new_with_attributes(N("Updates"),
+ my $cu = Gtk2::CellRendererToggle->new,
+ 'active' => $col{mainw}{is_update},
+ activatable => $col{mainw}{activatable}));
+ $list_tv->append_column(Gtk2::TreeViewColumn->new_with_attributes(N("Type"),
+ Gtk2::CellRendererText->new,
+ 'text' => $col{mainw}{type}));
+ $list_tv->append_column(Gtk2::TreeViewColumn->new_with_attributes(N("Medium"),
+ Gtk2::CellRendererText->new,
+ 'text' => $col{mainw}{name}));
+ my $id;
+ $id = $tr->signal_connect(
+ toggled => sub {
+ my (undef, $path) = @_;
+ $tr->signal_handler_block($id);
+ my $_guard = before_leaving { $tr->signal_handler_unblock($id) };
+ my $iter = $list->get_iter_from_string($path);
+ $urpm->{media}[$path]{ignore} = !$urpm->{media}[$path]{ignore} || undef;
+ $list->set($iter, $col{mainw}{is_enabled}, !$urpm->{media}[$path]{ignore});
+ urpm::media::write_config($urpm);
+ my $ignored = $urpm->{media}[$path]{ignore};
+ $reread_media->();
+ if (!$ignored && $urpm->{media}[$path]{ignore}) {
+ # reread media failed to un-ignore an ignored medium
+ # probably because urpm::media::check_existing_medium() complains
+ # about missing synthesis when the medium never was enabled before;
+ # thus it restored the ignore bit
+ $urpm->{media}[$path]{ignore} = !$urpm->{media}[$path]{ignore} || undef;
+ urpm::media::write_config($urpm);
+ #- Enabling this media failed, force update
+ interactive_msg('rpmdragora',
+ N("This medium needs to be updated to be usable. Update it now?"),
+ yesno => 1,
+ ) and $reread_media->($urpm->{media}[$path]{name});
+ }
+ },
+ );
+
+ $cu->signal_connect(
+ toggled => sub {
+ my (undef, $path) = @_;
+ my $iter = $list->get_iter_from_string($path);
+ $urpm->{media}[$path]{update} = !$urpm->{media}[$path]{update} || undef;
+ $list->set($iter, $col{mainw}{is_update}, ! !$urpm->{media}[$path]{update});
+ $something_changed = 1;
+ },
+ );
+
+ $reread_media = sub {
+ my ($name) = @_;
+ $reorder_ok = 0;
+ $something_changed = 1;
+ if (defined $name) {
+ urpm::media::select_media($urpm, $name);
+ update_sources_check(
+ $urpm,
+ { nolock => 1 },
+ N_("Unable to update medium, errors reported:\n\n%s"),
+ $name,
+ );
+ }
+ # reread configuration after updating media else ignore bit will be restored
+ # by urpm::media::check_existing_medium():
+ $urpm = fast_open_urpmi_db();
+ $list->clear;
+ foreach (grep { ! $_->{external} } @{$urpm->{media}}) {
+ my $name = $_->{name};
+ $list->append_set($col{mainw}{is_enabled} => !$_->{ignore},
+ $col{mainw}{is_update} => ! !$_->{update},
+ $col{mainw}{type} => get_medium_type($_),
+ $col{mainw}{name} => $name,
+ $col{mainw}{activatable} => to_bool($::expert),
+ );
+ }
+ $reorder_ok = 1;
+ };
+ $reread_media->();
+ $something_changed = 0;
+
+ gtkadd(
+ $mainw->{window},
+ gtkpack_(
+ gtknew('VBox', spacing => 5),
+ 0, $menu,
+ ($0 =~ /rpm-edit-media|edit-urpm-sources/ ? (0, Gtk2::Banner->new($ugtk2::wm_icon, N("Configure media"))) : ()),
+ 1, gtkpack_(
+ gtknew('HBox', spacing => 10),
+ 1, gtknew('ScrolledWindow', child => $list_tv),
+ 0, gtkpack__(
+ gtknew('VBox', spacing => 5),
+ gtksignal_connect(
+ $remove_button = Gtk2::Button->new(but(N("Remove"))),
+ clicked => sub { remove_callback() and $reread_media->() },
+ ),
+ gtksignal_connect(
+ $edit_button = Gtk2::Button->new(but(N("Edit"))),
+ clicked => sub {
+ my $name = edit_callback(); defined $name and $reread_media->($name);
+ }
+ ),
+ gtksignal_connect(
+ Gtk2::Button->new(but(N("Add"))),
+ clicked => sub { easy_add_callback() and $reread_media->() },
+ ),
+ gtkpack(
+ gtknew('HBox'),
+ gtksignal_connect(
+ $up_button = gtknew('Button',
+ image => gtknew('Image', stock => 'gtk-go-up')),
+ clicked => \&upwards_callback),
+
+ gtksignal_connect(
+ $dw_button = gtknew('Button',
+ image => gtknew('Image', stock => 'gtk-go-down')),
+ clicked => \&downwards_callback),
+ ),
+ )
+ ),
+ 0, gtknew('HSeparator'),
+ 0, gtknew('HButtonBox', layout => 'edge', children_loose => [
+ gtksignal_connect(Gtk2::Button->new(but(N("Help"))), clicked => sub { rpmdragora::open_help('sources') }),
+ gtksignal_connect(Gtk2::Button->new(but(N("Ok"))), clicked => sub { Gtk2->main_quit })
+ ])
+ )
+ );
+ $_->set_sensitive(0) foreach $dw_button, $edit_button, $remove_button, $up_button;
+
+ $mainw->{rwindow}->set_size_request(600, 400);
+ $mainw->main;
+ return $something_changed;
+}
+
+
+sub run() {
+ # ignore rpmdragora's option regarding ignoring debug media:
+ local $ignore_debug_media = [ 0 ];
+ local $ugtk2::wm_icon = get_icon('rpmdragora-mdk', 'title-media');
+ my $lock;
+ {
+ $urpm = fast_open_urpmi_db();
+ my $err_msg = "urpmdb locked\n";
+ local $urpm->{fatal} = sub {
+ interactive_msg('rpmdragora',
+ N("The Package Database is locked. Please close other applications
+working with the Package Database. Do you have another media
+manager on another desktop, or are you currently installing
+packages as well?"));
+ die $err_msg;
+ };
+ # lock urpmi DB
+ eval { $lock = urpm::lock::urpmi_db($urpm, 'exclusive', wait => $urpm->{options}{wait_lock}) };
+ if (my $err = $@) {
+ return if $err eq $err_msg;
+ die $err;
+ }
+ }
+
+ my $res = mainwindow();
+ urpm::media::write_config($urpm);
+
+ writeconf();
+
+ undef $lock;
+ $res;
+}
+
+
+1;
diff --git a/AdminPanel/Rpmdragora/formatting.pm b/AdminPanel/Rpmdragora/formatting.pm
new file mode 100644
index 0000000..f271ed1
--- /dev/null
+++ b/AdminPanel/Rpmdragora/formatting.pm
@@ -0,0 +1,177 @@
+package AdminPanel::Rpmdragora::formatting;
+#*****************************************************************************
+#
+# Copyright (c) 2002 Guillaume Cottenceau
+# Copyright (c) 2002-2006 Thierry Vignaud <tvignaud@mandriva.com>
+# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA
+# Copyright (c) 2005, 2006 Mandriva SA
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2, as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#*****************************************************************************
+#
+# $Id: formatting.pm 261189 2009-10-01 14:44:39Z tv $
+
+use strict;
+use utf8;
+use POSIX qw(strftime);
+use AdminPanel::rpmdragora;
+use lib qw(/usr/lib/libDrakX);
+use common;
+#use ugtk2 qw(escape_text_for_TextView_markup_format);
+
+use Exporter;
+our @ISA = qw(Exporter);
+our @EXPORT = qw(
+ $spacing
+ ensure_utf8
+ format_changelog_changelogs
+ format_changelog_string
+ format_field
+ format_header
+ format_list
+ format_name_n_summary
+ format_size
+ format_filesize
+ format_update_field
+ my_fullname
+ pkg2medium
+ rpm_description
+ split_fullname
+ urpm_name
+ );
+
+
+# from rpmtools, #37482:
+sub ensure_utf8 {
+ if (utf8::is_utf8($_[0])) {
+ utf8::valid($_[0]) and return;
+
+ utf8::encode($_[0]); #- disable utf8 flag
+ utf8::upgrade($_[0]);
+ } else {
+ utf8::decode($_[0]); #- try to set utf8 flag
+ utf8::valid($_[0]) and return;
+ warn "do not know what to with $_[0]\n";
+ }
+}
+
+sub rpm_description {
+ my ($description) = @_;
+ ensure_utf8($description);
+ my ($t, $tmp);
+ foreach (split "\n", $description) {
+ s/^\s*//;
+ if (/^$/ || /^\s*(-|\*|\+|o)\s/) {
+ $t || $tmp and $t .= "$tmp\n";
+ $tmp = $_;
+ } else {
+ $tmp = ($tmp ? "$tmp " : ($t && "\n") . $tmp) . $_;
+ }
+ }
+ "$t$tmp\n";
+}
+
+sub split_fullname { $_[0] =~ /^(.*)-([^-]+)-([^-]+)\.([^.-]+)$/ }
+
+sub my_fullname {
+ return '?-?-?' unless ref $_[0];
+ my ($name, $version, $release) = $_[0]->fullname;
+ "$name-$version-$release";
+}
+
+sub urpm_name {
+ return '?-?-?.?' unless ref $_[0];
+ scalar $_[0]->fullname;
+}
+
+sub pkg2medium {
+ my ($p, $urpm) = @_;
+ return if !ref $p;
+ return { name => N("None (installed)") } if !defined($p->id); # if installed
+ URPM::pkg2media($urpm->{media}, $p) || { name => N("Unknown"), fake => 1 };
+}
+
+# [ duplicate urpmi's urpm::msg::localtime2changelog() ]
+#- strftime returns a string in the locale charset encoding;
+#- but gtk2 requires UTF-8, so we use to_utf8() to ensure the
+#- output of localtime2changelog() is always in UTF-8
+#- as to_utf8() uses LC_CTYPE for locale encoding and strftime() uses LC_TIME,
+#- it doesn't work if those two variables have values with different
+#- encodings; but if a user has a so broken setup we can't do much anyway
+sub localtime2changelog { to_utf8(POSIX::strftime("%c", localtime($_[0]))) }
+
+our $spacing = " ";
+sub format_changelog_string {
+ my ($installed_version, $string) = @_;
+ #- preprocess changelog for faster TextView insert reaction
+ require Gtk2::Pango;
+ my %date_attr = ('weight' => Gtk2::Pango->PANGO_WEIGHT_BOLD);
+ my %update_attr = ('style' => 'italic');
+ my $version;
+ my $highlight;
+ [ map {
+ my %attrs;
+ if (/^\*/) {
+ add2hash(\%attrs, \%date_attr);
+ ($version) = /(\S*-\S*)\s*$/;
+ $highlight = $installed_version ne N("(none)") && 0 < URPM::rpmvercmp($version, $installed_version);
+ }
+ add2hash(\%attrs, \%update_attr) if $highlight;
+ [ "$spacing$_\n", if_(%attrs, \%attrs) ];
+ } split("\n", $string) ];
+}
+
+sub format_changelog_changelogs {
+ my ($installed_version, @changelogs) = @_;
+ format_changelog_string($installed_version, join("\n", map {
+ "* " . localtime2changelog($_->{time}) . " $_->{name}\n\n$_->{text}\n";
+ } @changelogs));
+}
+
+sub format_update_field {
+ my ($name) = @_;
+ '<i>' . eval { escape_text_for_TextView_markup_format($name) } . '</i>';
+}
+
+sub format_name_n_summary {
+ my ($name, $summary) = @_;
+ join("\n", '<b>' . $name . '</b>', escape_text_for_TextView_markup_format($summary));
+}
+
+sub format_header {
+ my ($str) = @_;
+ '<big>' . escape_text_for_TextView_markup_format($str) . '</big>';
+}
+
+sub format_field {
+ my ($str) = @_;
+ '<b>' . escape_text_for_TextView_markup_format($str) . '</b>';
+}
+
+sub format_size {
+ my ($size) = @_;
+ $size >= 0 ?
+ N("%s of additional disk space will be used.", formatXiB($size)) :
+ N("%s of disk space will be freed.", formatXiB(-$size));
+}
+
+sub format_filesize {
+ my ($filesize) = @_;
+ $filesize ? N("%s of packages will be retrieved.", formatXiB($filesize)) : ();
+}
+
+sub format_list { join("\n", map { s/^(\s)/ $1/mg; "- $_" } sort { uc($a) cmp uc($b) } @_) }
+
+1;
diff --git a/AdminPanel/Rpmdragora/gui.pm b/AdminPanel/Rpmdragora/gui.pm
new file mode 100644
index 0000000..9c0b7a0
--- /dev/null
+++ b/AdminPanel/Rpmdragora/gui.pm
@@ -0,0 +1,1105 @@
+package AdminPanel::Rpmdragora::gui;
+#*****************************************************************************
+#
+# Copyright (c) 2002 Guillaume Cottenceau
+# Copyright (c) 2002-2007 Thierry Vignaud <tvignaud@mandriva.com>
+# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA
+# Copyright (c) 2005-2007 Mandriva SA
+# Copyright (c) 2013 Matteo Pasotti <matteo.pasotti@gmail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2, as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#*****************************************************************************
+#
+# $Id$
+
+############################################################
+# WARNING: do not modify before asking to matteo or anaselli
+############################################################
+
+use strict;
+our @ISA = qw(Exporter);
+use lib qw(/usr/lib/libDrakX);
+use common;
+use yui;
+use AdminPanel::rpmdragora;
+use AdminPanel::Rpmdragora::open_db;
+use AdminPanel::Rpmdragora::formatting;
+use AdminPanel::Rpmdragora::init;
+use AdminPanel::Rpmdragora::icon;
+use AdminPanel::Rpmdragora::pkg;
+use feature 'state';
+
+our @EXPORT = qw(
+ $descriptions
+ $find_entry
+ $force_displaying_group
+ $force_rebuild
+ $pkgs
+ $results_ok
+ $results_none
+ $size_free
+ $size_selected
+ $urpm
+ %grp_columns
+ %pkg_columns
+ @filtered_pkgs
+ @initial_selection
+ ask_browse_tree_given_widgets_for_rpmdragora
+ build_tree
+ callback_choices
+ compute_main_window_size
+ do_action
+ get_info
+ get_summary
+ is_locale_available
+ node_state
+ pkgs_provider
+ real_quit
+ reset_search
+ set_node_state
+ sort_callback
+ switch_pkg_list_mode
+ toggle_all
+ toggle_nodes
+ );
+
+our ($descriptions, %filters, @filtered_pkgs, %filter_methods, $force_displaying_group, $force_rebuild, @initial_selection, $pkgs, $size_free, $size_selected, $urpm);
+our ($results_ok, $results_none) = (N("Search results"), N("Search results (none)"));
+
+our %grp_columns = (
+ label => 0,
+ icon => 2,
+);
+
+our %pkg_columns = (
+ text => 0,
+ state_icon => 1,
+ state => 2,
+ selected => 3,
+ short_name => 4,
+ version => 5,
+ release => 6,
+ 'arch' => 7,
+ selectable => 8,
+);
+
+sub compute_main_window_size {
+ my ($w) = @_;
+ ($typical_width) = string_size($w->{real_window}, translate("Graphical Environment") . "xmms-more-vis-plugins");
+ $typical_width > 600 and $typical_width = 600; #- try to not being crazy with a too large value
+ $typical_width < 150 and $typical_width = 150;
+}
+
+sub get_summary {
+ my ($key) = @_;
+ my $summary = translate($pkgs->{$key}{pkg}->summary);
+ require utf8;
+ utf8::valid($summary) ? $summary : @{[]};
+}
+
+sub build_expander {
+ my ($pkg, $label, $type, $get_data, $o_installed_version) = @_;
+ my $textview;
+ gtkadd(
+ gtkshow(my $exp = gtksignal_connect(
+ Gtk2::Expander->new(format_field($label)),
+ activate => sub {
+ state $first;
+ return if $first;
+ $first = 1;
+ slow_func($::main_window->window, sub {
+ extract_header($pkg, $urpm, $type, $o_installed_version);
+ gtktext_insert($textview, $get_data->() || [ [ N("(Not available)") ] ]);
+ });
+ })),
+ $textview = gtknew('TextView')
+ );
+ $exp->set_use_markup(1);
+ $exp;
+}
+
+
+sub get_advisory_link {
+ my ($update_descr) = @_;
+ my $link = gtkshow(Gtk2::LinkButton->new($update_descr->{URL}, N("Security advisory")));
+ $link->set_uri_hook(\&run_help_callback);
+ [ $link ];
+}
+
+sub get_description {
+ my ($pkg, $update_descr) = @_;
+ @{ ugtk2::markup_to_TextView_format(join("\n",
+ (eval {
+ escape_text_for_TextView_markup_format(
+ $pkg->{description}
+ || $update_descr->{description});
+ } || '<i>' . N("No description") . '</i>')
+ )) };
+}
+
+sub get_string_from_keywords {
+ my ($medium, $name) = @_;
+ my @media_types;
+ if ($medium->{mediacfg}) {
+ my ($distribconf, $medium_path) = @{$medium->{mediacfg}};
+ @media_types = split(':', $distribconf->getvalue($medium_path, 'media_type')) if $distribconf;
+ }
+
+ my $unsupported = N("It is <b>not supported</b> by Mageia.");
+ my $dangerous = N("It may <b>break</b> your system.");
+ my $s;
+ $s .= N("This package is not free software") . "\n" if member('non-free', @media_types);
+ if ($pkgs->{$name}{is_backport} || member('backport', @media_types)) {
+ return join("\n",
+ N("This package contains a new version that was backported."),
+ $unsupported, $dangerous, $s);
+ } elsif (member('testing', @media_types)) {
+ return join("\n",
+ N("This package is a potential candidate for an update."),
+ $unsupported, $dangerous, $s);
+ } elsif (member('updates', @media_types)) {
+ return join("\n",
+ (member('official', @media_types) ?
+ N("This is an official update which is supported by Mageia.")
+ : (N("This is an unofficial update."), $unsupported))
+ ,
+ $s);
+ } else {
+ $s .= N("This is an official package supported by Mageia") . "\n" if member('official', @media_types);
+ return $s;
+ }
+}
+
+sub get_main_text {
+ my ($medium, $fullname, $name, $summary, $is_update, $update_descr) = @_;
+
+ my $txt = get_string_from_keywords($medium, $fullname);
+
+ ugtk2::markup_to_TextView_format(
+ # force align "name - summary" to the right with RTL languages (#33603):
+ if_(lang::text_direction_rtl(), "\x{200f}") .
+ join("\n",
+ format_header(join(' - ', $name, $summary)) .
+ # workaround gtk+ bug where GtkTextView wronly limit embedded widget size to bigger line's width (#25533):
+ "\x{200b} \x{feff}" . ' ' x 120,
+ if_($txt, format_field(N("Notice: ")) . $txt),
+ if_($is_update, # is it an update?
+ format_field(N("Importance: ")) . format_update_field($update_descr->{importance}),
+ format_field(N("Reason for update: ")) . format_update_field(rpm_description($update_descr->{pre})),
+ ),
+ '' # extra empty line
+ ));
+}
+
+sub get_details {
+ my ($pkg, $upkg, $installed_version, $raw_medium) = @_;
+ my $a = ugtk2::markup_to_TextView_format(
+ $spacing . join("\n$spacing",
+ format_field(N("Version: ")) . $upkg->EVR,
+ ($upkg->flag_installed ?
+ format_field(N("Currently installed version: ")) . $installed_version : ()
+ ),
+ format_field(N("Group: ")) . translate_group($upkg->group),
+ format_field(N("Architecture: ")) . $upkg->arch,
+ format_field(N("Size: ")) . N("%s KB", int($upkg->size/1024)),
+ eval { format_field(N("Medium: ")) . $raw_medium->{name} },
+ ),
+ );
+ my @link = get_url_link($upkg, $pkg);
+ push @$a, @link if @link;
+ $a;
+}
+
+sub get_new_deps {
+ my ($urpm, $upkg) = @_;
+ my $deps_textview;
+ my @a = [ gtkadd(
+ gtksignal_connect(
+ gtkshow(my $dependencies = Gtk2::Expander->new(format_field(N("New dependencies:")))),
+ activate => sub {
+ slow_func($::main_window->window, sub {
+ my $state = {};
+ my $db = open_rpm_db();
+ my @requested = $urpm->resolve_requested__no_suggests_(
+ $db, $state,
+ { $upkg->id => 1 },
+ );
+ @requested = $urpm->resolve_requested_suggests($db, $state, \@requested);
+ undef $db;
+ my @nodes_with_deps = map { urpm_name($_) } @requested;
+ my @deps = sort { $a cmp $b } difference2(\@nodes_with_deps, [ urpm_name($upkg) ]);
+ @deps = N("All dependencies installed.") if !@deps;
+ gtktext_insert($deps_textview, join("\n", @deps));
+ });
+ }
+ ),
+ $deps_textview = gtknew('TextView')
+ ) ];
+ $dependencies->set_use_markup(1);
+ @a;
+}
+
+sub get_url_link {
+ my ($upkg, $pkg) = @_;
+
+ my $url = $upkg->url || $pkg->{url};
+
+ if (!$url) {
+ open_rpm_db()->traverse_tag_find('name', $upkg->name, sub { $url = $_[0]->url });
+ }
+
+ return if !$url;
+
+ my @a =
+ (@{ ugtk2::markup_to_TextView_format(format_field("\n$spacing" . N("URL: "))) },
+ [ my $link = gtkshow(Gtk2::LinkButton->new($url, $url)) ]);
+ $link->set_uri_hook(\&run_help_callback);
+ @a;
+}
+
+sub files_format {
+ my ($files) = @_;
+ ugtk2::markup_to_TextView_format(
+ '<tt>' . $spacing #- to highlight information
+ . join("\n$spacing", map { "\x{200e}$_" } @$files)
+ . '</tt>');
+}
+
+sub format_pkg_simplifiedinfo {
+ my ($pkgs, $key, $urpm, $descriptions) = @_;
+ my ($name) = split_fullname($key);
+ my $pkg = $pkgs->{$key};
+ my $upkg = $pkg->{pkg};
+ return if !$upkg;
+ my $raw_medium = pkg2medium($upkg, $urpm);
+ my $medium = !$raw_medium->{fake} ? $raw_medium->{name} : undef;
+ my $update_descr = $descriptions->{$medium}{$name};
+ # discard update fields if not matching:
+ my $is_update = ($upkg->flag_upgrade && $update_descr && $update_descr->{pre});
+ my $summary = get_summary($key);
+ my $s = get_main_text($raw_medium, $key, $name, $summary, $is_update, $update_descr);
+ push @$s, get_advisory_link($update_descr) if $is_update;
+
+ push @$s, get_description($pkg, $update_descr);
+ push @$s, [ "\n" ];
+ my $installed_version = eval { find_installed_version($upkg) };
+
+ push @$s, [ gtkadd(gtkshow(my $details_exp = Gtk2::Expander->new(format_field(N("Details:")))),
+ gtknew('TextView', text => get_details($pkg, $upkg, $installed_version, $raw_medium))) ];
+ $details_exp->set_use_markup(1);
+ push @$s, [ "\n\n" ];
+ push @$s, [ build_expander($pkg, N("Files:"), 'files', sub { files_format($pkg->{files}) }) ];
+ push @$s, [ "\n\n" ];
+ push @$s, [ build_expander($pkg, N("Changelog:"), 'changelog', sub { $pkg->{changelog} }, $installed_version) ];
+
+ push @$s, [ "\n\n" ];
+ if ($upkg->id) { # If not installed
+ push @$s, get_new_deps($urpm, $upkg);
+ }
+ $s;
+}
+
+sub format_pkg_info {
+ my ($pkgs, $key, $urpm, $descriptions) = @_;
+ my $pkg = $pkgs->{$key};
+ my $upkg = $pkg->{pkg};
+ my ($name, $version) = split_fullname($key);
+ my @files = (
+ format_field(N("Files:\n")),
+ exists $pkg->{files}
+ ? '<tt>' . join("\n", map { "\x{200e}$_" } @{$pkg->{files}}) . '</tt>' #- to highlight information
+ : N("(Not available)"),
+ );
+ my @chglo = (format_field(N("Changelog:\n")), ($pkg->{changelog} ? @{$pkg->{changelog}} : N("(Not available)")));
+ my @source_info = (
+ $MODE eq 'remove' || !@$max_info_in_descr
+ ? ()
+ : (
+ format_field(N("Medium: ")) . pkg2medium($upkg, $urpm)->{name},
+ format_field(N("Currently installed version: ")) . find_installed_version($upkg),
+ )
+ );
+ my @max_info = @$max_info_in_descr && $changelog_first ? (@chglo, @files) : (@files, '', @chglo);
+ ugtk2::markup_to_TextView_format(join("\n", format_field(N("Name: ")) . $name,
+ format_field(N("Version: ")) . $version,
+ format_field(N("Architecture: ")) . $upkg->arch,
+ format_field(N("Size: ")) . N("%s KB", int($upkg->size/1024)),
+ if_(
+ $MODE eq 'update',
+ format_field(N("Importance: ")) . $descriptions->{$name}{importance}
+ ),
+ @source_info,
+ '', # extra empty line
+ format_field(N("Summary: ")) . $upkg->summary,
+ '', # extra empty line
+ if_(
+ $MODE eq 'update',
+ format_field(N("Reason for update: ")) . rpm_description($descriptions->{$name}{pre}),
+ ),
+ format_field(N("Description: ")), ($pkg->{description} || $descriptions->{$name}{description} || N("No description")),
+ @max_info,
+ ));
+}
+
+sub warn_if_no_pkg {
+ my ($name) = @_;
+ my ($short_name) = split_fullname($name);
+ state $warned;
+ if (!$warned) {
+ $warned = 1;
+ interactive_msg(N("Warning"),
+ join("\n",
+ N("The package \"%s\" was found.", $name),
+ N("However this package is not in the package list."),
+ N("You may want to update your urpmi database."),
+ '',
+ N("Matching packages:"),
+ '',
+ join("\n", sort map {
+ #-PO: this is list fomatting: "- <package_name> (medium: <medium_name>)"
+ #-PO: eg: "- rpmdragora (medium: "Main Release"
+ N("- %s (medium: %s)", $_, pkg2medium($pkgs->{$_}{pkg}, $urpm)->{name});
+ } grep { /^$short_name/ } keys %$pkgs),
+ ),
+ scroll => 1,
+ );
+ }
+ return 'XXX';
+}
+
+sub node_state {
+ my ($name) = @_;
+ #- checks $_[0] -> hack for partial tree displaying
+ return 'XXX' if !$name;
+ my $pkg = $pkgs->{$name};
+ my $urpm_obj = $pkg->{pkg};
+ return warn_if_no_pkg($name) if !$urpm_obj;
+ $pkg->{selected} ?
+ ($urpm_obj->flag_installed ?
+ ($urpm_obj->flag_upgrade ? 'to_install' : 'to_remove')
+ : 'to_install')
+ : ($urpm_obj->flag_installed ?
+ ($pkgs->{$name}{is_backport} ? 'backport' :
+ ($urpm_obj->flag_upgrade ? 'to_update'
+ : ($urpm_obj->flag_base ? 'base' : 'installed')))
+ : 'uninstalled');
+}
+
+my ($common, $w, %wtree, %ptree, %pix);
+
+sub set_node_state {
+ my ($iter, $state, $model) = @_;
+ return if $state eq 'XXX' || !$state;
+ $pix{$state} ||= gtkcreate_pixbuf('state_' . $state);
+ $model->set($iter, $pkg_columns{state_icon} => $pix{$state});
+ $model->set($iter, $pkg_columns{state} => $state);
+ $model->set($iter, $pkg_columns{selected} => to_bool(member($state, qw(base installed to_install)))); #$pkg->{selected}));
+ $model->set($iter, $pkg_columns{selectable} => to_bool($state ne 'base'));
+}
+
+sub set_leaf_state {
+ my ($leaf, $state, $model) = @_;
+ set_node_state($_, $state, $model) foreach @{$ptree{$leaf}};
+}
+
+sub grep_unselected { grep { exists $pkgs->{$_} && !$pkgs->{$_}{selected} } @_ }
+
+my %groups_tree;
+
+sub add_parent {
+ my ($tree, $root, $state) = @_;
+ $tree or return undef;
+ $root or return undef;
+ my $parent = 0;
+ my $parentItem = 0;
+ my @items = split('\|', $root);
+ my $i = 0;
+ for my $item (@items) {
+ my $treeItem = new yui::YTreeItem($item, 0);
+ if($i == 0){
+ $parent = $item;
+ $parentItem = $treeItem;
+ if(!defined($groups_tree{$item})) {
+ $groups_tree{$parent} = ();
+ $tree->addItem($treeItem);
+ }
+ }else{
+ if(!grep {$_ eq $item} @{$groups_tree{$parent}}){
+ push @{$groups_tree{$parent}}, $item;
+ }
+ #$treeItem = new yui::YTreeItem($parentItem, $item, 0);
+ $parentItem->addChild($treeItem);
+ }
+ $i++;
+ }
+ $tree->rebuildTree();
+ #use Data::Dumper;
+ #my @chiavi = keys %groups_tree;
+ #for(keys %groups_tree){
+ # print $_."\n";
+ # print Dumper($groups_tree{$_});
+ #}
+ # ORIGINAL
+ #if (my $w = $wtree{$root}) { return $w }
+ #my $s;
+ #foreach (split '\|', $root) {
+ #my $s2 = $s ? "$s|$_" : $_;
+ #$wtree{$s2} ||=do {
+ ##my $pixbuf = get_icon($s2, $s);
+ ##my $iter = $w->{tree_model}->append_set($s ? add_parent($s, $state) : undef,
+ ## [ $grp_columns{label} => $_, if_($pixbuf, $grp_columns{icon} => $pixbuf) ]);
+ ##my $iter = $w->{tree}->addItem($s ? add_parent($s, $state) : undef);
+ ##my $item = new yui::YTreeItem($s ? add_parent($s, $state) : undef, 0);
+ #print "S: $root :: $s :: $2 \n";
+ #my $item = new yui::YTreeItem($s, 0);
+ #my $iter = $w->{tree}->currentItem()->addChild($item);
+ #$w->{tree}->rebuildTree();
+ #$iter;
+ #};
+ #$s = $s2;
+ #}
+ ##set_node_state($wtree{$s}, $state, $w->{tree_model}); #- use this state by default as tree is building. #
+ #$wtree{$s};
+}
+
+sub add_node {
+ my ($leaf, $root, $o_options) = @_;
+ my $state = node_state($leaf) or return;
+ if ($leaf) {
+ my $iter;
+ if (is_a_package($leaf)) {
+ my ($name, $version, $release, $arch) = split_fullname($leaf);
+ $iter = $w->{detail_list_model}->append_set([ $pkg_columns{text} => $leaf,
+ $pkg_columns{short_name} => format_name_n_summary($name, get_summary($leaf)),
+ $pkg_columns{version} => $version,
+ $pkg_columns{release} => $release,
+ $pkg_columns{arch} => $arch,
+ ]);
+ set_node_state($iter, $state, $w->{detail_list_model});
+ $ptree{$leaf} = [ $iter ];
+ } else {
+ $iter = $w->{tree_model}->append_set(add_parent($w->{tree},$root, $state), [ $grp_columns{label} => $leaf ]);
+ push @{$wtree{$leaf}}, $iter;
+ }
+ } else {
+ my $parent = add_parent($w->{tree}, $root, $state);
+ #- hackery for partial displaying of trees, used in rpmdragora:
+ #- if leaf is void, we may create the parent and one child (to have the [+] in front of the parent in the ctree)
+ #- though we use '' as the label of the child; then rpmdragora will connect on tree_expand, and whenever
+ #- the first child has '' as the label, it will remove the child and add all the "right" children
+ $o_options->{nochild} or $w->{tree_model}->append_set($parent, [ $grp_columns{label} => '' ]); # test $leaf?
+ }
+}
+
+my ($prev_label);
+sub update_size {
+ my ($common) = shift @_;
+ if ($w->{status}) {
+ my $new_label = $common->{get_status}();
+ $prev_label ne $new_label and $w->{status}->setText($prev_label = $new_label);
+ }
+}
+
+sub children {
+ my ($w) = @_;
+ map { $w->{detail_list_model}->get($_, $pkg_columns{text}) } gtktreeview_children($w->{detail_list_model});
+}
+
+sub toggle_all {
+ my ($common, $_val) = @_;
+ my $w = $common->{widgets};
+ my @l = children($w) or return;
+
+ my @unsel = grep_unselected(@l);
+ my @p = @unsel ?
+ #- not all is selected, select all if no option to potentially override
+ (exists $common->{partialsel_unsel} && $common->{partialsel_unsel}->(\@unsel, \@l) ? difference2(\@l, \@unsel) : @unsel)
+ : @l;
+ toggle_nodes($w->{detail_list}->window, $w->{detail_list_model}, \&set_leaf_state, node_state($p[0]), @p);
+ update_size($common);
+}
+
+# ask_browse_tree_given_widgets_for_rpmdragora will run gtk+ loop. its main parameter "common" is a hash containing:
+# - a "widgets" subhash which holds:
+# o a "w" reference on a ugtk2 object
+# o "tree" & "info" references a TreeView
+# o "info" is a TextView
+# o "tree_model" is the associated model of "tree"
+# o "status" references a Label
+# - some methods: get_info, node_state, build_tree, partialsel_unsel, grep_unselected, rebuild_tree, toggle_nodes, get_status
+# - "tree_submode": the default mode (by group, ...), ...
+# - "state": a hash of misc flags: => { flat => '0' },
+# o "flat": is the tree flat or not
+# - "tree_mode": mode of the tree ("gui_pkgs", "by_group", ...) (mainly used by rpmdragora)
+
+sub ask_browse_tree_given_widgets_for_rpmdragora {
+ ($common) = @_;
+ $w = $common->{widgets};
+
+ $w->{detail_list} ||= $w->{tree};
+ #$w->{detail_list_model} ||= $w->{tree_model};
+
+ $common->{add_parent} = \&add_parent;
+ my $clear_all_caches = sub {
+ %ptree = %wtree = ();
+ };
+ $common->{clear_all_caches} = $clear_all_caches;
+ $common->{delete_all} = sub {
+ $clear_all_caches->();
+ #$w->{detail_list_model}->clear;
+ #$w->{tree_model}->clear;
+ };
+ $common->{rebuild_tree} = sub {
+ $common->{delete_all}->();
+ $common->{build_tree}($common->{state}{flat}, $common->{tree_mode});
+ update_size($common);
+ };
+ $common->{delete_category} = sub {
+ my ($cat) = @_;
+ exists $wtree{$cat} or return;
+ %ptree = ();
+
+ if (exists $wtree{$cat}) {
+ my $_iter_str = $w->{tree_model}->get_path_str($wtree{$cat});
+ $w->{tree_model}->remove($wtree{$cat});
+ delete $wtree{$cat};
+ }
+ update_size($common);
+ };
+ $common->{add_nodes} = sub {
+ my (@nodes) = @_;
+ print "@nodes\n";
+ #$w->{detail_list}->clear;
+ #$w->{detail_list}->scroll_to_point(0, 0);
+ add_node($_->[0], $_->[1], $_->[2]) foreach @nodes;
+ update_size($common);
+ };
+
+ $common->{display_info} = sub {
+ gtktext_insert($w->{info}, get_info($_[0], $w->{tree}->window));
+ $w->{info}->scroll_to_iter($w->{info}->get_buffer->get_start_iter, 0, 0, 0, 0);
+ 0;
+ };
+
+ my $fast_toggle = sub {
+ my ($iter) = @_;
+ gtkset_mousecursor_wait($w->{w}{rwindow}->window);
+ my $_cleaner = before_leaving { gtkset_mousecursor_normal($w->{w}{rwindow}->window) };
+ my $name = $w->{detail_list_model}->get($iter, $pkg_columns{text});
+ my $urpm_obj = $pkgs->{$name}{pkg};
+
+ if ($urpm_obj->flag_base) {
+ interactive_msg(N("Warning"),
+ N("Removing package %s would break your system", $name));
+ return '';
+ }
+
+ if ($urpm_obj->flag_skip) {
+ interactive_msg(N("Warning"), N("The \"%s\" package is in urpmi skip list.\nDo you want to select it anyway?", $name), yesno => 1) or return '';
+ $urpm_obj->set_flag_skip(0);
+ }
+
+ if ($Rpmdragora::pkg::need_restart && !$priority_up_alread_warned) {
+ $priority_up_alread_warned = 1;
+ interactive_msg(N("Warning"), '<b>' . N("Rpmdragora or one of its priority dependencies needs to be updated first. Rpmdragora will then restart.") . '</b>' . "\n\n");
+ }
+
+ toggle_nodes($w->{tree}->window, $w->{detail_list_model}, \&set_leaf_state, $w->{detail_list_model}->get($iter, $pkg_columns{state}),
+ $w->{detail_list_model}->get($iter, $pkg_columns{text}));
+ update_size($common);
+ };
+ #$w->{detail_list}->get_selection->signal_connect(changed => sub {
+ #my ($model, $iter) = $_[0]->get_selected;
+ #$model && $iter or return;
+ # $common->{display_info}($model->get($iter, $pkg_columns{text}));
+ #});
+ #($w->{detail_list}->get_column(0)->get_cell_renderers)[0]->signal_connect(toggled => sub {
+ # my ($_cell, $path) = @_; #text_
+ # my $iter = $w->{detail_list_model}->get_iter_from_string($path);
+ # $fast_toggle->($iter) if $iter;
+ # 1;
+ #});
+ $common->{rebuild_tree}->();
+ update_size($common);
+ #$common->{initial_selection} and toggle_nodes($w->{tree}->window, $w->{detail_list_model}, \&set_leaf_state, undef, @{$common->{initial_selection}});
+ #my $_b = before_leaving { $clear_all_caches->() };
+ $common->{init_callback}->() if $common->{init_callback};
+ #OLD $w->{w}->main;
+ $w->{w};
+}
+
+our $find_entry;
+
+sub reset_search() {
+ return if !$common;
+ $common->{delete_category}->($_) foreach $results_ok, $results_none;
+ # clear package list:
+ $common->{add_nodes}->();
+}
+
+sub is_a_package {
+ my ($pkg) = @_;
+ return exists $pkgs->{$pkg};
+}
+
+sub switch_pkg_list_mode {
+ my ($mode) = @_;
+ return if !$mode;
+ return if !$filter_methods{$mode};
+ $force_displaying_group = 1;
+ $filter_methods{$mode}->();
+}
+
+sub is_updatable {
+ my $p = $pkgs->{$_[0]};
+ $p->{pkg} && !$p->{selected} && $p->{pkg}->flag_installed && $p->{pkg}->flag_upgrade;
+}
+
+sub pkgs_provider {
+ my ($mode, %options) = @_;
+ return if !$mode;
+ my $h = &get_pkgs(%options);
+ ($urpm, $descriptions) = @$h{qw(urpm update_descr)};
+ $pkgs = $h->{all_pkgs};
+ %filters = (
+ non_installed => $h->{installable},
+ installed => $h->{installed},
+ all => [ keys %$pkgs ],
+ );
+ my %tmp_filter_methods = (
+ all => sub {
+ [ difference2([ keys %$pkgs ], $h->{inactive_backports}) ];
+ },
+ all_updates => sub {
+ # potential "updates" from media not tagged as updates:
+ if (!$options{pure_updates} && !$Rpmdragora::pkg::need_restart) {
+ [ @{$h->{updates}},
+ difference2([ grep { is_updatable($_) } @{$h->{installable}} ], $h->{backports}) ];
+ } else {
+ [ difference2($h->{updates}, $h->{inactive_backports}) ];
+ }
+ },
+ backports => sub { $h->{backports} },
+ meta_pkgs => sub {
+ [ difference2($h->{meta_pkgs}, $h->{inactive_backports}) ];
+ },
+ gui_pkgs => sub {
+ [ difference2($h->{gui_pkgs}, $h->{inactive_backports}) ];
+ },
+ );
+ foreach my $importance (qw(bugfix security normal)) {
+ $tmp_filter_methods{$importance} = sub {
+ my @media = keys %$descriptions;
+ [ grep {
+ my ($name) = split_fullname($_);
+ my $medium = find { $descriptions->{$_}{$name} } @media;
+ $medium && $descriptions->{$medium}{$name}{importance} eq $importance } @{$h->{updates}} ];
+ };
+ }
+
+ undef %filter_methods;
+ foreach my $type (keys %tmp_filter_methods) {
+ $filter_methods{$type} = sub {
+ $force_rebuild = 1; # force rebuilding tree since we changed filter (FIXME: switch to SortModel)
+ @filtered_pkgs = intersection($filters{$filter->[0]}, $tmp_filter_methods{$type}->());
+ };
+ }
+
+ switch_pkg_list_mode($mode);
+}
+
+sub closure_removal {
+ local $urpm->{state} = {};
+ urpm::select::find_packages_to_remove($urpm, $urpm->{state}, \@_);
+}
+
+sub is_locale_available {
+ my ($name) = @_;
+ any { $urpm->{depslist}[$_]->flag_selected } keys %{$urpm->{provides}{$name} || {}} and return 1;
+ my $found;
+ open_rpm_db()->traverse_tag_find('name', $name, sub { $found = 1 });
+ return $found;
+}
+
+sub callback_choices {
+ my (undef, undef, undef, $choices) = @_;
+ return $choices->[0] if $::rpmdragora_options{auto};
+ foreach my $pkg (@$choices) {
+ foreach ($pkg->requires_nosense) {
+ /locales-/ or next;
+ is_locale_available($_) and return $pkg;
+ }
+ }
+ my $callback = sub { interactive_msg(N("More information on package..."), get_info($_[0]), scroll => 1) };
+ $choices = [ sort { $a->name cmp $b->name } @$choices ];
+ my @choices = interactive_list_(N("Please choose"), (scalar(@$choices) == 1 ?
+ N("The following package is needed:") : N("One of the following packages is needed:")),
+ [ map { urpm_name($_) } @$choices ], $callback, nocancel => 1);
+ defined $choices[0] ? $choices->[$choices[0]] : undef;
+}
+
+sub deps_msg {
+ return 1 if $dont_show_selections->[0];
+ my ($title, $msg, $nodes, $nodes_with_deps) = @_;
+ my @deps = sort { $a cmp $b } difference2($nodes_with_deps, $nodes);
+ @deps > 0 or return 1;
+ deps_msg_again:
+ my $results = interactive_msg(
+ $title, $msg .
+ format_list(map { scalar(urpm::select::translate_why_removed_one($urpm, $urpm->{state}, $_)) } @deps)
+ . "\n\n" . format_size($urpm->selected_size($urpm->{state})),
+ yesno => [ N("Cancel"), N("More info"), N("Ok") ],
+ scroll => 1,
+ );
+ if ($results eq
+ #-PO: Keep it short, this is gonna be on a button
+ N("More info")) {
+ interactive_packtable(
+ N("Information on packages"),
+ $::main_window,
+ undef,
+ [ map { my $pkg = $_;
+ [ gtknew('HBox', children_tight => [ gtkset_selectable(gtknew('Label', text => $pkg), 1) ]),
+ gtknew('Button', text => N("More information on package..."),
+ clicked => sub {
+ interactive_msg(N("More information on package..."), get_info($pkg), scroll => 1);
+ }) ] } @deps ],
+ [ gtknew('Button', text => N("Ok"),
+ clicked => sub { Gtk2->main_quit }) ]
+ );
+ goto deps_msg_again;
+ } else {
+ return $results eq N("Ok");
+ }
+}
+
+sub toggle_nodes {
+ my ($widget, $model, $set_state, $old_state, @nodes) = @_;
+ @nodes = grep { exists $pkgs->{$_} } @nodes
+ or return;
+ #- avoid selecting too many packages at once
+ return if !$dont_show_selections->[0] && @nodes > 2000;
+ my $new_state = !$pkgs->{$nodes[0]}{selected};
+
+ my @nodes_with_deps;
+
+ my $bar_id = statusbar_msg(N("Checking dependencies of package..."), 0);
+
+ my $warn_about_additional_packages_to_remove = sub {
+ my ($msg) = @_;
+ statusbar_msg_remove($bar_id);
+ deps_msg(N("Some additional packages need to be removed"),
+ formatAlaTeX($msg) . "\n\n",
+ \@nodes, \@nodes_with_deps) or @nodes_with_deps = ();
+ };
+
+ if (member($old_state, qw(to_remove installed))) { # remove pacckages
+ if ($new_state) {
+ my @remove;
+ slow_func($widget, sub { @remove = closure_removal(@nodes) });
+ @nodes_with_deps = grep { !$pkgs->{$_}{selected} && !/^basesystem/ } @remove;
+ $warn_about_additional_packages_to_remove->(
+ N("Because of their dependencies, the following package(s) also need to be removed:"));
+ my @impossible_to_remove;
+ foreach (grep { exists $pkgs->{$_}{base} } @remove) {
+ ${$pkgs->{$_}{base}} == 1 ? push @impossible_to_remove, $_ : ${$pkgs->{$_}{base}}--;
+ }
+ @impossible_to_remove and interactive_msg(N("Some packages cannot be removed"),
+ N("Removing these packages would break your system, sorry:\n\n") .
+ format_list(@impossible_to_remove));
+ @nodes_with_deps = difference2(\@nodes_with_deps, \@impossible_to_remove);
+ } else {
+ slow_func($widget,
+ sub { @nodes_with_deps = grep { intersection(\@nodes, [ closure_removal($_) ]) }
+ grep { $pkgs->{$_}{selected} && !member($_, @nodes) } keys %$pkgs });
+ push @nodes_with_deps, @nodes;
+ $warn_about_additional_packages_to_remove->(
+ N("Because of their dependencies, the following package(s) must be unselected now:\n\n"));
+ $pkgs->{$_}{base} && ${$pkgs->{$_}{base}}++ foreach @nodes_with_deps;
+ }
+ } else {
+ if ($new_state) {
+ if (@nodes > 1) {
+ #- unselect i18n packages of which locales is not already present (happens when user clicks on KDE group)
+ my @bad_i18n_pkgs;
+ foreach my $sel (@nodes) {
+ foreach ($pkgs->{$sel}{pkg}->requires_nosense) {
+ /locales-([^-]+)/ or next;
+ $sel =~ /-$1[-_]/ && !is_locale_available($_) and push @bad_i18n_pkgs, $sel;
+ }
+ }
+ @nodes = difference2(\@nodes, \@bad_i18n_pkgs);
+ }
+ my @requested;
+ slow_func(
+ $widget,
+ sub {
+ @requested = $urpm->resolve_requested(
+ open_rpm_db(), $urpm->{state},
+ { map { $pkgs->{$_}{pkg}->id => 1 } @nodes },
+ callback_choices => \&callback_choices,
+ );
+ },
+ );
+ @nodes_with_deps = map { urpm_name($_) } @requested;
+ statusbar_msg_remove($bar_id);
+ if (!deps_msg(N("Additional packages needed"),
+ formatAlaTeX(N("To satisfy dependencies, the following package(s) also need to be installed:\n\n")) . "\n\n",
+ \@nodes, \@nodes_with_deps)) {
+ @nodes_with_deps = ();
+ $urpm->disable_selected(open_rpm_db(), $urpm->{state}, @requested);
+ goto packages_selection_ok;
+ }
+
+ if (my $conflicting_msg = urpm::select::conflicting_packages_msg($urpm, $urpm->{state})) {
+ if (!interactive_msg(N("Conflicting Packages"), $conflicting_msg, yesno => 1, scroll => 1)) {
+ @nodes_with_deps = ();
+ $urpm->disable_selected(open_rpm_db(), $urpm->{state}, @requested);
+ goto packages_selection_ok;
+ }
+ }
+
+ if (my @cant = sort(difference2(\@nodes, \@nodes_with_deps))) {
+ my @ask_unselect = urpm::select::unselected_packages($urpm->{state});
+ my @reasons = map {
+ my $cant = $_;
+ my $unsel = find { $_ eq $cant } @ask_unselect;
+ $unsel
+ ? join("\n", urpm::select::translate_why_unselected($urpm, $urpm->{state}, $unsel))
+ : ($pkgs->{$_}{pkg}->flag_skip ? N("%s (belongs to the skip list)", $cant) : $cant);
+ } @cant;
+ my $count = @reasons;
+ interactive_msg(
+ ($count == 1 ? N("One package cannot be installed") : N("Some packages cannot be installed")),
+ ($count == 1 ?
+ N("Sorry, the following package cannot be selected:\n\n%s", format_list(@reasons))
+ : N("Sorry, the following packages cannot be selected:\n\n%s", format_list(@reasons))),
+ scroll => 1,
+ );
+ foreach (@cant) {
+ next unless $pkgs->{$_}{pkg};
+ $pkgs->{$_}{pkg}->set_flag_requested(0);
+ $pkgs->{$_}{pkg}->set_flag_required(0);
+ }
+ }
+ packages_selection_ok:
+ } else {
+ my @unrequested;
+ slow_func($widget,
+ sub { @unrequested = $urpm->disable_selected(open_rpm_db(), $urpm->{state},
+ map { $pkgs->{$_}{pkg} } @nodes) });
+ @nodes_with_deps = map { urpm_name($_) } @unrequested;
+ statusbar_msg_remove($bar_id);
+ if (!deps_msg(N("Some packages need to be removed"),
+ N("Because of their dependencies, the following package(s) must be unselected now:\n\n"),
+ \@nodes, \@nodes_with_deps)) {
+ @nodes_with_deps = ();
+ $urpm->resolve_requested(open_rpm_db(), $urpm->{state}, { map { $_->id => 1 } @unrequested });
+ goto packages_unselection_ok;
+ }
+ packages_unselection_ok:
+ }
+ }
+
+ foreach (@nodes_with_deps) {
+ #- some deps may exist on some packages which aren't listed because
+ #- not upgradable (older than what currently installed)
+ exists $pkgs->{$_} or next;
+ if (!$pkgs->{$_}{pkg}) { #- can't be removed # FIXME; what about next packages in the loop?
+ undef $pkgs->{$_}{selected};
+ log::explanations("can't be removed: $_");
+ } else {
+ $pkgs->{$_}{selected} = $new_state;
+ }
+ $set_state->($_, node_state($_), $model);
+ if (my $pkg = $pkgs->{$_}{pkg}) {
+ # FIXME: shouldn't we threat all of them as POSITIVE (as selected size)
+ $size_selected += $pkg->size * ($pkg->flag_installed && !$pkg->flag_upgrade ? ($new_state ? -1 : 1) : ($new_state ? 1 : -1));
+ }
+ }
+}
+
+sub is_there_selected_packages() {
+ int(grep { $pkgs->{$_}{selected} } keys %$pkgs);
+}
+
+sub real_quit() {
+ if (is_there_selected_packages()) {
+ interactive_msg(N("Some packages are selected."), N("Some packages are selected.") . "\n" . N("Do you really want to quit?"), yesno => 1) or return;
+ }
+ Gtk2->main_quit;
+}
+
+sub do_action__real {
+ my ($options, $callback_action, $o_info) = @_;
+ require urpm::sys;
+ if (!urpm::sys::check_fs_writable()) {
+ $urpm->{fatal}(1, N("Error: %s appears to be mounted read-only.", $urpm::sys::mountpoint));
+ return 1;
+ }
+ if (!$Rpmdragora::pkg::need_restart && !is_there_selected_packages()) {
+ interactive_msg(N("You need to select some packages first."), N("You need to select some packages first."));
+ return 1;
+ }
+ my $size_added = sum(map { if_($_->flag_selected && !$_->flag_installed, $_->size) } @{$urpm->{depslist}});
+ if ($MODE eq 'install' && $size_free - $size_added/1024 < 50*1024) {
+ interactive_msg(N("Too many packages are selected"),
+ N("Warning: it seems that you are attempting to add so many
+packages that your filesystem may run out of free diskspace,
+during or after package installation ; this is particularly
+dangerous and should be considered with care.
+
+Do you really want to install all the selected packages?"), yesno => 1)
+ or return 1;
+ }
+ my $res = $callback_action->($urpm, $pkgs);
+ if (!$res) {
+ $force_rebuild = 1;
+ pkgs_provider($options->{tree_mode}, if_($Rpmdragora::pkg::probe_only_for_updates, pure_updates => 1), skip_updating_mu => 1);
+ reset_search();
+ $size_selected = 0;
+ (undef, $size_free) = MDK::Common::System::df('/usr');
+ $options->{rebuild_tree}->() if $options->{rebuild_tree};
+ gtktext_insert($o_info, '') if $o_info;
+ }
+ $res;
+}
+
+sub do_action {
+ my ($options, $callback_action, $o_info) = @_;
+ my $res = eval { do_action__real($options, $callback_action, $o_info) };
+ my $err = $@;
+ # FIXME: offer to report the problem into bugzilla:
+ if ($err && $err !~ /cancel_perform/) {
+ interactive_msg(N("Fatal error"),
+ N("A fatal error occurred: %s.", $err));
+ }
+ $res;
+}
+
+sub translate_group {
+ join('/', map { translate($_) } split m|/|, $_[0]);
+}
+
+sub ctreefy {
+ join('|', map { translate($_) } split m|/|, $_[0]);
+}
+
+sub _build_tree {
+ my ($tree, $elems, @elems) = @_;
+ #- we populate all the groups tree at first
+ %$elems = ();
+ # better loop on packages, create groups tree and push packages in the proper place:
+ foreach my $pkg (@elems) {
+ my $grp = $pkg->[1];
+ # no state for groups (they're not packages and thus have no state)
+ add_parent($tree, $grp, undef);
+ $elems->{$grp} ||= [];
+ push @{$elems->{$grp}}, $pkg;
+ }
+}
+
+
+sub build_tree {
+ my ($tree, $tree_model, $elems, $options, $force_rebuild, $flat, $mode) = @_;
+ state $old_mode;
+ $mode = $options->{rmodes}{$mode} || $mode;
+ return if $old_mode eq $mode && !$force_rebuild;
+ $old_mode = $mode;
+ undef $force_rebuild;
+ my @elems;
+ my $wait; $wait = statusbar_msg(N("Please wait, listing packages...")) if $MODE ne 'update';
+ #gtkflush();
+ {
+ my @keys = @filtered_pkgs;
+ if (member($mode, qw(all_updates security bugfix normal))) {
+ @keys = grep {
+ my ($name) = split_fullname($_);
+ member($descriptions->{$name}{importance}, @$mandrakeupdate_wanted_categories)
+ || ! $descriptions->{$name}{importance};
+ } @keys;
+ if (@keys == 0) {
+ add_node($tree, '', N("(none)"), { nochild => 1 });
+ state $explanation_only_once;
+ $explanation_only_once or interactive_msg(N("No update"),
+ N("The list of updates is empty. This means that either there is
+no available update for the packages installed on your computer,
+or you already installed all of them."));
+ $explanation_only_once = 1;
+ }
+ }
+ # FIXME: better do this on first group access for faster startup...
+ @elems = map { [ $_, !$flat && ctreefy($pkgs->{$_}{pkg}->group) ] } sort_packages(@keys);
+ }
+ my %sortmethods = (
+ by_size => sub { sort { $pkgs->{$b->[0]}{pkg}->size <=> $pkgs->{$a->[0]}{pkg}->size } @_ },
+ by_selection => sub { sort { $pkgs->{$b->[0]}{selected} <=> $pkgs->{$a->[0]}{selected}
+ || uc($a->[0]) cmp uc($b->[0]) } @_ },
+ by_leaves => sub {
+ # inlining part of MDK::Common::Data::difference2():
+ my %l; @l{map { $_->[0] } @_} = ();
+ my @pkgs_times = ('rpm', '-q', '--qf', '%{name}-%{version}-%{release}.%{arch} %{installtime}\n',
+ map { chomp_($_) } run_program::get_stdout('urpmi_rpm-find-leaves'));
+ sort { $b->[1] <=> $a->[1] } grep { exists $l{$_->[0]} } map { chomp; [ split ] } run_rpm(@pkgs_times);
+ },
+ flat => sub { no locale; sort { uc($a->[0]) cmp uc($b->[0]) } @_ },
+ by_medium => sub { sort { $a->[2] <=> $b->[2] || uc($a->[0]) cmp uc($b->[0]) } @_ },
+ );
+ if ($flat) {
+ add_node($_->[0], '') foreach $sortmethods{$::mode->[0] || 'flat'}->(@elems);
+ } else {
+ if (0 && $MODE eq 'update') {
+ add_node($tree, $_->[0], N("All")) foreach $sortmethods{flat}->(@elems);
+ $tree->expand_row($tree_model->get_path($tree_model->get_iter_first), 0);
+ } elsif ($::mode->[0] eq 'by_source') {
+ _build_tree($tree, $elems, $sortmethods{by_medium}->(map {
+ my $m = pkg2medium($pkgs->{$_->[0]}{pkg}, $urpm); [ $_->[0], $m->{name}, $m->{priority} ];
+ } @elems));
+ } elsif ($::mode->[0] eq 'by_presence') {
+ _build_tree($tree, $elems, map {
+ my $pkg = $pkgs->{$_->[0]}{pkg};
+ [ $_->[0], $pkg->flag_installed ?
+ (!$pkg->flag_skip && $pkg->flag_upgrade ? N("Upgradable") : N("Installed"))
+ : N("Addable") ];
+ } $sortmethods{flat}->(@elems));
+ } else {
+ _build_tree($tree, $elems, @elems);
+ }
+ }
+ statusbar_msg_remove($wait) if defined $wait;
+}
+
+sub get_info {
+ my ($key, $widget) = @_;
+ #- the package information hasn't been loaded. Instead of rescanning the media, just give up.
+ exists $pkgs->{$key} or return [ [ N("Description not available for this package\n") ] ];
+ #- get the description if needed:
+ exists $pkgs->{$key}{description} or slow_func($widget, sub { extract_header($pkgs->{$key}, $urpm, 'info', find_installed_version($pkgs->{$key}{pkg})) });
+ format_pkg_simplifiedinfo($pkgs, $key, $urpm, $descriptions);
+}
+
+sub sort_callback {
+ my ($store, $treeiter1, $treeiter2) = @_;
+ URPM::rpmvercmp(map { $store->get_value($_, $pkg_columns{version}) } $treeiter1, $treeiter2);
+}
+
+sub run_help_callback {
+ my (undef, $url) = @_;
+ my ($user) = grep { $_->[2] eq $ENV{USERHELPER_UID} } list_passwd();
+ local $ENV{HOME} = $user->[7] if $user && $ENV{USERHELPER_UID};
+ run_program::raw({ detach => 1, as_user => 1 }, 'www-browser', $url);
+}
+
+1;
diff --git a/AdminPanel/Rpmdragora/gurpm.pm b/AdminPanel/Rpmdragora/gurpm.pm
new file mode 100644
index 0000000..412d589
--- /dev/null
+++ b/AdminPanel/Rpmdragora/gurpm.pm
@@ -0,0 +1,133 @@
+package AdminPanel::Rpmdragora::gurpm;
+#*****************************************************************************
+#
+# Copyright (c) 2002 Guillaume Cottenceau
+# Copyright (c) 2002-2007 Thierry Vignaud <tvignaud@mandriva.com>
+# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA
+# Copyright (c) 2005-2007 Mandriva SA
+# Copyright (c) 2013 Matteo Pasotti <matteo.pasotti@gmail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2, as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#*****************************************************************************
+#
+# $Id: gurpm.pm 255450 2009-04-03 16:00:16Z tv $
+
+package AdminPanel::Rpmdragora::gurpm;
+
+use strict;
+use lib qw(/usr/lib/libDrakX);
+use yui;
+use Time::HiRes;
+use feature 'state';
+
+sub new {
+ my ($class, $title, $initializing, %options) = @_;
+ my $self = {
+ my $label = 0,
+ my $factory = 0,
+ my $mainw = 0,
+ my $vbox = 0,
+ my $progressbar = 0,
+ my $cancel = 0
+ };
+ bless $self, 'AdminPanel::Rpmdragora::gurpm';
+ #my $mainw = bless(ugtk2->new($title, %options, default_width => 600, width => 600), $self);
+ $self->{factory} = yui::YUI::widgetFactory;
+ $self->{mainw} = $self->{factory}->createPopupDialog();
+ $::main_window = $self->{mainw};
+ $self->{vbox} = $self->{factory}->createVBox($self->{mainw});
+ #OLD $mainw->{label} = gtknew('Label', text => $initializing, alignment => [ 0.5, 0 ]);
+ $self->{label} = $self->{factory}->createLabel($self->{vbox}, $initializing);
+ # size label's heigh to 2 lines in order to prevent dummy vertical resizing:
+ #my $context = $mainw->{label}->get_layout->get_context;
+ #my $metrics = $context->get_metrics($mainw->{label}->style->font_desc, $context->get_language);
+ #$mainw->{label}->set_size_request(-1, 2 * Gtk2::Pango->PANGO_PIXELS($metrics->get_ascent + $metrics->get_descent));
+
+ #OLD $mainw->{progressbar} = gtknew('ProgressBar');
+ $self->{progressbar} = $self->{factory}->createProgressBar($self->{vbox}, "");
+ #gtkadd($mainw->{window}, $mainw->{vbox} = gtknew('VBox', spacing => 5, border_width => 6, children_tight => [
+ # $mainw->{label},
+ # $mainw->{progressbar}
+ #]));
+ #$mainw->{rwindow}->set_position('center-on-parent');
+ #$mainw->{real_window}->show_all;
+ #select(undef, undef, undef, 0.1); #- hackish :-(
+ #$mainw->SUPER::sync;
+ $self->{mainw}->recalcLayout();
+ $self->{mainw}->doneMultipleChanges();
+ $self;
+}
+
+sub label {
+ my ($self, $label) = @_;
+ $self->{label} = $self->{factory}->createLabel($self->{vbox},$label);
+ #select(undef, undef, undef, 0.1); #- hackish :-(
+ #$self->flush;
+}
+
+sub progress {
+ my ($self, $value) = @_;
+ state $time;
+ $value = 0 if $value < 0;
+ $value = 100 if 1 < $value;
+ $self->{progressbar}->setValue($value);
+ return if Time::HiRes::clock_gettime() - $time < 0.333;
+ $time = Time::HiRes::clock_gettime();
+ #$self->flush;
+}
+
+sub DESTROY {
+ my ($self) = @_;
+ #mygtk2::may_destroy($self);
+ $self and $self->{mainw}->destroy;
+ #$self = undef;
+ $self->{cancel} = undef; #- in case we'll do another one later
+}
+
+sub validate_cancel {
+ my ($self, $cancel_msg, $cancel_cb) = @_;
+ if (!$self->{cancel}) {
+ $self->{cancel} = $self->{factory}->createIconButton($self->{vbox},"",$cancel_msg);
+ #gtkpack__(
+ #$self->{vbox},
+ #$self->{hbox_cancel} = gtkpack__(
+ #gtknew('HButtonBox'),
+ #$self->{cancel} = gtknew('Button', text => $cancel_msg, clicked => \&$cancel_cb),
+ #),
+ #);
+ }
+ #$self->{cancel}->set_sensitive(1);
+ #$self->{cancel}->show;
+ $self->{mainw}->recalcLayout();
+ $self->{mainw}->doneMultipleChanges();
+}
+
+sub invalidate_cancel {
+ my ($self) = @_;
+ $self->{cancel} and $self->{cancel}->setEnabled(0);
+}
+
+sub invalidate_cancel_forever {
+ my ($self) = @_;
+ #$self->{hbox_cancel} or return;
+ #$self->{hbox_cancel}->destroy;
+ # FIXME: temporary workaround that prevents
+ # Gtk2::Label::set_text() set_text_internal() -> queue_resize() ->
+ # size_allocate() call chain to mess up when ->shrink_topwindow()
+ # has been called (#32613):
+ #$self->shrink_topwindow;
+}
+
+1;
diff --git a/AdminPanel/Rpmdragora/icon.pm b/AdminPanel/Rpmdragora/icon.pm
new file mode 100644
index 0000000..2616aad
--- /dev/null
+++ b/AdminPanel/Rpmdragora/icon.pm
@@ -0,0 +1,231 @@
+package AdminPanel::Rpmdragora::icon;
+#*****************************************************************************
+#
+# Copyright (c) 2002 Guillaume Cottenceau
+# Copyright (c) 2002-2007 Thierry Vignaud <tvignaud@mandriva.com>
+# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA
+# Copyright (c) 2005-2007 Mandriva SA
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2, as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#*****************************************************************************
+#
+# $Id: icon.pm 237459 2008-02-26 14:20:47Z tv $
+
+use strict;
+our @ISA = qw(Exporter);
+use lib qw(/usr/lib/libDrakX);
+use common;
+
+
+our @EXPORT = qw(get_icon);
+#- /usr/share/rpmlint/config (duplicates are normal, so that we are not too far away from .py)
+my %group_icons = (
+ N_("All") => 'system_section',
+ N_("Accessibility") => 'accessibility_section',
+ N_("Archiving") => 'archiving_section',
+ join('|', N_("Archiving"), N_("Backup")) => 'backup_section',
+ join('|', N_("Archiving"), N_("Cd burning")) => 'cd_burning_section',
+ join('|', N_("Archiving"), N_("Compression")) => 'compression_section',
+ join('|', N_("Archiving"), N_("Other")) => 'other_archiving',
+ N_("Communications") => 'communications_section',
+ join('|', N_("Communications"), N_("Bluetooth")) => 'communications_section',
+ join('|', N_("Communications"), N_("Bluetooth")) => 'communications_section',
+ join('|', N_("Communications"), N_("Dial-Up")) => 'communications_section',
+ join('|', N_("Communications"), N_("Fax")) => 'communications_section',
+ join('|', N_("Communications"), N_("Mobile")) => 'communications_section',
+ join('|', N_("Communications"), N_("Radio")) => 'communications_section',
+ join('|', N_("Communications"), N_("Serial")) => 'communications_section',
+ join('|', N_("Communications"), N_("Telephony")) => 'communications_section',
+ N_("Databases") => 'databases_section',
+ N_("Development") => 'development_section',
+ join('|', N_("Development"), N_("Basic")) => '',
+ join('|', N_("Development"), N_("C")) => '',
+ join('|', N_("Development"), N_("C++")) => '',
+ join('|', N_("Development"), N_("C#")) => '',
+ join('|', N_("Development"), N_("Databases")) => 'databases_section',
+ join('|', N_("Development"), N_("Erlang")) => '',
+ join('|', N_("Development"), N_("GNOME and GTK+")) => 'gnome_section',
+ join('|', N_("Development"), N_("Java")) => '',
+ join('|', N_("Development"), N_("KDE and Qt")) => 'kde_section',
+ join('|', N_("Development"), N_("Kernel")) => 'hardware_configuration_section',
+ join('|', N_("Development"), N_("OCaml")) => '',
+ join('|', N_("Development"), N_("Other")) => 'development_tools_section',
+ join('|', N_("Development"), N_("Perl")) => '',
+ join('|', N_("Development"), N_("PHP")) => '',
+ join('|', N_("Development"), N_("Python")) => '',
+ join('|', N_("Development"), N_("Tools")) => '',
+ join('|', N_("Development"), N_("X11")) => 'office_section',
+ N_("Documentation") => 'documentation_section',
+ N_("Editors") => 'emulators_section',
+ N_("Education") => 'education_section',
+ N_("Emulators") => 'emulators_section',
+ N_("File tools") => 'file_tools_section',
+ N_("Games") => 'amusement_section',
+ join('|', N_("Games"), N_("Adventure")) => 'adventure_section',
+ join('|', N_("Games"), N_("Arcade")) => 'arcade_section',
+ join('|', N_("Games"), N_("Boards")) => 'boards_section',
+ join('|', N_("Games"), N_("Cards")) => 'cards_section',
+ join('|', N_("Games"), N_("Other")) => 'other_amusement',
+ join('|', N_("Games"), N_("Puzzles")) => 'puzzle_section',
+ join('|', N_("Games"), N_("Shooter")) => 'other_amusement',
+ join('|', N_("Games"), N_("Sports")) => 'sport_section',
+ join('|', N_("Games"), N_("Strategy")) => 'strategy_section',
+ N_("Geography") => 'geosciences_section',
+ N_("Graphical desktop") => 'office_section',
+ join('|', N_("Graphical desktop"),
+ #-PO: This is a package/product name. Only translate it if needed:
+ N_("Enlightenment")) => '',
+ join('|', N_("Graphical desktop"), N_("FVWM based")) => '',
+ join('|', N_("Graphical desktop"),
+ #-PO: This is a package/product name. Only translate it if needed:
+ N_("GNOME")) => 'gnome_section',
+ join('|', N_("Graphical desktop"),
+ #-PO: This is a package/product name. Only translate it if needed:
+ N_("Icewm")) => '',
+ join('|', N_("Graphical desktop"),
+ #-PO: This is a package/product name. Only translate it if needed:
+ N_("KDE")) => 'kde_section',
+ join('|', N_("Graphical desktop"), N_("Other")) => 'more_applications_other_section',
+ join('|', N_("Graphical desktop"),
+ #-PO: This is a package/product name. Only translate it if needed:
+ N_("Sawfish")) => '',
+ join('|', N_("Graphical desktop"),
+ #-PO: This is a package/product name. Only translate it if needed:
+ N_("WindowMaker")) => '',
+ join('|', N_("Graphical desktop"),
+ #-PO: This is a package/product name. Only translate it if needed:
+ N_("Xfce")) => '',
+ N_("Graphics") => 'graphics_section',
+ join('|', N_("Graphics"), N_("3D")) => '',
+ join('|', N_("Graphics"), N_("Editors")) => '',
+ join('|', N_("Graphics"), N_("Other")) => '',
+ join('|', N_("Graphics"), N_("Photography")) => '',
+ join('|', N_("Graphics"), N_("Scanning")) => '',
+ join('|', N_("Graphics"), N_("Viewers")) => '',
+ N_("Monitoring") => 'monitoring_section',
+ N_("Multimedia") => 'multimedia_section',
+ join('|', N_("Multimedia"), N_("Video")) => 'video_section',
+ N_("Networking") => 'networking_section',
+ join('|', N_("Networking"), N_("Chat")) => 'chat_section',
+ join('|', N_("Networking"), N_("File transfer")) => 'file_transfer_section',
+ join('|', N_("Networking"), N_("IRC")) => 'irc_section',
+ join('|', N_("Networking"), N_("Instant messaging")) => 'instant_messaging_section',
+ join('|', N_("Networking"), N_("Mail")) => 'mail_section',
+ join('|', N_("Networking"), N_("News")) => 'news_section',
+ join('|', N_("Networking"), N_("Other")) => 'other_networking',
+ join('|', N_("Networking"), N_("Remote access")) => 'remote_access_section',
+ join('|', N_("Networking"), N_("WWW")) => 'networking_www_section',
+ N_("Office") => 'office_section',
+ join('|', N_("Office"), N_("Dictionary")) => '',
+ join('|', N_("Office"), N_("Finance")) => '',
+ join('|', N_("Office"), N_("Management")) => '',
+ join('|', N_("Office"), N_("Organizer")) => '',
+ join('|', N_("Office"), N_("Other")) => '',
+ join('|', N_("Office"), N_("Spreadsheet")) => '',
+ join('|', N_("Office"), N_("Suite")) => '',
+ join('|', N_("Office"), N_("Word processor")) => '',
+ N_("Public Keys") => 'packaging_section',
+ N_("Publishing") => 'publishing_section',
+ N_("Security") => 'packaging_section',
+ N_("Sciences") => 'sciences_section',
+ join('|', N_("Sciences"), N_("Astronomy")) => 'astronomy_section',
+ join('|', N_("Sciences"), N_("Biology")) => 'biology_section',
+ join('|', N_("Sciences"), N_("Chemistry")) => 'chemistry_section',
+ join('|', N_("Sciences"), N_("Computer science")) => 'computer_science_section',
+ join('|', N_("Sciences"), N_("Geosciences")) => 'geosciences_section',
+ join('|', N_("Sciences"), N_("Mathematics")) => 'mathematics_section',
+ join('|', N_("Sciences"), N_("Other")) => 'other_sciences',
+ join('|', N_("Sciences"), N_("Physics")) => 'physics_section',
+ N_("Shells") => 'shells_section',
+ N_("Sound") => 'sound_section',
+ join('|', N_("Sound"), N_("Editors and Converters")) => '',
+ join('|', N_("Sound"), N_("Midi")) => '',
+ join('|', N_("Sound"), N_("Mixers")) => '',
+ join('|', N_("Sound"), N_("Players")) => '',
+ join('|', N_("Sound"), N_("Utilities")) => '',
+ join('|', N_("Sound"), N_("Visualization")) => '',
+ N_("System") => 'system_section',
+ join('|', N_("System"), N_("Base")) => 'system_section',
+ join('|', N_("System"), N_("Cluster")) => 'parallel_computing_section',
+ join('|', N_("System"), N_("Configuration")) => 'configuration_section',
+ join('|', N_("System"), N_("Configuration"), N_("Boot and Init")) => 'boot_init_section',
+ join('|', N_("System"), N_("Configuration"), N_("Hardware")) => 'hardware_configuration_section',
+ join('|', N_("System"), N_("Configuration"), N_("Networking")) => 'networking_configuration_section',
+ join('|', N_("System"), N_("Configuration"), N_("Other")) => 'system_other_section',
+ join('|', N_("System"), N_("Configuration"), N_("Packaging")) => 'packaging_section',
+ join('|', N_("System"), N_("Configuration"), N_("Printing")) => 'printing_section',
+ join('|', N_("System"), N_("Fonts")) => 'chinese_section',
+ join('|', N_("System"), N_("Fonts"), N_("Console")) => 'interpreters_section',
+ join('|', N_("System"), N_("Fonts"), N_("True type")) => '',
+ join('|', N_("System"), N_("Fonts"), N_("Type1")) => '',
+ join('|', N_("System"), N_("Fonts"), N_("X11 bitmap")) => '',
+ join('|', N_("System"), N_("Internationalization")) => 'chinese_section',
+ join('|', N_("System"), N_("Kernel and hardware")) => 'hardware_configuration_section',
+ join('|', N_("System"), N_("Libraries")) => '',
+ join('|', N_("System"), N_("Printing")) => 'printing_section',
+ join('|', N_("System"), N_("Servers")) => '',
+ join('|', N_("System"),
+ #-PO: This is a package/product name. Only translate it if needed:
+ N_("X11")) => 'office_section',
+ N_("Terminals") => 'terminals_section',
+ N_("Text tools") => 'text_tools_section',
+ N_("Toys") => 'toys_section',
+ N_("Video") => 'video_section',
+ join('|', N_("Video"), N_("Editors and Converters")) => '',
+ join('|', N_("Video"), N_("Players")) => '',
+ join('|', N_("Video"), N_("Utilities")) => '',
+
+ # for Mageia Choice:
+ N_("Workstation") => 'office_section',
+ join('|', N_("Workstation"), N_("Configuration")) => 'configuration_section',
+ join('|', N_("Workstation"), N_("Console Tools")) => 'interpreters_section',
+ join('|', N_("Workstation"), N_("Documentation")) => 'documentation_section',
+ join('|', N_("Workstation"), N_("Game station")) => 'amusement_section',
+ join('|', N_("Workstation"), N_("Internet station")) => 'networking_section',
+ join('|', N_("Workstation"), N_("Multimedia station")) => 'multimedia_section',
+ join('|', N_("Workstation"), N_("Network Computer (client)")) => 'other_networking',
+ join('|', N_("Workstation"), N_("Office Workstation")) => 'office_section',
+ join('|', N_("Workstation"), N_("Scientific Workstation")) => 'sciences_section',
+ N_("Graphical Environment") => 'office_section',
+
+ join('|', N_("Graphical Environment"), N_("GNOME Workstation")) => 'gnome_section',
+ join('|', N_("Graphical Environment"), N_("IceWm Desktop")) => 'icewm',
+ join('|', N_("Graphical Environment"), N_("KDE Workstation")) => 'kde_section',
+ join('|', N_("Graphical Environment"), N_("Other Graphical Desktops")) => 'more_applications_other_section',
+ N_("Development") => 'development_section',
+ join('|', N_("Development"), N_("Development")) => 'development_section',
+ join('|', N_("Development"), N_("Documentation")) => 'documentation_section',
+ N_("Server") => 'archiving_section',
+ join('|', N_("Server"), N_("DNS/NIS")) => 'networking_section',
+ join('|', N_("Server"), N_("Database")) => 'databases_section',
+ join('|', N_("Server"), N_("Firewall/Router")) => 'networking_section',
+ join('|', N_("Server"), N_("Mail")) => 'mail_section',
+ join('|', N_("Server"), N_("Mail/Groupware/News")) => 'mail_section',
+ join('|', N_("Server"), N_("Network Computer server")) => 'networking_section',
+ join('|', N_("Server"), N_("Web/FTP")) => 'networking_www_section',
+
+ );
+
+sub get_icon {
+ my ($group, $o_parent) = @_;
+ my $pixbuf;
+ my $path = $group =~ /\|/ ? '/usr/share/icons/mini/' : '/usr/share/icons/';
+ my $create_pixbuf = sub { eval { gtknew('Pixbuf', file => join('', $path, $_[0], '.png')) } };
+ $pixbuf = $create_pixbuf->($group_icons{$group});
+ $pixbuf ||= $create_pixbuf->($group_icons{$o_parent}) if $o_parent;
+ $pixbuf ||= $create_pixbuf->('applications_section');
+}
+
+1;
diff --git a/AdminPanel/Rpmdragora/init.pm b/AdminPanel/Rpmdragora/init.pm
new file mode 100644
index 0000000..d178653
--- /dev/null
+++ b/AdminPanel/Rpmdragora/init.pm
@@ -0,0 +1,168 @@
+package AdminPanel::Rpmdragora::init;
+#*****************************************************************************
+#
+# Copyright (c) 2002 Guillaume Cottenceau
+# Copyright (c) 2002-2007 Thierry Vignaud <tvignaud@mandriva.com>
+# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA
+# Copyright (c) 2005-2007 Mandriva SA
+# Copyright (c) 2013 Matteo Pasotti <matteo.pasotti@gmail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2, as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#*****************************************************************************
+#
+# $Id: init.pm 263915 2009-12-03 17:41:04Z tv $
+
+use strict;
+use MDK::Common::Func 'any';
+use lib qw(/usr/lib/libDrakX);
+use common;
+BEGIN { $::no_global_argv_parsing = 1 }
+require urpm::args;
+
+use Exporter;
+our @ISA = qw(Exporter);
+our @EXPORT = qw(init
+ warn_about_user_mode
+ $MODE
+ $changelog_first
+ $default_list_mode
+ %rpmdragora_options
+ @ARGV_copy
+ );
+
+our @ARGV_copy = @ARGV;
+
+BEGIN { #- we want to run this code before the Gtk->init of the use-my_gtk
+ my $basename = sub { local $_ = shift; s|/*\s*$||; s|.*/||; $_ };
+ any { /^--?h/ } @ARGV and do {
+ printf join("\n", N("Usage: %s [OPTION]...", $basename->($0)),
+N(" --auto assume default answers to questions"),
+N(" --changelog-first display changelog before filelist in the description window"),
+N(" --media=medium1,.. limit to given media"),
+N(" --merge-all-rpmnew propose to merge all .rpmnew/.rpmsave files found"),
+N(" --mode=MODE set mode (install (default), remove, update)"),
+N(" --justdb update the database, but do not modify the filesystem"),
+N(" --no-confirmation don't ask first confirmation question in update mode"),
+N(" --no-media-update don't update media at startup"),
+N(" --no-verify-rpm don't verify package signatures"),
+if_($0 !~ /MageiaUpdate/, N(" --parallel=alias,host be in parallel mode, use \"alias\" group, use \"host\" machine to show needed deps")),
+N(" --rpm-root=path use another root for rpm installation"),
+N(" --urpmi-root use another root for urpmi db & rpm installation"),
+N(" --run-as-root force to run as root"),
+N(" --search=pkg run search for \"pkg\""),
+N(" --test only verify if the installation can be achieved correctly"),
+chomp_(N(" --version print this tool's version number
+")),
+""
+);
+ exit 0;
+ };
+}
+
+BEGIN { #- for mcc
+ if ("@ARGV" =~ /--embedded (\w+)/) {
+ $::XID = $1;
+ $::isEmbedded = 1;
+ }
+}
+
+
+#- This is needed because text printed by Gtk2 will always be encoded
+#- in UTF-8; we first check if LC_ALL is defined, because if it is,
+#- changing only LC_COLLATE will have no effect.
+use POSIX qw(setlocale LC_ALL LC_COLLATE strftime);
+use locale;
+my $collation_locale = $ENV{LC_ALL};
+if ($collation_locale) {
+ $collation_locale =~ /UTF-8/ or setlocale(LC_ALL, "$collation_locale.UTF-8");
+} else {
+ $collation_locale = setlocale(LC_COLLATE);
+ $collation_locale =~ /UTF-8/ or setlocale(LC_COLLATE, "$collation_locale.UTF-8");
+}
+
+our $version = 1;
+our %rpmdragora_options;
+
+my $i;
+foreach (@ARGV) {
+ $i++;
+ /^-?-(\S+)$/ or next;
+ my $val = $1;
+ if ($val =~ /=/) {
+ my ($name, $values) = split /=/, $val;
+ my @values = split /,/, $values;
+ $rpmdragora_options{$name} = \@values if @values;
+ } else {
+ if ($val eq 'version') {
+ print "$0 $version\n";
+ exit(0);
+ } elsif ($val =~ /^(test|expert)$/) {
+ eval "\$::$1 = 1";
+ } elsif ($val =~ /^(q|quiet)$/) {
+ urpm::args::set_verbose(-1);
+ } elsif ($val =~ /^(v|verbose)$/) {
+ urpm::args::set_verbose(1);
+ } else {
+ $rpmdragora_options{$val} = 1;
+ }
+ }
+}
+
+foreach my $option (qw(media mode parallel rpm-root search)) {
+ if (defined $rpmdragora_options{$option} && !ref($rpmdragora_options{$option})) {
+ warn qq(wrong usage of "$option" option!\n);
+ exit(-1); # too early for my_exit()
+ }
+}
+
+$urpm::args::options{basename} = 1;
+
+our $MODE = ref $rpmdragora_options{mode} ? $rpmdragora_options{mode}[0] : undef;
+our $overriding_config = defined $MODE;
+unless ($MODE) {
+ $MODE = 'install';
+ $0 =~ m|remove$| and $MODE = 'remove';
+ $0 =~ m|update$|i and $MODE = 'update';
+}
+
+our $default_list_mode;
+$default_list_mode = 'gui_pkgs' if $MODE eq 'install';
+if ($MODE eq 'remove') {
+ $default_list_mode = 'installed';
+} elsif ($MODE eq 'update') {
+ $default_list_mode = 'all_updates';
+}
+
+$MODE eq 'update' || $rpmdragora_options{'run-as-root'} and require_root_capability();
+$::noborderWhenEmbedded = 1;
+
+require AdminPanel::rpmdragora;
+
+our $changelog_first = $rpmdragora::changelog_first_config->[0];
+$changelog_first = 1 if $rpmdragora_options{'changelog-first'};
+
+sub warn_about_user_mode() {
+ $> and (AdminPanel::rpmdragora::interactive_msg(N("Running in user mode"),
+ N("You are launching this program as a normal user.
+You will not be able to perform modifications on the system,
+but you may still browse the existing database."), yesno => 1, text => { no => N("Cancel"), yes => N("Ok") })
+ or AdminPanel::rpmdragora::myexit(0));
+}
+
+sub init() {
+ URPM::bind_rpm_textdomain_codeset();
+}
+
+1;
diff --git a/AdminPanel/Rpmdragora/open_db.pm b/AdminPanel/Rpmdragora/open_db.pm
new file mode 100644
index 0000000..4eec7cd
--- /dev/null
+++ b/AdminPanel/Rpmdragora/open_db.pm
@@ -0,0 +1,161 @@
+package AdminPanel::Rpmdragora::open_db;
+#*****************************************************************************
+#
+# Copyright (c) 2002 Guillaume Cottenceau
+# Copyright (c) 2002-2007 Thierry Vignaud <tvignaud@mandriva.com>
+# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA
+# Copyright (c) 2005-2007 Mandriva SA
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2, as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#*****************************************************************************
+#
+# $Id: open_db.pm 268344 2010-05-06 13:06:08Z jvictor $
+
+use strict;
+use common;
+use AdminPanel::rpmdragora;
+use URPM;
+use urpm;
+use urpm::args;
+use urpm::select;
+use urpm::media;
+use feature 'state';
+
+use Exporter;
+our @ISA = qw(Exporter);
+our @EXPORT = qw(fast_open_urpmi_db
+ get_backport_media
+ get_inactive_backport_media
+ get_update_medias
+ is_it_a_devel_distro
+ open_rpm_db
+ open_urpmi_db
+ );
+
+
+# because rpm blocks some signals when rpm DB is opened, we don't keep open around:
+sub open_rpm_db {
+ my ($o_force) = @_;
+ my $host;
+ log::explanations("opening the RPM database");
+ if ($::rpmdragora_options{parallel} && ((undef, $host) = @{$::rpmdragora_options{parallel}})) {
+ state $done;
+ my $dblocation = "/var/cache/urpmi/distantdb/$host";
+ if (!$done || $o_force) {
+ print "syncing db from $host to $dblocation...";
+ mkdir_p "$dblocation/var/lib/rpm";
+ system "rsync -Sauz -e ssh $host:/var/lib/rpm/ $dblocation/var/lib/rpm";
+ $? == 0 or die "Couldn't sync db from $host to $dblocation";
+ $done = 1;
+ print "done.\n";
+ }
+ URPM::DB::open($dblocation) or die "Couldn't open RPM DB";
+ } else {
+ my $db;
+ if ($::env) {
+ #- URPM has same methods as URPM::DB and empty URPM will be seen as empty URPM::DB.
+ $db = new URPM;
+ $db->parse_synthesis("$::env/rpmdb.cz");
+ } else {
+ $db = URPM::DB::open($::rpmdragora_options{'rpm-root'}[0]);
+ }
+ $db or die "Couldn't open RPM DB (" . ($::env ? "$::env/rpmdb.cz" : $::rpmdragora_options{'rpm-root'}[0]) . ")";
+ }
+}
+
+# do not pay the urpm::media::configure() heavy cost:
+sub fast_open_urpmi_db() {
+ my $urpm = urpm->new;
+ my $error_happened;
+ $urpm->{fatal} = sub {
+ $error_happened = 1;
+ interactive_msg(N("Fatal error"),
+ N("A fatal error occurred: %s.", $_[1]));
+ };
+
+ urpm::set_files($urpm, $::rpmdragora_options{'urpmi-root'}[0]) if $::rpmdragora_options{'urpmi-root'}[0];
+ $::rpmdragora_options{'rpm-root'}[0] ||= $::rpmdragora_options{'urpmi-root'}[0];
+ urpm::args::set_root($urpm, $::rpmdragora_options{'rpm-root'}[0]) if $::rpmdragora_options{'rpm-root'}[0];
+ urpm::args::set_debug($urpm) if $::rpmdragora_options{debug};
+ $urpm->get_global_options;
+ $urpm->{options}{wait_lock} = $::rpmdragora_options{'wait-lock'};
+ $urpm->{options}{'verify-rpm'} = !$::rpmdragora_options{'no-verify-rpm'} if defined $::rpmdragora_options{'no-verify-rpm'};
+ $urpm->{options}{auto} = $::rpmdragora_options{auto} if defined $::rpmdragora_options{auto};
+ urpm::args::set_verbosity();
+ if ($::rpmdragora_options{env} && $::rpmdragora_options{env}[0]) {
+ $::env = $::rpmdragora_options{env}[0];
+ # prevent crashing in URPM.pm prevent when using --env:
+ $::env = "$ENV{PWD}/$::env" if $::env !~ m!^/!;
+ urpm::set_env($urpm, $::env);
+ }
+
+ $urpm::args::options{justdb} = $::rpmdragora_options{justdb};
+
+ urpm::media::read_config($urpm, 0);
+ foreach (@{$urpm->{media}}) {
+ next if $_->{ignore};
+ urpm::media::_tempignore($_, 1) if $ignore_debug_media->[0] && $_->{name} =~ /debug/i;
+ }
+ # FIXME: seems uneeded with newer urpmi:
+ if ($error_happened) {
+ touch('/etc/urpmi/urpmi.cfg');
+ exec('edit-urpm-sources.pl');
+ }
+ $urpm;
+}
+
+sub is_it_a_devel_distro() {
+ state $res;
+ return $res if defined $res;
+
+ my $path = $::rpmdragora_options{'urpmi-root'}[0] . '/etc/product.id';
+ $res = common::parse_LDAP_namespace_structure(cat_($path))->{branch} eq 'Devel';
+ return $res;
+}
+
+sub get_backport_media {
+ my ($urpm) = @_;
+ grep { $_->{name} =~ /backport/i &&
+ $_->{name} !~ /debug|sources/i } @{$urpm->{media}};
+}
+
+sub get_inactive_backport_media {
+ my ($urpm) = @_;
+ map { $_->{name} } grep { $_->{ignore} } get_backport_media($urpm);
+}
+
+sub get_update_medias {
+ my ($urpm) = @_;
+ if (is_it_a_devel_distro()) {
+ grep { !$_->{ignore} } @{$urpm->{media}};
+ } else {
+ grep { !$_->{ignore} && $_->{update} } @{$urpm->{media}};
+ }
+}
+
+sub open_urpmi_db {
+ my (%urpmi_options) = @_;
+ my $urpm = fast_open_urpmi_db();
+ my $media = ref $::rpmdragora_options{media} ? join(',', @{$::rpmdragora_options{media}}) : '';
+
+ my $searchmedia = $urpmi_options{update} ? undef : join(',', get_inactive_backport_media($urpm));
+ $urpm->{lock} = urpm::lock::urpmi_db($urpm, undef, wait => $urpm->{options}{wait_lock}) if !$::env;
+ my $previous = $::rpmdragora_options{'previous-priority-upgrade'};
+ urpm::select::set_priority_upgrade_option($urpm, (ref $previous ? join(',', @$previous) : ()));
+ urpm::media::configure($urpm, media => $media, if_($searchmedia, searchmedia => $searchmedia), %urpmi_options);
+ $urpm;
+}
+
+1;
diff --git a/AdminPanel/Rpmdragora/pkg.pm b/AdminPanel/Rpmdragora/pkg.pm
new file mode 100644
index 0000000..bf64004
--- /dev/null
+++ b/AdminPanel/Rpmdragora/pkg.pm
@@ -0,0 +1,990 @@
+package AdminPanel::Rpmdragora::pkg;
+#*****************************************************************************
+#
+# Copyright (c) 2002 Guillaume Cottenceau
+# Copyright (c) 2002-2007 Thierry Vignaud <tvignaud@mandriva.com>
+# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA
+# Copyright (c) 2005-2007 Mandriva SA
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2, as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#*****************************************************************************
+#
+# $Id: pkg.pm 270160 2010-06-22 19:55:40Z jvictor $
+
+use strict;
+use MDK::Common::Func 'any';
+use lib qw(/usr/lib/libDrakX);
+use common;
+use POSIX qw(_exit);
+use URPM;
+use utf8;
+use AdminPanel::Rpmdragora::open_db;
+use AdminPanel::Rpmdragora::gurpm;
+use AdminPanel::Rpmdragora::formatting;
+use AdminPanel::Rpmdragora::rpmnew;
+
+use AdminPanel::rpmdragora;
+use urpm;
+use urpm::lock;
+use urpm::install;
+use urpm::signature;
+use urpm::get_pkgs;
+use urpm::select;
+use urpm::main_loop;
+use urpm::args qw();
+
+
+use Exporter;
+our @ISA = qw(Exporter);
+our @EXPORT = qw(
+ $priority_up_alread_warned
+ download_callback
+ extract_header
+ find_installed_version
+ get_pkgs
+ perform_installation
+ perform_removal
+ run_rpm
+ sort_packages
+ );
+
+#use mygtk2 qw(gtknew);
+#use ugtk2 qw(:all);
+
+our $priority_up_alread_warned;
+
+sub sort_packages_biarch {
+ sort {
+ my ($na, $aa) = $a =~ /^(.*-[^-]+-[^-]+)\.([^.-]+)$/;
+ my ($nb, $ab) = $b =~ /^(.*-[^-]+-[^-]+)\.([^.-]+)$/;
+ $na cmp $nb || ($ab =~ /64$/) <=> ($aa =~ /64$/);
+ } @_;
+}
+
+sub sort_packages_monoarch {
+ sort { uc($a) cmp uc($b) } @_;
+}
+
+*sort_packages = arch() =~ /x86_64/ ? \&sort_packages_biarch : \&sort_packages_monoarch;
+
+sub run_rpm {
+ 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)) {
+ local $ENV{$_} = $ENV{$_} . '.UTF-8' if $ENV{$_} && $ENV{$_} !~ /UTF-8/;
+ }
+ my @l = map { ensure_utf8($_); $_ } run_program::get_stdout(@_);
+ wantarray() ? @l : join('', @l);
+}
+
+
+sub extract_header {
+ my ($pkg, $urpm, $xml_info, $o_installed_version) = @_;
+ my %fields = (
+ info => 'description',
+ files => 'files',
+ changelog => 'changelog',
+ );
+ # already extracted:
+ return if $pkg->{$fields{$xml_info}};
+
+ my $p = $pkg->{pkg};
+
+ if (!$p) {
+ warn ">> ghost package '$pkg' has no URPM object!!!\n";
+ return;
+ }
+
+ my $name = $p->fullname;
+ # fix extracting info for SRPMS and RPM GPG keys:
+ $name =~ s!\.src!!;
+
+ if ($p->flag_installed && !$p->flag_upgrade) {
+ my @files = map { chomp_($_) } run_rpm("rpm -ql $name");
+ add2hash($pkg, { files => [ @files ? @files : N("(none)") ],
+ description => rpm_description(scalar(run_rpm("rpm -q --qf '%{description}' $name"))),
+ changelog => format_changelog_string($o_installed_version, scalar(run_rpm("rpm -q --changelog $name"))) });
+ } else {
+ my $medium = pkg2medium($p, $urpm);
+ my ($local_source, %xml_info_pkgs, $bar_id);
+ my $_statusbar_clean_guard = before_leaving { $bar_id and statusbar_msg_remove($bar_id) };
+ my $dir = urpm::file_from_local_url($medium->{url});
+ $local_source = "$dir/" . $p->filename if $dir;
+
+ if (-e $local_source) {
+ $bar_id = statusbar_msg(N("Getting information from %s...", $dir), 0);
+ $urpm->{log}("getting information from rpms from $dir");
+ } else {
+ my $gurpm;
+ $bar_id = statusbar_msg(N("Getting '%s' from XML meta-data...", $xml_info), 0);
+ my $_gurpm_clean_guard = before_leaving { undef $gurpm };
+ if (my $xml_info_file = eval { urpm::media::any_xml_info($urpm, $medium, $xml_info, undef, sub {
+ $gurpm ||= Rpmdragora::gurpm->new(N("Please wait"),
+ '', # FIXME: add a real string after cooker
+ transient => $::main_window);
+ download_callback($gurpm, @_)
+ or goto header_non_available;
+ }) }) {
+ require urpm::xml_info;
+ require urpm::xml_info_pkg;
+ $urpm->{log}("getting information from $xml_info_file");
+ my %nodes = eval { urpm::xml_info::get_nodes($xml_info, $xml_info_file, [ $name ]) };
+ goto header_non_available if $@;
+ put_in_hash($xml_info_pkgs{$name} ||= {}, $nodes{$name});
+ } else {
+ if ($xml_info eq 'info') {
+ $urpm->{info}(N("No xml info for medium \"%s\", only partial result for package %s", $medium->{name}, $name));
+ } else {
+ $urpm->{error}(N("No xml info for medium \"%s\", unable to return any result for package %s", $medium->{name}, $name));
+ }
+ }
+ }
+
+ #- even if non-root, search for a header in the global cachedir
+ if (-s $local_source) {
+ $p->update_header($local_source) or do {
+ warn "Warning, could not extract header for $name from $medium!";
+ goto header_non_available;
+ };
+ my @files = $p->files;
+ @files = N("(none)") if !@files;
+ add2hash($pkg, { description => rpm_description($p->description),
+ files => \@files,
+ url => $p->url,
+ changelog => format_changelog_changelogs($o_installed_version, $p->changelogs) });
+ $p->pack_header; # needed in order to call methods on objects outside ->traverse
+ } elsif ($xml_info_pkgs{$name}) {
+ if ($xml_info eq 'info') {
+ add2hash($pkg, { description => rpm_description($xml_info_pkgs{$name}{description}),
+ url => $xml_info_pkgs{$name}{url}
+ });
+ } elsif ($xml_info eq 'files') {
+ my @files = map { chomp_(to_utf8($_)) } split("\n", $xml_info_pkgs{$name}{files});
+ add2hash($pkg, { files => [ @files ? @files : N("(none)") ] });
+ } elsif ($xml_info eq 'changelog') {
+ add2hash($pkg, {
+ changelog => format_changelog_changelogs($o_installed_version,
+ @{$xml_info_pkgs{$name}{changelogs}})
+ });
+ }
+ } else {
+ goto header_non_available;
+ }
+ return;
+ header_non_available:
+ add2hash($pkg, { summary => $p->summary || N("(Not available)"), description => undef });
+ }
+}
+
+sub find_installed_version {
+ my ($p) = @_;
+ my $version;
+ open_rpm_db()->traverse_tag_find('name', $p->name, sub { $version = $_[0]->EVR });
+ $version || N("(none)");
+}
+
+my $canceled;
+sub download_callback {
+ my ($gurpm, $mode, $file, $percent, $total, $eta, $speed) = @_;
+ $canceled = 0;
+ if ($mode eq 'start') {
+ $gurpm->label(N("Downloading package `%s'...", basename($file)));
+ $gurpm->validate_cancel(but(N("Cancel")), sub { $canceled = 1 });
+ } elsif ($mode eq 'progress') {
+ $gurpm->label(
+ join("\n",
+ N("Downloading package `%s'...", basename($file)),
+ (defined $total && defined $eta ?
+ N(" %s%% of %s completed, ETA = %s, speed = %s", $percent, $total, $eta, $speed)
+ : N(" %s%% completed, speed = %s", $percent, $speed)
+ ) =~ /^\s*(.*)/
+ ),
+ );
+ #$gurpm->progress($percenti/100);
+ $gurpm->progress($percent);
+ } elsif ($mode eq 'end') {
+ $gurpm->progress(100);
+ $gurpm->invalidate_cancel;
+ }
+ !$canceled;
+}
+
+
+# -=-=-=---=-=-=---=-=-=-- install packages -=-=-=---=-=-=---=-=-=-
+
+my (@update_medias, $is_update_media_already_asked);
+
+sub warn_about_media {
+ my ($w, %options) = @_;
+
+ return if $::MODE ne 'update';
+ return if $::rpmdragora_options{'no-media-update'};
+
+ # we use our own instance of the urpmi db in order not to mess up with skip-list managment (#31092):
+ # and no need to fully configure urpmi since we may have to do it again anyway because of new media:
+ my $urpm = fast_open_urpmi_db();
+
+ my $_lock = urpm::lock::urpmi_db($urpm, undef, wait => $urpm->{options}{wait_lock});
+
+ # build media list:
+ @update_medias = get_update_medias($urpm);
+
+ # do not update again media after installing/removing some packages:
+ $::rpmdragora_options{'no-media-update'} ||= 1;
+
+ if (@update_medias > 0) {
+ if (!$options{skip_updating_mu} && !$is_update_media_already_asked) {
+ $is_update_media_already_asked = 1;
+ $::rpmdragora_options{'no-confirmation'} or interactive_msg(N("Confirmation"),
+N("I need to contact the mirror to get latest update packages.
+Please check that your network is currently running.
+
+Is it ok to continue?"), yesno => 1,
+ widget => gtknew('CheckButton', text => N("Do not ask me next time"),
+ active_ref => \$::rpmdragora_options{'no-confirmation'}
+ )) or myexit(-1);
+ writeconf();
+ urpm::media::select_media($urpm, map { $_->{name} } @update_medias);
+ update_sources($urpm, noclean => 1, medialist => [ map { $_->{name} } @update_medias ]);
+ }
+ } else {
+ if (any { $_->{update} } @{$urpm->{media}}) {
+ interactive_msg(N("Already existing update media"),
+N("You already have at least one update medium configured, but
+all of them are currently disabled. You should run the Software
+Media Manager to enable at least one (check it in the \"%s\"
+column).
+
+Then, restart \"%s\".", N("Enabled"), $rpmdragora::myname_update));
+ myexit(-1);
+ }
+ my ($mirror) = choose_mirror($urpm, transient => $w->{real_window} || $::main_window,
+ message => join("\n\n",
+ N("You have no configured update media. MageiaUpdate cannot operate without any update media."),
+ N("I need to contact the Mageia website to get the mirror list.
+Please check that your network is currently running.
+
+Is it ok to continue?"),
+ ),
+ );
+ my $m = ref($mirror) ? $mirror->{url} : '';
+ $m or interactive_msg(N("How to choose manually your mirror"),
+N("You may also choose your desired mirror manually: to do so,
+launch the Software Media Manager, and then add a `Security
+updates' medium.
+
+Then, restart %s.", $rpmdragora::myname_update)), myexit(-1);
+ add_distrib_update_media($urpm, $mirror, only_updates => 1);
+ }
+}
+
+
+sub get_parallel_group() {
+ $::rpmdragora_options{parallel} ? $::rpmdragora_options{parallel}[0] : undef;
+}
+
+my ($count, $level, $limit, $new_stage, $prev_stage, $total);
+
+sub init_progress_bar {
+ my ($urpm) = @_;
+ undef $_ foreach $count, $prev_stage, $new_stage, $limit;
+ $level = 0.05;
+ $total = @{$urpm->{depslist}};
+}
+
+sub reset_pbar_count {
+ undef $prev_stage;
+ $count = 0;
+ $limit = $_[0];
+}
+
+sub update_pbar {
+ my ($gurpm) = @_;
+ return if !$total; # don't die if there's no source
+ $count++;
+ $new_stage = $level+($limit-$level)*$count/$total;
+ if ($prev_stage + 0.01*100 < $new_stage) {
+ $prev_stage = $new_stage;
+ $gurpm->progress($new_stage);
+ }
+}
+
+
+sub get_installed_packages {
+ my ($urpm, $db, $all_pkgs, $gurpm) = @_;
+
+ my @base = ("basesystem", split /,\s*/, $urpm->{global_config}{'prohibit-remove'});
+ my (%base, %basepackages, @installed_pkgs, @processed_base);
+ reset_pbar_count(0.33);
+ while (defined(local $_ = shift @base)) {
+ exists $basepackages{$_} and next;
+ $db->traverse_tag(m|^/| ? 'path' : 'whatprovides', [ $_ ], sub {
+ update_pbar($gurpm);
+ my $name = $_[0]->fullname;
+ # workaround looping in URPM:
+ return if member($name, @processed_base);
+ push @processed_base, $name;
+ push @{$basepackages{$_}}, $name;
+ push @base, $_[0]->requires_nosense;
+ });
+ }
+ foreach (values %basepackages) {
+ my $n = @$_; #- count number of times it's provided
+ foreach (@$_) {
+ $base{$_} = \$n;
+ }
+ }
+ # costly:
+ $db->traverse(sub {
+ my ($pkg) = @_;
+ update_pbar($gurpm);
+ my $fullname = urpm_name($pkg);
+ return if $fullname =~ /@/;
+ $all_pkgs->{$fullname} = {
+ pkg => $pkg, urpm_name => $fullname,
+ } if !($all_pkgs->{$fullname} && $all_pkgs->{$fullname}{description});
+ if (my $name = $base{$fullname}) {
+ $all_pkgs->{$fullname}{base} = \$name;
+ $pkg->set_flag_base(1) if $$name == 1;
+ }
+ push @installed_pkgs, $fullname;
+ $pkg->set_flag_installed;
+ $pkg->pack_header; # needed in order to call methods on objects outside ->traverse
+ });
+ @installed_pkgs;
+}
+
+urpm::select::add_packages_to_priority_upgrade_list('rpmdragora', 'perl-Glib', 'perl-Gtk2');
+
+my ($priority_state, $priority_requested);
+our $need_restart;
+
+our $probe_only_for_updates;
+
+sub get_updates_list {
+ my ($urpm, $db, $state, $requested, $requested_list, $requested_strict, $all_pkgs, %limit_preselect) = @_;
+
+ $urpm->request_packages_to_upgrade(
+ $db,
+ $state,
+ $requested,
+ %limit_preselect
+ );
+
+ my %common_opts = (
+ callback_choices => \&Rpmdragora::gui::callback_choices,
+ priority_upgrade => $urpm->{options}{'priority-upgrade'},
+ );
+
+ if ($urpm->{options}{'priority-upgrade'}) {
+ $need_restart =
+ urpm::select::resolve_priority_upgrades_after_auto_select($urpm, $db, $state,
+ $requested, %common_opts);
+ }
+
+ # list of updates (including those matching /etc/urpmi/skip.list):
+ @$requested_list = sort map {
+ my $name = urpm_name($_);
+ $all_pkgs->{$name} = { pkg => $_ };
+ $name;
+ } @{$urpm->{depslist}}[keys %$requested];
+
+ # list of pure updates (w/o those matching /etc/urpmi/skip.list but with their deps):
+ if ($probe_only_for_updates && !$need_restart) {
+ @$requested_strict = sort map {
+ urpm_name($_);
+ } $urpm->resolve_requested($db, $state, $requested, callback_choices => \&Rpmdragora::gui::callback_choices);
+
+ if (my @l = grep { $state->{selected}{$_->id} }
+ urpm::select::_priority_upgrade_pkgs($urpm, $urpm->{options}{'priority-upgrade'})) {
+ if (!$need_restart) {
+ $need_restart =
+ urpm::select::_resolve_priority_upgrades($urpm, $db, $state, $state->{selected},
+ \@l, %common_opts);
+ }
+ }
+ }
+
+ if ($need_restart) {
+ $requested_strict = [ map { scalar $_->fullname } @{$urpm->{depslist}}[keys %{$state->{selected}}] ];
+ # drop non priority updates:
+ @$requested_list = ();
+ }
+
+ # list updates including skiped ones + their deps in MageiaUpdate:
+ @$requested_list = uniq(@$requested_list, @$requested_strict);
+
+ # do not pre select updates in rpmdragora:
+ @$requested_strict = () if !$probe_only_for_updates;
+}
+
+sub get_pkgs {
+ my (%options) = @_;
+ my $w = $::main_window;
+
+ my $gurpm = AdminPanel::Rpmdragora::gurpm->new(1 ? N("Please wait") : N("Package installation..."), N("Initializing..."), transient => $::main_window);
+ my $_gurpm_clean_guard = before_leaving { undef $gurpm };
+ #my $_flush_guard = Gtk2::GUI_Update_Guard->new;
+
+ warn_about_media($w, %options);
+
+ my $urpm = open_urpmi_db(update => $probe_only_for_updates && !is_it_a_devel_distro());
+
+ my $_drop_lock = before_leaving { undef $urpm->{lock} };
+
+ $priority_up_alread_warned = 0;
+
+ # update media list in case warn_about_media() added some:
+ @update_medias = get_update_medias($urpm);
+
+ $gurpm->label(N("Reading updates description"));
+ $gurpm->progress(100);
+
+ #- parse the description file
+ my $update_descr = urpm::get_updates_description($urpm, @update_medias);
+
+ my $_unused = N("Please wait, finding available packages...");
+
+ # find out installed packages:
+
+ init_progress_bar($urpm);
+
+ $gurpm->label(N("Please wait, listing base packages..."));
+ $gurpm->progress($level*100);
+
+ my $db = eval { open_rpm_db() };
+ if (my $err = $@) {
+ interactive_msg(N("Error"), N("A fatal error occurred: %s.", $err));
+ return;
+ }
+
+ my $sig_handler = sub { undef $db; exit 3 };
+ local $SIG{INT} = $sig_handler;
+ local $SIG{QUIT} = $sig_handler;
+
+ $gurpm->label(N("Please wait, finding installed packages..."));
+ $gurpm->progress($level = 0.33*100);
+ reset_pbar_count(0.66*100);
+ my (@installed_pkgs, %all_pkgs);
+ if (!$probe_only_for_updates) {
+ @installed_pkgs = get_installed_packages($urpm, $db, \%all_pkgs, $gurpm);
+ }
+
+ if (my $group = get_parallel_group()) {
+ urpm::media::configure($urpm, parallel => $group);
+ }
+
+ # find out availlable packages:
+
+ $urpm->{state} = {};
+
+ $gurpm->label(N("Please wait, finding available packages..."));
+ $gurpm->progress($level = 0.66*100);
+
+ check_update_media_version($urpm, @update_medias);
+
+ my $requested = {};
+ my $state = {};
+ my (@requested, @requested_strict);
+
+ if ($compute_updates->[0] || $::MODE eq 'update') {
+ my %filter;
+ if ($options{pure_updates}) {
+ # limit to packages from update-media (dependencies can still come from other media)
+ %filter = (idlist => [ map { $_->{start} .. $_->{end} } @update_medias ]);
+ }
+ get_updates_list($urpm, $db, $state, $requested, \@requested, \@requested_strict, \%all_pkgs, %filter);
+ }
+
+ if ($need_restart) {
+ $priority_state = $state;
+ $priority_requested = $requested;
+ } else {
+ ($priority_state, $priority_requested) = ();
+ }
+
+ if (!$probe_only_for_updates) {
+ $urpm->compute_installed_flags($db); # TODO/FIXME: not for updates
+ $urpm->{depslist}[$_]->set_flag_installed foreach keys %$requested; #- pretend it's installed
+ }
+ $urpm->{rpmdragora_state} = $state; #- Don't forget it
+ $gurpm->progress($level = 0.7*100);
+
+ my %l;
+ reset_pbar_count(1);
+ foreach my $pkg (@{$urpm->{depslist}}) {
+ update_pbar($gurpm);
+ $pkg->flag_upgrade or next;
+ my $key = $pkg->name . $pkg->arch;
+ $l{$key} = $pkg if !$l{$key} || $l{$key}->compare($pkg);
+ }
+ my @installable_pkgs = map { my $n = $_->fullname; $all_pkgs{$n} = { pkg => $_ }; $n } values %l;
+ undef %l;
+
+ my @inactive_backports;
+ my @active_backports;
+ my @backport_medias = get_backport_media($urpm);
+
+ foreach my $medium (@backport_medias) {
+ update_pbar($gurpm);
+
+ # The 'searchmedia' flag differentiates inactive backport medias
+ # (because that option was passed to urpm::media::configure to
+ # temporarily enable them)
+
+ my $backports =
+ $medium->{searchmedia} ? \@inactive_backports : \@active_backports;
+
+ foreach my $pkg_id ($medium->{start} .. $medium->{end}) {
+ next if !$pkg_id;
+ my $pkg = $urpm->{depslist}[$pkg_id];
+ $pkg->flag_upgrade or next;
+ my $name = $pkg->fullname;
+ push @$backports, $name;
+ $all_pkgs{$name} = { pkg => $pkg, is_backport => 1 };
+ }
+ }
+ my @updates = @requested;
+ # selecting updates by default but skipped ones (MageiaUpdate only):
+ foreach (@requested_strict) {
+ $all_pkgs{$_}{selected} = 1;
+ }
+
+ # urpmi only care about the first medium where it found the package,
+ # so there's no need to list the same package several time:
+ @installable_pkgs = uniq(difference2(\@installable_pkgs, \@updates));
+
+ my @meta_pkgs = grep { /^task-|^basesystem/ } keys %all_pkgs;
+
+ my @gui_pkgs = map { chomp; $_ } cat_('/usr/share/rpmdragora/gui.lst');
+ # add meta packages to GUI packages list (which expect basic names not fullnames):
+ push @gui_pkgs, map { (split_fullname($_))[0] } @meta_pkgs;
+
+ +{ urpm => $urpm,
+ all_pkgs => \%all_pkgs,
+ installed => \@installed_pkgs,
+ installable => \@installable_pkgs,
+ updates => \@updates,
+ meta_pkgs => \@meta_pkgs,
+ gui_pkgs => [ grep { my $p = $all_pkgs{$_}{pkg}; $p && member(($p->fullname)[0], @gui_pkgs) } keys %all_pkgs ],
+ update_descr => $update_descr,
+ backports => [ @inactive_backports, @active_backports ],
+ inactive_backports => \@inactive_backports
+ };
+}
+
+sub display_READMEs_if_needed {
+ my ($urpm, $w) = @_;
+ return if !$urpm->{readmes};
+ my %Readmes = %{$urpm->{readmes}};
+ if (keys %Readmes) { #- display the README*.urpmi files
+ interactive_packtable(
+ N("Upgrade information"),
+ $w,
+ N("These packages come with upgrade information"),
+ [ map {
+ my $fullname = $_;
+ [ gtkpack__(
+ gtknew('HBox'),
+ gtkset_selectable(gtknew('Label', text => $Readmes{$fullname}),1),
+ ),
+ gtksignal_connect(
+ gtknew('Button', text => N("Upgrade information about this package")),
+ clicked => sub {
+ interactive_msg(
+ N("Upgrade information about package %s", $Readmes{$fullname}),
+ (join '' => map { s/$/\n/smg; $_ } formatAlaTeX(scalar cat_($fullname))),
+ scroll => 1,
+ );
+ },
+ ),
+ ] } keys %Readmes ],
+ [ gtknew('Button', text => N("Ok"), clicked => sub { Gtk2->main_quit }) ]
+ );
+ }
+}
+
+sub perform_parallel_install {
+ my ($urpm, $group, $w, $statusbar_msg_id) = @_;
+ my @pkgs = map { if_($_->flag_requested, urpm_name($_)) } @{$urpm->{depslist}};
+
+ my @error_msgs;
+ my $res = !run_program::run('urpmi', '2>', \@error_msgs, '-v', '--X', '--parallel', $group, @pkgs);
+
+ if ($res) {
+ $$statusbar_msg_id = statusbar_msg(
+ #N("Everything installed successfully"),
+ N("All requested packages were installed successfully."),
+ );
+ } else {
+ interactive_msg(
+ N("Problem during installation"),
+ N("There was a problem during the installation:\n\n%s", join("\n", @error_msgs)),
+ scroll => 1,
+ );
+ }
+ open_rpm_db('force_sync');
+ $w->set_sensitive(1);
+ return 0;
+}
+
+sub perform_installation { #- (partially) duplicated from /usr/sbin/urpmi :-(
+ my ($urpm, $pkgs) = @_;
+
+ my @error_msgs;
+ my $statusbar_msg_id;
+ my $gurpm;
+ local $urpm->{fatal} = sub {
+ my $fatal_msg = $_[1];
+ printf STDERR "Fatal: %s\n", $fatal_msg;
+ undef $gurpm;
+ interactive_msg(N("Installation failed"),
+ N("There was a problem during the installation:\n\n%s", $fatal_msg));
+ goto return_with_exit_code;
+ };
+ local $urpm->{error} = sub { printf STDERR "Error: %s\n", $_[0]; push @error_msgs, $_[0] };
+
+ my $w = $::main_window;
+ $w->set_sensitive(0);
+ my $_restore_sensitive = before_leaving { $w->set_sensitive(1) };
+
+ my $_flush_guard = Gtk2::GUI_Update_Guard->new;
+
+ if (my $group = get_parallel_group()) {
+ return perform_parallel_install($urpm, $group, $w, \$statusbar_msg_id);
+ }
+
+ my ($lock, $rpm_lock);
+ if (!$::env) {
+ $lock = urpm::lock::urpmi_db($urpm, undef, wait => $urpm->{options}{wait_lock});
+ $rpm_lock = urpm::lock::rpm_db($urpm, 'exclusive');
+ }
+ my $state = $priority_state || $probe_only_for_updates ? { } : $urpm->{rpmdragora_state};
+
+ my $bar_id = statusbar_msg(N("Checking validity of requested packages..."), 0);
+
+ # FIXME: THIS SET flag_requested on all packages!!!!
+ # select packages to install / enssure selected pkg set is consistant:
+ my %saved_flags;
+ my $requested = { map {
+ $saved_flags{$_->id} = $_->flag_requested;
+ $_->id => undef;
+ } grep { $_->flag_selected } @{$urpm->{depslist}} };
+ urpm::select::resolve_dependencies(
+ $urpm, $state, $requested,
+ rpmdb => $::env && "$::env/rpmdb.cz",
+ callback_choices => \&Rpmdragora::gui::callback_choices,
+ );
+ statusbar_msg_remove($bar_id);
+
+ my ($local_sources, $blist) = urpm::get_pkgs::selected2local_and_blists($urpm, $state->{selected});
+ if (!$local_sources && (!$blist || !@$blist)) {
+ interactive_msg(
+ N("Unable to get source packages."),
+ N("Unable to get source packages, sorry. %s",
+ @error_msgs ? N("\n\nError(s) reported:\n%s", join("\n", @error_msgs)) : ''),
+ scroll => 1,
+ );
+ goto return_with_exit_code;
+ }
+
+ my @to_install = @{$urpm->{depslist}}[keys %{$state->{selected}}];
+ my @pkgs = map { scalar($_->fullname) } sort(grep { $_->flag_selected } @to_install);
+
+ @{$urpm->{ask_remove}} = sort(urpm::select::removed_packages($urpm->{state}));
+ my @to_remove = map { if_($pkgs->{$_}{selected} && !$pkgs->{$_}{pkg}->flag_upgrade, $pkgs->{$_}{urpm_name}) } keys %$pkgs;
+
+ my $r = format_list(map { scalar(urpm::select::translate_why_removed_one($urpm, $urpm->{state}, $_)) } @to_remove);
+
+ my ($size, $filesize) = $urpm->selected_size_filesize($state);
+ my $install_count = int(@pkgs);
+ my $to_install = $install_count == 0 ? '' :
+ ($priority_state ? '<b>' . N("Rpmdragora or one of its priority dependencies needs to be updated first. Rpmdragora will then restart.") . '</b>' . "\n\n" : '') .
+ (P("The following package is going to be installed:", "The following %d packages are going to be installed:", $install_count, $install_count)
+ . "\n\n" . format_list(map { s!.*/!!; $_ } @pkgs));
+ my $remove_count = scalar(@to_remove);
+ interactive_msg(($to_install ? N("Confirmation") : N("Some packages need to be removed")),
+ join("\n\n",
+ ($r ?
+ (!$to_install ? (P("Remove one package?", "Remove %d packages?", $remove_count, $remove_count), $r) :
+ (($remove_count == 1 ?
+ N("The following package has to be removed for others to be upgraded:")
+ : N("The following packages have to be removed for others to be upgraded:")), $r), if_($to_install, $to_install))
+ : $to_install),
+ format_size($size),
+ format_filesize($filesize),
+ N("Is it ok to continue?")),
+ scroll => 1,
+ yesno => 1) or return 1;
+
+ my $_umount_guard = before_leaving { urpm::removable::try_umounting_removables($urpm) };
+
+ # select packages to uninstall for !update mode:
+ perform_removal($urpm, { map { $_ => $pkgs->{$_} } @to_remove }) if !$probe_only_for_updates;
+
+ $gurpm = Rpmdragora::gurpm->new(1 ? N("Please wait") : N("Package installation..."), N("Initializing..."), transient => $::main_window);
+ my $_gurpm_clean_guard = before_leaving { undef $gurpm };
+ my $something_installed;
+
+ if (@to_install && $::rpmdragora_options{auto_orphans}) {
+ urpm::orphans::compute_future_unrequested_orphans($urpm, $state);
+ if (my @orphans = map { scalar $_->fullname } @{$state->{orphans_to_remove}}) {
+ interactive_msg(N("Orphan packages"), P("The following orphan package will be removed.",
+ "The following orphan packages will be removed.", scalar(@orphans))
+ . "\n" . urpm::orphans::add_leading_spaces(join("\n", @orphans) . "\n"), scroll => 1);
+ }
+ }
+
+ urpm::orphans::mark_as_requested($urpm, $state, 0);
+
+ my ($progress, $total, @rpms_upgrade);
+ my $transaction;
+ my ($progress_nb, $transaction_progress_nb, $remaining, $done);
+ my $callback_inst = sub {
+ my ($urpm, $type, $id, $subtype, $amount, $total) = @_;
+ my $pkg = defined $id ? $urpm->{depslist}[$id] : undef;
+ if ($subtype eq 'start') {
+ if ($type eq 'trans') {
+ $gurpm->label(1 ? N("Preparing package installation...") : N("Preparing package installation transaction..."));
+ } elsif (defined $pkg) {
+ $something_installed = 1;
+ $gurpm->label(N("Installing package `%s' (%s/%s)...", $pkg->name, ++$transaction_progress_nb, scalar(@{$transaction->{upgrade}}))
+ . "\n" . N("Total: %s/%s", ++$progress_nb, $install_count));
+ }
+ } elsif ($subtype eq 'progress') {
+ $gurpm->progress($total ? ($amount/$total)*100 : 100);
+ }
+ };
+
+ # FIXME: sometimes state is lost:
+ my @ask_unselect = urpm::select::unselected_packages($state);
+
+ # fix flags for orphan computing:
+ foreach (keys %{$state->{selected}}) {
+ my $pkg = $urpm->{depslist}[$_];
+ $pkg->set_flag_requested($saved_flags{$pkg->id});
+ }
+ my $exit_code =
+ urpm::main_loop::run($urpm, $state, 1, \@ask_unselect,
+ {
+ completed => sub {
+ # explicitly destroy the progress window when it's over; we may
+ # have sg to display before returning (errors, rpmnew/rpmsave, ...):
+ undef $gurpm;
+
+ undef $lock;
+ undef $rpm_lock;
+ },
+ inst => $callback_inst,
+ trans => $callback_inst,
+ ask_yes_or_no => sub {
+ # handle 'allow-force' and 'allow-nodeps' options:
+ my ($title, $msg) = @_;
+ local $::main_window = $gurpm->{real_window};
+ interactive_msg($title, $msg, yesno => 1, scroll => 1,
+ );
+ },
+ message => sub {
+ my ($title, $message) = @_;
+ interactive_msg($title, $message, scroll => 1);
+ },
+ # cancel installation when 'cancel' button is pressed:
+ trans_log => sub { download_callback($gurpm, @_) or goto return_with_exit_code },
+ post_extract => sub {
+ my ($set, $transaction_sources, $transaction_sources_install) = @_;
+ $transaction = $set;
+ $transaction_progress_nb = 0;
+ $done += grep { !/\.src\.rpm$/ } values %$transaction_sources; #updates
+ $total = keys(%$transaction_sources_install) + keys %$transaction_sources;
+ push @rpms_upgrade, keys %$transaction_sources;
+ $done += grep { !/\.src\.rpm$/ } values %$transaction_sources_install; # installs
+ },
+ pre_removable => sub {
+ # Gtk2::GUI_Update_Guard->new use of alarm() kill us when
+ # running system(), thus making DVD being ejected and printing
+ # wrong error messages (#30463)
+
+ local $SIG{ALRM} = sub { die "ALARM" };
+ $remaining = alarm(0);
+ },
+
+ post_removable => sub { alarm $remaining },
+ copy_removable => sub {
+ my ($medium) = @_;
+ interactive_msg(
+ N("Change medium"),
+ N("Please insert the medium named \"%s\"", $medium),
+ yesno => 1, text => { no => N("Cancel"), yes => N("Ok") },
+ );
+ },
+ pre_check_sig => sub { $gurpm->label(N("Verifying package signatures...")) },
+ check_sig => sub { $gurpm->progress((++$progress/$total)*100) },
+ bad_signature => sub {
+ my ($msg, $msg2) = @_;
+ local $::main_window = $gurpm->{real_window};
+ $msg =~ s/:$/\n\n/m; # FIXME: to be fixed in urpmi after 2008.0
+ interactive_msg(
+ N("Warning"), "$msg\n\n$msg2", yesno => 1, if_(10 < ($msg =~ tr/\n/\n/), scroll => 1),
+ );
+ },
+ post_download => sub {
+ $canceled and goto return_with_exit_code;
+ $gurpm->invalidate_cancel_forever;
+ },
+ need_restart => sub {
+ my ($need_restart_formatted) = @_;
+ # FIXME: offer to restart the system
+ interactive_msg(N("Warning"), join("\n", values %$need_restart_formatted), scroll => 1);
+ },
+ trans_error_summary => sub {
+ my ($nok, $errors) = @_;
+ interactive_msg(
+ N("Problem during installation"),
+ if_($nok, N("%d installation transactions failed", $nok) . "\n\n") .
+ N("There was a problem during the installation:\n\n%s",
+ join("\n\n", @$errors, @error_msgs)),
+ scroll => 1,
+ );
+ },
+ need_restart => sub {
+ my ($need_restart_formatted) = @_;
+ interactive_msg(N("Warning"),
+ join("\n\n", values %$need_restart_formatted));
+ },
+ success_summary => sub {
+ if (!($done || @to_remove)) {
+ interactive_msg(N("Error"),
+ N("Unrecoverable error: no package found for installation, sorry."));
+ return;
+ }
+ my $id = statusbar_msg(N("Inspecting configuration files..."), 0);
+ my %pkg2rpmnew;
+ foreach my $id (@rpms_upgrade) {
+ my $pkg = $urpm->{depslist}[$id];
+ next if $pkg->arch eq 'src';
+ $pkg2rpmnew{$pkg->fullname} = [ grep { -r "$_.rpmnew" || -r "$_.rpmsave" } $pkg->conf_files ];
+ }
+ statusbar_msg_remove($id);
+ dialog_rpmnew(N("The installation is finished; everything was installed correctly.
+
+Some configuration files were created as `.rpmnew' or `.rpmsave',
+you may now inspect some in order to take actions:"),
+ %pkg2rpmnew)
+ and statusbar_msg(N("All requested packages were installed successfully."), 1);
+ statusbar_msg(N("Looking for \"README\" files..."), 1);
+ display_READMEs_if_needed($urpm, $w);
+ },
+ already_installed_or_not_installable => sub {
+ my ($msg1, $msg2) = @_;
+ my $msg = join("\n", @$msg1, @$msg2);
+ return if !$msg; # workaround missing state
+ interactive_msg(N("Error"), $msg);
+ },
+ },
+ );
+
+ #- restart rpmdragora if needed, keep command line for that.
+ if ($need_restart && !$exit_code && $something_installed) {
+ log::explanations("restarting rpmdragora");
+ #- it seems to work correctly with exec instead of system, provided we stop timers
+ #- added --previous-priority-upgrade to allow checking if yet if
+ #- priority-upgrade list has changed. and make sure we don't uselessly restart
+ my @argv = ('--previous-priority-upgrade=' . $urpm->{options}{'priority-upgrade'},
+ grep { !/^--no-priority-upgrade$|--previous-priority-upgrade=/ } @Rpmdragora::init::ARGV_copy);
+ # remove "--emmbedded <id>" from argv:
+ my $i = 0;
+ foreach (@argv) {
+ splice @argv, $i, 2 if /^--embedded$/;
+ $i++;
+ }
+ alarm(0);
+ # remember not to ask again questions and the like:
+ writeconf();
+ exec($0, @argv);
+ exit(0);
+ }
+
+ my $_s1 = N("RPM transaction %d/%d", 0, 0);
+ my $_s2 = N("Unselect all");
+ my $_s3 = N("Details");
+
+ statusbar_msg_remove($statusbar_msg_id); #- XXX maybe remove this
+
+ if ($exit_code == 0 && !$::rpmdragora_options{auto_orphans}) {
+ if (urpm::orphans::check_unrequested_orphans_after_auto_select($urpm)) {
+ if (my $msg = urpm::orphans::get_now_orphans_gui_msg($urpm)) {
+ interactive_msg(N("Orphan packages"), $msg, scroll => 1);
+ }
+ }
+ }
+
+ return_with_exit_code:
+ return !($something_installed || scalar(@to_remove));
+}
+
+
+# -=-=-=---=-=-=---=-=-=-- remove packages -=-=-=---=-=-=---=-=-=-
+
+sub perform_removal {
+ my ($urpm, $pkgs) = @_;
+ my @toremove = map { if_($pkgs->{$_}{selected}, $pkgs->{$_}{urpm_name}) } keys %$pkgs;
+ return if !@toremove;
+ my $gurpm = Rpmdragora::gurpm->new(1 ? N("Please wait") : N("Please wait, removing packages..."), N("Initializing..."), transient => $::main_window);
+ my $_gurpm_clean_guard = before_leaving { undef $gurpm };
+
+ my $may_be_orphans = 1;
+ urpm::orphans::unrequested_orphans_after_remove($urpm, \@toremove)
+ or $may_be_orphans = 0;
+
+ my $progress = -1;
+ local $urpm->{log} = sub {
+ my $str = $_[0];
+ print $str;
+ $progress++;
+ return if $progress <= 0; # skip first "creating transaction..." message
+ $gurpm->label($str); # display "removing package %s"
+ $gurpm->progress(min(0.99*100, scalar($progress/@toremove)*100));
+ #gtkflush();
+ };
+
+ my @results;
+ slow_func_statusbar(
+ N("Please wait, removing packages..."),
+ $::main_window,
+ sub {
+ @results = $::rpmdragora_options{parallel}
+ ? urpm::parallel::remove($urpm, \@toremove)
+ : urpm::install::install($urpm, \@toremove, {}, {},
+ callback_report_uninst => sub { $gurpm->label($_[0]) },
+ );
+ open_rpm_db('force_sync');
+ },
+ );
+ if (@results) {
+ interactive_msg(
+ N("Problem during removal"),
+ N("There was a problem during the removal of packages:\n\n%s", join("\n", @results)),
+ if_(@results > 1, scroll => 1),
+ );
+ return 1;
+ } else {
+ if ($may_be_orphans && !$::rpmdragora_options{auto_orphans}) {
+ if (my $msg = urpm::orphans::get_now_orphans_gui_msg($urpm)) {
+ interactive_msg(N("Information"), $msg, scroll => 1);
+ }
+ }
+ return 0;
+ }
+}
+
+1;
diff --git a/AdminPanel/Rpmdragora/rpmnew.pm b/AdminPanel/Rpmdragora/rpmnew.pm
new file mode 100644
index 0000000..4df63c6
--- /dev/null
+++ b/AdminPanel/Rpmdragora/rpmnew.pm
@@ -0,0 +1,204 @@
+package AdminPanel::Rpmdragora::rpmnew;
+#*****************************************************************************
+#
+# Copyright (c) 2002 Guillaume Cottenceau
+# Copyright (c) 2002-2007 Thierry Vignaud <tvignaud@mandriva.com>
+# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA
+# Copyright (c) 2005-2007 Mandriva SA
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2, as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#*****************************************************************************
+#
+# $Id: rpmnew.pm 263914 2009-12-03 17:41:02Z tv $
+
+use strict;
+use lib qw(/usr/lib/libDrakX);
+use common;
+use AdminPanel::rpmdragora;
+use AdminPanel::Rpmdragora::init;
+use AdminPanel::Rpmdragora::pkg;
+use AdminPanel::Rpmdragora::open_db;
+use AdminPanel::Rpmdragora::formatting;
+use Exporter;
+our @ISA = qw(Exporter);
+our @EXPORT = qw(dialog_rpmnew do_merge_if_needed);
+
+# /var/lib/nfs/etab /var/lib/nfs/rmtab /var/lib/nfs/xtab /var/cache/man/whatis
+my %ignores_rpmnew = map { $_ => 1 } qw(
+ /etc/adjtime
+ /etc/fstab
+ /etc/group
+ /etc/ld.so.conf
+ /etc/localtime
+ /etc/modules
+ /etc/passwd
+ /etc/security/fileshare.conf
+ /etc/shells
+ /etc/sudoers
+ /etc/sysconfig/alsa
+ /etc/sysconfig/autofsck
+ /etc/sysconfig/harddisks
+ /etc/sysconfig/harddrake2/previous_hw
+ /etc/sysconfig/init
+ /etc/sysconfig/installkernel
+ /etc/sysconfig/msec
+ /etc/sysconfig/nfs
+ /etc/sysconfig/pcmcia
+ /etc/sysconfig/rawdevices
+ /etc/sysconfig/saslauthd
+ /etc/sysconfig/syslog
+ /etc/sysconfig/usb
+ /etc/sysconfig/xinetd
+);
+
+sub inspect {
+ my ($file) = @_;
+ my ($rpmnew, $rpmsave) = ("$file.rpmnew", "$file.rpmsave");
+ my @inspect_wsize = ($typical_width*2.5, 500);
+ my $rpmfile = 'rpmnew';
+ -r $rpmnew or $rpmfile = 'rpmsave';
+ -r $rpmnew && -r $rpmsave && (stat $rpmsave)[9] > (stat $rpmnew)[9] and $rpmfile = 'rpmsave';
+ $rpmfile eq 'rpmsave' and $rpmnew = $rpmsave;
+
+ 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)) {
+ local $ENV{$_} = $ENV{$_} . '.UTF-8' if $ENV{$_} && $ENV{$_} !~ /UTF-8/;
+ }
+ my @diff = map { ensure_utf8($_); $_ } `/usr/bin/diff -u '$file' '$rpmnew'`;
+ @diff = N("(none)") if !@diff;
+ my $d = ugtk2->new(N("Inspecting %s", $file), grab => 1, transient => $::main_window);
+ my $save_wsize = sub { @inspect_wsize = $d->{rwindow}->get_size };
+ my %texts;
+ require Gtk2::SourceView2;
+ my $lang_manager = Gtk2::SourceView2::LanguageManager->get_default;
+ gtkadd(
+ $d->{window},
+ gtkpack_(
+ gtknew('VBox', spacing => 5),
+ 1, create_vpaned(
+ create_vpaned(
+ gtkpack_(
+ gtknew('VBox'),
+ 0, gtknew('Label', text_markup => qq(<span font_desc="monospace">$file:</span>)),
+ 1, gtknew('ScrolledWindow', child => $texts{file} = Gtk2::SourceView2::View->new),
+ ),
+ gtkpack_(
+ gtknew('VBox'),
+ 0, gtknew('Label', text_markup => qq(<span font_desc="monospace">$rpmnew:</span>)),
+ 1, gtknew('ScrolledWindow', child => $texts{rpmnew} = Gtk2::SourceView2::View->new),
+ ),
+ resize1 => 1,
+ ),
+ gtkpack_(
+ gtknew('VBox'),
+ 0, gtknew('Label', text => N("Changes:")),
+ 1, gtknew('ScrolledWindow', child => $texts{diff} = Gtk2::SourceView2::View->new),
+ ),
+ resize1 => 1,
+ ),
+ 0, Gtk2::HSeparator->new,
+ 0, gtknew('WrappedLabel',
+ # prevent bad sizing of Gtk2::WrappedLabel:
+ width => $inspect_wsize[0],
+ text => N("You can either remove the .%s file, use it as main file or do nothing. If unsure, keep the current file (\"%s\").",
+ $rpmfile, N("Remove .%s", $rpmfile)),
+ ),
+ 0, gtkpack__(
+ gtknew('HButtonBox'),
+ gtksignal_connect(
+ gtknew('Button', text => N("Remove .%s", $rpmfile)),
+ clicked => sub { $save_wsize->(); unlink $rpmnew; Gtk2->main_quit },
+ ),
+ gtksignal_connect(
+ gtknew('Button', text => N("Use .%s as main file", $rpmfile)),
+ clicked => sub { $save_wsize->(); renamef($rpmnew, $file); Gtk2->main_quit },
+ ),
+ gtksignal_connect(
+ gtknew('Button', text => N("Do nothing")),
+ clicked => sub { $save_wsize->(); Gtk2->main_quit },
+ ),
+ )
+ )
+ );
+ my %files = (file => $file, rpmnew => $rpmnew);
+ foreach (keys %files) {
+ gtktext_insert($texts{$_}, [ [ scalar(cat_($files{$_})), { 'font' => 'monospace' } ] ]);
+ my $lang = $lang_manager->guess_language($files{$_});
+ $lang ||= $lang_manager->get_language('sh');
+ my $buffer = $texts{$_}->get_buffer;
+ $buffer->set_language($lang) if $lang;
+ }
+ gtktext_insert($texts{diff}, [ [ join('', @diff), { 'font' => 'monospace' } ] ]);
+ my $buffer = $texts{diff}->get_buffer;
+ my $lang = $lang_manager->get_language('diff');
+ $buffer->set_language($lang) if $lang;
+ $d->{rwindow}->set_default_size(@inspect_wsize);
+ $d->main;
+}
+
+sub dialog_rpmnew {
+ my ($msg, %p2r) = @_;
+ @{$p2r{$_}} = grep { !$ignores_rpmnew{$_} } @{$p2r{$_}} foreach keys %p2r;
+ my $sum_rpmnew = sum(map { int @{$p2r{$_}} } keys %p2r);
+ $sum_rpmnew == 0 and return 1;
+ interactive_packtable(
+ N("Installation finished"),
+ $::main_window,
+ $msg,
+ [ map { my $pkg = $_;
+ map {
+ my $f = $_;
+ my $b;
+ [ gtkpack__(
+ gtknew('HBox'),
+ gtkset_markup(
+ gtkset_selectable(gtknew('Label'), 1),
+ qq($pkg:<span font_desc="monospace">$f</span>),
+ )
+ ),
+ gtksignal_connect(
+ $b = gtknew('Button', text => N("Inspect...")),
+ clicked => sub {
+ inspect($f);
+ -r "$f.rpmnew" || -r "$f.rpmsave" or $b->set_sensitive(0);
+ },
+ ) ];
+ } @{$p2r{$pkg}};
+ } keys %p2r ],
+ [ gtknew('Button', text => N("Ok"),
+ clicked => sub { Gtk2->main_quit }) ]
+ );
+ return 0;
+}
+
+
+sub do_merge_if_needed() {
+ if ($rpmdragora_options{'merge-all-rpmnew'}) {
+ my %pkg2rpmnew;
+ my $wait = wait_msg(N("Please wait, searching..."));
+ print "Searching .rpmnew and .rpmsave files...\n";
+ # costly:
+ open_rpm_db()->traverse(sub {
+ my $n = my_fullname($_[0]);
+ $pkg2rpmnew{$n} = [ grep { m|^/etc| && (-r "$_.rpmnew" || -r "$_.rpmsave") } map { chomp_($_) } $_[0]->conf_files ];
+ });
+ print "done.\n";
+ undef $wait;
+ $typical_width = 330;
+ dialog_rpmnew('', %pkg2rpmnew) and print "Nothing to do.\n";
+ myexit(0);
+ }
+}
+
+1;
diff --git a/AdminPanel/Rpmdragora/widgets.pm b/AdminPanel/Rpmdragora/widgets.pm
new file mode 100644
index 0000000..2b42468
--- /dev/null
+++ b/AdminPanel/Rpmdragora/widgets.pm
@@ -0,0 +1,51 @@
+package Gtk2::Mdv::TextView;
+#*****************************************************************************
+#
+# Copyright (c) 2002 Guillaume Cottenceau
+# Copyright (c) 2002-2007 Thierry Vignaud <tvignaud@mandriva.com>
+# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA
+# Copyright (c) 2005-2007 Mandriva SA
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2, as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#*****************************************************************************
+#
+# $Id: widgets.pm 233986 2008-02-06 14:14:06Z tv $
+
+use strict;
+use MDK::Common::Func 'any';
+use lib qw(/usr/lib/libDrakX);
+
+use Time::HiRes;
+use feature 'state';
+
+
+sub new {
+ my ($_class) = @_;
+ my $w = gtknew('TextView', editable => 0);
+ state $time;
+ $w->signal_connect(size_allocate => sub {
+ my ($w, $requisition) = @_;
+ return if !ref($w->{anchors});
+ return if Time::HiRes::clock_gettime() - $time < 0.200;
+ $time = Time::HiRes::clock_gettime();
+ foreach my $anchor (@{$w->{anchors}}) {
+ $_->set_size_request($requisition->width-30, -1) foreach $anchor->get_widgets;
+ }
+ 1;
+ });
+ $w;
+}
+
+1;
diff --git a/AdminPanel/Shared.pm b/AdminPanel/Shared.pm
index 0779d0e..503a078 100644
--- a/AdminPanel/Shared.pm
+++ b/AdminPanel/Shared.pm
@@ -123,8 +123,8 @@ sub ask_YesOrNo {
$align = $factory->createRight($layout);
my $hbox = $factory->createHBox($align);
- my $yesButton = $factory->createPushButton($hbox, N("Yes"));
- my $noButton = $factory->createPushButton($hbox, N("No"));
+ my $yesButton = $factory->createPushButton($hbox, "Yes");
+ my $noButton = $factory->createPushButton($hbox, "No");
my $event = $msg_box->waitForEvent();
diff --git a/AdminPanel/rpmdragora.pm b/AdminPanel/rpmdragora.pm
new file mode 100644
index 0000000..c72f77b
--- /dev/null
+++ b/AdminPanel/rpmdragora.pm
@@ -0,0 +1,989 @@
+#*****************************************************************************
+#
+# Copyright (c) 2002 Guillaume Cottenceau
+# Copyright (c) 2002-2007 Thierry Vignaud <tvignaud@mandriva.com>
+# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA
+# Copyright (c) 2005, 2007 Mandriva SA
+# Copyright (c) 2013 Matteo Pasotti <matteo.pasotti@gmail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2, as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#*****************************************************************************
+#
+# $Id: rpmdragora.pm 267936 2010-04-26 16:40:21Z jvictor $
+
+package AdminPanel::rpmdragora;
+
+use lib qw(/usr/lib/libDrakX);
+use urpm::download ();
+use urpm::prompt;
+use urpm::media;
+
+use MDK::Common;
+use MDK::Common::System;
+use urpm;
+use urpm::cfg;
+use URPM;
+use URPM::Resolve;
+use strict;
+use c;
+use POSIX qw(_exit);
+use common;
+use Locale::gettext;
+use feature 'state';
+
+use AdminPanel::Shared;
+
+our @ISA = qw(Exporter);
+our $VERSION = '2.27';
+our @EXPORT = qw(
+ $changelog_first_config
+ $compute_updates
+ $filter
+ $dont_show_selections
+ $ignore_debug_media
+ $mandrakeupdate_wanted_categories
+ $mandrivaupdate_height
+ $mandrivaupdate_width
+ $max_info_in_descr
+ $mode
+ $NVR_searches
+ $offered_to_add_sources
+ $rpmdragora_height
+ $rpmdragora_width
+ $tree_flat
+ $tree_mode
+ $use_regexp
+ $typical_width
+ $clean_cache
+ $auto_select
+ add_distrib_update_media
+ add_medium_and_check
+ but
+ but_
+ check_update_media_version
+ choose_mirror
+ distro_type
+ fatal_msg
+ getbanner
+ get_icon
+ interactive_list
+ interactive_list_
+ interactive_msg
+ interactive_packtable
+ myexit
+ readconf
+ remove_wait_msg
+ run_drakbug
+ show_urpm_progress
+ slow_func
+ slow_func_statusbar
+ statusbar_msg
+ statusbar_msg_remove
+ strip_first_underscore
+ update_sources
+ update_sources_check
+ update_sources_interactive
+ update_sources_noninteractive
+ wait_msg
+ warn_for_network_need
+ writeconf
+);
+our $typical_width = 280;
+
+our $dont_show_selections;
+
+# i18n: IMPORTANT: to get correct namespace (rpmdragora instead of libDrakX)
+BEGIN { unshift @::textdomains, qw(rpmdragora urpmi rpm-summary-main rpm-summary-contrib rpm-summary-devel rpm-summary-non-free) }
+
+use yui;
+#ugtk2::add_icon_path('/usr/share/rpmdragora/icons');
+
+Locale::gettext::bind_textdomain_codeset('rpmdragora', 'UTF8');
+
+our $mageia_release = cat_(
+ -e '/etc/mageia-release' ? '/etc/mageia-release' : '/etc/release'
+) || '';
+chomp $mageia_release;
+our ($distro_version) = $mageia_release =~ /(\d+\.\d+)/;
+our ($branded, %distrib);
+$branded = -f '/etc/sysconfig/oem'
+ and %distrib = MDK::Common::System::distrib();
+our $myname_update = $branded ? N_("Software Update") : N_("Mageia Update");
+
+@rpmdragora::prompt::ISA = 'urpm::prompt';
+
+sub rpmdragora::prompt::prompt {
+ my ($self) = @_;
+ my @answers;
+ my $d = ugtk2->new("", grab => 1, if_($::main_window, transient => $::main_window));
+ $d->{rwindow}->set_position('center_on_parent');
+ gtkadd(
+ $d->{window},
+ gtkpack(
+ Gtk2::VBox->new(0, 5),
+ Gtk2::WrappedLabel->new($self->{title}),
+ (map { gtkpack(
+ Gtk2::HBox->new(0, 5),
+ Gtk2::Label->new($self->{prompts}[$_]),
+ $answers[$_] = gtkset_visibility(gtkentry(), !$self->{hidden}[$_]),
+ ) } 0 .. $#{$self->{prompts}}),
+ gtksignal_connect(Gtk2::Button->new(N("Ok")), clicked => sub { Gtk2->main_quit }),
+ ),
+ );
+ $d->main;
+ map { $_->get_text } @answers;
+}
+
+$urpm::download::PROMPT_PROXY = new rpmdragora::prompt(
+ N_("Please enter your credentials for accessing proxy\n"),
+ [ N_("User name:"), N_("Password:") ],
+ undef,
+ [ 0, 1 ],
+);
+
+sub myexit {
+ writeconf();
+ #ugtk2::exit(undef, @_);
+}
+
+my ($root) = grep { $_->[2] == 0 } list_passwd();
+$ENV{HOME} = $> == 0 ? $root->[7] : $ENV{HOME} || '/root';
+$ENV{HOME} = $::env if $::env = $Rpmdragora::init::rpmdragora_options{env}[0];
+
+our $configfile = "$ENV{HOME}/.rpmdragora";
+
+#
+# Configuration File Options
+#
+
+# clear download cache after successfull installation of packages
+our $clean_cache;
+
+# automatic select dependencies without user intervention
+our $auto_select;
+
+our ($changelog_first_config, $compute_updates, $filter, $max_info_in_descr, $mode, $NVR_searches, $tree_flat, $tree_mode, $use_regexp);
+our ($mandrakeupdate_wanted_categories, $ignore_debug_media, $offered_to_add_sources, $no_confirmation);
+our ($rpmdragora_height, $rpmdragora_width, $mandrivaupdate_height, $mandrivaupdate_width);
+
+our %config = (
+ clean_cache => {
+ var => \$clean_cache,
+ default => [ 0 ]
+ },
+ auto_select => {
+ var => \$auto_select,
+ default => [ 0 ]
+ },
+ changelog_first_config => { var => \$changelog_first_config, default => [ 0 ] },
+ compute_updates => { var => \$compute_updates, default => [ 1 ] },
+ dont_show_selections => { var => \$dont_show_selections, default => [ $> ? 1 : 0 ] },
+ filter => { var => \$filter, default => [ 'all' ] },
+ ignore_debug_media => { var => \$ignore_debug_media, default => [ 0 ] },
+ mandrakeupdate_wanted_categories => { var => \$mandrakeupdate_wanted_categories, default => [ qw(security) ] },
+ mandrivaupdate_height => { var => \$mandrivaupdate_height, default => [ 0 ] },
+ mandrivaupdate_width => { var => \$mandrivaupdate_width, default => [ 0 ] },
+ max_info_in_descr => { var => \$max_info_in_descr, default => [] },
+ mode => { var => \$mode, default => [ 'by_group' ] },
+ NVR_searches => { var => \$NVR_searches, default => [ 0 ] },
+ 'no-confirmation' => { var => \$no_confirmation, default => [ 0 ] },
+ offered_to_add_sources => { var => \$offered_to_add_sources, default => [ 0 ] },
+ rpmdragora_height => { var => \$rpmdragora_height, default => [ 0 ] },
+ rpmdragora_width => { var => \$rpmdragora_width, default => [ 0 ] },
+ tree_flat => { var => \$tree_flat, default => [ 0 ] },
+ tree_mode => { var => \$tree_mode, default => [ qw(gui_pkgs) ] },
+ use_regexp => { var => \$use_regexp, default => [ 0 ] },
+);
+
+sub readconf() {
+ ${$config{$_}{var}} = $config{$_}{default} foreach keys %config;
+ foreach my $l (cat_($configfile)) {
+ foreach (keys %config) {
+ ${$config{$_}{var}} = [ split ' ', $1 ] if $l =~ /^\Q$_\E(.*)/;
+ }
+ }
+ # special cases:
+ $::rpmdragora_options{'no-confirmation'} = $no_confirmation->[0] if !defined $::rpmdragora_options{'no-confirmation'};
+ $Rpmdragora::init::default_list_mode = $tree_mode->[0] if ref $tree_mode && !$Rpmdragora::init::overriding_config;
+}
+
+sub writeconf() {
+ return if $::env;
+ unlink $configfile;
+
+ # special case:
+ $no_confirmation->[0] = $::rpmdragora_options{'no-confirmation'};
+
+ output($configfile, map { "$_ " . (ref ${$config{$_}{var}} ? join(' ', @${$config{$_}{var}}) : undef) . "\n" } keys %config);
+}
+
+sub getbanner() {
+ $::MODE or return undef;
+ if (0) {
+ +{
+ remove => N("Software Packages Removal"),
+ update => N("Software Packages Update"),
+ install => N("Software Packages Installation"),
+ };
+ }
+# Gtk2::Banner->new($ugtk2::wm_icon, $::MODE eq 'update' ? N("Software Packages Update") : N("Software Management"));
+}
+
+# return value:
+# - undef if if closed (aka really canceled)
+# - 0 if if No/Cancel
+# - 1 if if Yes/Ok
+sub interactive_msg {
+ my ($title, $contents, %options) = @_;
+ my $retVal = ask_YesOrNo($title, $contents);
+ return 1 if($retVal eq "Yes");
+ return 0;
+=comment
+ $options{transient} ||= $::main_window if $::main_window;
+ local $::isEmbedded;
+ my $factory = yui::YUI::widgetFactory;
+ my $d = $factory->createPopupDialog();
+
+ my $d = ugtk2->new($title, grab => 1, if_(exists $options{transient}, transient => $options{transient}));
+ $d->{rwindow}->set_position($options{transient} ? 'center_on_parent' : 'center_always');
+ if ($options{scroll}) {
+ $contents = ugtk2::markup_to_TextView_format($contents) if !ref $contents;
+ } else { #- because we'll use a WrappedLabel
+ $contents = formatAlaTeX($contents) if !ref $contents;
+ }
+
+ my $button_yes;
+ my $vbox = $factory->createVBox($d);
+ my $text_w = $factory->createMultiLineEdit($vbox, "");
+ my $hbox = $factory->createHBox($vbox);
+
+ ref($options{yesno}) eq 'ARRAY' ? map {ss
+ my $label = $_;
+ my $button_yes = $factory->createIconButton($hbox,"",$label);
+ } @{$options{yesno}}
+ : (
+ $options{yesno} ? (
+ my $button_no = $factory->createIconButton($hbox, "", $options{text}{no} || N("No"));
+ $button_yes = $factory->createIconButton($hbox,"", $options{text}{yes} || N("Yes"));
+ )
+ : $button_yes = $factory->createIconButton($hbox,"",N("Ok"));
+ )
+
+ #$d->{window}->set_focus($button_yes);
+ #$text_w->set_size_request($typical_width*2, $options{scroll} ? 300 : -1);
+ #$d->main;
+ return $d->{retval};
+=cut
+}
+
+sub interactive_packtable {
+ my ($title, $parent_window, $top_label, $lines, $action_buttons) = @_;
+
+ my $w = ugtk2->new($title, grab => 1, transient => $parent_window);
+ local $::main_window = $w->{real_window};
+ $w->{rwindow}->set_position($parent_window ? 'center_on_parent' : 'center');
+ my $packtable = create_packtable({}, @$lines);
+
+ gtkadd($w->{window},
+ gtkpack_(Gtk2::VBox->new(0, 5),
+ if_($top_label, 0, Gtk2::Label->new($top_label)),
+ 1, create_scrolled_window($packtable),
+ 0, gtkpack__(create_hbox(), @$action_buttons)));
+ my $preq = $packtable->size_request;
+ my ($xpreq, $ypreq) = ($preq->width, $preq->height);
+ my $wreq = $w->{rwindow}->size_request;
+ my ($xwreq, $ywreq) = ($wreq->width, $wreq->height);
+ $w->{rwindow}->set_default_size(max($typical_width, min($typical_width*2.5, $xpreq+$xwreq)),
+ max(200, min(450, $ypreq+$ywreq)));
+ $w->main;
+}
+
+sub interactive_list {
+ my ($title, $contents, $list, $callback, %options) = @_;
+ my $d = ugtk2->new($title, grab => 1, if_(exists $options{transient}, transient => $options{transient}));
+ $d->{rwindow}->set_position($options{transient} ? 'center_on_parent' : 'center_always');
+ my @radios = gtkradio('', @$list);
+ my $vbradios = $callback ? create_packtable(
+ {},
+ mapn {
+ my $n = $_[1];
+ [ $_[0],
+ gtksignal_connect(
+ Gtk2::Button->new(but(N("Info..."))),
+ clicked => sub { $callback->($n) },
+ ) ];
+ } \@radios, $list,
+ ) : gtkpack__(Gtk2::VBox->new(0, 0), @radios);
+ my $choice;
+ my $button_ok;
+ gtkadd(
+ $d->{window},
+ gtkpack__(
+ Gtk2::VBox->new(0,5),
+ Gtk2::Label->new($contents),
+ int(@$list) > 8 ? gtkset_size_request(create_scrolled_window($vbradios), 250, 320) : $vbradios,
+ gtkpack__(
+ create_hbox(),
+ if_(!$options{nocancel},
+ gtksignal_connect(
+ Gtk2::Button->new(N("Cancel")), clicked => sub { Gtk2->main_quit }),
+ ),
+ gtksignal_connect(
+ $button_ok=Gtk2::Button->new(N("Ok")), clicked => sub {
+ each_index { $_->get_active and $choice = $::i } @radios;
+ Gtk2->main_quit;
+ }
+ )
+ )
+ )
+ );
+ $d->{window}->set_focus($button_ok);
+ $d->main;
+ $choice;
+}
+
+sub interactive_list_ { interactive_list(@_, if_($::main_window, transient => $::main_window)) }
+
+sub fatal_msg {
+ interactive_msg @_;
+ myexit -1;
+}
+
+sub wait_msg {
+ my ($msg, %options) = @_;
+ #return msgBox("Please wait");
+ #OLD my $mainw = ugtk2->new(N("Please wait"), grab => 1, if_(exists $options{transient}, transient => $options{transient}));
+ my $factory = yui::YUI::widgetFactory;
+ my $mainw = $factory->createPopupDialog();
+ #$mainw->{real_window}->set_position($options{transient} ? 'center_on_parent' : 'center_always');
+ my $vbox = $factory->createVBox($mainw);
+ my $title = $factory->createLabel($vbox, N("Please wait"));
+ #my $label = $factory->createLabel($vbox, $msg);
+ #OLD my $label = ref($msg) =~ /^Gtk/ ? $msg : Gtk2::WrappedLabel->new($msg);
+ #gtkadd(
+ #$mainw->{window},
+ #gtkpack__(
+ # gtkset_border_width(Gtk2::VBox->new(0, 5), 6),
+ # $label,
+ # if_(exists $options{widgets}, @{$options{widgets}}),
+ #)
+ #);
+ #$mainw->sync;
+ #gtkset_mousecursor_wait($mainw->{rwindow}->window) unless $options{no_wait_cursor};
+ #$mainw->flush;
+ $mainw->recalcLayout();
+ $mainw->doneMultipleChanges();
+ $mainw;
+}
+
+sub remove_wait_msg {
+ my $w = shift;
+ #gtkset_mousecursor_normal($w->{rwindow}->window);
+ $w->destroy;
+}
+
+sub but { " $_[0] " }
+sub but_ { " $_[0] " }
+
+sub slow_func ($&) {
+ my ($param, $func) = @_;
+ if (ref($param) =~ /^Gtk/) {
+ #gtkset_mousecursor_wait($param);
+ #ugtk2::flush();
+ #$func->();
+ #gtkset_mousecursor_normal($param);
+ } else {
+ my $w = wait_msg($param);
+ $func->();
+ remove_wait_msg($w);
+ }
+}
+
+sub statusbar_msg {
+ unless ($::statusbar) { #- fallback if no status bar
+ if (defined &::wait_msg_) { goto &::wait_msg_ } else { goto &wait_msg }
+ }
+ my ($msg, $o_timeout) = @_;
+ $::statusbar->setText($msg);
+ #- always use the same context description for now
+ #my $cx = $::statusbar->get_context_id("foo");
+ #$::w and $::w->{rwindow} and gtkset_mousecursor_wait($::w->{rwindow}->window);
+ #- returns a msg_id to be passed optionnally to statusbar_msg_remove
+ #my $id = $::statusbar->push($cx, $msg);
+ #gtkflush();
+ #Glib::Timeout->add(5000, sub { statusbar_msg_remove($id); 0 }) if $o_timeout;
+ Glib::Timeout->add(5000, sub { statusbar_msg_remove(); 0 }) if $o_timeout;
+ #$id;
+}
+
+sub statusbar_msg_remove {
+ #my ($msg_id) = @_;
+ #if (!$::statusbar || ref $msg_id) { #- fallback if no status bar
+ #goto &remove_wait_msg;
+ #}
+ #my $cx = $::statusbar->get_context_id("foo");
+ #if (defined $msg_id) {
+ #$::statusbar->remove($cx, $msg_id);
+ #} else {
+ #$::statusbar->pop($cx);
+ #}
+ #$::w and $::w->{rwindow} and gtkset_mousecursor_normal($::w->{rwindow}->window);
+ $::statusbar->setValue("");
+}
+
+sub slow_func_statusbar ($$&) {
+ my ($msg, $w, $func) = @_;
+ gtkset_mousecursor_wait($w->window);
+ my $msg_id = statusbar_msg($msg);
+ gtkflush();
+ $func->();
+ statusbar_msg_remove($msg_id);
+ gtkset_mousecursor_normal($w->window);
+}
+
+my %u2l = (
+ at => N_("Austria"),
+ au => N_("Australia"),
+ be => N_("Belgium"),
+ br => N_("Brazil"),
+ ca => N_("Canada"),
+ ch => N_("Switzerland"),
+ cr => N_("Costa Rica"),
+ cz => N_("Czech Republic"),
+ de => N_("Germany"),
+ dk => N_("Danmark"),
+ el => N_("Greece"),
+ es => N_("Spain"),
+ fi => N_("Finland"),
+ fr => N_("France"),
+ gr => N_("Greece"),
+ hu => N_("Hungary"),
+ il => N_("Israel"),
+ it => N_("Italy"),
+ jp => N_("Japan"),
+ ko => N_("Korea"),
+ nl => N_("Netherlands"),
+ no => N_("Norway"),
+ pl => N_("Poland"),
+ pt => N_("Portugal"),
+ ru => N_("Russia"),
+ se => N_("Sweden"),
+ sg => N_("Singapore"),
+ sk => N_("Slovakia"),
+ tw => N_("Taiwan"),
+ uk => N_("United Kingdom"),
+ cn => N_("China"),
+ com => N_("United States"),
+ org => N_("United States"),
+ net => N_("United States"),
+ edu => N_("United States"),
+ );
+my $us = [ qw(com org net edu) ];
+my %t2l = (
+ 'America/\w+' => $us,
+ 'Asia/Tel_Aviv' => [ qw(il ru it cz at de fr se) ],
+ 'Asia/Tokyo' => [ qw(jp ko tw), @$us ],
+ 'Asia/Seoul' => [ qw(ko jp tw), @$us ],
+ 'Asia/Taipei' => [ qw(tw jp), @$us ],
+ 'Asia/(Shanghai|Beijing)' => [ qw(cn tw sg), @$us ],
+ 'Asia/Singapore' => [ qw(cn sg), @$us ],
+ 'Atlantic/Reykjavik' => [ qw(uk no se fi dk), @$us, qw(nl de fr at cz it) ],
+ 'Australia/\w+' => [ qw(au jp ko tw), @$us ],
+ 'Brazil/\w+' => [ 'br', @$us ],
+ 'Canada/\w+' => [ 'ca', @$us ],
+ 'Europe/Amsterdam' => [ qw(nl be de at cz fr se dk it) ],
+ 'Europe/Athens' => [ qw(gr pl cz de it nl at fr) ],
+ 'Europe/Berlin' => [ qw(de be at nl cz it fr se) ],
+ 'Europe/Brussels' => [ qw(be de nl fr cz at it se) ],
+ 'Europe/Budapest' => [ qw(cz it at de fr nl se) ],
+ 'Europe/Copenhagen' => [ qw(dk nl de be se at cz it) ],
+ 'Europe/Dublin' => [ qw(uk fr be nl dk se cz it) ],
+ 'Europe/Helsinki' => [ qw(fi se no nl be de fr at it) ],
+ 'Europe/Istanbul' => [ qw(il ru it cz it at de fr nl se) ],
+ 'Europe/Lisbon' => [ qw(pt es fr it cz at de se) ],
+ 'Europe/London' => [ qw(uk fr be nl de at cz se it) ],
+ 'Europe/Madrid' => [ qw(es fr pt it cz at de se) ],
+ 'Europe/Moscow' => [ qw(ru de pl cz at se be fr it) ],
+ 'Europe/Oslo' => [ qw(no se fi dk de be at cz it) ],
+ 'Europe/Paris' => [ qw(fr be de at cz nl it se) ],
+ 'Europe/Prague' => [ qw(cz it at de fr nl se) ],
+ 'Europe/Rome' => [ qw(it fr cz de at nl se) ],
+ 'Europe/Stockholm' => [ qw(se no dk fi nl de at cz fr it) ],
+ 'Europe/Vienna' => [ qw(at de cz it fr nl se) ],
+ );
+
+#- get distrib release number (2006.0, etc)
+sub etc_version() {
+ (my $v) = split / /, cat_('/etc/version');
+ return $v;
+}
+
+#- returns the keyword describing the type of the distribution.
+#- the parameter indicates whether we want base or update sources
+sub distro_type {
+ my ($want_base_distro) = @_;
+ return 'cauldron' if $mageia_release =~ /cauldron/i;
+ #- we can't use updates for community while official is not out (release ends in ".0")
+ if ($want_base_distro || $mageia_release =~ /community/i && etc_version() =~ /\.0$/) {
+ return 'official' if $mageia_release =~ /official|limited/i;
+ return 'community' if $mageia_release =~ /community/i;
+ #- unknown: fallback to updates
+ }
+ return 'updates';
+}
+
+sub compat_arch_for_updates($) {
+ # FIXME: We prefer 64-bit packages to update on biarch platforms,
+ # since the system is populated with 64-bit packages anyway.
+ my ($arch) = @_;
+ return $arch =~ /x86_64|amd64/ if arch() eq 'x86_64';
+ MDK::Common::System::compat_arch($arch);
+}
+
+sub mirrors {
+ my ($urpm, $want_base_distro) = @_;
+ my $cachedir = $urpm->{cachedir} || '/root';
+ require mirror;
+ mirror::register_downloader(
+ sub {
+ my ($url) = @_;
+ my $file = $url;
+ $file =~ s!.*/!$cachedir/!;
+ unlink $file; # prevent "partial file" errors
+ before_leaving(sub { unlink $file });
+
+ my ($gurpm, $id, $canceled);
+ # display a message in statusbar (if availlable):
+ $::statusbar and $id = statusbar_msg(
+ $branded
+ ? N("Please wait, downloading mirror addresses.")
+ : N("Please wait, downloading mirror addresses from the Mageia website."),
+ 0);
+ my $_clean_guard = before_leaving {
+ undef $gurpm;
+ $id and statusbar_msg_remove($id);
+ };
+
+ require Rpmdragora::gurpm;
+ require Rpmdragora::pkg;
+
+ my $res = urpm::download::sync_url($urpm, $url,
+ dir => $cachedir,
+ callback => sub {
+ $gurpm ||=
+ Rpmdragora::gurpm->new(N("Please wait"),
+ transient => $::main_window);
+ $canceled ||=
+ !Rpmdragora::pkg::download_callback($gurpm, @_);
+ gtkflush();
+ },
+ );
+ $res or die N("retrieval of [%s] failed", $file) . "\n";
+ return $canceled ? () : cat_($file);
+ });
+ my @mirrors = @{ mirror::list(common::parse_LDAP_namespace_structure(cat_('/etc/product.id')), 'distrib') || [] };
+ require timezone;
+ my $tz = ${timezone::read()}{timezone};
+ foreach my $mirror (@mirrors) {
+ my $goodness;
+ each_index { $_ = $u2l{$_} || $_; $_ eq $mirror->{country} and $goodness ||= 100-$::i } (map { if_($tz =~ /^$_$/, @{$t2l{$_}}) } keys %t2l), @$us;
+ $mirror->{goodness} = $goodness + rand();
+ $mirror->{country} = translate($mirror->{country});
+ }
+ unless (-x '/usr/bin/rsync') {
+ @mirrors = grep { $_->{url} !~ /^rsync:/ } @mirrors;
+ }
+ return sort { $b->{goodness} <=> $a->{goodness} } @mirrors;
+}
+
+sub warn_for_network_need {
+ my ($message, %options) = @_;
+ $message ||=
+$branded
+? N("I need to access internet to get the mirror list.
+Please check that your network is currently running.
+
+Is it ok to continue?")
+: N("I need to contact the Mageia website to get the mirror list.
+Please check that your network is currently running.
+
+Is it ok to continue?");
+ interactive_msg(N("Mirror choice"), $message, yesno => 1, %options) or return '';
+}
+
+sub choose_mirror {
+ my ($urpm, %options) = @_;
+ delete $options{message};
+ my @transient_options = exists $options{transient} ? (transient => $options{transient}) : ();
+ warn_for_network_need($options{message}, %options) or return;
+ my @mirrors = eval { mirrors($urpm, $options{want_base_distro}) };
+ my $error = $@;
+ if ($error) {
+ $error = "\n$error\n";
+ interactive_msg(N("Error during download"),
+($branded
+? N("There was an error downloading the mirror list:
+
+%s
+The network, or the website, may be unavailable.
+Please try again later.", $error)
+: N("There was an error downloading the mirror list:
+
+%s
+The network, or the Mageia website, may be unavailable.
+Please try again later.", $error)), %options
+
+ );
+ return '';
+ }
+
+ !@mirrors and interactive_msg(N("No mirror"),
+($branded
+? N("I can't find any suitable mirror.")
+: N("I can't find any suitable mirror.
+
+There can be many reasons for this problem; the most frequent is
+the case when the architecture of your processor is not supported
+by Mageia Official Updates.")), %options
+ ), return '';
+
+ my $w = ugtk2->new(N("Mirror choice"), grab => 1, @transient_options);
+ $w->{rwindow}->set_position($options{transient} ? 'center_on_parent' : 'center_always');
+ my $tree_model = Gtk2::TreeStore->new("Glib::String");
+ my $tree = Gtk2::TreeView->new_with_model($tree_model);
+ $tree->get_selection->set_mode('browse');
+ $tree->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, text => 0));
+ $tree->set_headers_visible(0);
+
+ gtkadd(
+ $w->{window},
+ gtkpack_(
+ Gtk2::VBox->new(0,5),
+ 0, N("Please choose the desired mirror."),
+ 1, create_scrolled_window($tree),
+ 0, gtkpack(
+ create_hbox('edge'),
+ map {
+ my $retv = $_->[1];
+ gtksignal_connect(
+ Gtk2::Button->new(but($_->[0])),
+ clicked => sub {
+ if ($retv) {
+ my ($model, $iter) = $tree->get_selection->get_selected;
+ $model and $w->{retval} = { sel => $model->get($iter, 0) };
+ }
+ Gtk2->main_quit;
+ },
+ );
+ } [ N("Cancel"), 0 ], [ N("Ok"), 1 ]
+ ),
+ )
+ );
+ my %roots;
+ $tree_model->append_set($roots{$_->{country}} ||= $tree_model->append_set(undef, [ 0 => $_->{country} ]),
+ [ 0 => $_->{url} ]) foreach @mirrors;
+
+ $w->{window}->set_size_request(500, 400);
+ $w->{rwindow}->show_all;
+
+ my $path = Gtk2::TreePath->new_first;
+ $tree->expand_row($path, 0);
+ $path->down;
+ $tree->get_selection->select_path($path);
+
+ $w->main && return grep { $w->{retval}{sel} eq $_->{url} } @mirrors;
+}
+
+sub show_urpm_progress {
+ my ($label, $pb, $mode, $file, $percent, $total, $eta, $speed) = @_;
+ $file =~ s|([^:]*://[^/:\@]*:)[^/:\@]*(\@.*)|$1xxxx$2|; #- if needed...
+ state $medium;
+ if ($mode eq 'copy') {
+ $pb->set_fraction(0);
+ $label->set_label(N("Copying file for medium `%s'...", $file));
+ } elsif ($mode eq 'parse') {
+ $pb->set_fraction(0);
+ $label->set_label(N("Examining file of medium `%s'...", $file));
+ } elsif ($mode eq 'retrieve') {
+ $pb->set_fraction(0);
+ $label->set_label(N("Examining remote file of medium `%s'...", $file));
+ $medium = $file;
+ } elsif ($mode eq 'done') {
+ $pb->set_fraction(1.0);
+ $label->set_label($label->get_label . N(" done."));
+ $medium = undef;
+ } elsif ($mode eq 'failed') {
+ $pb->set_fraction(1.0);
+ $label->set_label($label->get_label . N(" failed!"));
+ $medium = undef;
+ } else {
+ # FIXME: we're displaying misplaced quotes such as "downloading `foobar from 'medium Main Updates'ยด"
+ $file = $medium && length($file) < 40 ? #-PO: We're downloading the said file from the said medium
+ N("%s from medium %s", basename($file), $medium)
+ : basename($file);
+ if ($mode eq 'start') {
+ $pb->set_fraction(0);
+ $label->set_label(N("Starting download of `%s'...", $file));
+ } elsif ($mode eq 'progress') {
+ if (defined $total && defined $eta) {
+ $pb->set_fraction($percent/100);
+ $label->set_label(N("Download of `%s'\ntime to go:%s, speed:%s", $file, $eta, $speed));
+ } else {
+ $pb->set_fraction($percent/100);
+ $label->set_label(N("Download of `%s'\nspeed:%s", $file, $speed));
+ }
+ }
+ }
+ Gtk2->main_iteration while Gtk2->events_pending;
+}
+
+sub update_sources {
+ my ($urpm, %options) = @_;
+ my $cancel = 0;
+ my $w; my $label; $w = wait_msg(
+ $label = Gtk2::Label->new(N("Please wait, updating media...")),
+ no_wait_cursor => 1,
+ widgets => [
+ my $pb = gtkset_size_request(Gtk2::ProgressBar->new, 300, -1),
+ gtkpack(
+ create_hbox(),
+ gtksignal_connect(
+ Gtk2::Button->new(N("Cancel")),
+ clicked => sub {
+ $cancel = 1;
+ $urpm->{error}->(N("Canceled"));
+ $w and $w->destroy;
+ },
+ ),
+ ),
+ ],
+ );
+ my @media; @media = @{$options{medialist}} if ref $options{medialist};
+ my $outerfatal = $urpm->{fatal};
+ local $urpm->{fatal} = sub { $w->destroy; $outerfatal->(@_) };
+ urpm::media::update_those_media($urpm, [ urpm::media::select_media_by_name($urpm, \@media) ],
+ %options, allow_failures => 1,
+ callback => sub {
+ $cancel and goto cancel_update;
+ my ($type, $media) = @_;
+ return if $type !~ /^(?:start|progress|end)$/ && @media && !member($media, @media);
+ if ($type eq 'failed') {
+ $urpm->{fatal}->(N("Error retrieving packages"),
+N("It's impossible to retrieve the list of new packages from the media
+`%s'. Either this update media is misconfigured, and in this case
+you should use the Software Media Manager to remove it and re-add it in order
+to reconfigure it, either it is currently unreachable and you should retry
+later.",
+ $media));
+ } else {
+ show_urpm_progress($label, $pb, @_);
+ }
+ },
+ );
+ $w->destroy;
+ cancel_update:
+}
+
+sub update_sources_check {
+ my ($urpm, $options, $error_msg, @media) = @_;
+ my @error_msgs;
+ local $urpm->{fatal} = sub { push @error_msgs, $_[1]; goto fatal_error };
+ local $urpm->{error} = sub { push @error_msgs, $_[0] };
+ update_sources($urpm, %$options, noclean => 1, medialist => \@media);
+ fatal_error:
+ if (@error_msgs) {
+ interactive_msg(N("Error"), sprintf(translate($error_msg), join("\n", map { formatAlaTeX($_) } @error_msgs)), scroll => 1);
+ return 0;
+ }
+ return 1;
+}
+
+sub update_sources_interactive {
+ my ($urpm, %options) = @_;
+ my $w = ugtk2->new(N("Update media"), grab => 1, center => 1, %options);
+ $w->{rwindow}->set_position($options{transient} ? 'center_on_parent' : 'center_always');
+ my @buttons;
+ my @media = grep { ! $_->{ignore} } @{$urpm->{media}};
+ unless (@media) {
+ interactive_msg(N("Warning"), N("No active medium found. You must enable some media to be able to update them."));
+ return 0;
+ }
+ gtkadd(
+ $w->{window},
+ gtkpack_(
+ 0, Gtk2::VBox->new(0,5),
+ 0, Gtk2::Label->new(N("Select the media you wish to update:")),
+ 1, gtknew('ScrolledWindow', height => 300, child =>
+ # FIXME: using a listview would be just better:
+ gtknew('VBox', spacing => 5, children_tight => [
+ @buttons = map {
+ Gtk2::CheckButton->new_with_label($_->{name});
+ } @media
+ ])
+ ),
+ 0, Gtk2::HSeparator->new,
+ 0, gtkpack(
+ create_hbox(),
+ gtksignal_connect(
+ Gtk2::Button->new(N("Cancel")),
+ clicked => sub { $w->{retval} = 0; Gtk2->main_quit },
+ ),
+ gtksignal_connect(
+ Gtk2::Button->new(N("Select all")),
+ clicked => sub { $_->set_active(1) foreach @buttons },
+ ),
+ gtksignal_connect(
+ Gtk2::Button->new(N("Update")),
+ clicked => sub {
+ $w->{retval} = any { $_->get_active } @buttons;
+ # list of media listed in the checkbox panel
+ my @buttonmedia = grep { !$_->{ignore} } @{$urpm->{media}};
+ @media = map_index { if_($_->get_active, $buttonmedia[$::i]{name}) } @buttons;
+ Gtk2->main_quit;
+ },
+ ),
+ )
+ )
+ );
+ if ($w->main) {
+ return update_sources_noninteractive($urpm, \@media, %options);
+ }
+ return 0;
+}
+
+sub update_sources_noninteractive {
+ my ($urpm, $media, %options) = @_;
+
+ urpm::media::select_media($urpm, @$media);
+ update_sources_check(
+ $urpm,
+ {},
+ N_("Unable to update medium; it will be automatically disabled.\n\nErrors:\n%s"),
+ @$media,
+ );
+ return 1;
+}
+
+sub add_medium_and_check {
+ my ($urpm, $options) = splice @_, 0, 2;
+ my @newnames = ($_[0]); #- names of added media
+ my $fatal_msg;
+ my @error_msgs;
+ local $urpm->{fatal} = sub { printf STDERR "Fatal: %s\n", $_[1]; $fatal_msg = $_[1]; goto fatal_error };
+ local $urpm->{error} = sub { printf STDERR "Error: %s\n", $_[0]; push @error_msgs, $_[0] };
+ if ($options->{distrib}) {
+ @newnames = urpm::media::add_distrib_media($urpm, @_);
+ } else {
+ urpm::media::add_medium($urpm, @_);
+ }
+ if (@error_msgs) {
+ interactive_msg(
+ N("Error"),
+ N("Unable to add medium, errors reported:\n\n%s",
+ join("\n", map { formatAlaTeX($_) } @error_msgs)) . "\n\n" . N("Medium: ") . "$_[0] ($_[1])",
+ scroll => 1,
+ );
+ return 0;
+ }
+
+ foreach my $name (@newnames) {
+ urpm::download::set_proxy_config($_, $options->{proxy}{$_}, $name) foreach keys %{$options->{proxy} || {}};
+ }
+
+ if (update_sources_check($urpm, $options, N_("Unable to add medium, errors reported:\n\n%s"), @newnames)) {
+ urpm::media::write_config($urpm);
+ $options->{proxy} and urpm::download::dump_proxy_config();
+ } else {
+ urpm::media::read_config($urpm, 0);
+ return 0;
+ }
+
+ my %newnames; @newnames{@newnames} = ();
+ if (any { exists $newnames{$_->{name}} } @{$urpm->{media}}) {
+ return 1;
+ } else {
+ interactive_msg(N("Error"), N("Unable to create medium."));
+ return 0;
+ }
+
+ fatal_error:
+ interactive_msg(N("Failure when adding medium"),
+ N("There was a problem adding medium:\n\n%s", $fatal_msg));
+ return 0;
+}
+
+#- Check whether the default update media (added by installation)
+#- matches the current mdk version
+sub check_update_media_version {
+ my $urpm = shift;
+ foreach (@_) {
+ if ($_->{name} =~ /(\d+\.\d+).*\bftp\du\b/ && $1 ne $distro_version) {
+ interactive_msg(
+ N("Warning"),
+ $branded
+ ? N("Your medium `%s', used for updates, does not match the version of %s you're running (%s).
+It will be disabled.",
+ $_->{name}, $distrib{system}, $distrib{product})
+ : N("Your medium `%s', used for updates, does not match the version of Mageia you're running (%s).
+It will be disabled.",
+ $_->{name}, $distro_version)
+ );
+ $_->{ignore} = 1;
+ urpm::media::write_config($urpm) if -w $urpm->{config};
+ return 0;
+ }
+ }
+ 1;
+}
+
+sub add_distrib_update_media {
+ my ($urpm, $mirror, %options) = @_;
+ #- ensure a unique medium name
+ my $medium_name = $rpmdragora::mageia_release =~ /(\d+\.\d+) \((\w+)\)/ ? $2 . $1 . '-' : 'distrib';
+ my $initial_number = 1 + max map { $_->{name} =~ /\(\Q$medium_name\E(\d+)\b/ ? $1 : 0 } @{$urpm->{media}};
+ add_medium_and_check(
+ $urpm,
+ { nolock => 1, distrib => 1 },
+ $medium_name,
+ ($mirror ? $mirror->{url} : (undef, mirrorlist => '$MIRRORLIST')),
+ probe_with => 'synthesis', initial_number => $initial_number, %options,
+ usedistrib => 1,
+ );
+}
+
+sub open_help {
+ my ($mode) = @_;
+ use run_program;
+ run_program::raw({ detach => 1, as_user => 1 }, 'drakhelp', '--id', $mode ? "software-management-$mode" : 'software-management');
+ my $_s = N("Help launched in background");
+ statusbar_msg(N("The help window has been started, it should appear shortly on your desktop."), 1);
+}
+
+sub run_drakbug {
+ my ($id) = @_;
+ run_program::raw({ detach => 1, as_user => 1 }, 'drakbug', '--report', $id);
+}
+
+#mygtk2::add_icon_path('/usr/share/mcc/themes/default/');
+sub get_icon {
+ my ($mcc_icon, $fallback_icon) = @_;
+ my $icon = eval { mygtk2::_find_imgfile($mcc_icon) };
+ $icon ||= eval { mygtk2::_find_imgfile($fallback_icon) };
+ $icon;
+}
+
+sub strip_first_underscore { join '', map { s/_//; $_ } @_ }
+
+1;