File size: 1,515 Bytes
acf77ab
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
from __future__ import annotations

import os
import subprocess
import time
from typing import TYPE_CHECKING

from codeforge.sandbox.models import ToolResult

if TYPE_CHECKING:
    from pathlib import Path


def run_tool(
    name: str,
    argv: list[str],
    *,
    cwd: Path,
    timeout: float = 60.0,
    env_overrides: dict[str, str] | None = None,
) -> ToolResult:
    t0 = time.monotonic()
    timed_out = False
    stdout = ""
    stderr = ""
    exit_code = -1

    try:
        proc = subprocess.run(
            argv,
            cwd=str(cwd),
            capture_output=True,
            text=True,
            timeout=timeout,
            check=False,
            env=None if env_overrides is None else {**_os_env(), **env_overrides},
        )
        exit_code = proc.returncode
        stdout = proc.stdout
        stderr = proc.stderr
    except subprocess.TimeoutExpired as e:
        timed_out = True
        stdout = e.stdout.decode() if isinstance(e.stdout, bytes) else (e.stdout or "")
        stderr = e.stderr.decode() if isinstance(e.stderr, bytes) else (e.stderr or "")
    except (FileNotFoundError, OSError) as e:
        stderr = f"binary not found: {e}"

    duration_ms = int((time.monotonic() - t0) * 1000)
    return ToolResult(
        name=name,
        argv=tuple(argv),
        exit_code=exit_code,
        stdout=stdout,
        stderr=stderr,
        duration_ms=duration_ms,
        timed_out=timed_out,
    )


def _os_env() -> dict[str, str]:
    return dict(os.environ)