lib.util.run_cmd(): Rewrite it to be async

run_cmd() is synchronous. Now that all commands are asynchronous, we
can await it, so rewrite it to be asynchronous, too.

Other changes:

  - Make it return stderr as well in case its needed

  - Drop into a pseuto-tty if
    - cmd_input == "mode:interactive" or
    - cmd_input == "mode:auto" and stdin is a TTY

  - Add argument env, defaulting to None. If it's a dict, it will be
    the environment the command is run in

This entails making all functions using run_cmd() async, too,
including run_curl(), get_username() and get_password().

Signed-off-by: Jan Lindemann <jan@janware.com>
This commit is contained in:
Jan Lindemann 2026-01-27 16:20:57 +01:00
commit 4274a71c62
4 changed files with 162 additions and 44 deletions

View file

@ -32,7 +32,7 @@ class SSHClient(abc.ABC):
return self.__username
@abc.abstractmethod
def run_cmd(self, cmd: str):
async def run_cmd(self, cmd: str):
pass
class SSHClientInternal(SSHClient): # export
@ -61,7 +61,7 @@ class SSHClientInternal(SSHClient): # export
def __scp(self):
return SCPClient(self.__ssh.get_transport())
def run_cmd(self, cmd: str):
async def run_cmd(self, cmd: str):
return self.__ssh.exec_command(find_cmd)
class SSHClientCmd(SSHClient): # export
@ -93,8 +93,9 @@ class SSHClientCmd(SSHClient): # export
self.__askpass_orig[key] = os.getenv(key)
os.environ[key] = val
def run_cmd(self, cmd: str):
async def run_cmd(self, cmd: str):
self.__init_askpass()
cmd_arr = ['ssh']
cmd_arr.append(self.hostname)
return run_cmd(['ssh', self.hostname, cmd])
stdout, stderr = await run_cmd('ssh', self.hostname, cmd)
return stdout