From cb2cf96a6a5e16af940a5b420fea6a760aff568c Mon Sep 17 00:00:00 2001 From: Angelo Naselli Date: Mon, 1 Dec 2014 22:34:58 +0100 Subject: Added rpmnew management --- MANIFEST | 1 + Makefile.PL | 1 + lib/AdminPanel/Rpmdragora/pkg.pm | 8 +- lib/AdminPanel/Rpmdragora/rpmnew.pm | 383 +++++++++++++++++++++++++----------- modules/rpmdragora/dragoraUpdate | 2 +- t/05-rpmnew.t | 36 ++++ 6 files changed, 308 insertions(+), 123 deletions(-) create mode 100644 t/05-rpmnew.t diff --git a/MANIFEST b/MANIFEST index 0759328..05ed13e 100644 --- a/MANIFEST +++ b/MANIFEST @@ -113,6 +113,7 @@ t/02-JournalCtl.t t/02-Users.t t/03-Shared_GUI.t t/04-Shared_TimeZone.t +t/05-rpmnew.t t/boilerplate.t t/manifest.t t/pod-coverage.t diff --git a/Makefile.PL b/Makefile.PL index 6bf52b8..a769022 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -31,6 +31,7 @@ WriteMakefile( # AdminPanel::Shared::Locales "Locale::gettext" => 0, "Text::Iconv" => 0, + "Text::Diff" => 0, "Date::Simple" => 0, "DateTime::TimeZone" => 0, "Time::Piece" => 0, diff --git a/lib/AdminPanel/Rpmdragora/pkg.pm b/lib/AdminPanel/Rpmdragora/pkg.pm index 5ad95f6..9823fb6 100644 --- a/lib/AdminPanel/Rpmdragora/pkg.pm +++ b/lib/AdminPanel/Rpmdragora/pkg.pm @@ -897,12 +897,12 @@ sub perform_installation { #- (partially) duplicated from /usr/sbin/urpmi :-( my $id = statusbar_msg($loc->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 ]; + 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($loc->N("The installation is finished; everything was installed correctly. + rpmnew_dialog($loc->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:"), diff --git a/lib/AdminPanel/Rpmdragora/rpmnew.pm b/lib/AdminPanel/Rpmdragora/rpmnew.pm index 5d86638..6ce912b 100644 --- a/lib/AdminPanel/Rpmdragora/rpmnew.pm +++ b/lib/AdminPanel/Rpmdragora/rpmnew.pm @@ -25,16 +25,21 @@ package AdminPanel::Rpmdragora::rpmnew; # $Id: rpmnew.pm 263914 2009-12-03 17:41:02Z tv $ use strict; -use lib qw(/usr/lib/libDrakX); -use common; +use Text::Diff; +use MDK::Common::Math; +use MDK::Common::File; + use AdminPanel::rpmdragora; use AdminPanel::Rpmdragora::init; use AdminPanel::Rpmdragora::pkg; use AdminPanel::Rpmdragora::open_db; use AdminPanel::Rpmdragora::formatting; + +use yui; + use Exporter; our @ISA = qw(Exporter); -our @EXPORT = qw(dialog_rpmnew do_merge_if_needed); +our @EXPORT = qw(rpmnew_dialog do_merge_if_needed); my $loc = AdminPanel::rpmdragora::locale(); @@ -66,126 +71,267 @@ my %ignores_rpmnew = map { $_ => 1 } qw( /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 = $loc->N("(none)") if !@diff; - my $d = ugtk2->new($loc->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($file:)), - 1, gtknew('ScrolledWindow', child => $texts{file} = Gtk2::SourceView2::View->new), - ), - gtkpack_( - gtknew('VBox'), - 0, gtknew('Label', text_markup => qq($rpmnew:)), - 1, gtknew('ScrolledWindow', child => $texts{rpmnew} = Gtk2::SourceView2::View->new), - ), - resize1 => 1, - ), - gtkpack_( - gtknew('VBox'), - 0, gtknew('Label', text => $loc->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 => $loc->N("You can either remove the .%s file, use it as main file or do nothing. If unsure, keep the current file (\"%s\").", - $rpmfile, $loc->N("Remove .%s", $rpmfile)), - ), - 0, gtkpack__( - gtknew('HButtonBox'), - gtksignal_connect( - gtknew('Button', text => $loc->N("Remove .%s", $rpmfile)), - clicked => sub { $save_wsize->(); unlink $rpmnew; Gtk2->main_quit }, - ), - gtksignal_connect( - gtknew('Button', text => $loc->N("Use .%s as main file", $rpmfile)), - clicked => sub { $save_wsize->(); renamef($rpmnew, $file); Gtk2->main_quit }, - ), - gtksignal_connect( - gtknew('Button', text => $loc->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; + +#============================================================= + +=head2 _rpmnewFile + +=head3 INPUT + + $filename: configuration file name + +=head3 OUTPUT + + $rpmnew_filename: new configuration file name + +=head3 DESCRIPTION + + This function evaluate the new configration file generated by + the update + +=cut + +#============================================================= +sub _rpmnewFile ($) { + my $filename = shift; + + my ($rpmnew, $rpmsave) = ("$filename.rpmnew", "$filename.rpmsave"); + 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; + + return $rpmnew; } -sub dialog_rpmnew { +#============================================================= + +=head2 _performDiff + +=head3 INPUT + + $file: configuration file name + $diffBox: YWidget that will show the difference + +=head3 DESCRIPTION + + This function gets the configuration file perfomrs + the difference with the new one and shows it into the + $diffBox + +=cut + +#============================================================= +sub _performDiff ($$) { + my ($file, $diffBox) = @_; + + my $rpmnew = _rpmnewFile($file); + + 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 = diff $file, $rpmnew, { STYLE => "Unified" }; + ensure_utf8($diff); + $diff = $loc->N("(none)") if !$diff; + $diff =~ s/\n/
/g; + + $diffBox->setValue($diff); + + return; +} + +#============================================================= + +=head2 rpmnew_dialog + +=head3 INPUT + + $msg: message to be shown during the choice + %o2r: HASH containing { + the package name => ARRAY of configration files + } + +=head3 OUTPUT + + 1 if nothing to do or 0 after user interaction + +=head3 DESCRIPTION + + This function shows the configuration files difference and + asks for action to be performed + +=cut + +#============================================================= +sub rpmnew_dialog { my ($msg, %p2r) = @_; + @{$p2r{$_}} = grep { !$ignores_rpmnew{$_} } @{$p2r{$_}} foreach keys %p2r; - my $sum_rpmnew = sum(map { int @{$p2r{$_}} } keys %p2r); + my $sum_rpmnew = MDK::Common::Math::sum(map { int @{$p2r{$_}} } keys %p2r); $sum_rpmnew == 0 and return 1; - interactive_packtable( - $loc->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:$f), - ) - ), - gtksignal_connect( - $b = gtknew('Button', text => $loc->N("Inspect...")), - clicked => sub { - inspect($f); - -r "$f.rpmnew" || -r "$f.rpmsave" or $b->set_sensitive(0); - }, - ) ]; - } @{$p2r{$pkg}}; - } keys %p2r ], - [ gtknew('Button', text => $loc->N("Ok"), - clicked => sub { Gtk2->main_quit }) ] - ); + + + ########################################################### + my $appTitle = yui::YUI::app()->applicationTitle(); + + ## set new title to get it in dialog + yui::YUI::app()->setApplicationTitle($loc->N("Installation finished")); + + my $factory = yui::YUI::widgetFactory; + + ## | [msg-label] | + ## | | + ## | pkg-tree | + ## | | + ## | info on selected pkg |(1) + ## | Remove( ) Use ( ) Do nothing (*) | + ## | | + ## | [cancel] [ok] | + #### + # (1) info on pkg list: + # selected configuration file diff between rpmnew/rpmsave and used one + + my $dialog = $factory->createPopupDialog; + my $vbox = $factory->createVBox( $dialog ); + my $msgBox = $factory->createLabel($vbox, $msg, 1); + $factory->createVSpacing($vbox, 1); + # Tree for groups + my $tree = $factory->createTree($vbox, ""); + $tree->setWeight($yui::YD_VERT,10); + $factory->createVSpacing($vbox, 1); + my $infoBox = $factory->createRichText($vbox, "", 0); + $infoBox->setWeight($yui::YD_HORIZ, 20); + $infoBox->setWeight($yui::YD_VERT, 20); + $factory->createVSpacing($vbox, 1); + my $radiobuttongroup = $factory->createRadioButtonGroup($vbox); + my $rbbox = $factory->createHBox($radiobuttongroup); + my $rdnBtn = { + remove_rpmnew => $loc->N("Remove new file"), + use_rpmnew => $loc->N("Use new file"), + do_onthing => $loc->N("Do nothing"), + }; +# my %byActionRdnBtn = reverse %{$rdnBtn}; + my %radiobutton = (); + my @rdnbtn_order = ('remove_rpmnew', 'use_rpmnew', 'do_onthing'); + foreach my $btn_name (@rdnbtn_order) { + $radiobutton{$btn_name} = $factory->createRadioButton($rbbox, $rdnBtn->{$btn_name}); + $radiobutton{$btn_name}->setNotify(1); + $radiobuttongroup->addRadioButton($radiobutton{$btn_name}); + } + $radiobuttongroup->setEnabled(0); + my $hbox = $factory->createHBox( $vbox ); + my $align = $factory->createRight($hbox); + my $okButton = $factory->createPushButton($hbox, $loc->N("Ok")); + + # adding packages to the list + my $itemColl = new yui::YItemCollection; + + my $num = 0; + my %file_action = (); + foreach my $p (keys %p2r) { + my $item = new yui::YTreeItem ("$p", ($num==0)); + foreach my $f (@{$p2r{$p}}) { + my $child = new yui::YTreeItem ($item, "$f"); + $child->DISOWN(); + $file_action{$f} = 'do_onthing'; + if ($num == 0) { + $child->setSelected(1); + $num = 1; + } + } + $itemColl->push($item); + $item->DISOWN(); + } + + $tree->addItems($itemColl); + $tree->setImmediateMode(1); + $tree->rebuildTree(); + + # show first diff occurence + my $filename = $tree->currentItem()->label(); + _performDiff($filename, $infoBox); + $radiobuttongroup->setEnabled(1); + yui::YUI::ui()->blockEvents(); + $radiobutton{$file_action{$filename}}->setValue(1); + yui::YUI::ui()->unblockEvents(); + + while(1) { + my $event = $dialog->waitForEvent(); + my $eventType = $event->eventType(); + + #event type checking + if ($eventType == $yui::YEvent::CancelEvent) { + last; + } + elsif ($eventType == $yui::YEvent::WidgetEvent) { + ### widget + my $widget = $event->widget(); + if ($widget == $tree) { + #change info + my $item = $tree->selectedItem(); + if ($item && !$item->hasChildren()) { + $filename = $tree->currentItem()->label(); + _performDiff($filename, $infoBox); + $radiobuttongroup->setEnabled(1); + #$radiobuttongroup->uncheckOtherButtons ($radiobutton{$file_action{$filename}}); + yui::YUI::ui()->blockEvents(); + $radiobutton{$file_action{$filename}}->setValue(1); + yui::YUI::ui()->unblockEvents(); + } + else { + $infoBox->setValue(""); + $radiobuttongroup->setEnabled(0); + } + } + elsif ($widget == $okButton) { + # TODO + foreach my $file (keys %file_action) { + my $rpmnew = _rpmnewFile($file); + if ($file_action{$file} eq 'remove_rpmnew') { + eval { unlink "$rpmnew"}; + } + elsif ($file_action{$file} eq 'use_rpmnew') { + MDK::Common::File::renamef($rpmnew, $file); + } + # else do_onthing + } + last; + } + else { + # radio buttons + RDNBTN: foreach my $btn_name (@rdnbtn_order) { + if ($widget == $radiobutton{$btn_name}) { + $filename = $tree->currentItem()->label(); + $file_action{$filename} = $btn_name; + last RDNBTN; + } + } + } + } + } + + destroy $dialog; + + # restore original title + yui::YUI::app()->setApplicationTitle($appTitle) if $appTitle; + return 0; } +#============================================================= + +=head2 do_merge_if_needed + +=head3 DESCRIPTION + + This function look for new configuration file versions + and ask for actions using the rpmnew_dialog + +=cut + +#============================================================= sub do_merge_if_needed() { if ($rpmdragora_options{'merge-all-rpmnew'}) { my %pkg2rpmnew; @@ -197,11 +343,12 @@ sub do_merge_if_needed() { $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); + remove_wait_msg($wait); + + rpmnew_dialog('', %pkg2rpmnew) and print "Nothing to do.\n"; } + + return; } 1; diff --git a/modules/rpmdragora/dragoraUpdate b/modules/rpmdragora/dragoraUpdate index e505be7..5758cd8 100755 --- a/modules/rpmdragora/dragoraUpdate +++ b/modules/rpmdragora/dragoraUpdate @@ -364,7 +364,7 @@ sub run_treeview_dialog { } # -=-=-=---=-=-=---=-=-=-- main -=-=-=---=-=-=---=-=-=- -# ---- do_merge_if_needed(); +AdminPanel::Rpmdragora::rpmnew::do_merge_if_needed(); AdminPanel::rpmdragora::readconf(); diff --git a/t/05-rpmnew.t b/t/05-rpmnew.t new file mode 100644 index 0000000..cc1021f --- /dev/null +++ b/t/05-rpmnew.t @@ -0,0 +1,36 @@ +use 5.006; +use strict; +use warnings FATAL => 'all'; +use Test::More; + +BEGIN { + use_ok( 'AdminPanel::Rpmdragora::rpmnew' ) || print "AdminPanel::Rpmdragora::rpmnew failed!\n"; +} + + diag "\n\nNext tests will create some gui dialogs"; + diag "Perform tests (y/n) [n] ?"; + + my $a = <>; chomp $a; $a = "n" unless $a; + + SKIP: { + #remember to skip the righ number of tests + skip "You didn't say yes...", 1, unless ( $a eq "y" ); + + open (MYFILE, '>/tmp/_rpmnew_test'); + print MYFILE "value = 1\n"; + print MYFILE "value1 = 2\n"; + close (MYFILE); + open (MYFILE, '>/tmp/_rpmnew_test.rpmnew'); + print MYFILE "value = 2\n"; + print MYFILE "value1 = 1\n"; + close (MYFILE); + + is( AdminPanel::Rpmdragora::rpmnew::rpmnew_dialog("Test rpmnew dialog", ( + test_package => ["/tmp/_rpmnew_test", "/tmp/rpmnew_test"], + test_package2 => ["/tmp/tp2"], + )), 0, 'rpmnew'); + + } + + +done_testing; -- cgit v1.2.1