1717
1818from commit0 .harness .constants import Files
1919from commit0 .harness .spec import Spec
20- from commit0 .harness .utils import (
21- EvaluationError ,
22- )
2320from commit0 .harness .docker_build import (
2421 close_logger ,
2522)
3229)
3330
3431
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-
4332class ExecutionBackend (StrEnum ):
4433 LOCAL = auto ()
4534 MODAL = auto ()
@@ -54,6 +43,7 @@ def __init__(
5443 num_cpus : int ,
5544 log_dir : Path ,
5645 files_to_copy : Optional [Files ] = None ,
46+ files_to_collect : Optional [list [str ]] = None ,
5747 ):
5848 """Create the remote execution context
5949
@@ -65,25 +55,13 @@ def __init__(
6555 self .timeout = timeout
6656 self .num_cpus = num_cpus
6757 self .log_dir = log_dir
58+ self .files_to_collect = files_to_collect
6859
6960 @abstractmethod
7061 def exec_run_with_timeout (self , command : str ) -> tuple [str , bool , float ]:
7162 """Execute a test command"""
7263 raise NotImplementedError
7364
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-
8765 def __enter__ (self ):
8866 return self
8967
@@ -106,8 +84,17 @@ def __init__(
10684 num_cpus : int ,
10785 log_dir : Path ,
10886 files_to_copy : Optional [Files ] = None ,
87+ files_to_collect : Optional [list [str ]] = None ,
10988 ):
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+ )
11198
11299 self .client = docker .from_env ()
113100 self .container = create_container (
@@ -126,17 +113,16 @@ def exec_run_with_timeout(self, command: str) -> tuple[str, bool, float]:
126113 """Exec"""
127114 output = exec_run_with_timeout (self .container , command , self .timeout )
128115
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 )
140126 return output
141127
142128 def __exit__ (
@@ -158,8 +144,17 @@ def __init__(
158144 num_cpus : int ,
159145 log_dir : Path ,
160146 files_to_copy : Optional [Files ] = None ,
147+ files_to_collect : Optional [list [str ]] = None ,
161148 ):
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+ )
163158
164159 self .app = modal .App ()
165160
@@ -176,13 +171,18 @@ def exec_run_with_timeout(self, command: str) -> tuple[str, bool, float]:
176171 """Execute command on modal sandbox"""
177172 start_time = time .time ()
178173 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
182182 self .sandbox = modal .Sandbox .create (
183183 "bash" ,
184184 "-c" ,
185- f" { command } && cp { str ( report_file ) } /vol/report.json" ,
185+ command ,
186186 image = self .image ,
187187 cpu = self .num_cpus ,
188188 timeout = self .timeout ,
@@ -191,26 +191,22 @@ def exec_run_with_timeout(self, command: str) -> tuple[str, bool, float]:
191191 )
192192 self .sandbox .wait ()
193193
194- # stdout has been redirected to stderr
195- stdout = read_stream (self .sandbox .stderr )
196-
197194 return_code = self .sandbox .returncode
198195 # https://github.com/modal-labs/modal-client/blob/d577b2916b5c3bf4ebbcb58fadced84d85e1cf8c/modal/sandbox.py#L413
199196 if return_code == 124 :
200197 timed_out = True
201198 else :
202199 timed_out = False
203200
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 )
208206
209207 self .sandbox .terminate ()
210-
211208 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
214210
215211 def __exit__ (
216212 self ,
0 commit comments