summaryrefslogtreecommitdiffstats
path: root/async_subprocess.py
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2010-10-02 15:39:18 -0400
committerColin Walters <walters@verbum.org>2010-10-02 15:39:18 -0400
commit77ad7371c5906b83db49de309ba39d867b673975 (patch)
treebe15ba7c0cd193de3542d42cc7e7594c7bbff995 /async_subprocess.py
downloadrpmci-77ad7371c5906b83db49de309ba39d867b673975.tar.gz
rpmci-77ad7371c5906b83db49de309ba39d867b673975.tar.xz
rpmci-77ad7371c5906b83db49de309ba39d867b673975.zip
Initial untested stab at vcs mirroring component, with DESIGN plan
Diffstat (limited to 'async_subprocess.py')
-rw-r--r--async_subprocess.py81
1 files changed, 81 insertions, 0 deletions
diff --git a/async_subprocess.py b/async_subprocess.py
new file mode 100644
index 0000000..53abaa1
--- /dev/null
+++ b/async_subprocess.py
@@ -0,0 +1,81 @@
+# async_subprocess.py:
+# Run a subprocess asynchronously using GLib
+#
+# Licensed under the new-BSD license (http://www.opensource.org/licenses/bsd-license.php)
+# Copyright (C) 2010 Red Hat, Inc.
+# Written by Colin Walters <walters@verbum.org>
+
+import glib
+import logging
+
+PIPE_STDOUT = 'pipe-stdout'
+
+def spawn_async_log_info(argv, cwd=None, stdout=None):
+ logging.info("Starting subprocess: %r" % (argv, ))
+ return AsyncProcess(argv, cwd=cwd, stdout=stdout)
+
+def spawn_async_output_to_file(argv, output_filepath, on_exited, cwd=None):
+ f = open(output_filepath, 'w')
+ process = AsyncProcess(argv, cwd=cwd, stdout=PIPE_STDOUT)
+ def _write_to_file(process, buf):
+ f.write(buf)
+ def _on_exited(process):
+ f.close()
+ on_exited()
+ process.set_callbacks(_write_to_file, _on_exited)
+ return process
+
+class AsyncProcess(object):
+ def __init__(self, argv, cwd=None, stdout=None):
+ self.argv = argv
+ if stdout == PIPE_STDOUT:
+ (pid, stdin, stdout, stderr) = glib.spawn_async(argv,
+ working_directory=cwd,
+ flags=(glib.SPAWN_SEARCH_PATH
+ | glib.SPAWN_DO_NOT_REAP_CHILD),
+ standard_output=True,
+ standard_error=None)
+ assert stdout == stderr
+ else:
+ (pid, stdin, stdout, stderr) = glib.spawn_async(argv,
+ working_directory=cwd,
+ (glib.SPAWN_SEARCH_PATH
+ | glib.SPAWN_DO_NOT_REAP_CHILD
+ | glib.SPAWN_STDOUT_TO_DEV_NULL
+ | glib.SPAWN_STDERR_TO_DEV_NULL))
+ assert stdout is None
+ assert stderr is None
+
+ assert stdin is None
+ self.pid = pid
+ self._child_watch_id = glib.child_watch_add(pid, self._on_child_exited)
+ self._stdout_fd = stdout
+
+ def set_callbacks(self, output_callback, exited_callback):
+ self._output_callback = output_callback
+ self._exited_callback = exited_callback
+ if (self.stdout and self._stdout_watch_id == 0):
+ glib.io_add_watch(self.stdout, glib.IO_IN | glib.IO_ERR | glib.IO_HUP,
+ self._on_io)
+
+ def _on_child_exited(self, pid, condition):
+ logging.info("Child pid %d exited with code %r" % (pid, condition))
+ self._exited_callback(self, condition)
+
+ def _on_io(self, source, condition):
+ have_read = condition & gobject.IO_IN
+ if have_read:
+ buf = os.read(source, 8192)
+ self._output_callback(self, buf)
+ if ((condition & glib.IO_ERR) > 0
+ or (condition & glib.IO_HUP) > 0):
+ os.close(source)
+ self._stdout_watch_id = 0
+ return False
+ return have_read
+
+
+
+
+
+