Skip to content

Commit 8edea09

Browse files
A support of 'cwd' parameter is added to OsOperations::exec_command (#272)
1 parent 9da8981 commit 8edea09

File tree

3 files changed

+99
-24
lines changed

3 files changed

+99
-24
lines changed

testgres/operations/local_ops.py

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,13 @@ def _process_output(encoding, temp_file_path):
6767
output = output.decode(encoding)
6868
return output, None # In Windows stderr writing in stdout
6969

70-
def _run_command__nt(self, cmd, shell, input, stdin, stdout, stderr, get_process, timeout, encoding, exec_env=None):
70+
def _run_command__nt(
71+
self, cmd, shell, input, stdin, stdout, stderr, get_process, timeout, encoding,
72+
exec_env: typing.Optional[dict],
73+
cwd: typing.Optional[str],
74+
):
7175
assert exec_env is None or type(exec_env) == dict # noqa: E721
76+
assert cwd is None or type(cwd) == str # noqa: E721
7277

7378
# TODO: why don't we use the data from input?
7479

@@ -104,6 +109,7 @@ def _run_command__nt(self, cmd, shell, input, stdin, stdout, stderr, get_process
104109
stdin=stdin or subprocess.PIPE if input is not None else None,
105110
stdout=stdout,
106111
stderr=stderr,
112+
cwd=cwd,
107113
**extParams,
108114
)
109115
if get_process:
@@ -116,8 +122,13 @@ def _run_command__nt(self, cmd, shell, input, stdin, stdout, stderr, get_process
116122
output, error = self._process_output(encoding, temp_file_path)
117123
return process, output, error
118124

119-
def _run_command__generic(self, cmd, shell, input, stdin, stdout, stderr, get_process, timeout, encoding, exec_env=None):
125+
def _run_command__generic(
126+
self, cmd, shell, input, stdin, stdout, stderr, get_process, timeout, encoding,
127+
exec_env: typing.Optional[dict],
128+
cwd: typing.Optional[str],
129+
):
120130
assert exec_env is None or type(exec_env) == dict # noqa: E721
131+
assert cwd is None or type(cwd) == str # noqa: E721
121132

122133
input_prepared = None
123134
if not get_process:
@@ -154,6 +165,7 @@ def _run_command__generic(self, cmd, shell, input, stdin, stdout, stderr, get_pr
154165
stdin=stdin or subprocess.PIPE if input is not None else None,
155166
stdout=stdout or subprocess.PIPE,
156167
stderr=stderr or subprocess.PIPE,
168+
cwd=cwd,
157169
**extParams
158170
)
159171
assert not (process is None)
@@ -173,26 +185,44 @@ def _run_command__generic(self, cmd, shell, input, stdin, stdout, stderr, get_pr
173185
error = error.decode(encoding)
174186
return process, output, error
175187

176-
def _run_command(self, cmd, shell, input, stdin, stdout, stderr, get_process, timeout, encoding, exec_env=None):
188+
def _run_command(
189+
self, cmd, shell, input, stdin, stdout, stderr, get_process, timeout, encoding,
190+
exec_env: typing.Optional[dict],
191+
cwd: typing.Optional[str],
192+
):
177193
"""Execute a command and return the process and its output."""
194+
195+
assert exec_env is None or type(exec_env) == dict # noqa: E721
196+
assert cwd is None or type(cwd) == str # noqa: E721
197+
178198
if os.name == 'nt' and stdout is None: # Windows
179199
method = __class__._run_command__nt
180200
else: # Other OS
181201
method = __class__._run_command__generic
182202

183-
return method(self, cmd, shell, input, stdin, stdout, stderr, get_process, timeout, encoding, exec_env=exec_env)
203+
return method(self, cmd, shell, input, stdin, stdout, stderr, get_process, timeout, encoding, exec_env, cwd)
184204

185-
def exec_command(self, cmd, wait_exit=False, verbose=False, expect_error=False, encoding=None, shell=False,
186-
text=False, input=None, stdin=None, stdout=None, stderr=None, get_process=False, timeout=None,
187-
ignore_errors=False, exec_env=None):
205+
def exec_command(
206+
self, cmd, wait_exit=False, verbose=False, expect_error=False, encoding=None, shell=False,
207+
text=False, input=None, stdin=None, stdout=None, stderr=None, get_process=False, timeout=None,
208+
ignore_errors=False,
209+
exec_env: typing.Optional[dict] = None,
210+
cwd: typing.Optional[str] = None
211+
):
188212
"""
189213
Execute a command in a subprocess and handle the output based on the provided parameters.
190214
"""
191215
assert type(expect_error) == bool # noqa: E721
192216
assert type(ignore_errors) == bool # noqa: E721
193217
assert exec_env is None or type(exec_env) == dict # noqa: E721
218+
assert cwd is None or type(cwd) == str # noqa: E721
219+
220+
process, output, error = self._run_command(
221+
cmd, shell, input, stdin, stdout, stderr, get_process, timeout, encoding,
222+
exec_env,
223+
cwd
224+
)
194225

195-
process, output, error = self._run_command(cmd, shell, input, stdin, stdout, stderr, get_process, timeout, encoding, exec_env=exec_env)
196226
if get_process:
197227
return process
198228

testgres/operations/remote_ops.py

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,13 @@ def __init__(self, conn_params: ConnectionParams):
6363
def __enter__(self):
6464
return self
6565

66-
def exec_command(self, cmd, wait_exit=False, verbose=False, expect_error=False,
67-
encoding=None, shell=True, text=False, input=None, stdin=None, stdout=None,
68-
stderr=None, get_process=None, timeout=None, ignore_errors=False,
69-
exec_env=None):
66+
def exec_command(
67+
self, cmd, wait_exit=False, verbose=False, expect_error=False,
68+
encoding=None, shell=True, text=False, input=None, stdin=None, stdout=None,
69+
stderr=None, get_process=None, timeout=None, ignore_errors=False,
70+
exec_env: typing.Optional[dict] = None,
71+
cwd: typing.Optional[str] = None
72+
):
7073
"""
7174
Execute a command in the SSH session.
7275
Args:
@@ -75,28 +78,29 @@ def exec_command(self, cmd, wait_exit=False, verbose=False, expect_error=False,
7578
assert type(expect_error) == bool # noqa: E721
7679
assert type(ignore_errors) == bool # noqa: E721
7780
assert exec_env is None or type(exec_env) == dict # noqa: E721
81+
assert cwd is None or type(cwd) == str # noqa: E721
7882

7983
input_prepared = None
8084
if not get_process:
8185
input_prepared = Helpers.PrepareProcessInput(input, encoding) # throw
8286

8387
assert input_prepared is None or (type(input_prepared) == bytes) # noqa: E721
8488

85-
if type(cmd) == str: # noqa: E721
86-
cmd_s = cmd
87-
elif type(cmd) == list: # noqa: E721
88-
cmd_s = subprocess.list2cmdline(cmd)
89-
else:
90-
raise ValueError("Invalid 'cmd' argument type - {0}".format(type(cmd).__name__))
89+
cmds = []
9190

92-
assert type(cmd_s) == str # noqa: E721
91+
if cwd is not None:
92+
assert type(cwd) == str # noqa: E721
93+
cmds.append(__class__._build_cmdline(["cd", cwd]))
94+
95+
cmds.append(__class__._build_cmdline(cmd, exec_env))
9396

94-
cmd_items = __class__._make_exec_env_list(exec_env=exec_env)
95-
cmd_items.append(cmd_s)
97+
assert len(cmds) >= 1
9698

97-
env_cmd_s = ';'.join(cmd_items)
99+
cmdline = ";".join(cmds)
100+
assert type(cmdline) == str # noqa: E721
101+
assert cmdline != ""
98102

99-
ssh_cmd = ['ssh', self.ssh_dest] + self.ssh_args + [env_cmd_s]
103+
ssh_cmd = ['ssh', self.ssh_dest] + self.ssh_args + [cmdline]
100104

101105
process = subprocess.Popen(ssh_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
102106
assert not (process is None)
@@ -718,7 +722,31 @@ def _is_port_free__process_1(error: str) -> bool:
718722
return True
719723

720724
@staticmethod
721-
def _make_exec_env_list(exec_env: typing.Dict) -> typing.List[str]:
725+
def _build_cmdline(cmd, exec_env: typing.Dict = None) -> str:
726+
cmd_items = __class__._create_exec_env_list(exec_env)
727+
728+
assert type(cmd_items) == list # noqa: E721
729+
730+
cmd_items.append(__class__._ensure_cmdline(cmd))
731+
732+
cmdline = ';'.join(cmd_items)
733+
assert type(cmdline) == str # noqa: E721
734+
return cmdline
735+
736+
@staticmethod
737+
def _ensure_cmdline(cmd) -> typing.List[str]:
738+
if type(cmd) == str: # noqa: E721
739+
cmd_s = cmd
740+
elif type(cmd) == list: # noqa: E721
741+
cmd_s = subprocess.list2cmdline(cmd)
742+
else:
743+
raise ValueError("Invalid 'cmd' argument type - {0}".format(type(cmd).__name__))
744+
745+
assert type(cmd_s) == str # noqa: E721
746+
return cmd_s
747+
748+
@staticmethod
749+
def _create_exec_env_list(exec_env: typing.Dict) -> typing.List[str]:
722750
env: typing.Dict[str, str] = dict()
723751

724752
# ---------------------------------- SYSTEM ENV

tests/test_os_ops_common.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,23 @@ def test_exec_command_with_exec_env(self, os_ops: OsOperations):
118118
assert type(response) == bytes # noqa: E721
119119
assert response == b'\n'
120120

121+
def test_exec_command_with_cwd(self, os_ops: OsOperations):
122+
assert isinstance(os_ops, OsOperations)
123+
124+
RunConditions.skip_if_windows()
125+
126+
cmd = ["pwd"]
127+
128+
response = os_ops.exec_command(cmd, cwd="/tmp")
129+
assert response is not None
130+
assert type(response) == bytes # noqa: E721
131+
assert response == b'/tmp\n'
132+
133+
response = os_ops.exec_command(cmd)
134+
assert response is not None
135+
assert type(response) == bytes # noqa: E721
136+
assert response != b'/tmp\n'
137+
121138
def test_exec_command__test_unset(self, os_ops: OsOperations):
122139
assert isinstance(os_ops, OsOperations)
123140

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy