From 77ad7371c5906b83db49de309ba39d867b673975 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Sat, 2 Oct 2010 15:39:18 -0400 Subject: Initial untested stab at vcs mirroring component, with DESIGN plan --- async_subprocess.py | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 async_subprocess.py (limited to 'async_subprocess.py') 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 + +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 + + + + + + -- cgit