def spawn_program(args, reply_handler, error_handler): """Spawn the program specified by 'args' using the GLib mainloop. When the program finishes, 'reply_handler' will be called with a single argument that will be the porgram status code. If there is an error, error_handler will be called with an instance of SpawnError. """ def child_watch(pid, status): """Handle child termination.""" # pylint: disable=E1103 GLib.spawn_close_pid(pid) # pylint: enable=E1103 if os.WIFEXITED(status): status = os.WEXITSTATUS(status) reply_handler(status) else: msg = 'Child terminated abnormally, '\ 'status from waitpid is %r' % status error_handler(msg=msg, failed_to_start=False) def handle_error(gerror): """Handle error when spawning the process.""" failed_to_start = NO_SUCH_FILE_OR_DIR in gerror.message msg = 'GError is: code %r, message %r' % (gerror.code, gerror.message) error_handler(msg=msg, failed_to_start=failed_to_start) flags = GLib.SpawnFlags.DO_NOT_REAP_CHILD | \ GLib.SpawnFlags.SEARCH_PATH | \ GLib.SpawnFlags.STDOUT_TO_DEV_NULL | \ GLib.SpawnFlags.STDERR_TO_DEV_NULL pid = None bytes_args = [] for arg in args: if isinstance(arg, compat.text_type): arg = arg.encode('utf-8') if not isinstance(arg, compat.basestring): arg = compat.binary_type(arg) bytes_args.append(arg) try: pid, _, _, _ = GLib.spawn_async(argv=bytes_args, flags=flags) except GLib.GError as e: handle_error(e) else: logger.debug('Spawning the program %r with the glib mainloop ' '(returned pid is %r).', args, pid) GLib.child_watch_add(pid, child_watch)
def spawn_program(args, reply_handler, error_handler): """Spawn the program specified by 'args' using the twisted reactor. When the program finishes, 'reply_handler' will be called with a single argument that will be the porgram status code. If there is an error, error_handler will be called with an instance of SpawnError. """ def child_watch(args): """Handle child termination.""" stdout, stderr, exit_code = args if stdout: logger.debug('Returned stdout is (exit code was %r): %r', exit_code, stdout) if stderr: logger.warning('Returned stderr is (exit code was %r): %r', exit_code, stderr) if OSError.__name__ in stderr: failed_to_start = NO_SUCH_FILE_OR_DIR in stderr error_handler(msg=stderr, failed_to_start=failed_to_start) else: reply_handler(exit_code) def handle_error(failure): """Handle error when spawning the process.""" error_handler(msg=failure.getErrorMessage()) args = list(args) program = args[0] argv = args[1:] bytes_args = [] for arg in argv: if isinstance(arg, compat.text_type): arg = arg.encode('utf-8') if not isinstance(arg, compat.basestring): arg = compat.binary_type(arg) bytes_args.append(arg) if program and not os.access(program, os.X_OK): # handle searching the executable in the PATH, since # twisted will not solve that for us :-/ paths = os.environ['PATH'].split(os.pathsep) for path in paths: target = os.path.join(path, program) if not target.endswith(EXE_EXT): target += EXE_EXT if os.access(target, os.X_OK): program = target break try: d = utils.getProcessOutputAndValue(program, bytes_args, env=os.environ) except OSError as e: error_handler(msg=e, failed_to_start=True) except Exception as e: error_handler(msg=e, failed_to_start=False) else: logger.debug( 'Spawning the program %r with the twisted reactor ' '(returned deferred is %r).', repr(args), d) d.addCallback(child_watch) d.addErrback(handle_error)
def spawn_program(args, reply_handler, error_handler): """Spawn the program specified by 'args' using the twisted reactor. When the program finishes, 'reply_handler' will be called with a single argument that will be the porgram status code. If there is an error, error_handler will be called with an instance of SpawnError. """ def child_watch(args): """Handle child termination.""" stdout, stderr, exit_code = args if stdout: logger.debug('Returned stdout is (exit code was %r): %r', exit_code, stdout) if stderr: logger.warning('Returned stderr is (exit code was %r): %r', exit_code, stderr) if OSError.__name__ in stderr: failed_to_start = NO_SUCH_FILE_OR_DIR in stderr error_handler(msg=stderr, failed_to_start=failed_to_start) else: reply_handler(exit_code) def handle_error(failure): """Handle error when spawning the process.""" error_handler(msg=failure.getErrorMessage()) args = list(args) program = args[0] argv = args[1:] bytes_args = [] for arg in argv: if isinstance(arg, compat.text_type): arg = arg.encode('utf-8') if not isinstance(arg, compat.basestring): arg = compat.binary_type(arg) bytes_args.append(arg) if program and not os.access(program, os.X_OK): # handle searching the executable in the PATH, since # twisted will not solve that for us :-/ paths = os.environ['PATH'].split(os.pathsep) for path in paths: target = os.path.join(path, program) if not target.endswith(EXE_EXT): target += EXE_EXT if os.access(target, os.X_OK): program = target break try: d = utils.getProcessOutputAndValue(program, bytes_args, env=os.environ) except OSError as e: error_handler(msg=e, failed_to_start=True) except Exception as e: error_handler(msg=e, failed_to_start=False) else: logger.debug('Spawning the program %r with the twisted reactor ' '(returned deferred is %r).', repr(args), d) d.addCallback(child_watch) d.addErrback(handle_error)