From f04d7fc0f42bd78f0dfa9f28f61b2d446f55102d Mon Sep 17 00:00:00 2001 From: ChrisTimperley Date: Sat, 12 Oct 2019 19:24:14 -0400 Subject: [PATCH 1/5] added CompletedProcess class --- src/dockerblade/shell.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/dockerblade/shell.py b/src/dockerblade/shell.py index efdb9a5..9bfd38f 100644 --- a/src/dockerblade/shell.py +++ b/src/dockerblade/shell.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- -__all__ = ('Shell', 'ShellFactory') +__all__ = ('Shell', 'ShellFactory', 'CompletedProcess') -from typing import Tuple, Optional +from typing import Tuple, Optional, Generic, TypeVar import shlex from loguru import logger @@ -11,6 +11,26 @@ from .stopwatch import Stopwatch +T = TypeVar('T', str, bytes) + + +@attr.s(slots=True, auto_attribs=True) +class CompletedProcess(Generic[T]): + """Stores the result of a completed process. + + Attributes + ---------- + args: str + The arguments that were used to launch the process. + returncode: int + The returncode that was produced by the process. + output: T, optional + The output, if any, that was produced by the process. + """ + args: str + returncode: int + output: Optional[T] + @attr.s(eq=False, hash=False) class Shell: From 0c47a449e9c4ddfaf2be9ca06006ea0fc80251ab Mon Sep 17 00:00:00 2001 From: ChrisTimperley Date: Sat, 12 Oct 2019 19:24:25 -0400 Subject: [PATCH 2/5] freeze --- src/dockerblade/shell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dockerblade/shell.py b/src/dockerblade/shell.py index 9bfd38f..52d3a03 100644 --- a/src/dockerblade/shell.py +++ b/src/dockerblade/shell.py @@ -14,7 +14,7 @@ T = TypeVar('T', str, bytes) -@attr.s(slots=True, auto_attribs=True) +@attr.s(slots=True, auto_attribs=True, frozen=True) class CompletedProcess(Generic[T]): """Stores the result of a completed process. From 3cf8f6b968e42208f341883600c881c67a36d944 Mon Sep 17 00:00:00 2001 From: ChrisTimperley Date: Sat, 12 Oct 2019 19:29:25 -0400 Subject: [PATCH 3/5] updated execute to run --- src/dockerblade/shell.py | 37 +++++++++++++++++++------------------ test/test_shell.py | 6 +++--- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/dockerblade/shell.py b/src/dockerblade/shell.py index 52d3a03..b4a15f7 100644 --- a/src/dockerblade/shell.py +++ b/src/dockerblade/shell.py @@ -24,11 +24,14 @@ class CompletedProcess(Generic[T]): The arguments that were used to launch the process. returncode: int The returncode that was produced by the process. + duration: float + The number of seconds taken to complete the process. output: T, optional The output, if any, that was produced by the process. """ args: str returncode: int + duration: float output: Optional[T] @@ -78,36 +81,34 @@ def environ(self, var: str) -> str: """ raise NotImplementedError - def execute(self, - command: str, - *, - context: str = '/' - ) -> Tuple[int, str, float]: + def run(self, + args: str, + *, + context: str = '/' + ) -> CompletedProcess: """Executes a given command and blocks until its completion. Returns ------- - Tuple[int, str, float] - The return code, output, and wall-clock running time of the - execution, measured in seconds. + CompletedProcess + A summary of the outcome of the command execution. """ - logger.debug(f"executing command: {command}") + logger.debug(f"executing command: {args}") container = self._container - command_instrumented = self._instrument(command) + args_instrumented = self._instrument(args) with Stopwatch() as timer: retcode, output = container.exec_run( - command_instrumented, + args_instrumented, workdir=context) - duration = timer.duration output = output.decode('utf-8').rstrip('\n') - logger.debug("executed command [{command}] " - "(retcode: {retcode}; time: {time:.3f} s)" - "\n{output}", - command=command, retcode=retcode, time=duration, - output=output) - return retcode, output, duration + result = CompletedProcess(args=args, + returncode=retcode, + duration=timer.duration, + output=output) + logger.debug(f"executed command: {result}") + return result @attr.s(slots=True, frozen=True) diff --git a/test/test_shell.py b/test/test_shell.py index ce0275f..2878913 100644 --- a/test/test_shell.py +++ b/test/test_shell.py @@ -26,6 +26,6 @@ def shell_factory(): def test_hello_world(alpine_310, shell_factory): shell = shell_factory.build(alpine_310.id, '/bin/sh') - retcode, output, duration = shell.execute("echo 'hello world'") - assert retcode == 0 - assert output == 'hello world' + result = shell.run("echo 'hello world'") + assert result.returncode == 0 + assert result.output == 'hello world' From f44c5da034fa047ac56d9d40529a5b05c26f0020 Mon Sep 17 00:00:00 2001 From: ChrisTimperley Date: Sat, 12 Oct 2019 19:30:51 -0400 Subject: [PATCH 4/5] added import --- src/dockerblade/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dockerblade/__init__.py b/src/dockerblade/__init__.py index eef75dd..a144c8d 100644 --- a/src/dockerblade/__init__.py +++ b/src/dockerblade/__init__.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- from . import exceptions from .files import FileSystem -from .shell import Shell, ShellFactory +from .shell import Shell, ShellFactory, CompletedProcess from .stopwatch import Stopwatch From 5bb70afd0b9ea6887cdcc338ec6680dd274d8b45 Mon Sep 17 00:00:00 2001 From: ChrisTimperley Date: Sat, 12 Oct 2019 19:33:12 -0400 Subject: [PATCH 5/5] removed slots=True as Python 3.6 workaround: https://github.com/python-attrs/attrs/issues/313 --- src/dockerblade/shell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dockerblade/shell.py b/src/dockerblade/shell.py index b4a15f7..ab8c51e 100644 --- a/src/dockerblade/shell.py +++ b/src/dockerblade/shell.py @@ -14,7 +14,7 @@ T = TypeVar('T', str, bytes) -@attr.s(slots=True, auto_attribs=True, frozen=True) +@attr.s(auto_attribs=True, frozen=True) class CompletedProcess(Generic[T]): """Stores the result of a completed process.