17
17
18
18
from commit0 .harness .constants import Files
19
19
from commit0 .harness .spec import Spec
20
- from commit0 .harness .utils import (
21
- EvaluationError ,
22
- )
23
20
from commit0 .harness .docker_build import (
24
21
close_logger ,
25
22
)
32
29
)
33
30
34
31
35
- def read_stream (stream : modal .io_streams .StreamReader ) -> str :
36
- """Read stream"""
37
- strings = []
38
- for line in stream :
39
- strings .append (line )
40
- return "\n " .join (strings )
41
-
42
-
43
32
class ExecutionBackend (StrEnum ):
44
33
LOCAL = auto ()
45
34
MODAL = auto ()
@@ -54,6 +43,7 @@ def __init__(
54
43
num_cpus : int ,
55
44
log_dir : Path ,
56
45
files_to_copy : Optional [Files ] = None ,
46
+ files_to_collect : Optional [list [str ]] = None ,
57
47
):
58
48
"""Create the remote execution context
59
49
@@ -65,25 +55,13 @@ def __init__(
65
55
self .timeout = timeout
66
56
self .num_cpus = num_cpus
67
57
self .log_dir = log_dir
58
+ self .files_to_collect = files_to_collect
68
59
69
60
@abstractmethod
70
61
def exec_run_with_timeout (self , command : str ) -> tuple [str , bool , float ]:
71
62
"""Execute a test command"""
72
63
raise NotImplementedError
73
64
74
- def write_test_output (self , test_output : str , timed_out : bool ) -> None :
75
- """Write test output"""
76
- test_output_path = self .log_dir / "test_output.txt"
77
- with open (test_output_path , "w" ) as f :
78
- f .write (test_output )
79
- if timed_out :
80
- f .write (f"\n \n Timeout error: { self .timeout } seconds exceeded." )
81
- raise EvaluationError (
82
- self .spec .repo ,
83
- f"Test timed out after { self .timeout } seconds." ,
84
- self .logger ,
85
- )
86
-
87
65
def __enter__ (self ):
88
66
return self
89
67
@@ -106,8 +84,17 @@ def __init__(
106
84
num_cpus : int ,
107
85
log_dir : Path ,
108
86
files_to_copy : Optional [Files ] = None ,
87
+ files_to_collect : Optional [list [str ]] = None ,
109
88
):
110
- super ().__init__ (spec , logger , timeout , num_cpus , log_dir )
89
+ super ().__init__ (
90
+ spec ,
91
+ logger ,
92
+ timeout ,
93
+ num_cpus ,
94
+ log_dir ,
95
+ files_to_copy = files_to_copy ,
96
+ files_to_collect = files_to_collect ,
97
+ )
111
98
112
99
self .client = docker .from_env ()
113
100
self .container = create_container (
@@ -126,17 +113,16 @@ def exec_run_with_timeout(self, command: str) -> tuple[str, bool, float]:
126
113
"""Exec"""
127
114
output = exec_run_with_timeout (self .container , command , self .timeout )
128
115
129
- # copy back report.json if there is any
130
- report_file = Path (self .spec .repo_directory ) / "report.json"
131
- # Run the test command inside the container to check if the file exists
132
- exit_code , test_output = self .container .exec_run (
133
- f"test -e { report_file } " , demux = True
134
- )
135
- # Check the exit code of the command
136
- if exit_code == 0 :
137
- copy_from_container (
138
- self .container , report_file , self .log_dir / "report.json"
139
- )
116
+ if self .files_to_collect :
117
+ for fname in self .files_to_collect :
118
+ file = Path (self .spec .repo_directory ) / fname
119
+ # Run the test command inside the container to check if the file exists
120
+ exit_code , test_output = self .container .exec_run (
121
+ f"test -e { file } " , demux = True
122
+ )
123
+ # Check the exit code of the command
124
+ if exit_code == 0 :
125
+ copy_from_container (self .container , file , self .log_dir / fname )
140
126
return output
141
127
142
128
def __exit__ (
@@ -158,8 +144,17 @@ def __init__(
158
144
num_cpus : int ,
159
145
log_dir : Path ,
160
146
files_to_copy : Optional [Files ] = None ,
147
+ files_to_collect : Optional [list [str ]] = None ,
161
148
):
162
- super ().__init__ (spec , logger , timeout , num_cpus , log_dir )
149
+ super ().__init__ (
150
+ spec ,
151
+ logger ,
152
+ timeout ,
153
+ num_cpus ,
154
+ log_dir ,
155
+ files_to_copy = files_to_copy ,
156
+ files_to_collect = files_to_collect ,
157
+ )
163
158
164
159
self .app = modal .App ()
165
160
@@ -176,13 +171,18 @@ def exec_run_with_timeout(self, command: str) -> tuple[str, bool, float]:
176
171
"""Execute command on modal sandbox"""
177
172
start_time = time .time ()
178
173
with modal .Volume .ephemeral () as vol :
179
- # copy back report.json if there is any
180
- report_file = Path (self .spec .repo_directory ) / "report.json"
181
-
174
+ cp_cmd = ""
175
+ if self .files_to_collect :
176
+ for fname in self .files_to_collect :
177
+ remote_file = Path (self .spec .repo_directory ) / fname
178
+ curr_cp_cmd = f" && cp { str (remote_file )} /vol/{ fname } 2>/dev/null"
179
+ cp_cmd += curr_cp_cmd
180
+
181
+ command += cp_cmd
182
182
self .sandbox = modal .Sandbox .create (
183
183
"bash" ,
184
184
"-c" ,
185
- f" { command } && cp { str ( report_file ) } /vol/report.json" ,
185
+ command ,
186
186
image = self .image ,
187
187
cpu = self .num_cpus ,
188
188
timeout = self .timeout ,
@@ -191,26 +191,22 @@ def exec_run_with_timeout(self, command: str) -> tuple[str, bool, float]:
191
191
)
192
192
self .sandbox .wait ()
193
193
194
- # stdout has been redirected to stderr
195
- stdout = read_stream (self .sandbox .stderr )
196
-
197
194
return_code = self .sandbox .returncode
198
195
# https://github.com/modal-labs/modal-client/blob/d577b2916b5c3bf4ebbcb58fadced84d85e1cf8c/modal/sandbox.py#L413
199
196
if return_code == 124 :
200
197
timed_out = True
201
198
else :
202
199
timed_out = False
203
200
204
- # copy over report.json from mount
205
- with (self .log_dir / "report.json" ).open ("wb" ) as f :
206
- for data in vol .read_file ("report.json" ):
207
- f .write (data )
201
+ if self .files_to_collect :
202
+ for fname in self .files_to_collect :
203
+ with (self .log_dir / fname ).open ("wb" ) as f :
204
+ for data in vol .read_file (fname ):
205
+ f .write (data )
208
206
209
207
self .sandbox .terminate ()
210
-
211
208
end_time = time .time ()
212
-
213
- return stdout , timed_out , end_time - start_time
209
+ return self .sandbox .stderr .read (), timed_out , end_time - start_time
214
210
215
211
def __exit__ (
216
212
self ,
0 commit comments