[latexila] Create the build command runner



commit 789cf56d7af01a0810b32304463eca021eeda055
Author: SÃbastien Wilmet <swilmet src gnome org>
Date:   Mon Jul 9 20:06:54 2012 +0200

    Create the build command runner
    
    Initially, the build command runner (it was maybe another name, I don't
    recall exactly) was the parent class of the build tool runner. Then the
    two classes has been merged. And now instead of using inheritance,
    delegation is used.
    
    It is a first step to clean and refactor the build tool runner.

 src/build_command_runner.vala |  170 +++++++++++++++++++++++++++++++++++++++++
 src/build_tool_runner.vala    |  151 ++++---------------------------------
 2 files changed, 184 insertions(+), 137 deletions(-)
---
diff --git a/src/build_command_runner.vala b/src/build_command_runner.vala
new file mode 100644
index 0000000..e470a3f
--- /dev/null
+++ b/src/build_command_runner.vala
@@ -0,0 +1,170 @@
+/*
+ * This file is part of LaTeXila.
+ *
+ * Copyright  2010-2012 SÃbastien Wilmet
+ *
+ * LaTeXila is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LaTeXila 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 LaTeXila.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: SÃbastien Wilmet
+ */
+
+// Run a single command line.
+
+public class BuildCommandRunner : GLib.Object
+{
+    private string[] _command_args;
+    private string? _working_directory;
+
+    private Pid? _child_pid = null;
+    private uint _child_watch_handler = 0;
+    private IOChannel? _out_channel = null;
+
+    public signal void finished (int exit_status);
+
+    public BuildCommandRunner (string[] command_args, string? working_directory)
+    {
+        _command_args = command_args;
+        _working_directory = working_directory;
+    }
+
+    public void execute_with_output () throws Error
+    {
+        int std_out;
+
+        Process.spawn_async_with_pipes (
+            _working_directory,
+            _command_args,
+            null,
+            SpawnFlags.DO_NOT_REAP_CHILD | SpawnFlags.SEARCH_PATH,
+            redirect_stderr_to_stdout,
+            out _child_pid,
+            null,
+            out std_out
+        );
+
+        _child_watch_handler = ChildWatch.add (_child_pid, on_exit);
+
+        _out_channel = new IOChannel.unix_new (std_out);
+        _out_channel.set_encoding (null);
+    }
+
+    public void execute_without_output () throws Error
+    {
+        SpawnFlags flags =
+            SpawnFlags.DO_NOT_REAP_CHILD |
+            SpawnFlags.SEARCH_PATH |
+            SpawnFlags.STDOUT_TO_DEV_NULL |
+            SpawnFlags.STDERR_TO_DEV_NULL;
+
+        Process.spawn_async (_working_directory, _command_args, null, flags, null,
+            out _child_pid);
+
+        _child_watch_handler = ChildWatch.add (_child_pid, on_exit);
+    }
+
+    public void abort ()
+    {
+        if (_child_pid != null)
+        {
+            Posix.kill (_child_pid, Posix.SIGTERM);
+            _child_pid = null;
+        }
+    }
+
+    public string get_output ()
+    {
+        if (_out_channel == null)
+            return "";
+
+        /* Read the output */
+
+        string output = "";
+
+        try
+        {
+            _out_channel.read_to_end (out output, null);
+        }
+        catch (ConvertError e)
+        {
+            warning ("Read output: convert error: %s", e.message);
+        }
+        catch (IOChannelError e)
+        {
+            warning ("Read output: IO channel error: %s", e.message);
+        }
+
+        /* Close the channel */
+
+        try
+        {
+            _out_channel.shutdown (false);
+        }
+        catch (Error e) {}
+
+        _out_channel = null;
+
+        /* Return the result */
+
+        // Check if the output is a valid UTF-8 string
+        if (output.validate ())
+            return output;
+
+        return validate_output (output);
+    }
+
+    private void on_exit (Pid pid, int exit_status)
+    {
+        _child_watch_handler = 0;
+        _child_pid = null;
+
+        finished (exit_status);
+    }
+
+    private void redirect_stderr_to_stdout ()
+    {
+        Posix.dup2 (Posix.STDOUT_FILENO, Posix.STDERR_FILENO);
+    }
+
+    // Convert the output to UTF-8
+    private string validate_output (string output)
+    {
+        // Make the conversion into UTF-8 line by line, because if it is done to the all
+        // string at once, there are some encodings troubles with the "latex" and
+        // "pdflatex" commands (with accents in the filename for instance).
+
+        string new_output = "";
+        string[] lines = output.split ("\n");
+
+        foreach (string line in lines)
+        {
+            string? line_utf8 = line.locale_to_utf8 (-1, null, null);
+
+            if (line_utf8 == null)
+            {
+                try
+                {
+                    line_utf8 = convert (line, -1, "UTF-8", "ISO-8859-1");
+                }
+                catch (ConvertError e) {}
+            }
+
+            if (line_utf8 != null && line_utf8.validate ())
+                new_output += line_utf8 + "\n";
+            else
+                warning ("Read output failed: %s", line);
+        }
+
+        return new_output;
+    }
+}
diff --git a/src/build_tool_runner.vala b/src/build_tool_runner.vala
index 3ebf39f..acc4416 100644
--- a/src/build_tool_runner.vala
+++ b/src/build_tool_runner.vala
@@ -21,12 +21,7 @@ using Gtk;
 
 public class BuildToolRunner : GLib.Object
 {
-    private static const int POLL_INTERVAL = 250;
-    private Pid? child_pid = null;
-    private uint[] handlers = {};
-    private IOChannel out_channel;
-    private bool read_output = true;
-    private string output = "";
+    private BuildCommandRunner? _command_runner = null;
 
     private BuildView view;
     private bool latexmk_show_all;
@@ -124,69 +119,11 @@ public class BuildToolRunner : GLib.Object
         return true;
     }
 
-    private void execute (string[] command, string? working_directory) throws Error
-    {
-//        stdout.printf ("command arguments:\n");
-//        foreach (string arg in command)
-//            stdout.printf ("%s\n", arg);
-//        stdout.printf ("\n");
-
-        try
-        {
-            int std_out;
-
-            Process.spawn_async_with_pipes (working_directory, command, null,
-                SpawnFlags.DO_NOT_REAP_CHILD | SpawnFlags.SEARCH_PATH,
-
-                // redirect stderr into stdout
-                () => { Posix.dup2 (Posix.STDOUT_FILENO, Posix.STDERR_FILENO); },
-
-                out child_pid, null, out std_out);
-
-            // we want to know the exit code
-            handlers += ChildWatch.add (child_pid, on_exit);
-
-            out_channel = new IOChannel.unix_new (std_out);
-            out_channel.set_flags (IOFlags.NONBLOCK);
-            out_channel.set_encoding (null);
-
-            handlers += Timeout.add (POLL_INTERVAL, on_output);
-        }
-        catch (Error e)
-        {
-            throw e;
-        }
-    }
-
-    private void execute_without_output (string[] command, string? working_directory)
-        throws Error
-    {
-        read_output = false;
-
-        try
-        {
-            Process.spawn_async (working_directory, command, null,
-                SpawnFlags.DO_NOT_REAP_CHILD | SpawnFlags.SEARCH_PATH, null,
-                out child_pid);
-
-            // we want to know the exit code
-            handlers += ChildWatch.add (child_pid, on_exit);
-        }
-        catch (Error e)
-        {
-            throw e;
-        }
-    }
-
     /* Abort the running process */
     public void abort ()
     {
-        if (child_pid == null)
-            return;
-
-        foreach (uint handler in handlers)
-            Source.remove (handler);
-        Posix.kill (child_pid, Posix.SIGTERM);
+        if (_command_runner != null)
+            _command_runner.abort ();
 
         action_stop_exec.set_sensitive (false);
         view.set_partition_state (root_partition, PartitionState.ABORTED);
@@ -194,72 +131,11 @@ public class BuildToolRunner : GLib.Object
             view.set_partition_state (job_partitions[i], PartitionState.ABORTED);
     }
 
-    private bool on_output ()
+    private void on_command_finished (int exit_status)
     {
-        return_val_if_fail (read_output, false);
+        return_if_fail (_command_runner != null);
 
-        string? text = null;
-        size_t length;
-
-        try
-        {
-            out_channel.read_to_end (out text, out length);
-        }
-        catch (ConvertError e)
-        {
-            warning ("Read output: convert error: %s", e.message);
-        }
-        catch (IOChannelError e)
-        {
-            warning ("Read output: IO channel error: %s", e.message);
-        }
-
-        if (length <= 0)
-            return true;
-
-        // check if the output is a valid UTF-8 string
-        if (text.validate ())
-        {
-            output += text;
-            return true;
-        }
-
-        // make the conversion into UTF-8 line by line, because if it is done to the all
-        // string at once, there are some encodings troubles with the "latex" and
-        // "pdflatex" commands (with accents in the filename for instance).
-        string[] lines = text.split ("\n");
-        foreach (string line in lines)
-        {
-            string? line_utf8 = line.locale_to_utf8 (-1, null, null);
-
-            if (line_utf8 == null)
-            {
-                try
-                {
-                    line_utf8 = convert (line, -1, "UTF-8", "ISO-8859-1");
-                }
-                catch (ConvertError e) {}
-            }
-
-            if (line_utf8 != null && line_utf8.validate ())
-                output += line_utf8 + "\n";
-            else
-                warning ("Read output failed: %s", line);
-        }
-
-        return true;
-    }
-
-    private void on_exit (Pid pid, int status)
-    {
-        foreach (uint handler in handlers)
-            Source.remove (handler);
-
-        // read remaining output
-        if (read_output)
-            on_output ();
-
-        // create post processor
+        // Create post processor
         PostProcessor post_processor;
         switch (current_job.post_processor)
         {
@@ -284,8 +160,8 @@ public class BuildToolRunner : GLib.Object
                 break;
         }
 
-        post_processor.set_status (status);
-        post_processor.process (file, output);
+        post_processor.set_status (exit_status);
+        post_processor.process (file, _command_runner.get_output ());
 
         view.append_messages (job_partitions[job_num], post_processor.get_messages ());
 
@@ -313,9 +189,6 @@ public class BuildToolRunner : GLib.Object
             return;
         }
 
-        // reset output because it's the same variable for all jobs
-        output = "";
-
         current_job = jobs[job_num];
         string[] command;
 
@@ -346,12 +219,14 @@ public class BuildToolRunner : GLib.Object
             view.append_single_message (job_partitions[job_num], message);
         }
 
+        _command_runner = new BuildCommandRunner (command, directory);
+
         try
         {
             if (current_job.post_processor == PostProcessorType.NO_OUTPUT)
-                execute_without_output (command, directory);
+                _command_runner.execute_without_output ();
             else
-                execute (command, directory);
+                _command_runner.execute_with_output ();
         }
         catch (Error e)
         {
@@ -377,6 +252,8 @@ public class BuildToolRunner : GLib.Object
 
             failed ();
         }
+
+        _command_runner.finished.connect (on_command_finished);
     }
 
     private string[] get_command_args (string command_line, bool for_printing = false)



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]