From 356950579c2b155f9d41c04ed63c7efde561b43a Mon Sep 17 00:00:00 2001 From: Thomas Mangin Date: Sun, 5 Apr 2020 14:02:49 +0100 Subject: util: T2226: improve popen, cmd and add run improves open and cmd adds a new help function run. the extra optional arguments provide all the features of subprocess used by every module of VyOS. popen matches closely subprocess.Popen cmd matches closely subprocess.check_output run matches closely subprocess.call and os.system popen returns the string and errord code cmd returns the string and raise on error (the class can be defined the default is OSError) run returns the return code of the command the options are: shell=None, the code auto-detect is a shell is required decode=None, use .decode() otherwise the encoding will be used env=None, universal_newlines=None: as per subprocess.Popen input=None, timeout=None, stdout=PIPE, stderr=STDOUT, as per Popen.communicate --- python/vyos/util.py | 67 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 15 deletions(-) (limited to 'python') diff --git a/python/vyos/util.py b/python/vyos/util.py index c8ab43c11..f63ed057e 100644 --- a/python/vyos/util.py +++ b/python/vyos/util.py @@ -16,7 +16,7 @@ import os import re import sys -from subprocess import Popen, PIPE, STDOUT +from subprocess import Popen, PIPE, STDOUT, DEVNULL # debugging @@ -33,29 +33,63 @@ def debug_msg(message, section=''): # commands - -def popen(command, section=''): - p = Popen(command, stdout=PIPE, stderr=STDOUT, shell=True) - tmp = p.communicate()[0].strip() +# popen does not raise +# it returns the output of the command and the error code +def popen(command, section='', shell=None, input=None, timeout=None, env=None, universal_newlines=None, stdout=PIPE, stderr=STDOUT, decode=None): + use_shell = shell + if shell is None: + use_shell = True if ' ' in command else False + p = Popen( + command, + stdout=stdout, stderr=stderr, + env=env, shell=use_shell, + universal_newlines=universal_newlines, + ) + tmp = p.communicate(input, timeout)[0].strip() debug_msg(f"cmd '{command}'", section) - decoded = tmp.decode() + decoded = tmp.decode(decode) if decode else tmp.decode() if decoded: debug_msg(f"returned:\n{decoded}", section) return decoded, p.returncode - -def cmd(command, section=''): - decoded, code = popen(command, section) +# run does not raise +# it returns the error code +def run(command, section='', shell=None, input=None, timeout=None, env=None, universal_newlines=None, stdout=PIPE, stderr=STDOUT, decode=None): + _, code = popen( + command, section, + stdout=stdout, stderr=stderr, + input=input, timeout=timeout, + env=env, shell=shell, + universal_newlines=universal_newlines, + decode=decode, + ) + return code + +# cmd does raise +# it returns the output +def cmd(command, section='', shell=None, input=None, timeout=None, env=None, universal_newlines=None, stdout=PIPE, stderr=STDOUT, decode=None, raising=None, message=''): + decoded, code = popen( + command, section, + stdout=stdout, stderr=stderr, + input=input, timeout=timeout, + env=env, shell=shell, + universal_newlines=universal_newlines, + decode=decode, + ) if code != 0: - # error code can be recovered with .errno - raise OSError(code, f'{command}\nreturned: {decoded}') + feedback = message + '\n' if message else '' + feedback += f'failed to run command: {command}\n' + feedback += f'returned: {decoded}\n' + feedback += f'exit code: {code}' + if raising is None: + # error code can be recovered with .errno + raise OSError(code, feedback) + else: + raise raising(feedback) return decoded -# file manipulation - - - +# This is now deprecated def subprocess_cmd(command): """ execute arbitrary command via Popen """ from subprocess import Popen, PIPE @@ -63,6 +97,9 @@ def subprocess_cmd(command): p.communicate() +# file manipulation + + def read_file(path): """ Read a file to string """ with open(path, 'r') as f: -- cgit v1.2.3