@@ -38,32 +38,6 @@ def __init__(self, conn_params=None):
3838 self .remote = False
3939 self .username = conn_params .username or self .get_user ()
4040
41- @staticmethod
42- def _run_command (cmd , shell , input , stdin , stdout , stderr , timeout , encoding , temp_file = None , get_process = None ):
43- """Execute a command and return the process."""
44- if temp_file is not None :
45- stdout = stdout or temp_file
46- stderr = stderr or subprocess .STDOUT
47- else :
48- stdout = stdout or subprocess .PIPE
49- stderr = stderr or subprocess .PIPE
50-
51- process = subprocess .Popen (
52- cmd ,
53- shell = shell ,
54- stdin = stdin or subprocess .PIPE if input is not None else None ,
55- stdout = stdout ,
56- stderr = stderr ,
57- )
58-
59- if get_process :
60- return None , process
61- try :
62- return process .communicate (input = input .encode (encoding ) if input else None , timeout = timeout ), process
63- except subprocess .TimeoutExpired :
64- process .kill ()
65- raise ExecUtilException ("Command timed out after {} seconds." .format (timeout ))
66-
6741 @staticmethod
6842 def _raise_exec_exception (message , command , exit_code , output ):
6943 """Raise an ExecUtilException."""
@@ -72,105 +46,72 @@ def _raise_exec_exception(message, command, exit_code, output):
7246 exit_code = exit_code ,
7347 out = output )
7448
75- def exec_command (self , cmd , wait_exit = False , verbose = False ,
76- expect_error = False , encoding = None , shell = False , text = False ,
77- input = None , stdin = None , stdout = None , stderr = None ,
78- get_process = None , timeout = None ):
79- """
80- Execute a command in a subprocess.
81-
82- Args:
83- - cmd: The command to execute.
84- - wait_exit: Whether to wait for the subprocess to exit before returning.
85- - verbose: Whether to return verbose output.
86- - expect_error: Whether to raise an error if the subprocess exits with an error status.
87- - encoding: The encoding to use for decoding the subprocess output.
88- - shell: Whether to use shell when executing the subprocess.
89- - text: Whether to return str instead of bytes for the subprocess output.
90- - input: The input to pass to the subprocess.
91- - stdout: The stdout to use for the subprocess.
92- - stderr: The stderr to use for the subprocess.
93- - proc: The process to use for subprocess creation.
94- :return: The output of the subprocess.
95- """
96- if os .name == 'nt' :
97- return self ._exec_command_windows (cmd , wait_exit = wait_exit , verbose = verbose ,
98- expect_error = expect_error , encoding = encoding , shell = shell , text = text ,
99- input = input , stdin = stdin , stdout = stdout , stderr = stderr ,
100- get_process = get_process , timeout = timeout )
101- else :
49+ @staticmethod
50+ def _process_output (encoding , temp_file_path ):
51+ """Process the output of a command from a temporary file."""
52+ with open (temp_file_path , 'rb' ) as temp_file :
53+ output = temp_file .read ()
54+ if encoding :
55+ output = output .decode (encoding )
56+ return output , None # In Windows stderr writing in stdout
57+
58+ def _run_command (self , cmd , shell , input , stdin , stdout , stderr , get_process , timeout , encoding ):
59+ """Execute a command and return the process and its output."""
60+ if os .name == 'nt' and stdout is None : # Windows
61+ with tempfile .NamedTemporaryFile (mode = 'w+b' , delete = False ) as temp_file :
62+ stdout = temp_file
63+ stderr = subprocess .STDOUT
64+ process = subprocess .Popen (
65+ cmd ,
66+ shell = shell ,
67+ stdin = stdin or subprocess .PIPE if input is not None else None ,
68+ stdout = stdout ,
69+ stderr = stderr ,
70+ )
71+ if get_process :
72+ return process , None , None
73+ temp_file_path = temp_file .name
74+
75+ # Wait process finished
76+ process .wait ()
77+
78+ output , error = self ._process_output (encoding , temp_file_path )
79+ return process , output , error
80+ else : # Other OS
10281 process = subprocess .Popen (
10382 cmd ,
10483 shell = shell ,
105- stdin = stdin ,
106- stdout = stdout ,
107- stderr = stderr ,
84+ stdin = stdin or subprocess . PIPE if input is not None else None ,
85+ stdout = stdout or subprocess . PIPE ,
86+ stderr = stderr or subprocess . PIPE ,
10887 )
10988 if get_process :
110- return process
111-
89+ return process , None , None
11290 try :
113- result , error = process .communicate (input , timeout = timeout )
91+ output , error = process .communicate (input = input .encode (encoding ) if input else None , timeout = timeout )
92+ if encoding :
93+ output = output .decode (encoding )
94+ error = error .decode (encoding )
95+ return process , output , error
11496 except subprocess .TimeoutExpired :
11597 process .kill ()
11698 raise ExecUtilException ("Command timed out after {} seconds." .format (timeout ))
117- exit_status = process .returncode
11899
119- error_found = exit_status != 0 or has_errors (error )
120-
121- if encoding :
122- result = result .decode (encoding )
123- error = error .decode (encoding )
124-
125- if expect_error :
126- raise Exception (result , error )
127-
128- if exit_status != 0 or error_found :
129- if exit_status == 0 :
130- exit_status = 1
131- self ._raise_exec_exception ('Utility exited with non-zero code. Error `{}`' , cmd , exit_status , result )
132- if verbose :
133- return exit_status , result , error
134- else :
135- return result
100+ def exec_command (self , cmd , wait_exit = False , verbose = False , expect_error = False , encoding = None , shell = False ,
101+ text = False , input = None , stdin = None , stdout = None , stderr = None , get_process = False , timeout = None ):
102+ """
103+ Execute a command in a subprocess and handle the output based on the provided parameters.
104+ """
105+ process , output , error = self ._run_command (cmd , shell , input , stdin , stdout , stderr , get_process , timeout , encoding )
106+ if get_process :
107+ return process
108+ if process .returncode != 0 or (has_errors (error ) and not expect_error ):
109+ self ._raise_exec_exception ('Utility exited with non-zero code. Error `{}`' , cmd , process .returncode , error )
136110
137- @staticmethod
138- def _process_output (process , encoding , temp_file = None ):
139- """Process the output of a command."""
140- if temp_file is not None :
141- temp_file .seek (0 )
142- output = temp_file .read ()
111+ if verbose :
112+ return process .returncode , output , error
143113 else :
144- output = process .stdout .read ()
145-
146- if encoding :
147- output = output .decode (encoding )
148-
149- return output
150-
151- def _exec_command_windows (self , cmd , wait_exit = False , verbose = False ,
152- expect_error = False , encoding = None , shell = False , text = False ,
153- input = None , stdin = None , stdout = None , stderr = None ,
154- get_process = None , timeout = None ):
155- with tempfile .NamedTemporaryFile (mode = 'w+b' ) as temp_file :
156- _ , process = self ._run_command (cmd , shell , input , stdin , stdout , stderr , timeout , encoding , temp_file , get_process )
157- if get_process :
158- return process
159- result = self ._process_output (process , encoding , temp_file )
160-
161- if process .returncode != 0 or has_errors (result ):
162- if process .returncode == 0 :
163- process .returncode = 1
164- if expect_error :
165- if verbose :
166- return process .returncode , result , result
167- else :
168- return result
169- else :
170- self ._raise_exec_exception ('Utility exited with non-zero code. Error `{}`' , cmd , process .returncode ,
171- result )
172-
173- return (process .returncode , result , result ) if verbose else result
114+ return output
174115
175116 # Environment setup
176117 def environ (self , var_name ):
0 commit comments