Description:
[grader] +grade submission git-svn-id: http://theory.cpe.ku.ac.th/grader/judge/trunk/scripts@264 6386c4cd-e34a-4fa8-8920-d93eb39b512e
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r61:3dcc15f24294 - - 3 files changed: 34 inserted, 0 deleted

@@ -1,189 +1,212
1 #!/usr/bin/ruby
1 #!/usr/bin/ruby
2
2
3 def stop_grader(id)
3 def stop_grader(id)
4 if id==:all
4 if id==:all
5 File.open(File.dirname(__FILE__) + "/stop.all",'w').close
5 File.open(File.dirname(__FILE__) + "/stop.all",'w').close
6 else
6 else
7 File.open(File.dirname(__FILE__) + "/stop.#{id}",'w').close
7 File.open(File.dirname(__FILE__) + "/stop.#{id}",'w').close
8 end
8 end
9 end
9 end
10
10
11 def check_stopfile
11 def check_stopfile
12 FileTest.exist?(File.dirname(__FILE__) + "/stop.all") or
12 FileTest.exist?(File.dirname(__FILE__) + "/stop.all") or
13 FileTest.exist?(File.dirname(__FILE__) + "/stop.#{Process.pid}")
13 FileTest.exist?(File.dirname(__FILE__) + "/stop.#{Process.pid}")
14 end
14 end
15
15
16 def clear_stopfile
16 def clear_stopfile
17 if FileTest.exist?(File.dirname(__FILE__) + "/stop.#{Process.pid}")
17 if FileTest.exist?(File.dirname(__FILE__) + "/stop.#{Process.pid}")
18 system("rm " + File.dirname(__FILE__) + "/stop.#{Process.pid}")
18 system("rm " + File.dirname(__FILE__) + "/stop.#{Process.pid}")
19 end
19 end
20 end
20 end
21
21
22 def config
22 def config
23 Grader::Configuration.get_instance
23 Grader::Configuration.get_instance
24 end
24 end
25
25
26 def log_file_name
26 def log_file_name
27 if !File.exists?(config.log_dir)
27 if !File.exists?(config.log_dir)
28 raise "Log directory does not exist: #{config.log_dir}"
28 raise "Log directory does not exist: #{config.log_dir}"
29 end
29 end
30 config.log_dir +
30 config.log_dir +
31 "/#{GRADER_ENV}_#{config.grader_mode}.#{Process.pid}"
31 "/#{GRADER_ENV}_#{config.grader_mode}.#{Process.pid}"
32 end
32 end
33
33
34 def log(str)
34 def log(str)
35 if config.talkative
35 if config.talkative
36 puts str
36 puts str
37 end
37 end
38 if config.logging
38 if config.logging
39 fp = File.open(log_file_name,"a")
39 fp = File.open(log_file_name,"a")
40 fp.puts("GRADER: #{Time.new.strftime("%H:%M")} #{str}")
40 fp.puts("GRADER: #{Time.new.strftime("%H:%M")} #{str}")
41 fp.close
41 fp.close
42 end
42 end
43 end
43 end
44
44
45 def display_manual
45 def display_manual
46 puts <<USAGE
46 puts <<USAGE
47 Grader.
47 Grader.
48 using: (1) grader
48 using: (1) grader
49 (2) grader environment [mode]
49 (2) grader environment [mode]
50 (3) grader stop [all|pids-list]
50 (3) grader stop [all|pids-list]
51 (4) grader --help
51 (4) grader --help
52 (1) call grader with environment = 'exam', mode = 'queue'
52 (1) call grader with environment = 'exam', mode = 'queue'
53 (2) possible modes are: 'queue', 'prob', 'test_request'
53 (2) possible modes are: 'queue', 'prob', 'test_request'
54 (3) create stop-file to stop running grader in queue mode
54 (3) create stop-file to stop running grader in queue mode
55 (4) You are here.
55 (4) You are here.
56 USAGE
56 USAGE
57 end
57 end
58
58
59 #########################################
59 #########################################
60 # main program
60 # main program
61 #########################################
61 #########################################
62
62
63 # with --help
63 # with --help
64 if (ARGV.length==1) and (/help/.match(ARGV[0]))
64 if (ARGV.length==1) and (/help/.match(ARGV[0]))
65 display_manual
65 display_manual
66 exit(0)
66 exit(0)
67 end
67 end
68
68
69 # reading environment and options
69 # reading environment and options
70 if (ARGV.length >= 1) and (ARGV[0]=='stop')
70 if (ARGV.length >= 1) and (ARGV[0]=='stop')
71 if ARGV.length==1
71 if ARGV.length==1
72 puts "you should specify pid-list or 'all'"
72 puts "you should specify pid-list or 'all'"
73 display_manual
73 display_manual
74 elsif (ARGV.length==2) and (ARGV[1]=='all')
74 elsif (ARGV.length==2) and (ARGV[1]=='all')
75 stop_grader(:all)
75 stop_grader(:all)
76 puts "A global stop file ('stop.all') created."
76 puts "A global stop file ('stop.all') created."
77 puts "You should remove it manually later."
77 puts "You should remove it manually later."
78 else
78 else
79 (1..ARGV.length-1).each do |i|
79 (1..ARGV.length-1).each do |i|
80 stop_grader(ARGV[i])
80 stop_grader(ARGV[i])
81 end
81 end
82 puts "stop file(s) created"
82 puts "stop file(s) created"
83 end
83 end
84 exit(0)
84 exit(0)
85 end
85 end
86
86
87 if check_stopfile
87 if check_stopfile
88 puts "Stop file exists. Terminated."
88 puts "Stop file exists. Terminated."
89 clear_stopfile
89 clear_stopfile
90 exit(0)
90 exit(0)
91 end
91 end
92
92
93 grader_mode = 'queue'
93 grader_mode = 'queue'
94 if ARGV.length >= 1
94 if ARGV.length >= 1
95 GRADER_ENV = ARGV[0]
95 GRADER_ENV = ARGV[0]
96 if ARGV.length >=2
96 if ARGV.length >=2
97 grader_mode = ARGV[1]
97 grader_mode = ARGV[1]
98 end
98 end
99 else
99 else
100 GRADER_ENV = 'exam'
100 GRADER_ENV = 'exam'
101 end
101 end
102
102
103 puts "environment: #{GRADER_ENV}"
103 puts "environment: #{GRADER_ENV}"
104 require File.join(File.dirname(__FILE__),'config/environment')
104 require File.join(File.dirname(__FILE__),'config/environment')
105
105
106 # add grader_mode to config
106 # add grader_mode to config
107 # this is needed because method log needs it. TODO: clean this up
107 # this is needed because method log needs it. TODO: clean this up
108 class << config
108 class << config
109 attr_accessor :grader_mode
109 attr_accessor :grader_mode
110 end
110 end
111 config.grader_mode = grader_mode
111 config.grader_mode = grader_mode
112
112
113 # reading rails environment
113 # reading rails environment
114 log 'Reading rails environment'
114 log 'Reading rails environment'
115
115
116 RAILS_ENV = config.rails_env
116 RAILS_ENV = config.rails_env
117 require RAILS_ROOT + '/config/environment'
117 require RAILS_ROOT + '/config/environment'
118
118
119 # register grader process
119 # register grader process
120 if config.report_grader
120 if config.report_grader
121 grader_proc = GraderProcess.register(config.grader_hostname,
121 grader_proc = GraderProcess.register(config.grader_hostname,
122 Process.pid,
122 Process.pid,
123 grader_mode)
123 grader_mode)
124 else
124 else
125 grader_proc = nil
125 grader_proc = nil
126 end
126 end
127
127
128 #set loggin environment
128 #set loggin environment
129 ENV['GRADER_LOGGING'] = log_file_name
129 ENV['GRADER_LOGGING'] = log_file_name
130
130
131 #
131 #
132 # MAIN LOOP
132 # MAIN LOOP
133 #
133 #
134
134
135 case grader_mode
135 case grader_mode
136 when "queue", "test_request"
136 when "queue", "test_request"
137 log "Grader: #{grader_mode}"
137 log "Grader: #{grader_mode}"
138 if grader_mode=="queue"
138 if grader_mode=="queue"
139 engine = Grader::Engine.new
139 engine = Grader::Engine.new
140 else
140 else
141 engine = Grader::Engine.new(Grader::TestRequestRoomMaker.new,
141 engine = Grader::Engine.new(Grader::TestRequestRoomMaker.new,
142 Grader::TestRequestReporter.new)
142 Grader::TestRequestReporter.new)
143 end
143 end
144
144
145 runner = Grader::Runner.new(engine, grader_proc)
145 runner = Grader::Runner.new(engine, grader_proc)
146 while true
146 while true
147
147
148 if check_stopfile # created by calling grader stop
148 if check_stopfile # created by calling grader stop
149 clear_stopfile
149 clear_stopfile
150 log "stopped (with stop file)"
150 log "stopped (with stop file)"
151 break
151 break
152 end
152 end
153
153
154 if grader_mode=="queue"
154 if grader_mode=="queue"
155 task = runner.grade_oldest_task
155 task = runner.grade_oldest_task
156 else
156 else
157 task = runner.grade_oldest_test_request
157 task = runner.grade_oldest_test_request
158 end
158 end
159 if task==nil
159 if task==nil
160 sleep(1)
160 sleep(1)
161 end
161 end
162 end
162 end
163
163
164 when "prob"
164 when "prob"
165 engine = Grader::Engine.new
165 engine = Grader::Engine.new
166 runner = Grader::Runner.new(engine, grader_proc)
166 runner = Grader::Runner.new(engine, grader_proc)
167
167
168 grader_proc.report_active if grader_proc!=nil
168 grader_proc.report_active if grader_proc!=nil
169
169
170 ARGV.shift
170 ARGV.shift
171 ARGV.shift
171 ARGV.shift
172
172
173 ARGV.each do |prob_name|
173 ARGV.each do |prob_name|
174 prob = Problem.find_by_name(prob_name)
174 prob = Problem.find_by_name(prob_name)
175 if prob==nil
175 if prob==nil
176 puts "cannot find problem: #{prob_name}"
176 puts "cannot find problem: #{prob_name}"
177 else
177 else
178 runner.grade_problem(prob)
178 runner.grade_problem(prob)
179 end
179 end
180 end
180 end
181
181
182 + when "sub"
183 + engine = Grader::Engine.new
184 + runner = Grader::Runner.new(engine, grader_proc)
185 +
186 + grader_proc.report_active if grader_proc!=nil
187 +
188 + ARGV.shift
189 + ARGV.shift
190 +
191 + ARGV.each do |sub_id|
192 + puts "Grading #{sub_id}"
193 + begin
194 + submission = Submission.find(sub_id.to_i)
195 + rescue ActiveRecord::RecordNotFound
196 + puts "Record not found"
197 + submission = nil
198 + end
199 +
200 + if submission!=nil
201 + runner.grade_submission(submission)
202 + end
203 + end
204 +
182 else
205 else
183 display_manual
206 display_manual
184 exit(0)
207 exit(0)
185 end
208 end
186
209
187 # report inactive
210 # report inactive
188 grader_proc.report_inactive if grader_proc!=nil
211 grader_proc.report_inactive if grader_proc!=nil
189
212
@@ -1,56 +1,61
1 #
1 #
2 # A runner drives the engine into various tasks.
2 # A runner drives the engine into various tasks.
3 #
3 #
4
4
5 module Grader
5 module Grader
6
6
7 class Runner
7 class Runner
8
8
9 def initialize(engine, grader_process=nil)
9 def initialize(engine, grader_process=nil)
10 @engine = engine
10 @engine = engine
11 @grader_process = grader_process
11 @grader_process = grader_process
12 end
12 end
13
13
14 def grade_oldest_task
14 def grade_oldest_task
15 task = Task.get_inqueue_and_change_status(Task::STATUS_GRADING)
15 task = Task.get_inqueue_and_change_status(Task::STATUS_GRADING)
16 if task!=nil
16 if task!=nil
17 @grader_process.report_active(task) if @grader_process!=nil
17 @grader_process.report_active(task) if @grader_process!=nil
18
18
19 submission = Submission.find(task.submission_id)
19 submission = Submission.find(task.submission_id)
20 @engine.grade(submission)
20 @engine.grade(submission)
21 task.status_complete!
21 task.status_complete!
22 @grader_process.report_inactive(task) if @grader_process!=nil
22 @grader_process.report_inactive(task) if @grader_process!=nil
23 end
23 end
24 return task
24 return task
25 end
25 end
26
26
27 def grade_problem(problem)
27 def grade_problem(problem)
28 users = User.find(:all)
28 users = User.find(:all)
29 users.each do |u|
29 users.each do |u|
30 puts "user: #{u.login}"
30 puts "user: #{u.login}"
31 last_sub = Submission.find(:first,
31 last_sub = Submission.find(:first,
32 :conditions => "user_id = #{u.id} and " +
32 :conditions => "user_id = #{u.id} and " +
33 "problem_id = #{problem.id}",
33 "problem_id = #{problem.id}",
34 :order => 'submitted_at DESC')
34 :order => 'submitted_at DESC')
35 if last_sub!=nil
35 if last_sub!=nil
36 @engine.grade(last_sub)
36 @engine.grade(last_sub)
37 end
37 end
38 end
38 end
39 end
39 end
40
40
41 + def grade_submission(submission)
42 + puts "Submission: #{submission.id} by #{submission.user.full_name}"
43 + @engine.grade(submission)
44 + end
45 +
41 def grade_oldest_test_request
46 def grade_oldest_test_request
42 test_request = TestRequest.get_inqueue_and_change_status(Task::STATUS_GRADING)
47 test_request = TestRequest.get_inqueue_and_change_status(Task::STATUS_GRADING)
43 if test_request!=nil
48 if test_request!=nil
44 @grader_process.report_active(test_request) if @grader_process!=nil
49 @grader_process.report_active(test_request) if @grader_process!=nil
45
50
46 @engine.grade(test_request)
51 @engine.grade(test_request)
47 test_request.status_complete!
52 test_request.status_complete!
48 @grader_process.report_inactive(test_request) if @grader_process!=nil
53 @grader_process.report_inactive(test_request) if @grader_process!=nil
49 end
54 end
50 return test_request
55 return test_request
51 end
56 end
52
57
53 end
58 end
54
59
55 end
60 end
56
61
@@ -1,132 +1,138
1 #!/usr/bin/ruby
1 #!/usr/bin/ruby
2
2
3 def log(str='')
3 def log(str='')
4 if ENV['TALKATIVE']!=nil
4 if ENV['TALKATIVE']!=nil
5 puts str
5 puts str
6 end
6 end
7 if ENV['GRADER_LOGGING']!=nil
7 if ENV['GRADER_LOGGING']!=nil
8 log_fname = ENV['GRADER_LOGGING']
8 log_fname = ENV['GRADER_LOGGING']
9 fp = File.open(log_fname,"a")
9 fp = File.open(log_fname,"a")
10 fp.puts("judge: #{Time.new.strftime("%H:%M")} #{str}")
10 fp.puts("judge: #{Time.new.strftime("%H:%M")} #{str}")
11 fp.close
11 fp.close
12 end
12 end
13 end
13 end
14
14
15 problem_home = ENV['PROBLEM_HOME']
15 problem_home = ENV['PROBLEM_HOME']
16
16
17 def execute(command, error_message="")
17 def execute(command, error_message="")
18 if not system(command)
18 if not system(command)
19 msg = "ERROR: #{error_message}"
19 msg = "ERROR: #{error_message}"
20 log msg
20 log msg
21 raise msg
21 raise msg
22 end
22 end
23 end
23 end
24
24
25 # ARGV[0] --- language
25 # ARGV[0] --- language
26 # ARGV[1] --- program source file
26 # ARGV[1] --- program source file
27 # ARGV[2] --- test result directory
27 # ARGV[2] --- test result directory
28 # ARGV[3] --- sandbox directory
28 # ARGV[3] --- sandbox directory
29
29
30 if ARGV.length < 2 || ARGV.length > 4
30 if ARGV.length < 2 || ARGV.length > 4
31 puts "Usage: judge <language> <program-source> [<test-result-directory>] [<sandbox-directory>]"
31 puts "Usage: judge <language> <program-source> [<test-result-directory>] [<sandbox-directory>]"
32 puts " <sandbox-directory> is defaulted to ./sandbox"
32 puts " <sandbox-directory> is defaulted to ./sandbox"
33 puts " <test-result-directory> is defaulted to ./test-result"
33 puts " <test-result-directory> is defaulted to ./test-result"
34 puts "WARNING: The judge script will forcefully create the (implicitly and explicitly) specified directories and remove anything inside it."
34 puts "WARNING: The judge script will forcefully create the (implicitly and explicitly) specified directories and remove anything inside it."
35 exit(127)
35 exit(127)
36 end
36 end
37
37
38 language = ARGV[0]
38 language = ARGV[0]
39 if language != "c" && language != "c++" && language != "pas"
39 if language != "c" && language != "c++" && language != "pas"
40 log "You specified a language that is not supported: #{language}."
40 log "You specified a language that is not supported: #{language}."
41 exit(127)
41 exit(127)
42 end
42 end
43
43
44 source_file = ARGV[1]
44 source_file = ARGV[1]
45 if File.exist?(source_file) == false
45 if File.exist?(source_file) == false
46 log "The source file does not exist."
46 log "The source file does not exist."
47 exit(127)
47 exit(127)
48 end
48 end
49
49
50 log "Making test result and sandbox directories..."
50 log "Making test result and sandbox directories..."
51
51
52 current_dir = `pwd`
52 current_dir = `pwd`
53 current_dir.strip!
53 current_dir.strip!
54
54
55 if ARGV.length >= 3
55 if ARGV.length >= 3
56 test_result_dir = ARGV[2]
56 test_result_dir = ARGV[2]
57 else
57 else
58 test_result_dir = "#{current_dir}/test-result"
58 test_result_dir = "#{current_dir}/test-result"
59 end
59 end
60 log "Test result directory: #{test_result_dir}"
60 log "Test result directory: #{test_result_dir}"
61 system("rm -Rf #{test_result_dir}")
61 system("rm -Rf #{test_result_dir}")
62 execute("mkdir #{test_result_dir}", "Cannot make directory #{test_result_dir}.")
62 execute("mkdir #{test_result_dir}", "Cannot make directory #{test_result_dir}.")
63
63
64 if ARGV.length >= 4
64 if ARGV.length >= 4
65 sandbox_dir = ARGV[3]
65 sandbox_dir = ARGV[3]
66 else
66 else
67 sandbox_dir = "#{current_dir}/sandbox"
67 sandbox_dir = "#{current_dir}/sandbox"
68 end
68 end
69 log "Sandbox directory: #{sandbox_dir}"
69 log "Sandbox directory: #{sandbox_dir}"
70 system("rm -Rf #{sandbox_dir}")
70 system("rm -Rf #{sandbox_dir}")
71 execute("mkdir #{sandbox_dir}", "Cannot make directory #{sandbox_dir}")
71 execute("mkdir #{sandbox_dir}", "Cannot make directory #{sandbox_dir}")
72
72
73 # Compile
73 # Compile
74 log
74 log
75 log "Compiling..."
75 log "Compiling..."
76 execute("cp #{source_file} #{sandbox_dir}", "Cannot copy the source file to #{sandbox_dir}")
76 execute("cp #{source_file} #{sandbox_dir}", "Cannot copy the source file to #{sandbox_dir}")
77 begin
77 begin
78 Dir.chdir sandbox_dir
78 Dir.chdir sandbox_dir
79 rescue
79 rescue
80 log "ERROR: Cannot change directory to #{sandbox_dir}."
80 log "ERROR: Cannot change directory to #{sandbox_dir}."
81 exit(127)
81 exit(127)
82 end
82 end
83 execute("#{problem_home}/script/compile #{language} #{source_file}", "Compilation error!")
83 execute("#{problem_home}/script/compile #{language} #{source_file}", "Compilation error!")
84 compile_message = `cat compiler_message`
84 compile_message = `cat compiler_message`
85 compile_message.strip!
85 compile_message.strip!
86 execute("mv compiler_message #{test_result_dir}", "Cannot move the compiler message to #{test_result_dir}.")
86 execute("mv compiler_message #{test_result_dir}", "Cannot move the compiler message to #{test_result_dir}.")
87 if !FileTest.exist?("a.out")
87 if !FileTest.exist?("a.out")
88 log "Cannot compile the source code. See message in #{test_result_dir}/compile_message"
88 log "Cannot compile the source code. See message in #{test_result_dir}/compile_message"
89 exit(127)
89 exit(127)
90 else
90 else
91 execute("mv a.out #{test_result_dir}", "Cannot move the compiled program to #{test_result_dir}")
91 execute("mv a.out #{test_result_dir}", "Cannot move the compiled program to #{test_result_dir}")
92 system("rm -Rf #{sandbox_dir}/*")
92 system("rm -Rf #{sandbox_dir}/*")
93 end
93 end
94
94
95 require "#{problem_home}/script/test_dsl.rb"
95 require "#{problem_home}/script/test_dsl.rb"
96 load "#{problem_home}/test_cases/all_tests.cfg"
96 load "#{problem_home}/test_cases/all_tests.cfg"
97 problem = Problem.get_instance
97 problem = Problem.get_instance
98
98
99 if problem.well_formed? == false
99 if problem.well_formed? == false
100 log "The problem specification is not well formed."
100 log "The problem specification is not well formed."
101 exit(127)
101 exit(127)
102 end
102 end
103
103
104 # Doing the testing.
104 # Doing the testing.
105 (1..(problem.num_tests)).each do |test_num|
105 (1..(problem.num_tests)).each do |test_num|
106 +
107 + $stdout.print "[#{test_num}]"
108 + $stdout.flush
109 +
106 log "Test number: #{test_num}"
110 log "Test number: #{test_num}"
107 execute("cp #{test_result_dir}/a.out #{sandbox_dir}", "Cannot copy the compiled program into #{sandbox_dir}")
111 execute("cp #{test_result_dir}/a.out #{sandbox_dir}", "Cannot copy the compiled program into #{sandbox_dir}")
108 begin
112 begin
109 execute("#{problem_home}/script/run #{language} #{test_num}", "Error occured during execution of the run script")
113 execute("#{problem_home}/script/run #{language} #{test_num}", "Error occured during execution of the run script")
110 rescue
114 rescue
111 # do nothing
115 # do nothing
112 end
116 end
113 execute("mkdir #{test_result_dir}/#{test_num}", "Cannot create directory #{test_result_dir}/#{test_num}")
117 execute("mkdir #{test_result_dir}/#{test_num}", "Cannot create directory #{test_result_dir}/#{test_num}")
114 execute("mv #{sandbox_dir}/result #{test_result_dir}/#{test_num}", "Cannot copy the result file into #{test_result_dir}/#{test_num}")
118 execute("mv #{sandbox_dir}/result #{test_result_dir}/#{test_num}", "Cannot copy the result file into #{test_result_dir}/#{test_num}")
115 execute("mv #{sandbox_dir}/comment #{test_result_dir}/#{test_num}", "Cannot copy the comment file into #{test_result_dir}/#{test_num}")
119 execute("mv #{sandbox_dir}/comment #{test_result_dir}/#{test_num}", "Cannot copy the comment file into #{test_result_dir}/#{test_num}")
116 execute("mv #{sandbox_dir}/output.txt #{test_result_dir}/#{test_num}", "Cannot copy the output file into #{test_result_dir}/#{test_num}")
120 execute("mv #{sandbox_dir}/output.txt #{test_result_dir}/#{test_num}", "Cannot copy the output file into #{test_result_dir}/#{test_num}")
117 execute("rm -Rf #{sandbox_dir}/*", "Cannot clear #{sandbox_dir}")
121 execute("rm -Rf #{sandbox_dir}/*", "Cannot clear #{sandbox_dir}")
118 end
122 end
119
123
124 + $stdout.print "[done]\n"
125 +
120 # Grade
126 # Grade
121 log
127 log
122 log "Grading..."
128 log "Grading..."
123 begin
129 begin
124 Dir.chdir test_result_dir
130 Dir.chdir test_result_dir
125 rescue
131 rescue
126 log "ERROR: Cannot change directory to #{test_result_dir}."
132 log "ERROR: Cannot change directory to #{test_result_dir}."
127 exit(127)
133 exit(127)
128 end
134 end
129 execute("#{problem_home}/script/grade", "An error occured during grading!")
135 execute("#{problem_home}/script/grade", "An error occured during grading!")
130
136
131 log
137 log
132 log "All done!"
138 log "All done!"
You need to be logged in to leave comments. Login now