@@ -38,32 +38,6 @@ def __init__(self, conn_params=None):
38
38
self .remote = False
39
39
self .username = conn_params .username or self .get_user ()
40
40
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
-
67
41
@staticmethod
68
42
def _raise_exec_exception (message , command , exit_code , output ):
69
43
"""Raise an ExecUtilException."""
@@ -72,105 +46,72 @@ def _raise_exec_exception(message, command, exit_code, output):
72
46
exit_code = exit_code ,
73
47
out = output )
74
48
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
102
81
process = subprocess .Popen (
103
82
cmd ,
104
83
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 ,
108
87
)
109
88
if get_process :
110
- return process
111
-
89
+ return process , None , None
112
90
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
114
96
except subprocess .TimeoutExpired :
115
97
process .kill ()
116
98
raise ExecUtilException ("Command timed out after {} seconds." .format (timeout ))
117
- exit_status = process .returncode
118
99
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 )
136
110
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
143
113
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
174
115
175
116
# Environment setup
176
117
def environ (self , var_name ):
0 commit comments