Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion src/agent_env/env/envs/computer/utils/resolve_in_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,18 @@ def _wheels(layer: dict, dest: Path) -> list[str]:
return sorted(path.name for path in dest.glob("*.whl"))


def cli(argv: list[str]) -> None:
"""``main`` on ``argv``. A command that fails ends it with that command's exit code and no traceback, so the last
line of the output, which the composer reports as the reason, is the command's own error (apt's ``E:`` line); one
whose output was captured has it printed first."""
try:
main(*argv)
except subprocess.CalledProcessError as e:
captured = e.stderr or e.stdout
if captured:
sys.stderr.write(captured if isinstance(captured, str) else captured.decode(errors="replace"))
sys.exit(e.returncode)
Comment thread
greptile-apps[bot] marked this conversation as resolved.
Resolved


if __name__ == "__main__":
main(*sys.argv[1:])
cli(sys.argv[1:])
29 changes: 29 additions & 0 deletions tst/unit/env/envs/test_computer_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import logging
import re
import shutil
import subprocess
import urllib.parse
from datetime import timedelta
from pathlib import Path
Expand Down Expand Up @@ -2046,6 +2047,34 @@ def _local(work, context):
return builder.LocalBuilder("LocalSandboxProvider", work, base, "linux/arm64")


def test_a_command_the_resolver_runs_that_fails_ends_it_with_the_commands_code_and_no_traceback(monkeypatch, capsys):
"""The composer reports the output's last line as the reason: it must be the command's error, apt's ``E:`` line,
not a traceback naming the command."""
def fail(*_args):
raise subprocess.CalledProcessError(100, ["apt-get", "install"])

monkeypatch.setattr(resolve_in_base, "main", fail)

with pytest.raises(SystemExit) as exited:
resolve_in_base.cli(["request.json", "out"])

assert exited.value.code == 100
assert capsys.readouterr().err == ""


def test_a_captured_command_that_fails_has_its_error_printed_last(monkeypatch, capsys):
def fail(*_args):
raise subprocess.CalledProcessError(2, ["dpkg-deb", "-f"], stderr="dpkg-deb: error: not a Debian archive\n")

monkeypatch.setattr(resolve_in_base, "main", fail)

with pytest.raises(SystemExit) as exited:
resolve_in_base.cli(["request.json", "out"])

assert exited.value.code == 2
assert capsys.readouterr().err.strip().splitlines()[-1] == "dpkg-deb: error: not a Debian archive"


def test_the_resolver_installs_the_apt_packages_it_downloads_before_building_wheels(tmp_path, monkeypatch):
ran = []
monkeypatch.setattr(resolve_in_base, "KEYRINGS", tmp_path / "keyrings")
Expand Down
Loading