[kupfer] utils: Add AsyncCommand
- From: Ulrik Sverdrup <usverdrup src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [kupfer] utils: Add AsyncCommand
- Date: Tue, 4 May 2010 22:18:48 +0000 (UTC)
commit 911f158d26ec7dc630eee901dc5e9d4d5bd1b821
Author: Ulrik Sverdrup <ulrik sverdrup gmail com>
Date: Wed May 5 00:17:24 2010 +0200
utils: Add AsyncCommand
Add a loosely tested facility for asynchronous external commands where
we gather the output.
kupfer/utils.py | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 62 insertions(+), 0 deletions(-)
---
diff --git a/kupfer/utils.py b/kupfer/utils.py
index 634d02b..6ca51d9 100644
--- a/kupfer/utils.py
+++ b/kupfer/utils.py
@@ -4,6 +4,8 @@ from os import path as os_path
import locale
import gobject
+import glib
+
from kupfer import pretty
from kupfer import kupferstring
@@ -68,6 +70,66 @@ def locale_sort(seq, key=unicode):
seq.sort(cmp=locale_cmp)
return seq
+
+class AsyncCommand (object):
+ # the maximum input (bytes) we'll read in one shot (one io_callback)
+ max_input_buf = 512 * 1024
+ """
+ Run a command asynchronously (using the GLib mainloop)
+
+ call @finish_callback when command terminates, or
+ when command is killed after @timeout_s seconds, whichever
+ comes first.
+
+ finish_callback -> (AsyncCommand, stdout_output)
+ """
+
+ def __init__(self, argv, finish_callback, timeout_s):
+ self.stdout = []
+ self.timeout = False
+ self.killed = False
+ self.finished = False
+ self.finish_callback = finish_callback
+ flags = (glib.SPAWN_SEARCH_PATH | glib.SPAWN_STDERR_TO_DEV_NULL |
+ glib.SPAWN_DO_NOT_REAP_CHILD)
+ pid, stdin_fd, stdout_fd, stderr_fd = \
+ glib.spawn_async(argv, standard_output=True, standard_input=True,
+ child_setup=self.child_setup, flags=flags)
+ os.close(stdin_fd)
+ glib.io_add_watch(stdout_fd, glib.IO_IN | glib.IO_ERR |
+ glib.IO_HUP | glib.IO_NVAL,
+ self.io_callback)
+ self.pid = pid
+ glib.child_watch_add(pid, self.child_callback)
+ glib.timeout_add_seconds(timeout_s, self.timeout_callback)
+
+ def child_setup(self):
+ pass
+
+ def io_callback(self, sourcefd, condition):
+ if condition & glib.IO_IN:
+ self.stdout.append(os.read(sourcefd, self.max_input_buf))
+ return True
+ return False
+
+ def child_callback(self, pid, condition):
+ self.finished = True
+ self.finish_callback(self, "".join(self.stdout))
+
+ def timeout_callback(self):
+ "send term signal on timeout"
+ if not self.finished:
+ self.timeout = True
+ os.kill(self.pid, 15)
+ glib.timeout_add_seconds(2, self.kill_callback)
+
+ def kill_callback(self):
+ "Last resort, send kill signal"
+ if not self.finished:
+ self.killed = True
+ os.kill(self.pid, signal.SIGKILL)
+
+
def spawn_async(argv, in_dir="."):
pretty.print_debug(__name__, "Spawn commandline", argv, in_dir)
argv = [kupferstring.tolocale(A) if isinstance(A, unicode) else A
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]