From 1214451c15d27ed50e7f6f27a5e67d72b1191676 Mon Sep 17 00:00:00 2001 From: Jan Lindemann Date: Wed, 15 Apr 2026 21:00:58 +0200 Subject: [PATCH] lib.ExecContext.close(): Add method Add ExecContext.close() as a hook to clean up async resources living longer than an ExecContext method call. Also, implement __aenter__() and __aexit__(), to allow using ExecContext as context manager. close() is invoked it goes out of scope. Signed-off-by: Jan Lindemann --- .../jw/pkg/cmds/projects/CmdListRepos.py | 27 ++++++++++++------- src/python/jw/pkg/lib/ExecContext.py | 12 +++++++++ 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/python/jw/pkg/cmds/projects/CmdListRepos.py b/src/python/jw/pkg/cmds/projects/CmdListRepos.py index 44dbed4f..e71d9528 100644 --- a/src/python/jw/pkg/cmds/projects/CmdListRepos.py +++ b/src/python/jw/pkg/cmds/projects/CmdListRepos.py @@ -32,16 +32,23 @@ class CmdListRepos(Cmd): # export match url.scheme: case 'ssh': if re.match(r'ssh://.*git\.janware\.com/', args.base_url): - from jw.pkg.lib.ec.SSHClient import ssh_client - ssh = ssh_client(args.base_url, interactive=self.app.interactive, verbose_default=self.app.verbose) - if username is not None: - ssh.set_username(username) - if password is not None: - ssh.set_password(password) - cmd = ['/opt/jw-pkg/bin/git-srv-admin.sh', '-u', args.from_owner, '-j', 'list-personal-projects'] - result = await ssh.run(cmd) - print('\n'.join(result.stdout.decode().splitlines())) - return + from jw.pkg.lib.ec.SSHClient import SSHClient, ssh_client + ssh: SSHClient|None = None + try: + ssh = ssh_client(args.base_url, interactive=self.app.interactive, verbose_default=self.app.verbose) + if username is not None: + ssh.set_username(username) + if password is not None: + ssh.set_password(password) + cmd = ['/opt/jw-pkg/bin/git-srv-admin.sh', '-u', args.from_owner, '-j', 'list-personal-projects'] + result = await ssh.run(cmd) + print('\n'.join(result.stdout.decode().splitlines())) + return + except: + raise + finally: + if ssh is not None: + ssh.close() case 'https': from jw.pkg.lib.ExecContext import InputMode cmd_input = InputMode.NonInteractive diff --git a/src/python/jw/pkg/lib/ExecContext.py b/src/python/jw/pkg/lib/ExecContext.py index ebbf0f16..ba5b6a93 100644 --- a/src/python/jw/pkg/lib/ExecContext.py +++ b/src/python/jw/pkg/lib/ExecContext.py @@ -171,6 +171,12 @@ class ExecContext(abc.ABC): self.__verbose_default = verbose_default assert verbose_default is not None + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + await self.close() + @property def uri(self) -> str: return self.__uri @@ -402,6 +408,12 @@ class ExecContext(abc.ABC): return await self._put(content, path, wd=wd, throw=throw, verbose=verbose, title=title, owner=owner, group=group, mode=mode) + async def _close(self) -> None: + pass + + async def close(self) -> None: + await self._close() + @classmethod def create(cls, uri: str, *args, **kwargs) -> Self: tokens = re.split(r'://', uri)