# # # patch "lib/perl/Annotate.pm" # from [9a778d09c5f605b1795e81b05eb21f8feb4b1fb0] # to [91b47ddd78719db24155c0802848e2d1d63e3838] # # patch "lib/perl/Common.pm" # from [d6df7409384166de94c655c2a24103ebdd33d4e2] # to [57dd6913d5e258aff37e2bb9601aa81e0572e950] # # patch "lib/perl/History.pm" # from [7b9c9357c231510a04bb673b076cfbffc4fbb7a0] # to [8b821d263a1376c0b81ca75e31651494f4eb3fd4] # # patch "lib/ui/mtn-browse.glade" # from [fba49e593b91f655d1edcbe681f8bdfe406cff19] # to [969d7bc6d90ed297737fa7c5fbf027a3c5200b34] # ============================================================ --- lib/perl/Annotate.pm 9a778d09c5f605b1795e81b05eb21f8feb4b1fb0 +++ lib/perl/Annotate.pm 91b47ddd78719db24155c0802848e2d1d63e3838 @@ -810,7 +810,8 @@ sub mtn_annotate($$$$) my($buffer, @cmd, $cwd, - $exception); + $exception, + $ret_val); # Run mtn annotate in the root directory so as to avoid any workspace # conflicts. @@ -826,7 +827,7 @@ sub mtn_annotate($$$$) eval { die("chdir failed: " . $!) unless (chdir(File::Spec->rootdir())); - return unless (run_command(\$buffer, @cmd)); + $ret_val = run_command(\$buffer, undef, @cmd); }; $exception = $@; chdir($cwd); @@ -850,7 +851,7 @@ sub mtn_annotate($$$$) @$list = split(/\n/, $buffer); - return 1; + return $ret_val; } ============================================================ --- lib/perl/Common.pm d6df7409384166de94c655c2a24103ebdd33d4e2 +++ lib/perl/Common.pm 57dd6913d5e258aff37e2bb9601aa81e0572e950 @@ -89,7 +89,7 @@ sub register_help_callbacks($@); sub open_database($$$); sub program_valid($;$); sub register_help_callbacks($@); -sub run_command($@); +sub run_command($$@); sub save_as_file($$$); sub set_label_value($$); sub treeview_column_searcher($$$$); @@ -154,6 +154,9 @@ sub generate_tmp_path($) # # Data - $buffer : A reference to the buffer that is to contain # the output from the command. +# $abort : Either a reference to a boolean that is set +# to true if the command is to be aborted or +# undef if no abort checking is required. # $args : A list containing the command to run and its # arguments. # Return Value : True if the command worked, otherwise false @@ -163,12 +166,13 @@ sub generate_tmp_path($) -sub run_command($@) +sub run_command($$@) { - my($buffer, @args) = @_; + my($buffer, $abort, @args) = @_; - my(@err, + my($dummy_flag, + @err, $fd_err, $fd_in, $fd_out, @@ -178,6 +182,8 @@ sub run_command($@) $total_bytes, $watcher); + $abort = \$dummy_flag unless (defined($abort)); + # Run the command. $fd_err = gensym(); @@ -225,7 +231,7 @@ sub run_command($@) # Setup a watch handler to read our data and handle GTK2 events whilst the # command is running. - $stop = $total_bytes = 0; + $total_bytes = 0; $$buffer = ""; $watcher = Gtk2::Helper->add_watch (fileno($fd_out), "in", @@ -235,7 +241,8 @@ sub run_command($@) $$buffer, 32768, $total_bytes)) - == 0) + == 0 + || ! defined($bytes_read)) { $stop = 1; } @@ -245,15 +252,23 @@ sub run_command($@) } return TRUE; }); - while (! $stop) + while (! $stop && ! $$abort) { Gtk2->main_iteration(); } Gtk2::Helper->remove_watch($watcher); - # Get any error output. + # If we have been asked to abort then terminate the subprocess, otherwise + # get any error output as the subprocess has just exited of its own accord. - @err = readline($fd_err); + if ($$abort) + { + kill("TERM", $pid); + } + else + { + @err = readline($fd_err) unless ($$abort); + } close($fd_in); close($fd_out); @@ -288,43 +303,47 @@ sub run_command($@) if ($wait_status == $pid) { - my $exit_status = $?; - if (WIFEXITED($exit_status) && WEXITSTATUS($exit_status) != 0) + if (! $$abort) { - my $dialog = Gtk2::MessageDialog->new_with_markup - (undef, - ["modal"], - "warning", - "close", - __x("The {name} subprocess failed with an exit status\n" - . "of {exit_code} and printed the following on " - . "stderr:\n" - . "{error_message}", - name => Glib::Markup::escape_text($args[0]), - exit_code => WEXITSTATUS($exit_status), - error_message => Glib::Markup::escape_text - (join("", @err)))); - WindowManager->instance()->allow_input - (sub { $dialog->run(); }); - $dialog->destroy(); - return; + my $exit_status = $?; + if (WIFEXITED($exit_status) && WEXITSTATUS($exit_status) != 0) + { + my $dialog = Gtk2::MessageDialog->new_with_markup + (undef, + ["modal"], + "warning", + "close", + __x("The {name} subprocess failed with an exit " + . "status\n" + . "of {exit_code} and printed the following " + . "on stderr:\n" + . "{error_message}", + name => Glib::Markup::escape_text($args[0]), + exit_code => WEXITSTATUS($exit_status), + error_message => Glib::Markup::escape_text + (join("", @err)))); + WindowManager->instance()->allow_input + (sub { $dialog->run(); }); + $dialog->destroy(); + return; + } + elsif (WIFSIGNALED($exit_status)) + { + my $dialog = Gtk2::MessageDialog->new + (undef, + ["modal"], + "warning", + "close", + __x("The {name} subprocess was terminated by signal " + . "{number}.", + name => Glib::Markup::escape_text($args[0]), + number => WTERMSIG($exit_status))); + WindowManager->instance()->allow_input + (sub { $dialog->run(); }); + $dialog->destroy(); + return; + } } - elsif (WIFSIGNALED($exit_status)) - { - my $dialog = Gtk2::MessageDialog->new - (undef, - ["modal"], - "warning", - "close", - __x("The {name} subprocess was terminated by signal " - . "{number}.", - name => Glib::Markup::escape_text($args[0]), - number => WTERMSIG($exit_status))); - WindowManager->instance()->allow_input - (sub { $dialog->run(); }); - $dialog->destroy(); - return; - } last; } ============================================================ --- lib/perl/History.pm 7b9c9357c231510a04bb673b076cfbffc4fbb7a0 +++ lib/perl/History.pm 8b821d263a1376c0b81ca75e31651494f4eb3fd4 @@ -94,10 +94,10 @@ sub get_history_window(); sub file_comparison_combobox_changed_cb($$); sub get_file_history_helper($$$); sub get_history_window(); -sub get_revision_comparison_window(); +sub get_revision_comparison_window($); sub get_revision_history_helper($$); sub history_list_button_clicked_cb($$); -sub mtn_diff($$$$;$); +sub mtn_diff($$$$$;$); sub save_differences_button_clicked_cb($$); # ############################################################################## @@ -538,7 +538,7 @@ sub display_revision_comparison($$$;$) $iter); my $wm = WindowManager->instance(); - $instance = get_revision_comparison_window(); + $instance = get_revision_comparison_window($mtn); local $instance->{in_cb} = 1; $instance->{window}-> @@ -560,37 +560,77 @@ sub display_revision_comparison($$$;$) $wm->make_busy($instance, 1); $instance->{appbar}->push($instance->{appbar}->get_status()->get_text()); + $instance->{stop_button}->set_sensitive(TRUE); $wm->update_gui(); $instance->{mtn} = $mtn; $instance->{revision_id_1} = $revision_id_1; $instance->{revision_id_2} = $revision_id_2; - # Get Monotone to do the comparison. + # Get Monotone to do the comparison, later versions can do this via + # automate stdio. $instance->{appbar}->set_status(__("Calculating differences")); $wm->update_gui(); if ($mtn->supports(MTN_CONTENT_DIFF_EXTRA_OPTIONS)) { + + my $exception; + + local $instance->{kill_mtn_subprocess} = 1; + + # The stop button callback will kill off the mtn subprocess so suppress + # any resultant errors. + $mtn->suppress_utf8_conversion(1); - $mtn->content_diff($instance->{diff_output}, - ["with-header"], - $revision_id_1, - $revision_id_2, - $file_name); + CachingAutomateStdio->register_error_handler + (MTN_SEVERITY_ALL, + sub { + my($severity, $message, $instance) = @_; + mtn_error_handler($severity, $message) + if ($severity == MTN_SEVERITY_WARNING + || ! $instance->{stop}); + }, + $instance); + eval + { + $mtn->content_diff($instance->{diff_output}, + ["with-header"], + $revision_id_1, + $revision_id_2, + $file_name); + }; + $exception = $@; + CachingAutomateStdio->register_error_handler(MTN_SEVERITY_ALL, + \&mtn_error_handler); $mtn->suppress_utf8_conversion(0); + + # If we have aborted the comparison by killing off the mtn subprocess + # then cleanly closedown and restart it, otherwise rethrow any raised + # exceptions. + + if ($instance->{stop}) + { + my $dummy; + $mtn->closedown(); + $mtn->interface_version(\$dummy); + } + elsif ($exception) + { + die($exception); + } + } else { mtn_diff($instance->{diff_output}, + \$instance->{stop}, $mtn->get_db_name(), $revision_id_1, $revision_id_2, $file_name); } - $instance->{stop_button}->set_sensitive(TRUE); - # Does the user want pretty printed differences output? if ($user_preferences->{coloured_diffs}) @@ -1751,16 +1791,20 @@ sub get_revision_history_helper($$) # Description - Creates or prepares an existing revision comparison window # for use. # -# Data - Return Value : A reference to the newly created or unused +# Data - $mtn : The Monotone::AutomateStdio object that is +# to be used to do the comparison. +# Return Value : A reference to the newly created or unused # change log instance record. # ############################################################################## -sub get_revision_comparison_window() +sub get_revision_comparison_window($) { + my $mtn = $_[0]; + my($height, $instance, $renderer, @@ -1821,8 +1865,24 @@ sub get_revision_comparison_window() return TRUE; }, $instance); - $instance->{stop_button}->signal_connect - ("clicked", sub { $_[1]->{stop} = 1; }, $instance); + if ($mtn->supports(MTN_CONTENT_DIFF_EXTRA_OPTIONS)) + { + $instance->{kill_mtn_subprocess} = 0; + $instance->{stop_button}->signal_connect + ("clicked", + sub { + my($widget, $instance) = @_; + $instance->{stop} = 1; + kill("TERM", $instance->{mtn}->get_pid()) + if ($instance->{kill_mtn_subprocess}); + }, + $instance); + } + else + { + $instance->{stop_button}->signal_connect + ("clicked", sub { $_[1]->{stop} = 1; }, $instance); + } # Setup the file combobox. @@ -2045,6 +2105,9 @@ sub external_diffs($$$$$$) # # Data - $list : A reference to the list that is to contain # the output from the diff command. +# $abort : A reference to an abort flag that when +# true will cause the mtn diff process to +# stop. # $mtn_db : The Monotone database that is to be used # or undef if the database associated with # the current workspace is to be used. @@ -2063,15 +2126,21 @@ sub external_diffs($$$$$$) -sub mtn_diff($$$$;$) +sub mtn_diff($$$$$;$) { - my($list, $mtn_db, $revision_id_1, $revision_id_2, $file_name) = @_; + my($list, + $abort, + $mtn_db, + $revision_id_1, + $revision_id_2, + $file_name) = @_; my($buffer, @cmd, $cwd, - $exception); + $exception, + $ret_val); # Run mtn diff in the root directory so as to avoid any workspace # conflicts. @@ -2089,32 +2158,40 @@ sub mtn_diff($$$$;$) eval { die("chdir failed: " . $!) unless (chdir(File::Spec->rootdir())); - return unless (run_command(\$buffer, @cmd)); + $ret_val = run_command(\$buffer, $abort, @cmd); }; $exception = $@; chdir($cwd); - if ($exception) + if (! $$abort) { - my $dialog = Gtk2::MessageDialog->new_with_markup - (undef, - ["modal"], - "warning", - "close", - __x("Problem running mtn diff, got:\n" - . "{error_message}\n" - . "This should not be happening!", - error_message => Glib::Markup::escape_text($exception))); - WindowManager->instance()->allow_input(sub { $dialog->run(); }); - $dialog->destroy(); - return; - } + if ($exception) + { + my $dialog = Gtk2::MessageDialog->new_with_markup + (undef, + ["modal"], + "warning", + "close", + __x("Problem running mtn diff, got:\n" + . "{error_message}\n" + . "This should not be happening!", + error_message => Glib::Markup::escape_text($exception))); + WindowManager->instance()->allow_input(sub { $dialog->run(); }); + $dialog->destroy(); + return; + } - # Break up the input into a list of lines. + # Break up the input into a list of lines. - @$list = split(/\n/, $buffer); + @$list = split(/\n/, $buffer); - return 1; + } + else + { + @$list = (); + } + return $ret_val; + } 1; ============================================================ --- lib/ui/mtn-browse.glade fba49e593b91f655d1edcbe681f8bdfe406cff19 +++ lib/ui/mtn-browse.glade 969d7bc6d90ed297737fa7c5fbf027a3c5200b34 @@ -3690,8 +3690,8 @@ Tag True - Revision id of the first selected -file version that is to be compared + The first of two revision ids +selected for comparison True False @@ -3724,8 +3724,8 @@ file version that is to be compared True - Revision id of the second selected -file version that is to be compared + The second of two revision +ids selected for comparison True False @@ -4038,7 +4038,7 @@ selected file in an external viewer True False - Stop formatting the comparison results + Stop the comparison True GTK_RELIEF_NONE False