Description:
add python support we compile it into bytecode before run (see 'judge' and 'run')
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r154:3e585749d18c - - 3 files changed: 34 inserted, 13 deleted

@@ -6,54 +6,57
6 6 #
7 7 # Standard Compile Script
8 8 #
9 9 # Supported compilers:
10 10 # gcc, g++, and fpc.
11 11 #
12 12 ##############################
13 13
14 14 def talk(str='')
15 15 if ENV['TALKATIVE']!=nil
16 16 puts str
17 17 end
18 18 if ENV['GRADER_LOGGING']!=nil
19 19 log_fname = ENV['GRADER_LOGGING']
20 20 fp = File.open(log_fname,"a")
21 21 fp.puts("run: #{Time.new.strftime("%H:%M")} #{str}")
22 22 fp.close
23 23 end
24 24 end
25 25
26 26 C_COMPILER = "/usr/bin/gcc"
27 27 CPLUSPLUS_COMPILER = "/usr/bin/g++"
28 28 PASCAL_COMPILER = "/usr/bin/fpc"
29 29 JAVA_COMPILER = "/usr/bin/javac"
30 - RUBY_INTEPRETER = "/home/dae/.rvm/rubies/ruby-1.9.2-p320/bin/ruby"
30 + RUBY_INTERPRETER = "/home/dae/.rvm/rubies/ruby-1.9.2-p320/bin/ruby"
31 + PYTHON_INTERPRETER = "/usr/bin/python"
32 + PYTHON_CHECKER = "/usr/bin/pyflakes"
31 33
32 34 C_OPTIONS = "-O2 -s -static -std=c99 -DCONTEST -lm -Wall"
33 35 CPLUSPLUS_OPTIONS = "-O2 -s -static -DCONTEST -lm -Wall"
34 36 PASCAL_OPTIONS = "-O1 -XS -dCONTEST"
35 37 JAVA_OPTIONS = ""
38 + PYTHON_OPTIONS = ""
36 39
37 40 # Check for the correct number of arguments. Otherwise, print usage.
38 41 if ARGV.length == 0 or ARGV.length > 4
39 42 puts "Usage: compile <language> [<source-file>] [<output-file>] [<message-file>]"
40 43 puts
41 44 puts "<source-file> is defaulted to \"source\"."
42 45 puts "<output-file> is defaulted to \"a.out\"."
43 46 puts "<message-file> is defaulted to \"compiler_message\"."
44 47 puts
45 48 exit(127)
46 49 end
47 50
48 51 PARAMS = {
49 52 :source_file => [1,'source'],
50 53 :output_file => [2,'a.out'],
51 54 :message_file => [3,'compiler_message']
52 55 }
53 56
54 57 params = {}
55 58 params[:prog_lang] = ARGV[0]
56 59 PARAMS.each_key do |param_name|
57 60 index, default = PARAMS[param_name]
58 61 if ARGV.length > index
59 62 params[param_name] = ARGV[index]
@@ -66,79 +69,94
66 69 # Remove any remaining output files or message files.
67 70 if FileTest.exists? params[:output_file]
68 71 FileUtils.rm(params[:output_file])
69 72 end
70 73 if FileTest.exists? params[:message_file]
71 74 FileUtils.rm(params[:message_file])
72 75 end
73 76
74 77 # Check if the source file exists before attempt compiling.
75 78 if !FileTest.exists? params[:source_file]
76 79 talk("ERROR: The source file does not exist!")
77 80 open(params[:message_file],"w") do |f|
78 81 f.puts "ERROR: The source file did not exist."
79 82 end
80 83 exit(127)
81 84 end
82 85
83 86 if params[:prog_lang]=='cpp'
84 87 params[:prog_lang] = 'c++'
85 88 end
86 89
87 90 # Compile.
88 91 case params[:prog_lang]
89 92
90 - when "c"
93 + when "c"
91 94 command = "#{C_COMPILER} #{params[:source_file]} -o #{params[:output_file]} #{C_OPTIONS} 2> #{params[:message_file]}"
92 95 system(command)
93 96
94 - when "c++"
97 + when "c++"
95 98 command = "#{CPLUSPLUS_COMPILER} #{params[:source_file]} -o #{params[:output_file]} #{CPLUSPLUS_OPTIONS} 2> #{params[:message_file]}"
96 99 system(command)
97 100
98 - when "pas"
101 + when "pas"
99 102 command = "#{PASCAL_COMPILER} #{params[:source_file]} -ooutpas #{PASCAL_OPTIONS} > #{params[:message_file]}"
100 103 system(command)
101 104 FileUtils.mv("output", params[:output_file])
102 105
103 - when "java"
106 + when "java"
104 107 #rename the file to the public class name
105 108
106 109 #get the class name
107 110 classname = 'DUMMY'
108 111 File.foreach(params[:source_file]) do |line|
109 112 md = /\s*public\s*class\s*(\w*)/.match(line)
110 113 classname=md[1] if md
111 114 end
112 115 system("cp #{params[:source_file]} #{classname}.java")
113 116 command = "#{JAVA_COMPILER} #{classname}.java 2> #{params[:message_file]}"
114 117 system(command)
115 118 if File.exists?(classname + ".class")
116 119 File.open(params[:output_file],"w") {|file| file.write("#!/bin/sh\n/usr/bin/java #{classname}\n")}
117 120 File.chmod(0755, params[:output_file])
118 121 end
119 122
120 - when "ruby"
121 - command = "#{RUBY_INTEPRETER} -c #{params[:source_file]} > #{params[:message_file]}"
123 + when "ruby"
124 + command = "#{RUBY_INTERPRETER} -c #{params[:source_file]} > #{params[:message_file]}"
122 125 system(command)
123 126 File.open(params[:output_file],"w") do |out_file|
124 - out_file.puts "#!#{RUBY_INTEPRETER}"
127 + out_file.puts "#!#{RUBY_INTERPRETER}"
125 128 File.open(params[:source_file],"r").each do |line|
126 129 out_file.print line
127 130 end
128 131 end
129 132 File.chmod(0755, params[:output_file])
133 +
134 + when "python"
135 + command = "#{PYTHON_CHECKER} #{params[:source_file]} > #{params[:message_file]}"
136 + if system(command)
137 + #compile to python bytecode
138 + command = "#{PYTHON_INTERPRETER} -m py_compile #{params[:source_file]}"
139 + puts "compile: #{command}"
140 + system(command)
141 + puts "pwd: " + Dir.pwd
142 + Dir.new('.').each {|file| puts file}
143 + File.open(params[:output_file],"w") do |out_file|
144 + out_file.puts "#!#{PYTHON_INTERPRETER} #{params[:source_file]}c"
145 + end
146 + File.chmod(0755, params[:output_file])
147 + end
130 148
131 - else
149 + else
132 150 talk("ERROR: Invalid language specified!")
133 151 open(params[:message_file],"w") do |f|
134 152 f.puts "ERROR: Invalid language specified!"
135 153 end
136 154 exit(127)
137 155 end
138 156
139 157 # Report success or failure.
140 158 if FileTest.exists? params[:output_file]
141 159 talk "Compilation was successful!"
142 160 else
143 161 talk "ERROR: Something was wrong during the compilation!"
144 162 end
@@ -32,49 +32,49
32 32 log msg
33 33 raise msg
34 34 end
35 35 end
36 36
37 37 def clear_and_create_empty_dir(dir)
38 38 FileUtils.rm_rf(dir, :secure => true)
39 39 call_and_log("Cannot make directory #{dir}.") { FileUtils.mkdir(dir) }
40 40 end
41 41
42 42 # ARGV[0] --- language
43 43 # ARGV[1] --- program source file
44 44 # ARGV[2] --- test result directory
45 45 # ARGV[3] --- sandbox directory
46 46
47 47 if ARGV.length < 2 || ARGV.length > 4
48 48 puts "Usage: judge <language> <program-source> [<test-result-directory>] [<sandbox-directory>]"
49 49 puts " <sandbox-directory> is defaulted to ./sandbox"
50 50 puts " <test-result-directory> is defaulted to ./test-result"
51 51 puts "WARNING: The judge script will forcefully create the (implicitly and explicitly) specified directories and remove anything inside it."
52 52 exit(127)
53 53 end
54 54
55 55 language = ARGV[0]
56 - if language != "c" && language != "c++" && language != "pas" && language != "java" && language != "ruby"
56 + if language != "c" && language != "c++" && language != "pas" && language != "java" && language != "ruby" && language != "python"
57 57 log "You specified a language that is not supported: #{language}."
58 58 exit(127)
59 59 end
60 60
61 61 source_file = ARGV[1]
62 62 if File.exist?(source_file) == false
63 63 log "The source file does not exist."
64 64 exit(127)
65 65 end
66 66
67 67 log "Making test result and sandbox directories..."
68 68
69 69 current_dir = FileUtils.pwd
70 70 current_dir.strip!
71 71
72 72 if ARGV.length >= 3
73 73 test_result_dir = ARGV[2]
74 74 else
75 75 test_result_dir = "#{current_dir}/test-result"
76 76 end
77 77
78 78 log "Test result directory: #{test_result_dir}"
79 79 clear_and_create_empty_dir(test_result_dir)
80 80
@@ -90,72 +90,74
90 90 log
91 91 log "Compiling..."
92 92 call_and_log("Cannot copy the source file to #{sandbox_dir}") {
93 93 FileUtils.cp(source_file, sandbox_dir)
94 94 }
95 95 begin
96 96 Dir.chdir sandbox_dir
97 97 rescue
98 98 log "ERROR: Cannot change directory to #{sandbox_dir}."
99 99 exit(127)
100 100 end
101 101 execute("#{problem_home}/script/compile #{language} #{source_file}", "Compilation error!")
102 102 compile_message = open("compiler_message").read
103 103 compile_message.strip!
104 104 call_and_log("Cannot move the compiler message to #{test_result_dir}.") {
105 105 FileUtils.mv("compiler_message", test_result_dir)
106 106 }
107 107 if !FileTest.exist?("a.out")
108 108 log "Cannot compile the source code. See message in #{test_result_dir}/compile_message"
109 109 exit(127)
110 110 else
111 111 call_and_log("Cannot move the compiled program to #{test_result_dir}") {
112 112 FileUtils.mv("a.out",test_result_dir)
113 113 if language == "java" then Dir["*.class"].each { |file| FileUtils.mv(file,test_result_dir)} end
114 + if language == "python" then Dir["*.pyc"].each { |file| FileUtils.mv(file,test_result_dir)} end
114 115 }
115 116 FileUtils.rm_rf("#{sandbox_dir}/.")
116 117 end
117 118
118 119 require "#{problem_home}/script/test_dsl.rb"
119 120 load "#{problem_home}/test_cases/all_tests.cfg"
120 121 problem = Problem.get_instance
121 122
122 123 if problem.well_formed? == false
123 124 log "The problem specification is not well formed."
124 125 exit(127)
125 126 end
126 127
127 128 # Doing the testing.
128 129 (1..(problem.num_tests)).each do |test_num|
129 130
130 131 $stdout.print "[#{test_num}]"
131 132 $stdout.flush
132 133
133 134 log "Test number: #{test_num}"
134 135
135 136 call_and_log("Cannot copy the compiled program into #{sandbox_dir}") {
136 137 FileUtils.cp("#{test_result_dir}/a.out", sandbox_dir, :preserve => true)
137 138 if language == "java" then Dir["#{test_result_dir}/*.class"].each { |file| FileUtils.cp(file,sandbox_dir)} end
139 + if language == "python" then Dir["#{test_result_dir}/*.pyc"].each { |file| FileUtils.cp(file,sandbox_dir)} end
138 140 }
139 141
140 142 begin
141 143 execute("#{problem_home}/script/run #{language} #{test_num}", "Error occured during execution of the run script")
142 144 rescue
143 145 # do nothing
144 146 end
145 147
146 148 call_and_log("Cannot create directory #{test_result_dir}/#{test_num}") {
147 149 FileUtils.mkdir "#{test_result_dir}/#{test_num}"
148 150 }
149 151 call_and_log("Cannot copy the result file into #{test_result_dir}/#{test_num}") {
150 152 FileUtils.mv "#{sandbox_dir}/result", "#{test_result_dir}/#{test_num}"
151 153 }
152 154 call_and_log("Cannot copy the comment file into #{test_result_dir}/#{test_num}") {
153 155 FileUtils.mv "#{sandbox_dir}/comment", "#{test_result_dir}/#{test_num}"
154 156 }
155 157 call_and_log("Cannot copy the output file into #{test_result_dir}/#{test_num}") {
156 158 FileUtils.mv "#{sandbox_dir}/output.txt", "#{test_result_dir}/#{test_num}"
157 159 }
158 160 call_and_log("Cannot clear #{sandbox_dir}") {
159 161 FileUtils.rm_rf(Dir.glob("#{sandbox_dir}/*"), :secure => true)
160 162 }
161 163 end
@@ -75,51 +75,52
75 75
76 76 # check if box is there, if not, compile it!
77 77 if !File.exists?("#{problem_home}/script/box")
78 78 log "WARNING: Compiling box: to increase efficiency, it should be compile manually"
79 79 compile_box("#{problem_home}/script/box.cc",
80 80 "#{problem_home}/script/box")
81 81 end
82 82
83 83 # Hide PROBLEM_HOME
84 84 ENV['PROBLEM_HOME'] = nil
85 85
86 86 # Run the program.
87 87 #run_command = "/usr/bin/time -f \"#{time_output_format}\" 2>run_result #{problem_home}/script/box_new -a 2 -f -t #{time_limit} -m #{mem_limit} -i #{input_file_name} -o output.txt #{program_name}"
88 88 #
89 89
90 90
91 91
92 92
93 93 case language
94 94 when "java"
95 95 # for java, we have to add additional systemcall and we don't check the mem limit (dunno how to fix...)
96 96 run_command = "#{problem_home}/script/box -T -t #{time_limit} -s getppid -s clone -s wait4 -p /usr/bin/ -p ./ -i #{input_file_name} -o output.txt #{program_name} 2>run_result"
97 97 when "ruby"
98 98 run_command = "#{problem_home}/script/box -T -t #{time_limit} -s getppid -s wait4 -s clone -s set_robust_list -s futex -s sigaltstack -p /dev/urandom -p ./ -p /home/dae/.rvm/rubies/ruby-1.9.2-p320/ -p #{problem_home}/ -i #{input_file_name} -o output.txt #{program_name} 2>run_result"
99 - when "c++"
100 - run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit} -m #{mem_limit} -i #{input_file_name} -o output.txt #{program_name} 2>run_result"
101 - else
99 + when "python"
100 + #this code just run without any checking
101 + run_command = "#{problem_home}/script/box -T -t #{time_limit} -p #{problem_home}/ -i #{input_file_name} -o output.txt #{program_name} 2>run_result"
102 + else # for c++, pascal, we do the normal checking
102 103 run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit} -m #{mem_limit} -i #{input_file_name} -o output.txt #{program_name} 2>run_result"
103 104 end
104 105
105 106
106 107 log "Running test #{test_num}..."
107 108 log run_command
108 109 log
109 110 system(run_command)
110 111
111 112 # Restore PROBLEM_HOME
112 113 ENV['PROBLEM_HOME'] = problem_home
113 114
114 115 # Create the result file.
115 116 result_file = File.new("result", "w")
116 117 comment_file = File.new("comment", "w")
117 118
118 119 # Check if the program actually produced any output.
119 120 run_result_file = File.new("run_result", "r")
120 121 run_result = run_result_file.readlines
121 122 run_result_file.close
122 123
123 124 run_stat = run_result[run_result.length-1]
124 125 running_time = extract_time(run_stat)
125 126
You need to be logged in to leave comments. Login now