#!/usr/bin/python3 # -*- coding: utf-8 -*- # ----------------------------------------------------------------------- # This file is part of TISBackup # # TISBackup 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. # # TISBackup 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 TISBackup. If not, see . # # ----------------------------------------------------------------------- """Process execution and monitoring utilities.""" import errno import os import select import subprocess def call_external_process(shell_string): """Execute a shell command and raise exception on non-zero exit code.""" p = subprocess.call(shell_string, shell=True) if p != 0: raise Exception("shell program exited with error code " + str(p), shell_string) def monitor_stdout(aprocess, onoutputdata, context): """Reads data from stdout and stderr from aprocess and return as a string on each chunk, call a call back onoutputdata(dataread) """ assert isinstance(aprocess, subprocess.Popen) read_set = [] stdout = [] line = "" if aprocess.stdout: read_set.append(aprocess.stdout) if aprocess.stderr: read_set.append(aprocess.stderr) while read_set: try: rlist, wlist, xlist = select.select(read_set, [], []) except select.error as e: if e.args[0] == errno.EINTR: continue raise # Reads one line from stdout if aprocess.stdout in rlist: data = os.read(aprocess.stdout.fileno(), 1) data = data.decode(errors="ignore") if data == "": aprocess.stdout.close() read_set.remove(aprocess.stdout) while data and data not in ("\n", "\r"): line += data data = os.read(aprocess.stdout.fileno(), 1) data = data.decode(errors="ignore") if line or data in ("\n", "\r"): stdout.append(line) if onoutputdata: onoutputdata(line, context) line = "" # Reads one line from stderr if aprocess.stderr in rlist: data = os.read(aprocess.stderr.fileno(), 1) data = data.decode(errors="ignore") if data == "": aprocess.stderr.close() read_set.remove(aprocess.stderr) while data and data not in ("\n", "\r"): line += data data = os.read(aprocess.stderr.fileno(), 1) data = data.decode(errors="ignore") if line or data in ("\n", "\r"): stdout.append(line) if onoutputdata: onoutputdata(line, context) line = "" aprocess.wait() if line: stdout.append(line) if onoutputdata: onoutputdata(line, context) return "\n".join(stdout)