99import socket
1010
1111import psutil
12+ import typing
1213
1314from ..exceptions import ExecUtilException
1415from ..exceptions import InvalidOperationException
@@ -46,9 +47,34 @@ def _process_output(encoding, temp_file_path):
4647 output = output .decode (encoding )
4748 return output , None # In Windows stderr writing in stdout
4849
49- def _run_command__nt (self , cmd , shell , input , stdin , stdout , stderr , get_process , timeout , encoding ):
50+ def _run_command__nt (self , cmd , shell , input , stdin , stdout , stderr , get_process , timeout , encoding , exec_env = None ):
51+ assert exec_env is None or type (exec_env ) == dict # noqa: E721
52+
5053 # TODO: why don't we use the data from input?
5154
55+ extParams : typing .Dict [str , str ] = dict ()
56+
57+ if exec_env is None :
58+ pass
59+ elif len (exec_env ) == 0 :
60+ pass
61+ else :
62+ env = os .environ .copy ()
63+ assert type (env ) == dict # noqa: E721
64+ for v in exec_env .items ():
65+ assert type (v ) == tuple # noqa: E721
66+ assert len (v ) == 2
67+ assert type (v [0 ]) == str # noqa: E721
68+ assert v [0 ] != ""
69+
70+ if v [1 ] is None :
71+ env .pop (v [0 ], None )
72+ else :
73+ assert type (v [1 ]) == str # noqa: E721
74+ env [v [0 ]] = v [1 ]
75+
76+ extParams ["env" ] = env
77+
5278 with tempfile .NamedTemporaryFile (mode = 'w+b' , delete = False ) as temp_file :
5379 stdout = temp_file
5480 stderr = subprocess .STDOUT
@@ -58,6 +84,7 @@ def _run_command__nt(self, cmd, shell, input, stdin, stdout, stderr, get_process
5884 stdin = stdin or subprocess .PIPE if input is not None else None ,
5985 stdout = stdout ,
6086 stderr = stderr ,
87+ ** extParams ,
6188 )
6289 if get_process :
6390 return process , None , None
@@ -69,19 +96,45 @@ def _run_command__nt(self, cmd, shell, input, stdin, stdout, stderr, get_process
6996 output , error = self ._process_output (encoding , temp_file_path )
7097 return process , output , error
7198
72- def _run_command__generic (self , cmd , shell , input , stdin , stdout , stderr , get_process , timeout , encoding ):
99+ def _run_command__generic (self , cmd , shell , input , stdin , stdout , stderr , get_process , timeout , encoding , exec_env = None ):
100+ assert exec_env is None or type (exec_env ) == dict # noqa: E721
101+
73102 input_prepared = None
74103 if not get_process :
75104 input_prepared = Helpers .PrepareProcessInput (input , encoding ) # throw
76105
77106 assert input_prepared is None or (type (input_prepared ) == bytes ) # noqa: E721
78107
108+ extParams : typing .Dict [str , str ] = dict ()
109+
110+ if exec_env is None :
111+ pass
112+ elif len (exec_env ) == 0 :
113+ pass
114+ else :
115+ env = os .environ .copy ()
116+ assert type (env ) == dict # noqa: E721
117+ for v in exec_env .items ():
118+ assert type (v ) == tuple # noqa: E721
119+ assert len (v ) == 2
120+ assert type (v [0 ]) == str # noqa: E721
121+ assert v [0 ] != ""
122+
123+ if v [1 ] is None :
124+ env .pop (v [0 ], None )
125+ else :
126+ assert type (v [1 ]) == str # noqa: E721
127+ env [v [0 ]] = v [1 ]
128+
129+ extParams ["env" ] = env
130+
79131 process = subprocess .Popen (
80132 cmd ,
81133 shell = shell ,
82134 stdin = stdin or subprocess .PIPE if input is not None else None ,
83135 stdout = stdout or subprocess .PIPE ,
84136 stderr = stderr or subprocess .PIPE ,
137+ ** extParams
85138 )
86139 assert not (process is None )
87140 if get_process :
@@ -100,25 +153,26 @@ def _run_command__generic(self, cmd, shell, input, stdin, stdout, stderr, get_pr
100153 error = error .decode (encoding )
101154 return process , output , error
102155
103- def _run_command (self , cmd , shell , input , stdin , stdout , stderr , get_process , timeout , encoding ):
156+ def _run_command (self , cmd , shell , input , stdin , stdout , stderr , get_process , timeout , encoding , exec_env = None ):
104157 """Execute a command and return the process and its output."""
105158 if os .name == 'nt' and stdout is None : # Windows
106159 method = __class__ ._run_command__nt
107160 else : # Other OS
108161 method = __class__ ._run_command__generic
109162
110- return method (self , cmd , shell , input , stdin , stdout , stderr , get_process , timeout , encoding )
163+ return method (self , cmd , shell , input , stdin , stdout , stderr , get_process , timeout , encoding , exec_env = exec_env )
111164
112165 def exec_command (self , cmd , wait_exit = False , verbose = False , expect_error = False , encoding = None , shell = False ,
113166 text = False , input = None , stdin = None , stdout = None , stderr = None , get_process = False , timeout = None ,
114- ignore_errors = False ):
167+ ignore_errors = False , exec_env = None ):
115168 """
116169 Execute a command in a subprocess and handle the output based on the provided parameters.
117170 """
118171 assert type (expect_error ) == bool # noqa: E721
119172 assert type (ignore_errors ) == bool # noqa: E721
173+ assert exec_env is None or type (exec_env ) == dict # noqa: E721
120174
121- process , output , error = self ._run_command (cmd , shell , input , stdin , stdout , stderr , get_process , timeout , encoding )
175+ process , output , error = self ._run_command (cmd , shell , input , stdin , stdout , stderr , get_process , timeout , encoding , exec_env = exec_env )
122176 if get_process :
123177 return process
124178
0 commit comments