From 284eb30ecf5c2baf4d74091a29ddbeda03808e08 Mon Sep 17 00:00:00 2001 From: Jan Lindemann Date: Wed, 18 Mar 2026 05:52:42 +0100 Subject: [PATCH] lib.SSHClient: Derive from ExecContext Make SSHClient an ExecContext by implementing _run() and _sudo(). Signed-off-by: Jan Lindemann --- src/python/jw/pkg/lib/SSHClient.py | 40 ++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/src/python/jw/pkg/lib/SSHClient.py b/src/python/jw/pkg/lib/SSHClient.py index afa45237..e55e39f2 100644 --- a/src/python/jw/pkg/lib/SSHClient.py +++ b/src/python/jw/pkg/lib/SSHClient.py @@ -6,11 +6,12 @@ import os, abc, shlex, sys from .util import run_cmd from .log import * -from .ExecContext import Result +from .ExecContext import ExecContext, Result -class SSHClient(abc.ABC): +class SSHClient(ExecContext): def __init__(self, hostname: str) -> None: + super().__init__(interactive=False, verbose_default=False) self.___ssh = None self.__hostname = hostname self.__password: str|None = None @@ -37,16 +38,26 @@ class SSHClient(abc.ABC): async def _run_cmd(self, cmd: list[str]) -> Result: pass - async def run_cmd( + async def run_cmd(self, *args, **kwargs) -> Result: + kwargs.setdefault('wd', None) + kwargs.setdefault('throw', True) + kwargs.setdefault('verbose', False) + kwargs.setdefault('cmd_input', None) + kwargs.setdefault('env', None) + kwargs.setdefault('title', None) + kwargs.setdefault('output_encoding', None) + return await self._run(*args, **kwargs) + + async def _run( self, args: list[str], - wd: str|None = None, - throw: bool = True, - verbose: bool = False, - cmd_input: str|None = None, - env: dict[str, str]|None = None, - title: str=None, - output_encoding: str|None = None, # None => unchanged; "bytes" => return raw bytes + wd: str|None, + throw: bool, + verbose: bool, + cmd_input: str|None, + env: dict[str, str]|None, + title: str, + output_encoding: str|None, # None => unchanged; "bytes" => return raw bytes ) -> Result: if wd is not None: @@ -81,6 +92,13 @@ class SSHClient(abc.ABC): return stdout_s, stderr_s, status + async def _sudo(self, cmd: list[str], mod_env: dict[str, str], opts: list[str], *args, **kwargs) -> Result: + if self.username != 'root': + cmd = ['sudo', *opts, *cmd] + if mod_env: + log(WARNING, f'Modifying environment over SSH is not implemented, ignored') + return await self._run(cmd, *args, **kwargs) + class SSHClientInternal(SSHClient): # export def __init__(self, hostname: str) -> None: @@ -114,7 +132,7 @@ class SSHClientInternal(SSHClient): # export if cmd_input is not None: stdin.write(cmd_input) exit_status = stdout.channel.recv_exit_status() - return stdout.read(), stderr.read(), exit_status + return Result(stdout.read(), stderr.read(), exit_status) class SSHClientCmd(SSHClient): # export