Description:
Merge pull request #14 from nattee/master upgrade to current working snapshot
Commit status:
[Not Reviewed]
References:
merge default
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r263:7950cf0bb006 - - 12 files changed: 448 inserted, 40 deleted

@@ -0,0 +1,93
1 + #!/usr/bin/env ruby
2 +
3 + def config
4 + Grader::Configuration.get_instance
5 + end
6 +
7 + def display_manual
8 + puts <<USAGE
9 + Check similarity between submission
10 + using: check_similar sub1 sub2
11 + -- or --
12 + check_similar problem_name
13 + sub1 and sub2 are submission IDs to be checked
14 + problem_name will check all submissions of the problem wit problem short name is 'problem_name'
15 +
16 + The output are given as
17 + sub1.login, sub1.id, sub1.point, sub2.login, sub2.id, sub2.point, similarity
18 +
19 + USAGE
20 + end
21 +
22 + def process_options_and_stop_file
23 +
24 + # Process 'help' option
25 + if (ARGV.length == 0) or ((ARGV.length==1) and (/help/.match(ARGV[0])))
26 + display_manual
27 + exit(0)
28 + end
29 +
30 + #default options
31 + options = {
32 + :dry_run => false,
33 + }
34 +
35 +
36 + if ARGV.length == 2
37 + options[:sub1] = ARGV[0].to_i
38 + options[:sub2] = ARGV[1].to_i
39 + elsif ARGV.length == 1
40 + options[:problem] = ARGV[0]
41 + end
42 +
43 +
44 + return options
45 + end
46 +
47 + def compare(sub1,sub2,full = sub1.problem.full_score)
48 + dis = @jarow.getDistance(sub1.source, sub2.source)
49 + puts [sub1.user.login,"##{sub1.id}",(sub1.points * 100.0 / full).to_i,
50 + sub2.user.login,"##{sub2.id}",(sub2.points * 100.0 / full).to_i,
51 + "#{dis * 100}%"].join(',')
52 + end
53 +
54 + #########################################
55 + # main program
56 + #########################################
57 +
58 + options = process_options_and_stop_file
59 +
60 + # load grader environment
61 + GRADER_ENV = 'grading'
62 + require File.join(File.dirname(__FILE__),'config/environment')
63 +
64 + # boot rails, to be able to use the active record
65 + RAILS_ENV = config.rails_env
66 + require RAILS_ROOT + '/config/environment'
67 +
68 + # load comparator
69 + require 'fuzzystringmatch'
70 + @jarow = FuzzyStringMatch::JaroWinkler.create( :native )
71 +
72 + if options[:problem]
73 + p = Problem.where(name: options[:problem]).first
74 + unless p
75 + puts "cannot find problem #{options[:problem]}"
76 + exit(0)
77 + end
78 + subs = Submission.where(problem: p)
79 + full_score = p.full_score.to_i
80 + subs.each.with_index do |s1,i|
81 + puts "processing #{i+1} out of #{subs.length}"
82 + subs.each do |s2|
83 + if s1.user != s2.user
84 + compare(s1,s2,full_score)
85 + end
86 + end
87 + end
88 + else
89 + sub1 = Submission.find(options[:sub1])
90 + sub2 = Submission.find(options[:sub2])
91 + compare(sub1,sub2)
92 + end
93 +
@@ -0,0 +1,6
1 + #!/bin/bash
2 + count=`ps aux | grep "cafe_grader" | grep "grader grading queue" | wc -l`
3 + if [ $count -lt 1 ]; then
4 + cd /home/dae/cafe_grader/judge
5 + /home/dae/.rvm/wrappers/ruby-2.3.0/ruby /home/dae/cafe_grader/judge/scripts/grader grading queue > /home/dae/grading.log &
6 + fi
@@ -0,0 +1,179
1 + #!/bin/sh
2 +
3 + echo "This script will install and configure Cafe grader."
4 +
5 + RUBY_VERSION=2.1.2
6 + echo "This will install Ruby $RUBY_VERSION under RVM"
7 +
8 + echo "Installing required apts"
9 +
10 + sudo zypper install \
11 + g++ gcc libmysqlclient18 build-essential \
12 + git-core openssl libreadline6 libreadline6-devel \
13 + zlib1g zlib1g-devel libssl37 libyaml-devel sqlite3-devel \
14 + sqlite3 libxml2-devel libxslt-devel autoconf libc6-devel \
15 + ncurses-devel automake libtool bison subversion \
16 + pkg-config curl nodejs unzip pyflakes java-1_8_0-openjdk \
17 + libmysqld-devel mercurial python-setuptools python-devel
18 +
19 +
20 + echo "Installing Ruby $RUBY_VERSION in RVM"
21 +
22 + rvm install $RUBY_VERSION
23 + rvm use $RUBY_VERSION
24 +
25 + echo "Fetching Cafe Grader from Git repositories"
26 +
27 + echo "Fetching web interface"
28 +
29 + mkdir cafe_grader
30 + cd cafe_grader
31 + #git clone -q git://github.com/jittat/cafe-grader-web.git web
32 + hg clone git+ssh://git@github.com/nattee/cafe-grader-web.git web
33 +
34 + echo "Configuring rails app"
35 +
36 + cp web/config/application.rb.SAMPLE web/config/application.rb
37 + cp web/config/initializers/cafe_grader_config.rb.SAMPLE web/config/initializers/cafe_grader_config.rb
38 +
39 + #replace UTC in application.rb with the system timezone
40 + timezone='UTC'
41 + if [ -f '/etc/timezone' ]; then
42 + timezone=\"`cat /etc/timezone`\"
43 + else
44 + if [ -f '/etc/sysconfig/clock' ]; then
45 + timezone=`grep -e '^TIMEZONE' /etc/sysconfig/clock | grep -o -e '\".*\"'`
46 + fi
47 + fi
48 + replace="s!'UTC'!$timezone!g"
49 + sed -i $replace web/config/application.rb
50 +
51 + echo "At this point we will need MySQL user and database."
52 + echo "Have you created MySQL user and database for Cafe grader? (Y/N) "
53 + read ch
54 +
55 + if [ "$ch" = "n" -o "$ch" = "N" ]
56 + then
57 + echo "Please open another terminal and create the user and database for Cafe grader."
58 + echo "Don't forget to grant access to that database for the user."
59 + echo "Please have username, password, and database name ready before continue."
60 + echo
61 + echo "The following are instructions:"
62 + echo "1. Run mysql:"
63 + echo
64 + echo " mysql -u root -p"
65 + echo
66 + echo " if you have just installed mysql, the root password is the one that you have just entered"
67 + echo "2. Create a new database, a new user, and grant access to grader database:"
68 + echo
69 + echo " create user 'USERNAME'@'localhost' identified by 'PASSWORD';"
70 + echo " create database \`DATABASENEME\`;"
71 + echo " grant all on \`DATABASENAME\`.* to 'USERNAME'@'localhost';"
72 + echo
73 + echo " Replace USERNAME, PASSWORD, and DATABASENAME accordingly."
74 + echo
75 + echo "Hit enter when ready..."
76 + read dummy
77 + fi
78 +
79 + CAFE_PATH=`pwd`
80 +
81 + cd web
82 +
83 + echo "Please provide grader database:"
84 + read database
85 +
86 + echo "Please provide grader username:"
87 + read username
88 +
89 + echo "Please provide $username password:"
90 + read password
91 +
92 + echo "development:" > config/database.yml
93 + echo " adapter: mysql2" >> config/database.yml
94 + echo " encoding: utf8" >> config/database.yml
95 + echo " reconnect: false" >> config/database.yml
96 + echo " database: $database" >> config/database.yml
97 + echo " pool: 5" >> config/database.yml
98 + echo " username: $username" >> config/database.yml
99 + echo " password: $password" >> config/database.yml
100 + echo " host: localhost" >> config/database.yml
101 + echo " socket: /run/mysql/mysql.sock" >> config/database.yml
102 + echo "" >> config/database.yml
103 + echo "production:" >> config/database.yml
104 + echo " adapter: mysql2" >> config/database.yml
105 + echo " encoding: utf8" >> config/database.yml
106 + echo " reconnect: false" >> config/database.yml
107 + echo " database: $database" >> config/database.yml
108 + echo " pool: 5" >> config/database.yml
109 + echo " username: $username" >> config/database.yml
110 + echo " password: $password" >> config/database.yml
111 + echo " host: localhost" >> config/database.yml
112 + echo " socket: /run/mysql/mysql.sock" >> config/database.yml
113 +
114 + echo "Object.instance_eval{remove_const :GRADER_ROOT_DIR}" >> config/initializers/cafe_grader_config.rb
115 + echo "Object.instance_eval{remove_const :GRADING_RESULT_DIR}" >> config/initializers/cafe_grader_config.rb
116 + echo "GRADER_ROOT_DIR = '$CAFE_PATH/judge'" >> config/initializers/cafe_grader_config.rb
117 + echo "GRADING_RESULT_DIR = '$CAFE_PATH/judge/result'" >> config/initializers/cafe_grader_config.rb
118 +
119 + echo "Installing required gems"
120 + gem install bundler
121 + bundle install
122 +
123 + echo "Running rake tasks to initialize database"
124 +
125 + rake db:migrate
126 + rake db:seed
127 +
128 + echo "Running rake tasks to precompile the assets"
129 +
130 + rake assets:precompile
131 +
132 + echo "Intalling web interface complete..."
133 + echo
134 + echo "Fetching grader"
135 +
136 + cd ..
137 +
138 + mkdir judge
139 + cd judge
140 + #git clone -q git://github.com/jittat/cafe-grader-judge-scripts.git scripts
141 + hg clone git+ssh://git@github.com/nattee/cafe-grader-judge-scripts.git scripts
142 + mkdir raw
143 + mkdir ev-exam
144 + mkdir ev
145 + mkdir result
146 + mkdir log
147 +
148 + echo "Configuring grader"
149 +
150 + cp scripts/config/env_exam.rb.SAMPLE scripts/config/env_exam.rb
151 + cp scripts/config/env_grading.rb.SAMPLE scripts/config/env_grading.rb
152 +
153 + # create new environment.rb file
154 + echo "RAILS_ROOT = '$CAFE_PATH/web'" > scripts/config/environment.rb
155 + echo "GRADER_ROOT = '$CAFE_PATH/judge/scripts'" >> scripts/config/environment.rb
156 + echo "require File.join(File.dirname(__FILE__),'../lib/boot')" >> scripts/config/environment.rb
157 + echo "require File.dirname(__FILE__) + \"/env_#{GRADER_ENV}.rb\"" >> scripts/config/environment.rb
158 +
159 + # compiling box
160 + MACHINE_TYPE=`uname -m`
161 + if [ ${MACHINE_TYPE} == 'x86_64' ]; then
162 + gcc -std=c99 -o scripts/std-script/box scripts/std-script/box64-new.c
163 + else
164 + g++ -o scripts/std-script/box scripts/std-script/box.cc
165 + fi
166 +
167 +
168 + cd ..
169 +
170 + echo "Now you are ready to run cafe grader...."
171 + echo
172 + echo "Try:"
173 + echo
174 + echo " cd web"
175 + echo " rails s"
176 + echo
177 + echo "and access web at http://localhost:3000/"
178 + echo "The root username is 'root', its password is 'ioionrails'."
179 +
@@ -0,0 +1,85
1 + #!/usr/bin/env ruby
2 +
3 + def config
4 + Grader::Configuration.get_instance
5 + end
6 +
7 + def display_manual
8 + puts <<USAGE
9 + load_testcases
10 + using: load_testcases [problem_name ...]
11 + problem_name are list of "short name" of the problems
12 +
13 + options:
14 + --dry-run do nothing, just simulate the run
15 + --all import all problem. This might take several minutes
16 +
17 + USAGE
18 + end
19 +
20 + def process_options_and_stop_file
21 +
22 + # Process 'help' option
23 + if (ARGV.length == 0) or ((ARGV.length==1) and (/help/.match(ARGV[0])))
24 + display_manual
25 + exit(0)
26 + end
27 +
28 + #default options
29 + options = {
30 + :dry_run => false,
31 + }
32 +
33 + options[:dry_run] = (ARGV.delete('--dry') != nil)
34 + options[:all] = (ARGV.delete('--all') != nil)
35 +
36 + return options
37 + end
38 +
39 + def process_problem(prob,dry_run = false)
40 + prob.testcases.destroy_all
41 + testcases_root = File.expand_path(GRADER_ROOT+"/../ev/#{prob.name}/test_cases/")
42 + num = 1
43 + puts "Processing problem #{prob.name}"
44 + loop do
45 + file_root = testcases_root + "/#{num}/"
46 + puts " checking file #{file_root}"
47 + break unless File.exists? file_root
48 + input = File.read(file_root + "/input-#{num}.txt")
49 + answer = File.read(file_root + "/answer-#{num}.txt")
50 + puts " got test case ##{num} of size #{input.size} and #{answer.size}"
51 +
52 + #THIS IS JUST A PLACE HOLDER
53 + group = num #this is wrong!!! fix it!!
54 + score = 10
55 + #BEWARE
56 +
57 + prob.testcases.create(input: input,sol: answer, num: num, score:score,group: group) unless dry_run
58 + num += 1
59 + end
60 + end
61 +
62 + #########################################
63 + # main program
64 + #########################################
65 +
66 + options = process_options_and_stop_file
67 +
68 + # load grader environment
69 + GRADER_ENV = 'grading'
70 + require File.join(File.dirname(__FILE__),'config/environment')
71 +
72 + # boot rails, to be able to use the active record
73 + RAILS_ENV = config.rails_env
74 + require RAILS_ROOT + '/config/environment'
75 +
76 + if options[:all]
77 + Problem.all.each { |prob| process_problem(prob,options[:dry_run]) }
78 + else
79 + ARGV.each do |name|
80 + prob = Problem.find_by(name: name)
81 + process_problem(prob,options[:dry_run]) if prob
82 + puts "Cannot find the problem #{name}" unless prob
83 + end
84 + end
85 +
@@ -87,150 +87,156
87 For wrapped checked script see comment in templates/check_wrapper for
87 For wrapped checked script see comment in templates/check_wrapper for
88 information."
88 information."
89 end
89 end
90
90
91 def count_testruns(testcase_dir, raw_prefix)
91 def count_testruns(testcase_dir, raw_prefix)
92 n = 0
92 n = 0
93 begin
93 begin
94 # check for test case n+1
94 # check for test case n+1
95 if ((Dir["#{testcase_dir}/#{raw_prefix}#{n+1}.in"].length==0) and
95 if ((Dir["#{testcase_dir}/#{raw_prefix}#{n+1}.in"].length==0) and
96 (Dir["#{testcase_dir}/#{raw_prefix}#{n+1}[a-z].in"].length==0))
96 (Dir["#{testcase_dir}/#{raw_prefix}#{n+1}[a-z].in"].length==0))
97 return n
97 return n
98 end
98 end
99 n += 1
99 n += 1
100 end while true
100 end while true
101 end
101 end
102
102
103 def create_dir_if_not_exists(dir)
103 def create_dir_if_not_exists(dir)
104 if ! FileTest.exists? dir
104 if ! FileTest.exists? dir
105 FileUtils.mkdir(dir)
105 FileUtils.mkdir(dir)
106 end
106 end
107 end
107 end
108
108
109 def import_problem(ev_dir, problem, testcase_dir, num_testruns, raw_prefix, check_script, options)
109 def import_problem(ev_dir, problem, testcase_dir, num_testruns, raw_prefix, check_script, options)
110 testrun_info = build_testrun_info_from_dir(num_testruns, testcase_dir, raw_prefix)
110 testrun_info = build_testrun_info_from_dir(num_testruns, testcase_dir, raw_prefix)
111
111
112 if !(FileTest.exists? ev_dir)
112 if !(FileTest.exists? ev_dir)
113 puts "Testdata dir (#{ev_dir}) not found."
113 puts "Testdata dir (#{ev_dir}) not found."
114 return
114 return
115 end
115 end
116
116
117 problem_dir = "#{ev_dir}/#{problem}"
117 problem_dir = "#{ev_dir}/#{problem}"
118
118
119 # start working
119 # start working
120 puts "creating directories"
120 puts "creating directories"
121
121
122 create_dir_if_not_exists("#{problem_dir}")
122 create_dir_if_not_exists("#{problem_dir}")
123 create_dir_if_not_exists("#{problem_dir}/script")
123 create_dir_if_not_exists("#{problem_dir}/script")
124 create_dir_if_not_exists("#{problem_dir}/test_cases")
124 create_dir_if_not_exists("#{problem_dir}/test_cases")
125
125
126 puts "copying testcases"
126 puts "copying testcases"
127
127
128 tr_num = 0
128 tr_num = 0
129
129
130 num_testcases = 0
130 num_testcases = 0
131
131
132 testrun_info.each do |testrun|
132 testrun_info.each do |testrun|
133 tr_num += 1
133 tr_num += 1
134 puts "testrun: #{tr_num}"
134 puts "testrun: #{tr_num}"
135 -
135 +
136 testrun.each do |testcase_info|
136 testrun.each do |testcase_info|
137 testcase_num, testcase_fname = testcase_info
137 testcase_num, testcase_fname = testcase_info
138 -
138 +
139 puts "copy #{testcase_fname} to #{testcase_num}"
139 puts "copy #{testcase_fname} to #{testcase_num}"
140 -
140 +
141 create_dir_if_not_exists("#{problem_dir}/test_cases/#{testcase_num}")
141 create_dir_if_not_exists("#{problem_dir}/test_cases/#{testcase_num}")
142 copy_testcase("#{testcase_dir}",testcase_fname,"#{problem_dir}/test_cases/#{testcase_num}",testcase_num)
142 copy_testcase("#{testcase_dir}",testcase_fname,"#{problem_dir}/test_cases/#{testcase_num}",testcase_num)
143 -
143 +
144 num_testcases += 1
144 num_testcases += 1
145 end
145 end
146 end
146 end
147 -
147 +
148 + #also include any .txt files
149 + Dir.glob("#{testcase_dir}/*.txt") do |file|
150 + puts "copy data file #{file}"
151 + FileUtils.cp(file,"#{problem_dir}")
152 + end
153 +
148 # generating all_tests.cfg
154 # generating all_tests.cfg
149 puts "generating testcase config file"
155 puts "generating testcase config file"
150 -
156 +
151 template = File.open(SCRIPT_DIR + "/templates/all_tests.cfg.erb").read
157 template = File.open(SCRIPT_DIR + "/templates/all_tests.cfg.erb").read
152 all_test_cfg = ERB.new(template)
158 all_test_cfg = ERB.new(template)
153 -
159 +
154 cfg_file = File.open("#{problem_dir}/test_cases/all_tests.cfg","w")
160 cfg_file = File.open("#{problem_dir}/test_cases/all_tests.cfg","w")
155 cfg_file.puts all_test_cfg.result binding
161 cfg_file.puts all_test_cfg.result binding
156 cfg_file.close
162 cfg_file.close
157 -
163 +
158 # copy check script
164 # copy check script
159 if res = /^wrapper:(.*)$/.match(check_script)
165 if res = /^wrapper:(.*)$/.match(check_script)
160 # wrapper script
166 # wrapper script
161 check_script_fname = res[1]
167 check_script_fname = res[1]
162 script_name = File.basename(check_script_fname)
168 script_name = File.basename(check_script_fname)
163 check_wrapper_template = File.open(SCRIPT_DIR + "/templates/check_wrapper").read
169 check_wrapper_template = File.open(SCRIPT_DIR + "/templates/check_wrapper").read
164 check_wrapper = ERB.new(check_wrapper_template)
170 check_wrapper = ERB.new(check_wrapper_template)
165 -
171 +
166 check_file = File.open("#{problem_dir}/script/check","w")
172 check_file = File.open("#{problem_dir}/script/check","w")
167 check_file.puts check_wrapper.result binding
173 check_file.puts check_wrapper.result binding
168 check_file.close
174 check_file.close
169 -
175 +
170 File.chmod(0755,"#{problem_dir}/script/check")
176 File.chmod(0755,"#{problem_dir}/script/check")
171 -
177 +
172 FileUtils.cp("#{check_script_fname}", "#{problem_dir}/script/#{script_name}")
178 FileUtils.cp("#{check_script_fname}", "#{problem_dir}/script/#{script_name}")
173 else
179 else
174 if File.exists?(SCRIPT_DIR + "/templates/check.#{check_script}")
180 if File.exists?(SCRIPT_DIR + "/templates/check.#{check_script}")
175 check_script_fname = SCRIPT_DIR + "/templates/check.#{check_script}"
181 check_script_fname = SCRIPT_DIR + "/templates/check.#{check_script}"
176 else
182 else
177 check_script_fname = check_script
183 check_script_fname = check_script
178 end
184 end
179 FileUtils.cp("#{check_script_fname}", "#{problem_dir}/script/check", :preserve => true)
185 FileUtils.cp("#{check_script_fname}", "#{problem_dir}/script/check", :preserve => true)
180 end
186 end
181 -
187 +
182 # generating test_request directory
188 # generating test_request directory
183 puts "generating test_request template"
189 puts "generating test_request template"
184 FileUtils.mkdir_p("#{ev_dir}/test_request/#{problem}/script")
190 FileUtils.mkdir_p("#{ev_dir}/test_request/#{problem}/script")
185 FileUtils.mkdir_p("#{ev_dir}/test_request/#{problem}/test_cases/1")
191 FileUtils.mkdir_p("#{ev_dir}/test_request/#{problem}/test_cases/1")
186 -
192 +
187 template = File.open(SCRIPT_DIR + "/templates/test_request_all_tests.cfg.erb").read
193 template = File.open(SCRIPT_DIR + "/templates/test_request_all_tests.cfg.erb").read
188 test_request_all_test_cfg = ERB.new(template)
194 test_request_all_test_cfg = ERB.new(template)
189 -
195 +
190 cfg_file = File.open("#{ev_dir}/test_request/#{problem}/test_cases/all_tests.cfg","w")
196 cfg_file = File.open("#{ev_dir}/test_request/#{problem}/test_cases/all_tests.cfg","w")
191 cfg_file.puts test_request_all_test_cfg.result
197 cfg_file.puts test_request_all_test_cfg.result
192 cfg_file.close
198 cfg_file.close
193 -
199 +
194 FileUtils.cp("#{SCRIPT_DIR}/templates/check_empty",
200 FileUtils.cp("#{SCRIPT_DIR}/templates/check_empty",
195 "#{ev_dir}/test_request/#{problem}/script/check")
201 "#{ev_dir}/test_request/#{problem}/script/check")
196 FileUtils.cp("#{SCRIPT_DIR}/templates/answer-1.txt",
202 FileUtils.cp("#{SCRIPT_DIR}/templates/answer-1.txt",
197 "#{ev_dir}/test_request/#{problem}/test_cases/1")
203 "#{ev_dir}/test_request/#{problem}/test_cases/1")
198 -
204 +
199 puts "done"
205 puts "done"
200 end
206 end
201
207
202
208
203 SCRIPT_DIR = File.dirname(__FILE__)
209 SCRIPT_DIR = File.dirname(__FILE__)
204
210
205 # print usage
211 # print usage
206 if (ARGV.length < 3) or (ARGV[2][0,1]=="-")
212 if (ARGV.length < 3) or (ARGV[2][0,1]=="-")
207 print_usage
213 print_usage
208 exit(127)
214 exit(127)
209 end
215 end
210
216
211 # processing arguments
217 # processing arguments
212 problem = ARGV[0]
218 problem = ARGV[0]
213 testcase_dir = ARGV[1]
219 testcase_dir = ARGV[1]
214 problem = File.basename(testcase_dir) if problem=="-"
220 problem = File.basename(testcase_dir) if problem=="-"
215 check_script = ARGV[2]
221 check_script = ARGV[2]
216 options = {:time_limit => 1, :mem_limit => 16}
222 options = {:time_limit => 1, :mem_limit => 16}
217 process_options(options)
223 process_options(options)
218
224
219 JUDGE_ENVIRONMENTS.each do |env|
225 JUDGE_ENVIRONMENTS.each do |env|
220 ev_dir = ENV_INFO[env][:ev_dir]
226 ev_dir = ENV_INFO[env][:ev_dir]
221 raw_prefix = ENV_INFO[env][:raw_prefix]
227 raw_prefix = ENV_INFO[env][:raw_prefix]
222
228
223 num_testruns = count_testruns(testcase_dir,raw_prefix)
229 num_testruns = count_testruns(testcase_dir,raw_prefix)
224
230
225 puts ""
231 puts ""
226 puts "*** Environment: #{env} (#{num_testruns} test runs) ***"
232 puts "*** Environment: #{env} (#{num_testruns} test runs) ***"
227 puts ""
233 puts ""
228
234
229 import_problem(ev_dir,
235 import_problem(ev_dir,
230 problem,
236 problem,
231 testcase_dir,
237 testcase_dir,
232 num_testruns,
238 num_testruns,
233 raw_prefix,
239 raw_prefix,
234 check_script,
240 check_script,
235 options)
241 options)
236 end
242 end
@@ -1,65 +1,66
1 #!/bin/sh
1 #!/bin/sh
2
2
3 echo "This script will install and configure Cafe grader."
3 echo "This script will install and configure Cafe grader."
4
4
5 RUBY_VERSION=2.1.2
5 RUBY_VERSION=2.1.2
6 echo "This will install Ruby $RUBY_VERSION under RVM"
6 echo "This will install Ruby $RUBY_VERSION under RVM"
7
7
8 echo "Installing required apts"
8 echo "Installing required apts"
9
9
10 sudo apt-get update
10 sudo apt-get update
11 sudo apt-get install mysql-server mysql-client \
11 sudo apt-get install mysql-server mysql-client \
12 - g++ gcc apache2 libmysqlclient15-dev build-essential \
12 + g++ gcc apache2 libmysqlclient20 build-essential \
13 git-core openssl libreadline6 libreadline6-dev \
13 git-core openssl libreadline6 libreadline6-dev \
14 zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-dev \
14 zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-dev \
15 sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev \
15 sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev \
16 ncurses-dev automake libtool bison subversion \
16 ncurses-dev automake libtool bison subversion \
17 - pkg-config curl nodejs unzip pyflakes ruby default-jdk
17 + pkg-config curl nodejs unzip pyflakes ruby default-jdk \
18 + libmysqld-dev mercurial python-setuptools python-dev python3-numpy
18
19
19 echo "Installing RVM"
20 echo "Installing RVM"
20 curl -k -L https://get.rvm.io | bash -s stable
21 curl -k -L https://get.rvm.io | bash -s stable
21 source ~/.rvm/scripts/rvm
22 source ~/.rvm/scripts/rvm
22
23
23 echo "Installing Ruby $RUBY_VERSION in RVM"
24 echo "Installing Ruby $RUBY_VERSION in RVM"
24
25
25 rvm install $RUBY_VERSION
26 rvm install $RUBY_VERSION
26 rvm use $RUBY_VERSION
27 rvm use $RUBY_VERSION
27
28
28 echo "Fetching Cafe Grader from Git repositories"
29 echo "Fetching Cafe Grader from Git repositories"
29
30
30 echo "Fetching web interface"
31 echo "Fetching web interface"
31
32
32 mkdir cafe_grader
33 mkdir cafe_grader
33 cd cafe_grader
34 cd cafe_grader
34 git clone -q git://github.com/jittat/cafe-grader-web.git web
35 git clone -q git://github.com/jittat/cafe-grader-web.git web
35
36
36 echo "Configuring rails app"
37 echo "Configuring rails app"
37
38
38 cp web/config/application.rb.SAMPLE web/config/application.rb
39 cp web/config/application.rb.SAMPLE web/config/application.rb
39 cp web/config/initializers/cafe_grader_config.rb.SAMPLE web/config/initializers/cafe_grader_config.rb
40 cp web/config/initializers/cafe_grader_config.rb.SAMPLE web/config/initializers/cafe_grader_config.rb
40
41
41 #replace UTC in application.rb with the system timezone
42 #replace UTC in application.rb with the system timezone
42 timezone='UTC'
43 timezone='UTC'
43 if [ -f '/etc/timezone' ]; then
44 if [ -f '/etc/timezone' ]; then
44 timezone=\"`cat /etc/timezone`\"
45 timezone=\"`cat /etc/timezone`\"
45 else
46 else
46 if [ -f '/etc/sysconfig/clock' ]; then
47 if [ -f '/etc/sysconfig/clock' ]; then
47 timezone=`grep -e '^TIMEZONE' /etc/sysconfig/clock | grep -o -e '\".*\"'`
48 timezone=`grep -e '^TIMEZONE' /etc/sysconfig/clock | grep -o -e '\".*\"'`
48 fi
49 fi
49 fi
50 fi
50 replace="s!'UTC'!$timezone!g"
51 replace="s!'UTC'!$timezone!g"
51 sed -i $replace web/config/application.rb
52 sed -i $replace web/config/application.rb
52
53
53 echo "At this point we will need MySQL user and database."
54 echo "At this point we will need MySQL user and database."
54 echo "Have you created MySQL user and database for Cafe grader? (Y/N) "
55 echo "Have you created MySQL user and database for Cafe grader? (Y/N) "
55 read ch
56 read ch
56
57
57 if [ "$ch" = "n" -o "$ch" = "N" ]
58 if [ "$ch" = "n" -o "$ch" = "N" ]
58 then
59 then
59 echo "Please open another terminal and create the user and database for Cafe grader."
60 echo "Please open another terminal and create the user and database for Cafe grader."
60 echo "Don't forget to grant access to that database for the user."
61 echo "Don't forget to grant access to that database for the user."
61 echo "Please have username, password, and database name ready before continue."
62 echo "Please have username, password, and database name ready before continue."
62 echo
63 echo
63 echo "The following are instructions:"
64 echo "The following are instructions:"
64 echo "1. Run mysql:"
65 echo "1. Run mysql:"
65 echo
66 echo
@@ -1,100 +1,100
1 #!/usr/bin/env ruby
1 #!/usr/bin/env ruby
2
2
3 ENVIRONMENT_DIRS = ['ev', 'ev-exam']
3 ENVIRONMENT_DIRS = ['ev', 'ev-exam']
4
4
5 def config
5 def config
6 Grader::Configuration.get_instance
6 Grader::Configuration.get_instance
7 end
7 end
8
8
9 def rename_problem(old_problem_name, new_problem_name)
9 def rename_problem(old_problem_name, new_problem_name)
10
10
11 - if valid_problem_name(new_problem_name)
11 + unless valid_problem_name(new_problem_name)
12 puts "Bad new problem name: #{new_problem_name}"
12 puts "Bad new problem name: #{new_problem_name}"
13 return
13 return
14 end
14 end
15
15
16 problem = Problem.find_by_name(old_problem_name)
16 problem = Problem.find_by_name(old_problem_name)
17 if problem==nil
17 if problem==nil
18 puts "Problem #{old_problem_name} does not exist."
18 puts "Problem #{old_problem_name} does not exist."
19 return
19 return
20 end
20 end
21
21
22 puts "Problem: #{old_problem_name} -> #{new_problem_name}"
22 puts "Problem: #{old_problem_name} -> #{new_problem_name}"
23
23
24 ENVIRONMENT_DIRS.each do |dir|
24 ENVIRONMENT_DIRS.each do |dir|
25 problem_dir = File.join(GRADER_ROOT,'..',dir,old_problem_name)
25 problem_dir = File.join(GRADER_ROOT,'..',dir,old_problem_name)
26 new_problem_dir = File.join(GRADER_ROOT,'..',dir,new_problem_name)
26 new_problem_dir = File.join(GRADER_ROOT,'..',dir,new_problem_name)
27
27
28 if FileTest.exists? problem_dir
28 if FileTest.exists? problem_dir
29 puts "Moving #{problem_dir} to #{new_problem_dir}."
29 puts "Moving #{problem_dir} to #{new_problem_dir}."
30 File.rename(problem_dir, new_problem_dir)
30 File.rename(problem_dir, new_problem_dir)
31
31
32 tr_problem_dir = File.join(GRADER_ROOT,'..',dir,
32 tr_problem_dir = File.join(GRADER_ROOT,'..',dir,
33 'test_request',old_problem_name)
33 'test_request',old_problem_name)
34 new_tr_problem_dir = File.join(GRADER_ROOT,'..',dir,
34 new_tr_problem_dir = File.join(GRADER_ROOT,'..',dir,
35 'test_request',new_problem_name)
35 'test_request',new_problem_name)
36 File.rename(tr_problem_dir, new_tr_problem_dir)
36 File.rename(tr_problem_dir, new_tr_problem_dir)
37 end
37 end
38 end
38 end
39
39
40 problem.name = new_problem_name
40 problem.name = new_problem_name
41 problem.save
41 problem.save
42 end
42 end
43
43
44 def usage
44 def usage
45 puts <<USAGE
45 puts <<USAGE
46 Usage:
46 Usage:
47 rename_problem [old_name] [new_name]
47 rename_problem [old_name] [new_name]
48 or
48 or
49 rename_problem -f [filename]
49 rename_problem -f [filename]
50
50
51 When using with -f, that file should contain, for each line, the old
51 When using with -f, that file should contain, for each line, the old
52 problem name and its new name.
52 problem name and its new name.
53
53
54 This script should be called at the judge root dir where dirs 'ev' and
54 This script should be called at the judge root dir where dirs 'ev' and
55 'ev-exam' are.
55 'ev-exam' are.
56 USAGE
56 USAGE
57 end
57 end
58
58
59 def valid_problem_name(name)
59 def valid_problem_name(name)
60 if name.length==0:
60 if name.length==0:
61 return false
61 return false
62 else
62 else
63 - return !(/^[a-zA-Z0-9_\-]+$/ === name)
63 + return (/^[a-zA-Z0-9_\-]+$/ === name)
64 end
64 end
65 end
65 end
66
66
67 if (ARGV.length!=2)
67 if (ARGV.length!=2)
68 usage
68 usage
69 exit(0)
69 exit(0)
70 end
70 end
71
71
72 if ARGV[0]=='-f' and !FileTest.exists?(ARGV[1])
72 if ARGV[0]=='-f' and !FileTest.exists?(ARGV[1])
73 puts "File #{ARGV[1]} does not exist."
73 puts "File #{ARGV[1]} does not exist."
74 usage
74 usage
75 exit(0)
75 exit(0)
76 end
76 end
77
77
78 # load grader environment
78 # load grader environment
79 GRADER_ENV = 'grading'
79 GRADER_ENV = 'grading'
80 require File.join(File.dirname(__FILE__),'config/environment')
80 require File.join(File.dirname(__FILE__),'config/environment')
81
81
82 # boot rails, to be able to rename the problem
82 # boot rails, to be able to rename the problem
83 RAILS_ENV = config.rails_env
83 RAILS_ENV = config.rails_env
84 require RAILS_ROOT + '/config/environment'
84 require RAILS_ROOT + '/config/environment'
85
85
86 if ARGV[0]!='-f'
86 if ARGV[0]!='-f'
87 old_problem_name = ARGV[0]
87 old_problem_name = ARGV[0]
88 new_problem_name = ARGV[1]
88 new_problem_name = ARGV[1]
89
89
90 rename_problem(old_problem_name, new_problem_name)
90 rename_problem(old_problem_name, new_problem_name)
91 else
91 else
92 lines = IO.readlines(ARGV[1])
92 lines = IO.readlines(ARGV[1])
93 lines.each do |line|
93 lines.each do |line|
94 items = line.split
94 items = line.split
95 if items.length==2
95 if items.length==2
96 old_name, new_name = items
96 old_name, new_name = items
97 rename_problem(old_name, new_name)
97 rename_problem(old_name, new_name)
98 end
98 end
99 end
99 end
100 end
100 end
@@ -558,96 +558,108
558 /* 266 */ [ __NR_symlinkat ] = "symlinkat",
558 /* 266 */ [ __NR_symlinkat ] = "symlinkat",
559 /* 267 */ [ __NR_readlinkat ] = "readlinkat",
559 /* 267 */ [ __NR_readlinkat ] = "readlinkat",
560 /* 268 */ [ __NR_fchmodat ] = "fchmodat",
560 /* 268 */ [ __NR_fchmodat ] = "fchmodat",
561 /* 269 */ [ __NR_faccessat ] = "faccessat",
561 /* 269 */ [ __NR_faccessat ] = "faccessat",
562 /* 270 */ [ __NR_pselect6 ] = "pselect6",
562 /* 270 */ [ __NR_pselect6 ] = "pselect6",
563 /* 271 */ [ __NR_ppoll ] = "ppoll",
563 /* 271 */ [ __NR_ppoll ] = "ppoll",
564 /* 272 */ [ __NR_unshare ] = "unshare",
564 /* 272 */ [ __NR_unshare ] = "unshare",
565 /* 273 */ [ __NR_set_robust_list ] = "set_robust_list",
565 /* 273 */ [ __NR_set_robust_list ] = "set_robust_list",
566 /* 274 */ [ __NR_get_robust_list ] = "get_robust_list",
566 /* 274 */ [ __NR_get_robust_list ] = "get_robust_list",
567 /* 275 */ [ __NR_splice ] = "splice",
567 /* 275 */ [ __NR_splice ] = "splice",
568 /* 276 */ [ __NR_tee ] = "tee",
568 /* 276 */ [ __NR_tee ] = "tee",
569 /* 277 */ [ __NR_sync_file_range ] = "sync_file_range",
569 /* 277 */ [ __NR_sync_file_range ] = "sync_file_range",
570 /* 278 */ [ __NR_vmsplice ] = "vmsplice",
570 /* 278 */ [ __NR_vmsplice ] = "vmsplice",
571 /* 279 */ [ __NR_move_pages ] = "move_pages",
571 /* 279 */ [ __NR_move_pages ] = "move_pages",
572 /* 280 */ [ __NR_utimensat ] = "utimensat",
572 /* 280 */ [ __NR_utimensat ] = "utimensat",
573 /* 281 */ [ __NR_epoll_pwait ] = "epoll_pwait",
573 /* 281 */ [ __NR_epoll_pwait ] = "epoll_pwait",
574 /* 282 */ [ __NR_signalfd ] = "signalfd",
574 /* 282 */ [ __NR_signalfd ] = "signalfd",
575 /* 283 */ [ __NR_timerfd_create ] = "timerfd_create",
575 /* 283 */ [ __NR_timerfd_create ] = "timerfd_create",
576 /* 284 */ [ __NR_eventfd ] = "eventfd",
576 /* 284 */ [ __NR_eventfd ] = "eventfd",
577 /* 285 */ [ __NR_fallocate ] = "fallocate",
577 /* 285 */ [ __NR_fallocate ] = "fallocate",
578 /* 286 */ [ __NR_timerfd_settime ] = "timerfd_settime",
578 /* 286 */ [ __NR_timerfd_settime ] = "timerfd_settime",
579 /* 287 */ [ __NR_timerfd_gettime ] = "timerfd_gettime",
579 /* 287 */ [ __NR_timerfd_gettime ] = "timerfd_gettime",
580 /* 288 */ [ __NR_accept4 ] = "accept4",
580 /* 288 */ [ __NR_accept4 ] = "accept4",
581 /* 289 */ [ __NR_signalfd4 ] = "signalfd4",
581 /* 289 */ [ __NR_signalfd4 ] = "signalfd4",
582 /* 290 */ [ __NR_eventfd2 ] = "eventfd2",
582 /* 290 */ [ __NR_eventfd2 ] = "eventfd2",
583 /* 291 */ [ __NR_epoll_create1 ] = "epoll_create1",
583 /* 291 */ [ __NR_epoll_create1 ] = "epoll_create1",
584 /* 292 */ [ __NR_dup3 ] = "dup3",
584 /* 292 */ [ __NR_dup3 ] = "dup3",
585 /* 293 */ [ __NR_pipe2 ] = "pipe2",
585 /* 293 */ [ __NR_pipe2 ] = "pipe2",
586 /* 294 */ [ __NR_inotify_init1 ] = "inotify_init1",
586 /* 294 */ [ __NR_inotify_init1 ] = "inotify_init1",
587 /* 295 */ [ __NR_preadv ] = "preadv",
587 /* 295 */ [ __NR_preadv ] = "preadv",
588 /* 296 */ [ __NR_pwritev ] = "pwritev",
588 /* 296 */ [ __NR_pwritev ] = "pwritev",
589 /* 297 */ [ __NR_rt_tgsigqueueinfo ] = "rt_tgsigqueueinfo",
589 /* 297 */ [ __NR_rt_tgsigqueueinfo ] = "rt_tgsigqueueinfo",
590 /* 298 */ [ __NR_perf_event_open ] = "perf_event_open",
590 /* 298 */ [ __NR_perf_event_open ] = "perf_event_open",
591 /* 299 */ [ __NR_recvmmsg ] = "recvmmsg",
591 /* 299 */ [ __NR_recvmmsg ] = "recvmmsg",
592 /* 300 */ [ __NR_fanotify_init ] = "fanotify_init",
592 /* 300 */ [ __NR_fanotify_init ] = "fanotify_init",
593 /* 301 */ [ __NR_fanotify_mark ] = "fanotify_mark",
593 /* 301 */ [ __NR_fanotify_mark ] = "fanotify_mark",
594 /* 302 */ [ __NR_prlimit64 ] = "prlimit64",
594 /* 302 */ [ __NR_prlimit64 ] = "prlimit64",
595 /* 303 */ [ __NR_name_to_handle_at ] = "name_to_handle_at",
595 /* 303 */ [ __NR_name_to_handle_at ] = "name_to_handle_at",
596 /* 304 */ [ __NR_open_by_handle_at ] = "open_by_handle_at",
596 /* 304 */ [ __NR_open_by_handle_at ] = "open_by_handle_at",
597 /* 305 */ [ __NR_clock_adjtime ] = "clock_adjtime",
597 /* 305 */ [ __NR_clock_adjtime ] = "clock_adjtime",
598 /* 306 */ [ __NR_syncfs ] = "syncfs",
598 /* 306 */ [ __NR_syncfs ] = "syncfs",
599 /* 307 */ [ __NR_sendmmsg ] = "sendmmsg",
599 /* 307 */ [ __NR_sendmmsg ] = "sendmmsg",
600 /* 308 */ [ __NR_setns ] = "setns",
600 /* 308 */ [ __NR_setns ] = "setns",
601 /* 309 */ [ __NR_getcpu ] = "getcpu",
601 /* 309 */ [ __NR_getcpu ] = "getcpu",
602 /* 310 */ [ __NR_process_vm_readv ] = "process_vm_readv",
602 /* 310 */ [ __NR_process_vm_readv ] = "process_vm_readv",
603 /* 311 */ [ __NR_process_vm_writev ] = "process_vm_writev",
603 /* 311 */ [ __NR_process_vm_writev ] = "process_vm_writev",
604 /* 312 */ [ __NR_kcmp ] = "kcmp",
604 /* 312 */ [ __NR_kcmp ] = "kcmp",
605 /* 313 */ [ __NR_finit_module ] = "finit_module",
605 /* 313 */ [ __NR_finit_module ] = "finit_module",
606 + /* 314 */ [ __NR_sched_setattr ] = "sched_setattr",
607 + /* 315 */ [ __NR_sched_getattr ] = "sched_getattr",
608 + /* 316 */ [ __NR_renameat2 ] = "renameat2",
609 + /* 317 */ [ __NR_seccomp ] = "seccomp",
610 + /* 318 */ [ __NR_getrandom ] = "getrandom",
611 + /* 319 */ [ __NR_memfd_create ] = "memfd_create",
612 + /* 320 */ [ __NR_kexec_file_load ] = "kexec_file_load",
613 + /* 321 */ [ __NR_bpf ] = "bpf",
614 + /* 322 */ [ __NR_execveat ] = "execveat",
615 + /* 323 */ [ __NR_userfaultfd ] = "userfaultfd",
616 + /* 324 */ [ __NR_membarrier ] = "membarrier",
617 + /* 325 */ [ __NR_mlock2 ] = "mlock2",
606 };
618 };
607 #define NUM_SYSCALLS ARRAY_SIZE(syscall_names)
619 #define NUM_SYSCALLS ARRAY_SIZE(syscall_names)
608 #define NUM_ACTIONS (NUM_SYSCALLS+64)
620 #define NUM_ACTIONS (NUM_SYSCALLS+64)
609
621
610 enum action {
622 enum action {
611 A_DEFAULT, // Use the default action
623 A_DEFAULT, // Use the default action
612 A_NO, // Always forbid
624 A_NO, // Always forbid
613 A_YES, // Always permit
625 A_YES, // Always permit
614 A_FILENAME, // Permit if arg1 is a known filename
626 A_FILENAME, // Permit if arg1 is a known filename
615 A_ACTION_MASK = 15,
627 A_ACTION_MASK = 15,
616 A_NO_RETVAL = 32, // Does not return a value
628 A_NO_RETVAL = 32, // Does not return a value
617 A_SAMPLE_MEM = 64, // Sample memory usage before the syscall
629 A_SAMPLE_MEM = 64, // Sample memory usage before the syscall
618 A_LIBERAL = 128, // Valid only in liberal mode
630 A_LIBERAL = 128, // Valid only in liberal mode
619 // Must fit in a unsigned char
631 // Must fit in a unsigned char
620 };
632 };
621
633
622 static unsigned char syscall_action[NUM_ACTIONS] = {
634 static unsigned char syscall_action[NUM_ACTIONS] = {
623 #define S(x) [__NR_##x]
635 #define S(x) [__NR_##x]
624
636
625 // Syscalls permitted for specific file names
637 // Syscalls permitted for specific file names
626 S(open) = A_FILENAME,
638 S(open) = A_FILENAME,
627 S(creat) = A_FILENAME,
639 S(creat) = A_FILENAME,
628 S(unlink) = A_FILENAME,
640 S(unlink) = A_FILENAME,
629 S(access) = A_FILENAME,
641 S(access) = A_FILENAME,
630 S(truncate) = A_FILENAME,
642 S(truncate) = A_FILENAME,
631 S(stat) = A_FILENAME,
643 S(stat) = A_FILENAME,
632 S(lstat) = A_FILENAME,
644 S(lstat) = A_FILENAME,
633 S(readlink) = A_FILENAME,
645 S(readlink) = A_FILENAME,
634 #ifndef CONFIG_BOX_USER_AMD64
646 #ifndef CONFIG_BOX_USER_AMD64
635 S(oldstat) = A_FILENAME,
647 S(oldstat) = A_FILENAME,
636 S(oldlstat) = A_FILENAME,
648 S(oldlstat) = A_FILENAME,
637 S(truncate64) = A_FILENAME,
649 S(truncate64) = A_FILENAME,
638 S(stat64) = A_FILENAME,
650 S(stat64) = A_FILENAME,
639 S(lstat64) = A_FILENAME,
651 S(lstat64) = A_FILENAME,
640 #endif
652 #endif
641
653
642 // Syscalls permitted always
654 // Syscalls permitted always
643 S(exit) = A_YES | A_SAMPLE_MEM,
655 S(exit) = A_YES | A_SAMPLE_MEM,
644 S(read) = A_YES,
656 S(read) = A_YES,
645 S(write) = A_YES,
657 S(write) = A_YES,
646 S(close) = A_YES,
658 S(close) = A_YES,
647 S(lseek) = A_YES,
659 S(lseek) = A_YES,
648 S(getpid) = A_YES,
660 S(getpid) = A_YES,
649 S(getuid) = A_YES,
661 S(getuid) = A_YES,
650 S(dup) = A_YES,
662 S(dup) = A_YES,
651 S(brk) = A_YES,
663 S(brk) = A_YES,
652 S(getgid) = A_YES,
664 S(getgid) = A_YES,
653 S(geteuid) = A_YES,
665 S(geteuid) = A_YES,
@@ -1,88 +1,90
1 #!/usr/bin/env ruby
1 #!/usr/bin/env ruby
2
2
3 require 'fileutils'
3 require 'fileutils'
4
4
5 ##############################
5 ##############################
6 #
6 #
7 # Standard Compile Script
7 # Standard Compile Script
8 #
8 #
9 # Supported compilers:
9 # Supported compilers:
10 # gcc, g++, and fpc.
10 # gcc, g++, and fpc.
11 #
11 #
12 ##############################
12 ##############################
13
13
14 def talk(str='')
14 def talk(str='')
15 if ENV['TALKATIVE']!=nil
15 if ENV['TALKATIVE']!=nil
16 puts str
16 puts str
17 end
17 end
18 if ENV['GRADER_LOGGING']!=nil
18 if ENV['GRADER_LOGGING']!=nil
19 log_fname = ENV['GRADER_LOGGING']
19 log_fname = ENV['GRADER_LOGGING']
20 fp = File.open(log_fname,"a")
20 fp = File.open(log_fname,"a")
21 fp.puts("run: #{Time.new.strftime("%H:%M")} #{str}")
21 fp.puts("run: #{Time.new.strftime("%H:%M")} #{str}")
22 fp.close
22 fp.close
23 end
23 end
24 end
24 end
25
25
26 C_COMPILER = "/usr/bin/gcc"
26 C_COMPILER = "/usr/bin/gcc"
27 CPLUSPLUS_COMPILER = "/usr/bin/g++"
27 CPLUSPLUS_COMPILER = "/usr/bin/g++"
28 PASCAL_COMPILER = "/usr/bin/fpc"
28 PASCAL_COMPILER = "/usr/bin/fpc"
29 JAVA_COMPILER = "/usr/bin/javac"
29 JAVA_COMPILER = "/usr/bin/javac"
30 RUBY_INTERPRETER = "/usr/bin/ruby"
30 RUBY_INTERPRETER = "/usr/bin/ruby"
31 - PYTHON_INTERPRETER = "/usr/bin/python"
31 + PYTHON_INTERPRETER = "/usr/bin/python3"
32 PYTHON_CHECKER = "/usr/bin/pyflakes"
32 PYTHON_CHECKER = "/usr/bin/pyflakes"
33 PHP_INTERPRETER = "/usr/bin/php"
33 PHP_INTERPRETER = "/usr/bin/php"
34 + HASKELL_COMPILER = "/usr/bin/ghc"
34
35
35 C_OPTIONS = "-O2 -s -static -std=c99 -DCONTEST -lm -Wall"
36 C_OPTIONS = "-O2 -s -static -std=c99 -DCONTEST -lm -Wall"
36 CPLUSPLUS_OPTIONS = "-O2 -s -std=c++11 -static -DCONTEST -lm -Wall"
37 CPLUSPLUS_OPTIONS = "-O2 -s -std=c++11 -static -DCONTEST -lm -Wall"
37 PASCAL_OPTIONS = "-O1 -XS -dCONTEST"
38 PASCAL_OPTIONS = "-O1 -XS -dCONTEST"
38 JAVA_OPTIONS = ""
39 JAVA_OPTIONS = ""
39 PYTHON_OPTIONS = ""
40 PYTHON_OPTIONS = ""
40 PHP_OPTIONS = "-l"
41 PHP_OPTIONS = "-l"
42 + HASKELL_OPTIONS = ""
41
43
42 # Check for the correct number of arguments. Otherwise, print usage.
44 # Check for the correct number of arguments. Otherwise, print usage.
43 if ARGV.length == 0 or ARGV.length > 4
45 if ARGV.length == 0 or ARGV.length > 4
44 puts "Usage: compile <language> [<source-file>] [<output-file>] [<message-file>]"
46 puts "Usage: compile <language> [<source-file>] [<output-file>] [<message-file>]"
45 puts
47 puts
46 puts "<source-file> is defaulted to \"source\"."
48 puts "<source-file> is defaulted to \"source\"."
47 puts "<output-file> is defaulted to \"a.out\"."
49 puts "<output-file> is defaulted to \"a.out\"."
48 puts "<message-file> is defaulted to \"compiler_message\"."
50 puts "<message-file> is defaulted to \"compiler_message\"."
49 puts
51 puts
50 exit(127)
52 exit(127)
51 end
53 end
52
54
53 PARAMS = {
55 PARAMS = {
54 :source_file => [1,'source'],
56 :source_file => [1,'source'],
55 :output_file => [2,'a.out'],
57 :output_file => [2,'a.out'],
56 :message_file => [3,'compiler_message']
58 :message_file => [3,'compiler_message']
57 }
59 }
58
60
59 params = {}
61 params = {}
60 params[:prog_lang] = ARGV[0]
62 params[:prog_lang] = ARGV[0]
61 PARAMS.each_key do |param_name|
63 PARAMS.each_key do |param_name|
62 index, default = PARAMS[param_name]
64 index, default = PARAMS[param_name]
63 if ARGV.length > index
65 if ARGV.length > index
64 params[param_name] = ARGV[index]
66 params[param_name] = ARGV[index]
65 else
67 else
66 params[param_name] = default
68 params[param_name] = default
67 end
69 end
68 talk "#{param_name}: #{params[param_name]}"
70 talk "#{param_name}: #{params[param_name]}"
69 end
71 end
70
72
71 # Remove any remaining output files or message files.
73 # Remove any remaining output files or message files.
72 if FileTest.exists? params[:output_file]
74 if FileTest.exists? params[:output_file]
73 FileUtils.rm(params[:output_file])
75 FileUtils.rm(params[:output_file])
74 end
76 end
75 if FileTest.exists? params[:message_file]
77 if FileTest.exists? params[:message_file]
76 FileUtils.rm(params[:message_file])
78 FileUtils.rm(params[:message_file])
77 end
79 end
78
80
79 # Check if the source file exists before attempt compiling.
81 # Check if the source file exists before attempt compiling.
80 if !FileTest.exists? params[:source_file]
82 if !FileTest.exists? params[:source_file]
81 talk("ERROR: The source file does not exist!")
83 talk("ERROR: The source file does not exist!")
82 open(params[:message_file],"w") do |f|
84 open(params[:message_file],"w") do |f|
83 f.puts "ERROR: The source file did not exist."
85 f.puts "ERROR: The source file did not exist."
84 end
86 end
85 exit(127)
87 exit(127)
86 end
88 end
87
89
88 if params[:prog_lang]=='cpp'
90 if params[:prog_lang]=='cpp'
@@ -100,89 +102,95
100 command = "#{CPLUSPLUS_COMPILER} #{params[:source_file]} -o #{params[:output_file]} #{CPLUSPLUS_OPTIONS}"
102 command = "#{CPLUSPLUS_COMPILER} #{params[:source_file]} -o #{params[:output_file]} #{CPLUSPLUS_OPTIONS}"
101 system(command, err: params[:message_file])
103 system(command, err: params[:message_file])
102
104
103 when "pas"
105 when "pas"
104 command = "#{PASCAL_COMPILER} #{params[:source_file]} -ooutpas #{PASCAL_OPTIONS}"
106 command = "#{PASCAL_COMPILER} #{params[:source_file]} -ooutpas #{PASCAL_OPTIONS}"
105 system(command,out: params[:message_file])
107 system(command,out: params[:message_file])
106 FileUtils.mv("output", params[:output_file])
108 FileUtils.mv("output", params[:output_file])
107
109
108 when "java"
110 when "java"
109 #rename the file to the public class name
111 #rename the file to the public class name
110
112
111 #get the class name
113 #get the class name
112 classname = 'DUMMY'
114 classname = 'DUMMY'
113 source = Array.new
115 source = Array.new
114 File.foreach(params[:source_file],'r:UTF-8') do |line|
116 File.foreach(params[:source_file],'r:UTF-8') do |line|
115 line.encode!('UTF-8','UTF-8',invalid: :replace, replace: '')
117 line.encode!('UTF-8','UTF-8',invalid: :replace, replace: '')
116 md = /\s*public\s*class\s*(\w*)/.match(line)
118 md = /\s*public\s*class\s*(\w*)/.match(line)
117 classname=md[1] if md
119 classname=md[1] if md
118 source << line unless line =~ /\s*package\s*\w+\s*\;/
120 source << line unless line =~ /\s*package\s*\w+\s*\;/
119 end
121 end
120 File.open("#{classname}.java","w") do |file|
122 File.open("#{classname}.java","w") do |file|
121 source.each do |s|
123 source.each do |s|
122 file.puts s
124 file.puts s
123 end
125 end
124 end
126 end
125 #system("cp #{params[:source_file]} #{classname}.java")
127 #system("cp #{params[:source_file]} #{classname}.java")
126 command = "#{JAVA_COMPILER} -encoding utf8 #{classname}.java"
128 command = "#{JAVA_COMPILER} -encoding utf8 #{classname}.java"
127 system(command, err: params[:message_file])
129 system(command, err: params[:message_file])
128 if File.exists?(classname + ".class")
130 if File.exists?(classname + ".class")
129 File.open(params[:output_file],"w") {|file| file.write("#{classname}")}
131 File.open(params[:output_file],"w") {|file| file.write("#{classname}")}
130 end
132 end
131 if classname == 'DUMMY'
133 if classname == 'DUMMY'
132 File.open(params[:message_file],"w") {|file| file.write("Cannot find any public class in the source code\n")}
134 File.open(params[:message_file],"w") {|file| file.write("Cannot find any public class in the source code\n")}
133 end
135 end
134
136
135 when "ruby"
137 when "ruby"
136 command = "#{RUBY_INTERPRETER} -c #{params[:source_file]}"
138 command = "#{RUBY_INTERPRETER} -c #{params[:source_file]}"
137 if system(command, err: params[:message_file])
139 if system(command, err: params[:message_file])
138 File.open(params[:output_file],"w") do |out_file|
140 File.open(params[:output_file],"w") do |out_file|
139 out_file.puts "#!#{RUBY_INTERPRETER}"
141 out_file.puts "#!#{RUBY_INTERPRETER}"
140 File.open(params[:source_file],"r").each do |line|
142 File.open(params[:source_file],"r").each do |line|
141 out_file.print line
143 out_file.print line
142 end
144 end
143 end
145 end
144 File.chmod(0755, params[:output_file])
146 File.chmod(0755, params[:output_file])
145 end
147 end
146
148
147 when "python"
149 when "python"
148 - command = "#{PYTHON_CHECKER} #{params[:source_file]}"
150 + #command = "#{PYTHON_CHECKER} #{params[:source_file]}"
149 - if system(command, out: params[:message_file])
151 + #if system(command, out: params[:message_file])
150 #compile to python bytecode
152 #compile to python bytecode
151 - command = "#{PYTHON_INTERPRETER} -m py_compile #{params[:source_file]}"
153 + command = "#{PYTHON_INTERPRETER} -c \"import py_compile; py_compile.compile('#{params[:source_file]}','#{params[:source_file]}c');\""
152 puts "compile: #{command}"
154 puts "compile: #{command}"
153 - system(command)
155 + system(command, err: params[:message_file])
154 - puts "pwd: " + Dir.pwd
156 + if FileTest.exists?("#{params[:source_file]}c")
155 - Dir.new('.').each {|file| puts file}
157 + puts "pwd: " + Dir.pwd
156 - File.open(params[:output_file],"w") do |out_file|
158 + Dir.new('.').each {|file| puts file}
157 - out_file.puts "#!#{PYTHON_INTERPRETER} #{params[:source_file]}c"
159 + File.open(params[:output_file],"w") do |out_file|
160 + out_file.puts "#!#{PYTHON_INTERPRETER} #{params[:source_file]}c"
161 + end
162 + File.chmod(0755, params[:output_file])
163 + FileUtils.cp("#{params[:source_file]}c",params[:output_file])
158 end
164 end
159 - File.chmod(0755, params[:output_file])
165 + #end
160 - FileUtils.cp("#{params[:source_file]}c",params[:output_file])
161 - end
162
166
163 when "php"
167 when "php"
164 command = "#{PHP_INTERPRETER} #{PHP_OPTIONS} #{params[:source_file]}"
168 command = "#{PHP_INTERPRETER} #{PHP_OPTIONS} #{params[:source_file]}"
165 if system(command, err: params[:message_file])
169 if system(command, err: params[:message_file])
166 File.open(params[:output_file],"w") do |out_file|
170 File.open(params[:output_file],"w") do |out_file|
167 out_file.puts "#!#{PHP_INTERPRETER}"
171 out_file.puts "#!#{PHP_INTERPRETER}"
168 File.open(params[:source_file],"r").each do |line|
172 File.open(params[:source_file],"r").each do |line|
169 out_file.print line
173 out_file.print line
170 end
174 end
171 end
175 end
172 File.chmod(0755, params[:output_file])
176 File.chmod(0755, params[:output_file])
173 end
177 end
174
178
179 + when "haskell"
180 + command = "#{HASKELL_COMPILER} #{params[:source_file]} -o #{params[:output_file]} #{HASKELL_OPTIONS}"
181 + system(command, err: params[:message_file])
182 +
175 else
183 else
176 talk("ERROR: Invalid language specified!")
184 talk("ERROR: Invalid language specified!")
177 open(params[:message_file],"w") do |f|
185 open(params[:message_file],"w") do |f|
178 f.puts "ERROR: Invalid language specified!"
186 f.puts "ERROR: Invalid language specified!"
179 end
187 end
180 exit(127)
188 exit(127)
181 end
189 end
182
190
183 # Report success or failure.
191 # Report success or failure.
184 if FileTest.exists? params[:output_file]
192 if FileTest.exists? params[:output_file]
185 talk "Compilation was successful!"
193 talk "Compilation was successful!"
186 else
194 else
187 talk "ERROR: Something was wrong during the compilation!"
195 talk "ERROR: Something was wrong during the compilation!"
188 end
196 end
@@ -8,173 +8,179
8 end
8 end
9 if ENV['GRADER_LOGGING']!=nil
9 if ENV['GRADER_LOGGING']!=nil
10 log_fname = ENV['GRADER_LOGGING']
10 log_fname = ENV['GRADER_LOGGING']
11 fp = File.open(log_fname,"a")
11 fp = File.open(log_fname,"a")
12 fp.puts("judge: #{Time.new.strftime("%H:%M")} #{str}")
12 fp.puts("judge: #{Time.new.strftime("%H:%M")} #{str}")
13 fp.close
13 fp.close
14 end
14 end
15 end
15 end
16
16
17 problem_home = ENV['PROBLEM_HOME']
17 problem_home = ENV['PROBLEM_HOME']
18
18
19 def execute(command, error_message="")
19 def execute(command, error_message="")
20 if not system(command)
20 if not system(command)
21 msg = "ERROR: #{error_message}"
21 msg = "ERROR: #{error_message}"
22 log msg
22 log msg
23 raise(msg)
23 raise(msg)
24 end
24 end
25 end
25 end
26
26
27 def call_and_log(error_message)
27 def call_and_log(error_message)
28 begin
28 begin
29 yield
29 yield
30 rescue
30 rescue
31 msg = "ERROR: #{error_message}"
31 msg = "ERROR: #{error_message}"
32 log msg
32 log msg
33 raise msg
33 raise msg
34 end
34 end
35 end
35 end
36
36
37 def clear_and_create_empty_dir(dir)
37 def clear_and_create_empty_dir(dir)
38 FileUtils.rm_rf(dir, :secure => true)
38 FileUtils.rm_rf(dir, :secure => true)
39 call_and_log("Cannot make directory #{dir}.") { FileUtils.mkdir(dir) }
39 call_and_log("Cannot make directory #{dir}.") { FileUtils.mkdir(dir) }
40 end
40 end
41
41
42 # ARGV[0] --- language
42 # ARGV[0] --- language
43 # ARGV[1] --- program source file
43 # ARGV[1] --- program source file
44 # ARGV[2] --- test result directory
44 # ARGV[2] --- test result directory
45 # ARGV[3] --- sandbox directory
45 # ARGV[3] --- sandbox directory
46
46
47 if ARGV.length < 2 || ARGV.length > 4
47 if ARGV.length < 2 || ARGV.length > 4
48 puts "Usage: judge <language> <program-source> [<test-result-directory>] [<sandbox-directory>]"
48 puts "Usage: judge <language> <program-source> [<test-result-directory>] [<sandbox-directory>]"
49 puts " <sandbox-directory> is defaulted to ./sandbox"
49 puts " <sandbox-directory> is defaulted to ./sandbox"
50 puts " <test-result-directory> is defaulted to ./test-result"
50 puts " <test-result-directory> is defaulted to ./test-result"
51 puts "WARNING: The judge script will forcefully create the (implicitly and explicitly) specified directories and remove anything inside it."
51 puts "WARNING: The judge script will forcefully create the (implicitly and explicitly) specified directories and remove anything inside it."
52 exit(127)
52 exit(127)
53 end
53 end
54
54
55 language = ARGV[0]
55 language = ARGV[0]
56 - if language != "c" && language != "c++" && language != "pas" && language != "java" && language != "ruby" && language != "python" && language != "php"
56 + if language != "c" && language != "c++" && language != "pas" && language != "java" && language != "ruby" && language != "python" && language != "php" && language != "haskell"
57 log "You specified a language that is not supported: #{language}."
57 log "You specified a language that is not supported: #{language}."
58 exit(127)
58 exit(127)
59 end
59 end
60
60
61 source_file = ARGV[1]
61 source_file = ARGV[1]
62 ENV['SOURCE_NAME'] = source_file
62 ENV['SOURCE_NAME'] = source_file
63 if File.exist?(source_file) == false
63 if File.exist?(source_file) == false
64 log "The source file does not exist."
64 log "The source file does not exist."
65 exit(127)
65 exit(127)
66 end
66 end
67
67
68 log "Making test result and sandbox directories..."
68 log "Making test result and sandbox directories..."
69
69
70 current_dir = FileUtils.pwd
70 current_dir = FileUtils.pwd
71 current_dir.strip!
71 current_dir.strip!
72
72
73 if ARGV.length >= 3
73 if ARGV.length >= 3
74 test_result_dir = ARGV[2]
74 test_result_dir = ARGV[2]
75 else
75 else
76 test_result_dir = "#{current_dir}/test-result"
76 test_result_dir = "#{current_dir}/test-result"
77 end
77 end
78
78
79 log "Test result directory: #{test_result_dir}"
79 log "Test result directory: #{test_result_dir}"
80 clear_and_create_empty_dir(test_result_dir)
80 clear_and_create_empty_dir(test_result_dir)
81
81
82 if ARGV.length >= 4
82 if ARGV.length >= 4
83 sandbox_dir = ARGV[3]
83 sandbox_dir = ARGV[3]
84 else
84 else
85 sandbox_dir = "#{current_dir}/sandbox"
85 sandbox_dir = "#{current_dir}/sandbox"
86 end
86 end
87 log "Sandbox directory: #{sandbox_dir}"
87 log "Sandbox directory: #{sandbox_dir}"
88 clear_and_create_empty_dir(sandbox_dir)
88 clear_and_create_empty_dir(sandbox_dir)
89
89
90 # Compile
90 # Compile
91 log
91 log
92 log "Compiling..."
92 log "Compiling..."
93 call_and_log("Cannot copy the source file to #{sandbox_dir}") {
93 call_and_log("Cannot copy the source file to #{sandbox_dir}") {
94 FileUtils.cp(source_file, sandbox_dir)
94 FileUtils.cp(source_file, sandbox_dir)
95 }
95 }
96 begin
96 begin
97 Dir.chdir sandbox_dir
97 Dir.chdir sandbox_dir
98 rescue
98 rescue
99 log "ERROR: Cannot change directory to #{sandbox_dir}."
99 log "ERROR: Cannot change directory to #{sandbox_dir}."
100 exit(127)
100 exit(127)
101 end
101 end
102 execute("#{problem_home}/script/compile #{language} #{source_file}", "Compilation error!")
102 execute("#{problem_home}/script/compile #{language} #{source_file}", "Compilation error!")
103 compile_message = open("compiler_message").read
103 compile_message = open("compiler_message").read
104 compile_message.strip!
104 compile_message.strip!
105 call_and_log("Cannot move the compiler message to #{test_result_dir}.") {
105 call_and_log("Cannot move the compiler message to #{test_result_dir}.") {
106 FileUtils.mv("compiler_message", test_result_dir)
106 FileUtils.mv("compiler_message", test_result_dir)
107 }
107 }
108 if !FileTest.exist?("a.out")
108 if !FileTest.exist?("a.out")
109 log "Cannot compile the source code. See message in #{test_result_dir}/compile_message"
109 log "Cannot compile the source code. See message in #{test_result_dir}/compile_message"
110 exit(127)
110 exit(127)
111 else
111 else
112 call_and_log("Cannot move the compiled program to #{test_result_dir}") {
112 call_and_log("Cannot move the compiled program to #{test_result_dir}") {
113 FileUtils.mv("a.out",test_result_dir)
113 FileUtils.mv("a.out",test_result_dir)
114 if language == "java" then Dir["*.class"].each { |file| FileUtils.mv(file,test_result_dir)} end
114 if language == "java" then Dir["*.class"].each { |file| FileUtils.mv(file,test_result_dir)} end
115 if language == "python" then Dir["*.pyc"].each { |file| FileUtils.mv(file,test_result_dir)} end
115 if language == "python" then Dir["*.pyc"].each { |file| FileUtils.mv(file,test_result_dir)} end
116 }
116 }
117 FileUtils.rm_rf("#{sandbox_dir}/.")
117 FileUtils.rm_rf("#{sandbox_dir}/.")
118 end
118 end
119
119
120 require "#{problem_home}/script/test_dsl.rb"
120 require "#{problem_home}/script/test_dsl.rb"
121 load "#{problem_home}/test_cases/all_tests.cfg"
121 load "#{problem_home}/test_cases/all_tests.cfg"
122 problem = Problem.get_instance
122 problem = Problem.get_instance
123
123
124 if problem.well_formed? == false
124 if problem.well_formed? == false
125 log "The problem specification is not well formed."
125 log "The problem specification is not well formed."
126 exit(127)
126 exit(127)
127 end
127 end
128
128
129 # Doing the testing.
129 # Doing the testing.
130 (1..(problem.num_tests)).each do |test_num|
130 (1..(problem.num_tests)).each do |test_num|
131
131
132 $stdout.print "[#{test_num}]"
132 $stdout.print "[#{test_num}]"
133 $stdout.flush
133 $stdout.flush
134
134
135 log "Test number: #{test_num}"
135 log "Test number: #{test_num}"
136
136
137 call_and_log("Cannot copy the compiled program into #{sandbox_dir}") {
137 call_and_log("Cannot copy the compiled program into #{sandbox_dir}") {
138 FileUtils.cp("#{test_result_dir}/a.out", sandbox_dir, :preserve => true)
138 FileUtils.cp("#{test_result_dir}/a.out", sandbox_dir, :preserve => true)
139 if language == "java" then Dir["#{test_result_dir}/*.class"].each { |file| FileUtils.cp(file,sandbox_dir)} end
139 if language == "java" then Dir["#{test_result_dir}/*.class"].each { |file| FileUtils.cp(file,sandbox_dir)} end
140 if language == "python" then Dir["#{test_result_dir}/*.pyc"].each { |file| FileUtils.cp(file,sandbox_dir)} end
140 if language == "python" then Dir["#{test_result_dir}/*.pyc"].each { |file| FileUtils.cp(file,sandbox_dir)} end
141 }
141 }
142
142
143 + #additionally copy any extra .txt file
144 + data_files = Dir[problem_home + '/*.txt']
145 + data_files.each do |file|
146 + FileUtils.cp(file,sandbox_dir)
147 + end
148 +
143 begin
149 begin
144 execute("#{problem_home}/script/run #{language} #{test_num} ", "Error occured during execution of the run script")
150 execute("#{problem_home}/script/run #{language} #{test_num} ", "Error occured during execution of the run script")
145 rescue
151 rescue
146 # do nothing
152 # do nothing
147 end
153 end
148
154
149 call_and_log("Cannot create directory #{test_result_dir}/#{test_num}") {
155 call_and_log("Cannot create directory #{test_result_dir}/#{test_num}") {
150 FileUtils.mkdir "#{test_result_dir}/#{test_num}"
156 FileUtils.mkdir "#{test_result_dir}/#{test_num}"
151 }
157 }
152 call_and_log("Cannot copy the result file into #{test_result_dir}/#{test_num}") {
158 call_and_log("Cannot copy the result file into #{test_result_dir}/#{test_num}") {
153 FileUtils.mv "#{sandbox_dir}/result", "#{test_result_dir}/#{test_num}"
159 FileUtils.mv "#{sandbox_dir}/result", "#{test_result_dir}/#{test_num}"
154 }
160 }
155 call_and_log("Cannot copy the comment file into #{test_result_dir}/#{test_num}") {
161 call_and_log("Cannot copy the comment file into #{test_result_dir}/#{test_num}") {
156 FileUtils.mv "#{sandbox_dir}/comment", "#{test_result_dir}/#{test_num}"
162 FileUtils.mv "#{sandbox_dir}/comment", "#{test_result_dir}/#{test_num}"
157 }
163 }
158 call_and_log("Cannot copy the output file into #{test_result_dir}/#{test_num}") {
164 call_and_log("Cannot copy the output file into #{test_result_dir}/#{test_num}") {
159 FileUtils.mv "#{sandbox_dir}/output.txt", "#{test_result_dir}/#{test_num}"
165 FileUtils.mv "#{sandbox_dir}/output.txt", "#{test_result_dir}/#{test_num}"
160 }
166 }
161 call_and_log("Cannot clear #{sandbox_dir}") {
167 call_and_log("Cannot clear #{sandbox_dir}") {
162 FileUtils.rm_rf(Dir.glob("#{sandbox_dir}/*"), :secure => true)
168 FileUtils.rm_rf(Dir.glob("#{sandbox_dir}/*"), :secure => true)
163 }
169 }
164 end
170 end
165
171
166 $stdout.print "[done]\n"
172 $stdout.print "[done]\n"
167
173
168 # Grade
174 # Grade
169 log
175 log
170 log "Grading..."
176 log "Grading..."
171 begin
177 begin
172 Dir.chdir test_result_dir
178 Dir.chdir test_result_dir
173 rescue
179 rescue
174 log "ERROR: Cannot change directory to #{test_result_dir}."
180 log "ERROR: Cannot change directory to #{test_result_dir}."
175 exit(127)
181 exit(127)
176 end
182 end
177 execute("#{problem_home}/script/grade", "An error occured during grading!")
183 execute("#{problem_home}/script/grade", "An error occured during grading!")
178
184
179 log
185 log
180 log "All done!"
186 log "All done!"
@@ -47,115 +47,118
47 require "#{problem_home}/script/test_dsl.rb"
47 require "#{problem_home}/script/test_dsl.rb"
48 load "#{problem_home}/test_cases/all_tests.cfg"
48 load "#{problem_home}/test_cases/all_tests.cfg"
49 problem = Problem.get_instance
49 problem = Problem.get_instance
50
50
51 sandbox_dir = Dir.getwd
51 sandbox_dir = Dir.getwd
52
52
53 if problem.well_formed? == false
53 if problem.well_formed? == false
54 log "The problem specification is not well formed."
54 log "The problem specification is not well formed."
55 exit(127)
55 exit(127)
56 end
56 end
57
57
58 # Check if the test number is okay.
58 # Check if the test number is okay.
59 if test_num <= 0 || test_num > problem.num_tests
59 if test_num <= 0 || test_num > problem.num_tests
60 log "You have specified a wrong test number."
60 log "You have specified a wrong test number."
61 exit(127)
61 exit(127)
62 end
62 end
63
63
64 #####################################
64 #####################################
65 # Set the relavant file names here. #
65 # Set the relavant file names here. #
66 #####################################
66 #####################################
67
67
68 input_file_name = "#{problem_home}/test_cases/#{test_num}/input-#{test_num}.txt"
68 input_file_name = "#{problem_home}/test_cases/#{test_num}/input-#{test_num}.txt"
69
69
70 #####################################
70 #####################################
71
71
72 time_limit = problem.get_time_limit test_num
72 time_limit = problem.get_time_limit test_num
73 mem_limit = problem.get_mem_limit(test_num) * 1024
73 mem_limit = problem.get_mem_limit(test_num) * 1024
74
74
75 # Copy the input file.
75 # Copy the input file.
76 #`cp #{problem_home}/test_cases/#{test_num}/#{input_file_name} .`
76 #`cp #{problem_home}/test_cases/#{test_num}/#{input_file_name} .`
77
77
78 # check if box is there, if not, compile it!
78 # check if box is there, if not, compile it!
79 if !File.exists?("#{problem_home}/script/box")
79 if !File.exists?("#{problem_home}/script/box")
80 log "WARNING: Compiling box: to increase efficiency, it should be compile manually"
80 log "WARNING: Compiling box: to increase efficiency, it should be compile manually"
81 compile_box("#{problem_home}/script/box.cc",
81 compile_box("#{problem_home}/script/box.cc",
82 "#{problem_home}/script/box")
82 "#{problem_home}/script/box")
83 end
83 end
84
84
85 # Hide PROBLEM_HOME
85 # Hide PROBLEM_HOME
86 ENV['PROBLEM_HOME'] = nil
86 ENV['PROBLEM_HOME'] = nil
87 ENV['SOURCE_NAME'] = nil
87 ENV['SOURCE_NAME'] = nil
88
88
89 # Run the program.
89 # Run the program.
90 #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}"
90 #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}"
91 #
91 #
92
92
93 JAVA_OPTION = "-s set_robust_list -s futex -s clone -s getppid -s clone -s wait4 -p /usr/bin/ -p ./"
93 JAVA_OPTION = "-s set_robust_list -s futex -s clone -s getppid -s clone -s wait4 -p /usr/bin/ -p ./"
94 RUBY_OPTION = "-p /usr/lib64/ -p /usr/local/lib64/ -p /usr/local/lib/ -p /lib64/ -p /dev/urandom -p #{sandbox_dir}/#{program_name} -p #{sandbox_dir}/ -s set_robust_list -s sched_getaffinity -s clock_gettime -s sigaltstack -s pipe2 -s clone -s futex -s openat -s pipe"
94 RUBY_OPTION = "-p /usr/lib64/ -p /usr/local/lib64/ -p /usr/local/lib/ -p /lib64/ -p /dev/urandom -p #{sandbox_dir}/#{program_name} -p #{sandbox_dir}/ -s set_robust_list -s sched_getaffinity -s clock_gettime -s sigaltstack -s pipe2 -s clone -s futex -s openat -s pipe"
95 - PYTHON_OPTION = "-p /usr/lib64/ -p /usr/local/lib64/ -p /usr/local/lib/ -p /usr/bin/ -p /lib64/ -p #{sandbox_dir}/#{program_name} -p ./#{program_name} -p #{sandbox_dir}/#{source_name} -s set_robust_list -s openat -s recvmsg -s connect -s socket -s sendto -s futex -E PYTHONNOUSERSITE=yes"
95 + PYTHON_OPTION = "-p /usr/lib64/ -p /usr/local/lib64/ -p /usr/local/lib/ -p /usr/bin/ -p /lib64/ -p /dev/urandom -p /usr/ -p #{sandbox_dir}/#{program_name} -p ./#{program_name} -p #{sandbox_dir}/#{source_name} -p /proc/sys/crypto/fips_enabled -p /proc/self/status -p /proc/mounts -p /var/lib/dpkg/status -s statfs -s set_robust_list -s openat -s sysinfo -s recvmsg -s connect -s socket -s sendto -s futex -s sigaltstack -s getrandom -E PYTHONNOUSERSITE=yes"
96 PHP_OPTION = "-p /usr/lib64/ -p/lib64/ -p /usr/bin/ -p #{sandbox_dir}/#{program_name} -p ./#{program_name} -p /usr/share/ -s setfsuid -s setfsgid -s openat -s set_robust_list -s futex -s clone -s socket -s connect"
96 PHP_OPTION = "-p /usr/lib64/ -p/lib64/ -p /usr/bin/ -p #{sandbox_dir}/#{program_name} -p ./#{program_name} -p /usr/share/ -s setfsuid -s setfsgid -s openat -s set_robust_list -s futex -s clone -s socket -s connect"
97 + HASKELL_OPTION = "-s set_robust_list -s clock_gettime -s sysinfo -s timer_create -s timer_settime -s futex -s timer_delete"
97
98
98 case language
99 case language
99 when "java"
100 when "java"
100 # for java, extract the classname
101 # for java, extract the classname
101 # wne have to add additional systemcall and we don't check the mem limit (dunno how to fix...)
102 # wne have to add additional systemcall and we don't check the mem limit (dunno how to fix...)
102 classname = 'DUMMY'
103 classname = 'DUMMY'
103 File.open(program_name,"r").each do |line|
104 File.open(program_name,"r").each do |line|
104 classname = line
105 classname = line
105 end
106 end
106 #for java, we cannot really check the memory limit...
107 #for java, we cannot really check the memory limit...
107 run_command = "#{problem_home}/script/box -a 3 -f -T -t #{time_limit} #{JAVA_OPTION} -i #{input_file_name} -o output.txt /usr/bin/java -A -Xmx#{mem_limit}k -A #{classname} "
108 run_command = "#{problem_home}/script/box -a 3 -f -T -t #{time_limit} #{JAVA_OPTION} -i #{input_file_name} -o output.txt /usr/bin/java -A -Xmx#{mem_limit}k -A #{classname} "
108 when "ruby"
109 when "ruby"
109 run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit*=2} -m #{mem_limit} #{RUBY_OPTION} -i #{input_file_name} -o output.txt /usr/bin/ruby #{program_name} "
110 run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit*=2} -m #{mem_limit} #{RUBY_OPTION} -i #{input_file_name} -o output.txt /usr/bin/ruby #{program_name} "
110 when "python"
111 when "python"
111 - run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit*=2} -m #{mem_limit} #{PYTHON_OPTION} -i #{input_file_name} -o output.txt /usr/bin/python #{program_name} "
112 + run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit*=2} -m #{[128 * 1024,mem_limit].max} #{PYTHON_OPTION} -i #{input_file_name} -o output.txt /usr/bin/python3 #{program_name} "
113 + when "haskell"
114 + run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit} -m #{[512 * 1024,mem_limit].max} #{HASKELL_OPTION} -i #{input_file_name} -o output.txt #{program_name} "
112 when "php"
115 when "php"
113 - run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit*=2} -m #{[128*1024,mem_limit].max} #{PHP_OPTION} -i #{input_file_name} -o output.txt /usr/bin/php -A -d -A memory_limit=#{mem_limit}k -A #{program_name} "
116 + run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit*=2} -m #{[128 * 1024,mem_limit].max} #{PHP_OPTION} -i #{input_file_name} -o output.txt /usr/bin/php -A -d -A memory_limit=#{mem_limit}k -A #{program_name} "
114 else # for c++, pascal, we do the normal checking
117 else # for c++, pascal, we do the normal checking
115 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} "
118 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} "
116 end
119 end
117
120
118
121
119 log "Running test #{test_num}..."
122 log "Running test #{test_num}..."
120 log run_command
123 log run_command
121 log
124 log
122 system(run_command,err: 'run_result')
125 system(run_command,err: 'run_result')
123
126
124 # Restore PROBLEM_HOME
127 # Restore PROBLEM_HOME
125 ENV['PROBLEM_HOME'] = problem_home
128 ENV['PROBLEM_HOME'] = problem_home
126
129
127 # Create the result file.
130 # Create the result file.
128 result_file = File.new("result", "w")
131 result_file = File.new("result", "w")
129 comment_file = File.new("comment", "w")
132 comment_file = File.new("comment", "w")
130
133
131 # Check if the program actually produced any output.
134 # Check if the program actually produced any output.
132 run_result_file = File.new("run_result", "r")
135 run_result_file = File.new("run_result", "r")
133 run_result = run_result_file.readlines
136 run_result = run_result_file.readlines
134 run_result_file.close
137 run_result_file.close
135
138
136 run_stat = run_result[run_result.length-1]
139 run_stat = run_result[run_result.length-1]
137 running_time = extract_time(run_stat)
140 running_time = extract_time(run_stat)
138
141
139 report = lambda{ |status, points, comment|
142 report = lambda{ |status, points, comment|
140 result_file.write status.strip
143 result_file.write status.strip
141 result_file.write "\n"
144 result_file.write "\n"
142 result_file.write points.to_s.strip
145 result_file.write points.to_s.strip
143 result_file.write "\n"
146 result_file.write "\n"
144 result_file.write run_stat.strip
147 result_file.write run_stat.strip
145 result_file.write "\n"
148 result_file.write "\n"
146 result_file.close
149 result_file.close
147 FileUtils.rm "run_result"
150 FileUtils.rm "run_result"
148 # `rm output.txt` --- keep the output
151 # `rm output.txt` --- keep the output
149
152
150 comment_file.write comment
153 comment_file.write comment
151
154
152 # added for debuggin --- jittat
155 # added for debuggin --- jittat
153 comment_file.write "--run-result--\n"
156 comment_file.write "--run-result--\n"
154 run_result.each do |l|
157 run_result.each do |l|
155 comment_file.write l
158 comment_file.write l
156 end
159 end
157
160
158 comment_file.close
161 comment_file.close
159
162
160 log "Done!"
163 log "Done!"
161 exit(0)
164 exit(0)
@@ -2,65 +2,74
2
2
3 problem_home = ENV['PROBLEM_HOME']
3 problem_home = ENV['PROBLEM_HOME']
4 require "#{problem_home}/script/test_dsl.rb"
4 require "#{problem_home}/script/test_dsl.rb"
5
5
6 if ARGV.length < 2
6 if ARGV.length < 2
7 puts "Usage: check <language> <test-number> [<output-file>]"
7 puts "Usage: check <language> <test-number> [<output-file>]"
8 exit(0)
8 exit(0)
9 end
9 end
10
10
11 language = ARGV[0]
11 language = ARGV[0]
12 test_num = ARGV[1].to_i
12 test_num = ARGV[1].to_i
13 if ARGV.length >= 3
13 if ARGV.length >= 3
14 output_file_name = ARGV[2]
14 output_file_name = ARGV[2]
15 else
15 else
16 output_file_name = "output.txt"
16 output_file_name = "output.txt"
17 end
17 end
18
18
19 load "#{problem_home}/test_cases/all_tests.cfg"
19 load "#{problem_home}/test_cases/all_tests.cfg"
20 problem = Problem.get_instance
20 problem = Problem.get_instance
21
21
22 output_file = File.new(output_file_name, "r")
22 output_file = File.new(output_file_name, "r")
23 answer_file = File.new("#{problem_home}/test_cases/#{test_num}/answer-#{test_num}.txt")
23 answer_file = File.new("#{problem_home}/test_cases/#{test_num}/answer-#{test_num}.txt")
24 result_file = File.new("check_result", "w")
24 result_file = File.new("check_result", "w")
25
25
26 output_file_content = output_file.read
26 output_file_content = output_file.read
27 answer_file_content = answer_file.read
27 answer_file_content = answer_file.read
28
28
29 report_correct = lambda {
29 report_correct = lambda {
30 result_file.write "Correct\n"
30 result_file.write "Correct\n"
31 result_file.write problem.get_score(test_num)
31 result_file.write problem.get_score(test_num)
32 result_file.write "\n"
32 result_file.write "\n"
33 result_file.close
33 result_file.close
34 exit(0)
34 exit(0)
35 }
35 }
36
36
37 report_wrong = lambda {
37 report_wrong = lambda {
38 result_file.write "Incorrect\n"
38 result_file.write "Incorrect\n"
39 result_file.write "0\n"
39 result_file.write "0\n"
40 result_file.close
40 result_file.close
41 exit(0)
41 exit(0)
42 }
42 }
43
43
44 ##################
44 ##################
45 # Your code here #
45 # Your code here #
46 ##################
46 ##################
47
47
48 ########### THIS IS FOR CHECKING FLOAT with EPSILON error ##########
48 ########### THIS IS FOR CHECKING FLOAT with EPSILON error ##########
49
49
50 +
51 + def is_float?(fl)
52 + !!Float(fl) rescue false
53 + end
54 +
50 EPSILON = 0.000001
55 EPSILON = 0.000001
51
56
52 out_items = output_file_content.split
57 out_items = output_file_content.split
53 ans_items = answer_file_content.split
58 ans_items = answer_file_content.split
54
59
55 if out_items.length != ans_items.length
60 if out_items.length != ans_items.length
56 report_wrong.call
61 report_wrong.call
57 else
62 else
58 out_items.length.times do |i|
63 out_items.length.times do |i|
59 - out_value = out_items[i].to_f
64 + if is_float?(out_items[i]) && is_float?(ans_items[i])
60 - ans_value = ans_items[i].to_f
65 + out_value = out_items[i].to_f
61 - if (out_value - ans_value).abs > EPSILON * [out_value.abs,ans_value.abs].max
66 + ans_value = ans_items[i].to_f
62 - report_wrong.call
67 + if (out_value - ans_value).abs > EPSILON * [out_value.abs,ans_value.abs].max
68 + report_wrong.call
69 + end
70 + else
71 + report_wrong.call if out_items[i] != ans_items[i]
63 end
72 end
64 end
73 end
65 report_correct.call
74 report_correct.call
66 end
75 end
You need to be logged in to leave comments. Login now