diff --git a/docker_agent_sandbox/sandbox.py b/docker_agent_sandbox/sandbox.py index 60a3ab3..014ca64 100644 --- a/docker_agent_sandbox/sandbox.py +++ b/docker_agent_sandbox/sandbox.py @@ -248,53 +248,28 @@ class DockerSandbox: # ------------------------------------------------------------------ def exec(self, command: str, timeout: int = 120, kill_grace: int = 5) -> tuple[int, str]: - """ - Run *command* inside the container via the low-level exec API. - - Returns ``(exit_code, combined_stdout_stderr)``. - - Exit code 124 indicates a timeout (137 if escalation to SIGKILL was - needed). *command* is passed as a single argv element to ``bash -c``, - so shell metacharacters within it need no extra escaping. - """ if self._container is None: return 1, "Sandbox container is not running." - create_kwargs: dict = {} - if self._working_dir is not None: - create_kwargs["workdir"] = self._working_dir - wrapped = [ - "timeout", - "--kill-after", - f"{kill_grace}s", - f"{timeout}s", - "bash", - "-c", - command, + "timeout", "--kill-after", f"{kill_grace}s", f"{timeout}s", + "bash", "-c", command, ] + kwargs = {} + if self._working_dir is not None: + kwargs["workdir"] = self._working_dir try: - exec_id = self._client.api.exec_create( - self._container.id, + exit_code, output = self._container.exec_run( wrapped, stdout=True, stderr=True, - **create_kwargs, + demux=False, + **kwargs, ) - sock = self._client.api.exec_start(exec_id["Id"], socket=True) - - gen = (demux_adaptor(*frame) for frame in frames_iter(sock, tty=False)) - stdout, stderr = consume_socket_output(gen, demux=True) - - exit_code = self._client.api.exec_inspect(exec_id["Id"])["ExitCode"] - if exit_code is None: - exit_code = 0 - - output = ((stdout or b"") + (stderr or b"")).decode("utf-8", errors="replace") - + text = (output or b"").decode("utf-8", errors="replace") if exit_code in (124, 137): - return exit_code, output + f"\n[command timed out after {timeout}s]" - return exit_code, output + return exit_code, text + f"\n[command timed out after {timeout}s]" + return exit_code, text except Exception as exc: return 1, f"Error running command in container: {exc}"