7
7
import time
8
8
import psutil
9
9
import glob
10
+ import shutil
10
11
from io import StringIO
11
12
from typing import Dict
12
13
@@ -438,7 +439,7 @@ def check_output(self, name, input_file, output_file_path, output, answer_file_p
438
439
return self .check_output_checker (name , input_file , output_file_path , answer_file_path )
439
440
440
441
def execute_oiejq (self , name , timetool_path , executable , result_file_path , input_file_path , output_file_path , answer_file_path ,
441
- time_limit , memory_limit , hard_time_limit ):
442
+ time_limit , memory_limit , hard_time_limit , execution_dir ):
442
443
command = f'"{ timetool_path } " "{ executable } "'
443
444
env = os .environ .copy ()
444
445
env ["MEM_LIMIT" ] = f'{ memory_limit } K'
@@ -449,7 +450,7 @@ def execute_oiejq(self, name, timetool_path, executable, result_file_path, input
449
450
with open (input_file_path , "r" ) as input_file , open (output_file_path , "w" ) as output_file , \
450
451
open (result_file_path , "w" ) as result_file :
451
452
process = subprocess .Popen (command , shell = True , stdin = input_file , stdout = output_file ,
452
- stderr = result_file , env = env , preexec_fn = os .setsid )
453
+ stderr = result_file , env = env , preexec_fn = os .setsid , cwd = execution_dir )
453
454
454
455
def sigint_handler (signum , frame ):
455
456
try :
@@ -518,7 +519,7 @@ def sigint_handler(signum, frame):
518
519
519
520
520
521
def execute_time (self , name , executable , result_file_path , input_file_path , output_file_path , answer_file_path ,
521
- time_limit , memory_limit , hard_time_limit ):
522
+ time_limit , memory_limit , hard_time_limit , execution_dir ):
522
523
if sys .platform == 'darwin' :
523
524
time_name = 'gtime'
524
525
elif sys .platform == 'linux' :
@@ -531,7 +532,7 @@ def execute_time(self, name, executable, result_file_path, input_file_path, outp
531
532
mem_limit_exceeded = False
532
533
with open (input_file_path , "r" ) as input_file , open (output_file_path , "w" ) as output_file :
533
534
process = subprocess .Popen (command , stdin = input_file , stdout = output_file , stderr = subprocess .DEVNULL ,
534
- preexec_fn = os .setsid )
535
+ preexec_fn = os .setsid , cwd = execution_dir )
535
536
536
537
def sigint_handler (signum , frame ):
537
538
try :
@@ -596,7 +597,7 @@ def sigint_handler(signum, frame):
596
597
program_exit_code = int (lines [0 ].strip ().split (" " )[- 1 ])
597
598
elif not mem_limit_exceeded :
598
599
result .Status = Status .RE
599
- result .Error = "Unexpected output from time command: " + "\n " .join (lines )
600
+ result .Error = "Unexpected output from time command: " + "" .join (lines )
600
601
return result
601
602
602
603
if program_exit_code is not None and program_exit_code != 0 :
@@ -630,20 +631,20 @@ def run_solution(self, data_for_execution: ExecutionData):
630
631
Run an execution and return the result as ExecutionResult object.
631
632
"""
632
633
633
- (name , executable , test , time_limit , memory_limit , timetool_path ) = data_for_execution
634
+ (name , executable , test , time_limit , memory_limit , timetool_path , execution_dir ) = data_for_execution
634
635
file_no_ext = paths .get_executions_path (name , package_util .extract_test_id (test , self .ID ))
635
636
output_file = file_no_ext + ".out"
636
637
result_file = file_no_ext + ".res"
637
638
hard_time_limit_in_s = math .ceil (2 * time_limit / 1000.0 )
638
639
639
640
if self .timetool_name == 'oiejq' :
640
641
return self .execute_oiejq (name , timetool_path , executable , result_file , test , output_file , self .get_output_file (test ),
641
- time_limit , memory_limit , hard_time_limit_in_s )
642
+ time_limit , memory_limit , hard_time_limit_in_s , execution_dir )
642
643
elif self .timetool_name == 'time' :
643
644
return self .execute_time (name , executable , result_file , test , output_file , self .get_output_file (test ),
644
- time_limit , memory_limit , hard_time_limit_in_s )
645
+ time_limit , memory_limit , hard_time_limit_in_s , execution_dir )
645
646
646
- def run_solutions (self , compiled_commands , names , solutions ):
647
+ def run_solutions (self , compiled_commands , names , solutions , executables_dir ):
647
648
"""
648
649
Run solutions on tests and print the results as a table to stdout.
649
650
"""
@@ -653,6 +654,13 @@ def run_solutions(self, compiled_commands, names, solutions):
653
654
all_results = collections .defaultdict (
654
655
lambda : collections .defaultdict (lambda : collections .defaultdict (map )))
655
656
657
+ for lang , files in self .config .get ('extra_execution_files' , {}).items ():
658
+ for file in files :
659
+ shutil .copy (os .path .join (os .getcwd (), "prog" , file ), executables_dir )
660
+ # Copy swig generated .so files
661
+ for file in glob .glob (os .path .join (os .getcwd (), "prog" , f"_{ self .ID } lib.so" )):
662
+ shutil .copy (file , executables_dir )
663
+
656
664
for (name , executable , result ) in compiled_commands :
657
665
lang = package_util .get_file_lang (name )
658
666
solution_cache = cache .get_cache_file (os .path .join (os .getcwd (), "prog" , name ))
@@ -670,7 +678,7 @@ def run_solutions(self, compiled_commands, names, solutions):
670
678
all_results [name ][self .get_group (test )][test ] = test_result .result
671
679
else :
672
680
executions .append ((name , executable , test , test_time_limit , test_memory_limit ,
673
- self .timetool_path ))
681
+ self .timetool_path , os . path . dirname ( executable ) ))
674
682
all_results [name ][self .get_group (test )][test ] = ExecutionResult (Status .PENDING )
675
683
os .makedirs (paths .get_executions_path (name ), exist_ok = True )
676
684
else :
@@ -743,7 +751,7 @@ def compile_and_run(self, solutions):
743
751
executables = [paths .get_executables_path (package_util .get_executable (solution )) for solution in solutions ]
744
752
compiled_commands = zip (solutions , executables , compilation_results )
745
753
names = solutions
746
- return self .run_solutions (compiled_commands , names , solutions )
754
+ return self .run_solutions (compiled_commands , names , solutions , paths . get_executables_path () )
747
755
748
756
def convert_status_to_string (self , dictionary ):
749
757
"""
@@ -1196,7 +1204,8 @@ def run(self, args):
1196
1204
title = self .config ["title" ]
1197
1205
print ("Task: %s (tag: %s)" % (title , self .ID ))
1198
1206
self .cpus = args .cpus or util .default_cpu_count ()
1199
- cache .save_to_cache_extra_compilation_files (self .config .get ("extra_compilation_files" , []), self .ID )
1207
+ cache .process_extra_compilation_files (self .config .get ("extra_compilation_files" , []), self .ID )
1208
+ cache .process_extra_execution_files (self .config .get ("extra_execution_files" , {}), self .ID )
1200
1209
cache .remove_results_if_contest_type_changed (self .config .get ("sinol_contest_type" , "default" ))
1201
1210
1202
1211
checker = package_util .get_files_matching_pattern (self .ID , f'{ self .ID } chk.*' )
0 commit comments