1
1
"""
2
2
BashProvider is a class that implements the BaseOutputProvider.
3
3
"""
4
+
4
5
import shlex
5
6
import subprocess
6
7
@@ -20,80 +21,104 @@ def validate_config(self):
20
21
pass
21
22
22
23
def _query (
23
- self ,
24
- timeout : int = 60 ,
25
- command : str = "" ,
26
- ** kwargs
27
- ):
24
+ self , timeout : int = 60 , command : str = "" , shell : bool = False , ** kwargs
25
+ ):
28
26
"""Bash provider eval shell command to get results
29
27
30
28
Returns:
31
29
_type_: _description_
32
30
"""
33
- # timeout = kwargs.get("timeout", 60)
34
- # command = kwargs.get("command", "")
35
31
parsed_command = self .io_handler .parse (command )
36
- # parse by pipes
37
- parsed_commands = parsed_command .split ("|" )
38
- # Initialize the input for the first command
39
- input_stream = None
40
-
41
- processes = []
42
-
43
- for cmd in parsed_commands :
44
- # Split the command string into a list of arguments
45
- cmd_args = shlex .split (cmd .strip ())
46
-
47
- # Run the command and pipe its output to the next command, capturing stderr
48
- process = subprocess .Popen (
49
- cmd_args ,
50
- stdin = input_stream ,
51
- stdout = subprocess .PIPE ,
52
- stderr = subprocess .PIPE ,
53
- )
54
-
55
- if input_stream is not None :
56
- # Close the input_stream (output of the previous command)
57
- input_stream .close ()
58
-
59
- # Update input_stream to be the output of the current command
60
- input_stream = process .stdout
61
-
62
- # Append the current process to the list of processes
63
- processes .append (process )
64
-
65
- # Get the final output
66
- try :
67
- stdout , stderr = processes [- 1 ].communicate (timeout = timeout )
68
- return_code = processes [- 1 ].returncode
69
- # stdout and stderr are strings or None
70
- if stdout or stdout == b"" :
71
- stdout = stdout .decode ()
72
-
73
- if stderr or stderr == b"" :
74
- stderr = stderr .decode ()
75
- except subprocess .TimeoutExpired :
76
- # use check_output to get the output of the last process
77
- # this is some MacOS bug, where communicate() doesn't work and raise TimeoutExpired (idk why but it works on Linux)
32
+
33
+ if shell :
34
+ # Use shell=True for complex commands
35
+ try :
36
+ result = subprocess .run (
37
+ parsed_command ,
38
+ shell = True ,
39
+ capture_output = True ,
40
+ timeout = timeout ,
41
+ text = True ,
42
+ )
43
+ return {
44
+ "stdout" : result .stdout ,
45
+ "stderr" : result .stderr ,
46
+ "return_code" : result .returncode ,
47
+ }
48
+ except subprocess .TimeoutExpired :
49
+ try :
50
+ self .logger .warning (
51
+ "TimeoutExpired, using check_output - MacOS bug?"
52
+ )
53
+ stdout = subprocess .check_output (
54
+ parsed_command ,
55
+ stderr = subprocess .STDOUT ,
56
+ timeout = timeout ,
57
+ shell = True ,
58
+ ).decode ()
59
+ return {
60
+ "stdout" : stdout ,
61
+ "stderr" : None ,
62
+ "return_code" : 0 ,
63
+ }
64
+ except Exception as e :
65
+ return {
66
+ "stdout" : None ,
67
+ "stderr" : str (e ),
68
+ "return_code" : - 1 ,
69
+ }
70
+ else :
71
+ # Original logic for simple commands
72
+ parsed_commands = parsed_command .split ("|" )
73
+ input_stream = None
74
+ processes = []
75
+
76
+ for cmd in parsed_commands :
77
+ cmd_args = shlex .split (cmd .strip ())
78
+ process = subprocess .Popen (
79
+ cmd_args ,
80
+ stdin = input_stream ,
81
+ stdout = subprocess .PIPE ,
82
+ stderr = subprocess .PIPE ,
83
+ )
84
+
85
+ if input_stream is not None :
86
+ input_stream .close ()
87
+
88
+ input_stream = process .stdout
89
+ processes .append (process )
90
+
78
91
try :
79
- self .logger .warning ("TimeoutExpired, using check_output - MacOS bug?" )
80
- stdout = subprocess .check_output (
81
- cmd , stderr = subprocess .STDOUT , timeout = timeout , shell = True
82
- ).decode ()
83
- stderr = None
84
- return_code = 0
85
- self .logger .warning ("check_output worked" )
86
- # todo: fix that
87
- except Exception as e :
88
- stdout = None
89
- stderr = e .args [1 ].decode ()
90
- return_code = e .args [0 ]
91
-
92
- return {
93
- "stdout" : str (stdout ),
94
- "stderr" : str (stderr ),
95
- "return_code" : return_code ,
96
- }
92
+ stdout , stderr = processes [- 1 ].communicate (timeout = timeout )
93
+ return_code = processes [- 1 ].returncode
94
+
95
+ if stdout or stdout == b"" :
96
+ stdout = stdout .decode ()
97
+ if stderr or stderr == b"" :
98
+ stderr = stderr .decode ()
99
+ except subprocess .TimeoutExpired :
100
+ try :
101
+ self .logger .warning (
102
+ "TimeoutExpired, using check_output - MacOS bug?"
103
+ )
104
+ stdout = subprocess .check_output (
105
+ parsed_command ,
106
+ stderr = subprocess .STDOUT ,
107
+ timeout = timeout ,
108
+ shell = True ,
109
+ ).decode ()
110
+ stderr = None
111
+ return_code = 0
112
+ except Exception as e :
113
+ stdout = None
114
+ stderr = str (e )
115
+ return_code = - 1
116
+
117
+ return {
118
+ "stdout" : str (stdout ),
119
+ "stderr" : str (stderr ),
120
+ "return_code" : return_code ,
121
+ }
97
122
98
123
def dispose (self ):
99
124
"""
0 commit comments