Description:
handle the case when problem id or submission id is null. Grader will simply skip such request. Add more report on console (for command line grading) (mercurial grafted from d233105d3965c5368c9b33125f390e39b25f910e)
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r181:5c6f0b732e70 - - 2 files changed: 30 inserted, 30 deleted

@@ -1,443 +1,443
1 #!/usr/bin/env ruby
1 #!/usr/bin/env 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 File.delete(File.dirname(__FILE__) + "/stop.#{Process.pid}")
18 File.delete(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', 'test_request', 'prob', 'sub', 'contest', and 'autonew'
53 (2) possible modes are: 'queue', 'test_request', 'prob', 'sub', 'contest', and 'autonew'
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 def process_options_and_stop_file
59 def process_options_and_stop_file
60 # The list of options are:
60 # The list of options are:
61 # - stop [all|process ids]
61 # - stop [all|process ids]
62 # -
62 # -
63
63
64 # Process 'help' option
64 # Process 'help' option
65 if (ARGV.length==1) and (/help/.match(ARGV[0]))
65 if (ARGV.length==1) and (/help/.match(ARGV[0]))
66 display_manual
66 display_manual
67 exit(0)
67 exit(0)
68 end
68 end
69
69
70 # Process 'stop' option.
70 # Process 'stop' option.
71 if (ARGV.length >= 1) and (ARGV[0]=='stop')
71 if (ARGV.length >= 1) and (ARGV[0]=='stop')
72 if ARGV.length==1
72 if ARGV.length==1
73 puts "you should specify pid-list or 'all'"
73 puts "you should specify pid-list or 'all'"
74 display_manual
74 display_manual
75 elsif (ARGV.length==2) and (ARGV[1]=='all')
75 elsif (ARGV.length==2) and (ARGV[1]=='all')
76 stop_grader(:all)
76 stop_grader(:all)
77 puts "A global stop file ('stop.all') created."
77 puts "A global stop file ('stop.all') created."
78 puts "You should remove it manually later."
78 puts "You should remove it manually later."
79 else
79 else
80 (1..ARGV.length-1).each do |i|
80 (1..ARGV.length-1).each do |i|
81 stop_grader(ARGV[i])
81 stop_grader(ARGV[i])
82 end
82 end
83 puts "stop file(s) created"
83 puts "stop file(s) created"
84 end
84 end
85 exit(0)
85 exit(0)
86 end
86 end
87
87
88 # Check stop file.
88 # Check stop file.
89 if check_stopfile
89 if check_stopfile
90 puts "Stop file exists. Terminated."
90 puts "Stop file exists. Terminated."
91 clear_stopfile
91 clear_stopfile
92 exit(0)
92 exit(0)
93 end
93 end
94
94
95 #default options
95 #default options
96 options = {
96 options = {
97 :mode => 'queue',
97 :mode => 'queue',
98 :environment => 'exam',
98 :environment => 'exam',
99 :dry_run => false,
99 :dry_run => false,
100 }
100 }
101
101
102 # Process mode and environment option
102 # Process mode and environment option
103 if ARGV.length >= 1
103 if ARGV.length >= 1
104 options[:environment] = ARGV.shift
104 options[:environment] = ARGV.shift
105 if ARGV.length >=1
105 if ARGV.length >=1
106 options[:mode] = ARGV.shift
106 options[:mode] = ARGV.shift
107 end
107 end
108 end
108 end
109
109
110 options[:dry_run] = (ARGV.delete('--dry') != nil)
110 options[:dry_run] = (ARGV.delete('--dry') != nil)
111 if options[:dry_run] and (not ['prob','contest','autonew'].include? options[:mode])
111 if options[:dry_run] and (not ['prob','contest','autonew'].include? options[:mode])
112 puts "Dry run currently works only for 'prob' or 'contest' modes."
112 puts "Dry run currently works only for 'prob' or 'contest' modes."
113 exit(0)
113 exit(0)
114 end
114 end
115
115
116 options[:report] = (ARGV.delete('--report') != nil)
116 options[:report] = (ARGV.delete('--report') != nil)
117 if options[:report] and (not ['prob','contest','autonew'].include? options[:mode])
117 if options[:report] and (not ['prob','contest','autonew'].include? options[:mode])
118 puts "Report currently works only for 'prob' or 'contest' modes."
118 puts "Report currently works only for 'prob' or 'contest' modes."
119 exit(0)
119 exit(0)
120 end
120 end
121
121
122 return options
122 return options
123 end
123 end
124
124
125 class ResultCollector
125 class ResultCollector
126 def initialize
126 def initialize
127 @results = {}
127 @results = {}
128 @problems = {}
128 @problems = {}
129 @users = {}
129 @users = {}
130 end
130 end
131
131
132 def after_save_hook(submission, grading_result)
132 def after_save_hook(submission, grading_result)
133 end
133 end
134
134
135 def save(submission, grading_result)
135 def save(submission, grading_result)
136 user = submission.user
136 user = submission.user
137 problem = submission.problem
137 problem = submission.problem
138 if not @problems.has_key? problem.id
138 if not @problems.has_key? problem.id
139 @problems[problem.id] = problem
139 @problems[problem.id] = problem
140 end
140 end
141 if not @users.has_key? user.id
141 if not @users.has_key? user.id
142 @users[user.id] = user
142 @users[user.id] = user
143 end
143 end
144 @results[[user.id, problem.id]] = grading_result
144 @results[[user.id, problem.id]] = grading_result
145
145
146 after_save_hook(submission, grading_result)
146 after_save_hook(submission, grading_result)
147 end
147 end
148
148
149 def print_report_by_user
149 def print_report_by_user
150 puts "---------------------"
150 puts "---------------------"
151 puts " REPORT"
151 puts " REPORT"
152 puts "---------------------"
152 puts "---------------------"
153
153
154 print "login,email"
154 print "login,email"
155 @problems.each_value do |problem|
155 @problems.each_value do |problem|
156 print ",#{problem.name}"
156 print ",#{problem.name}"
157 end
157 end
158 print "\n"
158 print "\n"
159
159
160 @users.each_value do |user|
160 @users.each_value do |user|
161 print "#{user.login},#{user.email}"
161 print "#{user.login},#{user.email}"
162 @problems.each_value do |problem|
162 @problems.each_value do |problem|
163 if @results.has_key? [user.id, problem.id]
163 if @results.has_key? [user.id, problem.id]
164 print ",#{@results[[user.id,problem.id]][:points]}"
164 print ",#{@results[[user.id,problem.id]][:points]}"
165 else
165 else
166 print ","
166 print ","
167 end
167 end
168 end
168 end
169 print "\n"
169 print "\n"
170 end
170 end
171 end
171 end
172 end
172 end
173
173
174 def grader_general_loop(engine, grader_proc, options)
174 def grader_general_loop(engine, grader_proc, options)
175 runner = Grader::Runner.new(engine, grader_proc)
175 runner = Grader::Runner.new(engine, grader_proc)
176 while true
176 while true
177
177
178 if check_stopfile # created by calling grader stop
178 if check_stopfile # created by calling grader stop
179 clear_stopfile
179 clear_stopfile
180 log "stopped (with stop file)"
180 log "stopped (with stop file)"
181 break
181 break
182 end
182 end
183
183
184 task = yield(runner)
184 task = yield(runner)
185
185
186 if task==nil
186 if task==nil
187 sleep(1)
187 sleep(1)
188 end
188 end
189 end
189 end
190 end
190 end
191
191
192 def grader_queue_loop(grader_proc, options)
192 def grader_queue_loop(grader_proc, options)
193 log "Grader: queue"
193 log "Grader: queue"
194 engine = Grader::Engine.new
194 engine = Grader::Engine.new
195 grader_general_loop(engine, grader_proc, options) do |runner|
195 grader_general_loop(engine, grader_proc, options) do |runner|
196 runner.grade_oldest_task
196 runner.grade_oldest_task
197 end
197 end
198 end
198 end
199
199
200 def grader_test_request_loop(grader_proc, options)
200 def grader_test_request_loop(grader_proc, options)
201 log "Grader: test_request"
201 log "Grader: test_request"
202 engine = Grader::Engine.new(:room_maker => Grader::TestRequestRoomMaker.new,
202 engine = Grader::Engine.new(:room_maker => Grader::TestRequestRoomMaker.new,
203 :reporter => Grader::TestRequestReporter.new)
203 :reporter => Grader::TestRequestReporter.new)
204 grader_general_loop(engine, grader_proc, options) do |runner|
204 grader_general_loop(engine, grader_proc, options) do |runner|
205 runner.grade_oldest_test_request
205 runner.grade_oldest_test_request
206 end
206 end
207 end
207 end
208
208
209 def grader_autonew_loop(grader_proc, options)
209 def grader_autonew_loop(grader_proc, options)
210 log "Grader: autonew"
210 log "Grader: autonew"
211
211
212 if options[:report]
212 if options[:report]
213 result_collector = ResultCollector.new
213 result_collector = ResultCollector.new
214 else
214 else
215 result_collector = nil
215 result_collector = nil
216 end
216 end
217
217
218 if options[:dry_run]
218 if options[:dry_run]
219 puts "Running in dry mode"
219 puts "Running in dry mode"
220 end
220 end
221
221
222 prob_reporter = Grader::SubmissionReporter.new(:dry_run => options[:dry_run],
222 prob_reporter = Grader::SubmissionReporter.new(:dry_run => options[:dry_run],
223 :result_collector => result_collector)
223 :result_collector => result_collector)
224
224
225 engine = Grader::Engine.new(:reporter => prob_reporter)
225 engine = Grader::Engine.new(:reporter => prob_reporter)
226 runner = Grader::Runner.new(engine, grader_proc)
226 runner = Grader::Runner.new(engine, grader_proc)
227
227
228 grader_proc.report_active if grader_proc!=nil
228 grader_proc.report_active if grader_proc!=nil
229
229
230 latest_submitted_at = nil
230 latest_submitted_at = nil
231 graded_submission_ids = {}
231 graded_submission_ids = {}
232
232
233 while true
233 while true
234
234
235 if check_stopfile # created by calling grader stop
235 if check_stopfile # created by calling grader stop
236 clear_stopfile
236 clear_stopfile
237 log "stopped (with stop file)"
237 log "stopped (with stop file)"
238 break
238 break
239 end
239 end
240
240
241 if latest_submitted_at==nil
241 if latest_submitted_at==nil
242 submissions = Submission.all
242 submissions = Submission.all
243 else
243 else
244 submissions = Submission.all(:conditions => ["submitted_at >= :latest",
244 submissions = Submission.all(:conditions => ["submitted_at >= :latest",
245 {:latest => latest_submitted_at}])
245 {:latest => latest_submitted_at}])
246 end
246 end
247
247
248 graded_any = false
248 graded_any = false
249
249
250 if submissions.length != 0
250 if submissions.length != 0
251 submissions.each do |submission|
251 submissions.each do |submission|
252 if (submission.problem == nil) or (!submission.problem.available)
252 if (submission.problem == nil) or (!submission.problem.available)
253 next
253 next
254 end
254 end
255 if ! graded_submission_ids[submission.id]
255 if ! graded_submission_ids[submission.id]
256 runner.grade_submission(submission)
256 runner.grade_submission(submission)
257 graded_submission_ids[submission.id] = true
257 graded_submission_ids[submission.id] = true
258 if (!latest_submitted_at or
258 if (!latest_submitted_at or
259 latest_submitted_at < submission.submitted_at)
259 latest_submitted_at < submission.submitted_at)
260 latest_submitted_at = submission.submitted_at
260 latest_submitted_at = submission.submitted_at
261 end
261 end
262 puts "graded: #{submission.id}"
262 puts "graded: #{submission.id}"
263 puts "latest: #{latest_submitted_at}"
263 puts "latest: #{latest_submitted_at}"
264 graded_any = true
264 graded_any = true
265 end
265 end
266 end
266 end
267 end
267 end
268
268
269 if ! graded_any
269 if ! graded_any
270 sleep(1)
270 sleep(1)
271 end
271 end
272 end
272 end
273 end
273 end
274
274
275 def grader_grade_problems(grader_proc, options)
275 def grader_grade_problems(grader_proc, options)
276 if options[:report]
276 if options[:report]
277 result_collector = ResultCollector.new
277 result_collector = ResultCollector.new
278 else
278 else
279 result_collector = nil
279 result_collector = nil
280 end
280 end
281
281
282 if options[:dry_run]
282 if options[:dry_run]
283 puts "Running in dry mode"
283 puts "Running in dry mode"
284 end
284 end
285
285
286 prob_reporter = Grader::SubmissionReporter.new(:dry_run => options[:dry_run],
286 prob_reporter = Grader::SubmissionReporter.new(:dry_run => options[:dry_run],
287 :result_collector => result_collector)
287 :result_collector => result_collector)
288 engine = Grader::Engine.new(:reporter => prob_reporter)
288 engine = Grader::Engine.new(:reporter => prob_reporter)
289 runner = Grader::Runner.new(engine, grader_proc)
289 runner = Grader::Runner.new(engine, grader_proc)
290
290
291 grader_proc.report_active if grader_proc!=nil
291 grader_proc.report_active if grader_proc!=nil
292
292
293 ARGV.each do |prob_name|
293 ARGV.each do |prob_name|
294 prob = Problem.find_by_name(prob_name)
294 prob = Problem.find_by_name(prob_name)
295 if prob==nil
295 if prob==nil
296 puts "cannot find problem: #{prob_name}"
296 puts "cannot find problem: #{prob_name}"
297 else
297 else
298 runner.grade_problem(prob)
298 runner.grade_problem(prob)
299 end
299 end
300 end
300 end
301
301
302 if options[:report]
302 if options[:report]
303 result_collector.print_report_by_user
303 result_collector.print_report_by_user
304 end
304 end
305 end
305 end
306
306
307 def grader_grade_contests(grader_proc, options)
307 def grader_grade_contests(grader_proc, options)
308 # always use dry run when grading during contest
308 # always use dry run when grading during contest
309 dry_run = options[:dry_run] = true
309 dry_run = options[:dry_run] = true
310
310
311 contest_name = ARGV.shift
311 contest_name = ARGV.shift
312
312
313 contest = Contest.find_by_name(contest_name)
313 contest = Contest.find_by_name(contest_name)
314 if contest==nil
314 if contest==nil
315 puts "cannot find contest: #{contest_name}"
315 puts "cannot find contest: #{contest_name}"
316 exit(0)
316 exit(0)
317 end
317 end
318
318
319 if options[:report]
319 if options[:report]
320 result_collector = ResultCollector.new
320 result_collector = ResultCollector.new
321 else
321 else
322 result_collector = nil
322 result_collector = nil
323 end
323 end
324
324
325 if options[:dry_run]
325 if options[:dry_run]
326 puts "Running in dry mode"
326 puts "Running in dry mode"
327 end
327 end
328
328
329 prob_reporter = Grader::SubmissionReporter.new(:dry_run => dry_run,
329 prob_reporter = Grader::SubmissionReporter.new(:dry_run => dry_run,
330 :result_collector => result_collector)
330 :result_collector => result_collector)
331 engine = Grader::Engine.new(:reporter => prob_reporter)
331 engine = Grader::Engine.new(:reporter => prob_reporter)
332 runner = Grader::Runner.new(engine, grader_proc)
332 runner = Grader::Runner.new(engine, grader_proc)
333
333
334 grader_proc.report_active if grader_proc!=nil
334 grader_proc.report_active if grader_proc!=nil
335
335
336 contest.problems.each do |problem|
336 contest.problems.each do |problem|
337 puts "Grading: #{problem.name}"
337 puts "Grading: #{problem.name}"
338 runner.grade_problem(problem,
338 runner.grade_problem(problem,
339 :user_conditions => lambda do |u|
339 :user_conditions => lambda do |u|
340 u.contest_finished? and
340 u.contest_finished? and
341 u.contest_ids.include?(contest.id)
341 u.contest_ids.include?(contest.id)
342 end)
342 end)
343 end
343 end
344
344
345 if options[:report]
345 if options[:report]
346 result_collector.print_report_by_user
346 result_collector.print_report_by_user
347 end
347 end
348 end
348 end
349
349
350 def grader_grade_submissions(grader_proc, options)
350 def grader_grade_submissions(grader_proc, options)
351 engine = Grader::Engine.new
351 engine = Grader::Engine.new
352 runner = Grader::Runner.new(engine, grader_proc)
352 runner = Grader::Runner.new(engine, grader_proc)
353
353
354 grader_proc.report_active if grader_proc!=nil
354 grader_proc.report_active if grader_proc!=nil
355
355
356 ARGV.each do |sub_id|
356 ARGV.each do |sub_id|
357 puts "Grading #{sub_id}"
357 puts "Grading #{sub_id}"
358 begin
358 begin
359 submission = Submission.find(sub_id.to_i)
359 submission = Submission.find(sub_id.to_i)
360 rescue ActiveRecord::RecordNotFound
360 rescue ActiveRecord::RecordNotFound
361 - puts "Record not found"
361 + puts "Submission #{sub_id} not found"
362 submission = nil
362 submission = nil
363 end
363 end
364
364
365 if submission!=nil
365 if submission!=nil
366 runner.grade_submission(submission)
366 runner.grade_submission(submission)
367 end
367 end
368 end
368 end
369 end
369 end
370
370
371 #########################################
371 #########################################
372 # main program
372 # main program
373 #########################################
373 #########################################
374
374
375 options = process_options_and_stop_file
375 options = process_options_and_stop_file
376 GRADER_ENV = options[:environment]
376 GRADER_ENV = options[:environment]
377 grader_mode = options[:mode]
377 grader_mode = options[:mode]
378 dry_run = options[:dry_run]
378 dry_run = options[:dry_run]
379
379
380 puts "environment: #{GRADER_ENV}"
380 puts "environment: #{GRADER_ENV}"
381 require File.join(File.dirname(__FILE__),'config/environment')
381 require File.join(File.dirname(__FILE__),'config/environment')
382
382
383 # add grader_mode to config
383 # add grader_mode to config
384 # this is needed because method log needs it. TODO: clean this up
384 # this is needed because method log needs it. TODO: clean this up
385 class << config
385 class << config
386 attr_accessor :grader_mode
386 attr_accessor :grader_mode
387 end
387 end
388 config.grader_mode = grader_mode
388 config.grader_mode = grader_mode
389
389
390 # reading rails environment
390 # reading rails environment
391 log 'Reading rails environment'
391 log 'Reading rails environment'
392
392
393 RAILS_ENV = config.rails_env
393 RAILS_ENV = config.rails_env
394 require RAILS_ROOT + '/config/environment'
394 require RAILS_ROOT + '/config/environment'
395
395
396 # register grader process
396 # register grader process
397 if config.report_grader
397 if config.report_grader
398 grader_proc = GraderProcess.register(config.grader_hostname,
398 grader_proc = GraderProcess.register(config.grader_hostname,
399 Process.pid,
399 Process.pid,
400 grader_mode)
400 grader_mode)
401 else
401 else
402 grader_proc = nil
402 grader_proc = nil
403 end
403 end
404
404
405 #set loggin environment
405 #set loggin environment
406 ENV['GRADER_LOGGING'] = log_file_name
406 ENV['GRADER_LOGGING'] = log_file_name
407
407
408 # register exit handler to report inactive, and terminated
408 # register exit handler to report inactive, and terminated
409 at_exit do
409 at_exit do
410 if grader_proc!=nil
410 if grader_proc!=nil
411 grader_proc.report_inactive
411 grader_proc.report_inactive
412 grader_proc.terminate
412 grader_proc.terminate
413 end
413 end
414 end
414 end
415
415
416 #
416 #
417 # MAIN LOOP
417 # MAIN LOOP
418 #
418 #
419
419
420 case grader_mode
420 case grader_mode
421 when "queue"
421 when "queue"
422 grader_queue_loop(grader_proc, options)
422 grader_queue_loop(grader_proc, options)
423
423
424 when "test_request"
424 when "test_request"
425 grader_test_request_loop(grader_proc, options)
425 grader_test_request_loop(grader_proc, options)
426
426
427 when "prob"
427 when "prob"
428 grader_grade_problems(grader_proc, options)
428 grader_grade_problems(grader_proc, options)
429
429
430 when "contest"
430 when "contest"
431 grader_grade_contests(grader_proc, options)
431 grader_grade_contests(grader_proc, options)
432
432
433 when "sub"
433 when "sub"
434 grader_grade_submissions(grader_proc, options)
434 grader_grade_submissions(grader_proc, options)
435
435
436 when "autonew"
436 when "autonew"
437 grader_autonew_loop(grader_proc, options)
437 grader_autonew_loop(grader_proc, options)
438
438
439 else
439 else
440 display_manual
440 display_manual
441 exit(0)
441 exit(0)
442 end
442 end
443
443
@@ -1,190 +1,190
1 require 'fileutils'
1 require 'fileutils'
2 require File.join(File.dirname(__FILE__),'dir_init')
2 require File.join(File.dirname(__FILE__),'dir_init')
3
3
4 module Grader
4 module Grader
5
5
6 #
6 #
7 # A grader engine grades a submission, against anything: a test
7 # A grader engine grades a submission, against anything: a test
8 # data, or a user submitted test data. It uses two helpers objects:
8 # data, or a user submitted test data. It uses two helpers objects:
9 # room_maker and reporter.
9 # room_maker and reporter.
10 #
10 #
11 class Engine
11 class Engine
12
12
13 attr_writer :room_maker
13 attr_writer :room_maker
14 attr_writer :reporter
14 attr_writer :reporter
15
15
16 def initialize(options={})
16 def initialize(options={})
17 # default options
17 # default options
18 if not options.include? :room_maker
18 if not options.include? :room_maker
19 options[:room_maker] = Grader::SubmissionRoomMaker.new
19 options[:room_maker] = Grader::SubmissionRoomMaker.new
20 end
20 end
21 if not options.include? :reporter
21 if not options.include? :reporter
22 options[:reporter] = Grader::SubmissionReporter.new
22 options[:reporter] = Grader::SubmissionReporter.new
23 end
23 end
24
24
25 @config = Grader::Configuration.get_instance
25 @config = Grader::Configuration.get_instance
26
26
27 @room_maker = options[:room_maker]
27 @room_maker = options[:room_maker]
28 @reporter = options[:reporter]
28 @reporter = options[:reporter]
29 end
29 end
30
30
31 # takes a submission, asks room_maker to produce grading directories,
31 # takes a submission, asks room_maker to produce grading directories,
32 # calls grader scripts, and asks reporter to save the result
32 # calls grader scripts, and asks reporter to save the result
33 def grade(submission)
33 def grade(submission)
34 current_dir = FileUtils.pwd
34 current_dir = FileUtils.pwd
35
35
36 user = submission.user
36 user = submission.user
37 problem = submission.problem
37 problem = submission.problem
38
38
39 - # TODO: will have to create real exception for this
39 + begin
40 - if user==nil or problem == nil
40 + # TODO: will have to create real exception for this
41 - @reporter.report_error(submission,"Grading error: problem with submission")
41 + if user==nil or problem == nil
42 - #raise "engine: user or problem is nil"
42 + @reporter.report_error(submission,"Grading error: problem with submission")
43 - end
43 + raise "engine: user or problem is nil"
44 -
44 + end
45 - # TODO: this is another hack so that output only task can be judged
46 - if submission.language!=nil
47 - language = submission.language.name
48 - lang_ext = submission.language.ext
49 - else
50 - language = 'c'
51 - lang_ext = 'c'
52 - end
53
45
54 - # This is needed because older version of std-scripts/compile
46 + # TODO: this is another hack so that output only task can be judged
55 - # only look for c++.
47 + if submission.language!=nil
56 - if language == 'cpp'
48 + language = submission.language.name
57 - language = 'c++'
49 + lang_ext = submission.language.ext
58 - end
50 + else
51 + language = 'c'
52 + lang_ext = 'c'
53 + end
59
54
60 - # COMMENT: should it be only source.ext?
55 + # This is needed because older version of std-scripts/compile
61 - if problem!=nil
56 + # only look for c++.
62 - source_name = "#{problem.name}.#{lang_ext}"
57 + if language == 'cpp'
63 - else
58 + language = 'c++'
64 - source_name = "source.#{lang_ext}"
59 + end
65 - end
66
60
67 - begin
61 + # COMMENT: should it be only source.ext?
62 + if problem!=nil
63 + source_name = "#{problem.name}.#{lang_ext}"
64 + else
65 + source_name = "source.#{lang_ext}"
66 + end
67 +
68 grading_dir = @room_maker.produce_grading_room(submission)
68 grading_dir = @room_maker.produce_grading_room(submission)
69 @room_maker.save_source(submission,source_name)
69 @room_maker.save_source(submission,source_name)
70 problem_home = @room_maker.find_problem_home(submission)
70 problem_home = @room_maker.find_problem_home(submission)
71
71
72 # puts "GRADING DIR: #{grading_dir}"
72 # puts "GRADING DIR: #{grading_dir}"
73 # puts "PROBLEM DIR: #{problem_home}"
73 # puts "PROBLEM DIR: #{problem_home}"
74
74
75 if !FileTest.exist?(problem_home)
75 if !FileTest.exist?(problem_home)
76 puts "PROBLEM DIR: #{problem_home}"
76 puts "PROBLEM DIR: #{problem_home}"
77 - puts "No test data. (check problem dir)"
77 + raise "engine: No test data."
78 - raise "No test data."
79 end
78 end
80
79
81 dinit = DirInit::Manager.new(problem_home)
80 dinit = DirInit::Manager.new(problem_home)
82
81
83 dinit.setup do
82 dinit.setup do
84 copy_log = copy_script(problem_home)
83 copy_log = copy_script(problem_home)
85 save_copy_log(problem_home,copy_log)
84 save_copy_log(problem_home,copy_log)
86 end
85 end
87
86
88 call_judge(problem_home,language,grading_dir,source_name)
87 call_judge(problem_home,language,grading_dir,source_name)
89
88
90 @reporter.report(submission,"#{grading_dir}/test-result")
89 @reporter.report(submission,"#{grading_dir}/test-result")
91
90
92 dinit.teardown do
91 dinit.teardown do
93 copy_log = load_copy_log(problem_home)
92 copy_log = load_copy_log(problem_home)
94 clear_copy_log(problem_home)
93 clear_copy_log(problem_home)
95 clear_script(copy_log,problem_home)
94 clear_script(copy_log,problem_home)
96 end
95 end
97
96
98 rescue RuntimeError => msg
97 rescue RuntimeError => msg
99 @reporter.report_error(submission, msg)
98 @reporter.report_error(submission, msg)
99 + puts "ERROR: #{msg}"
100
100
101 ensure
101 ensure
102 @room_maker.clean_up(submission)
102 @room_maker.clean_up(submission)
103 Dir.chdir(current_dir) # this is really important
103 Dir.chdir(current_dir) # this is really important
104 end
104 end
105 end
105 end
106
106
107 protected
107 protected
108
108
109 def talk(str)
109 def talk(str)
110 if @config.talkative
110 if @config.talkative
111 puts str
111 puts str
112 end
112 end
113 end
113 end
114
114
115 def call_judge(problem_home,language,grading_dir,fname)
115 def call_judge(problem_home,language,grading_dir,fname)
116 ENV['PROBLEM_HOME'] = problem_home
116 ENV['PROBLEM_HOME'] = problem_home
117 ENV['RUBYOPT'] = ''
117 ENV['RUBYOPT'] = ''
118
118
119 talk grading_dir
119 talk grading_dir
120 Dir.chdir grading_dir
120 Dir.chdir grading_dir
121 cmd = "#{problem_home}/script/judge #{language} #{fname}"
121 cmd = "#{problem_home}/script/judge #{language} #{fname}"
122 talk "CMD: #{cmd}"
122 talk "CMD: #{cmd}"
123 system(cmd)
123 system(cmd)
124 end
124 end
125
125
126 def get_std_script_dir
126 def get_std_script_dir
127 GRADER_ROOT + '/std-script'
127 GRADER_ROOT + '/std-script'
128 end
128 end
129
129
130 def copy_script(problem_home)
130 def copy_script(problem_home)
131 script_dir = "#{problem_home}/script"
131 script_dir = "#{problem_home}/script"
132 std_script_dir = get_std_script_dir
132 std_script_dir = get_std_script_dir
133
133
134 - raise "std-script directory not found" if !FileTest.exist?(std_script_dir)
134 + raise "engine: std-script directory not found" if !FileTest.exist?(std_script_dir)
135
135
136 scripts = Dir[std_script_dir + '/*']
136 scripts = Dir[std_script_dir + '/*']
137
137
138 copied = []
138 copied = []
139
139
140 scripts.each do |s|
140 scripts.each do |s|
141 fname = File.basename(s)
141 fname = File.basename(s)
142 next if FileTest.directory?(s)
142 next if FileTest.directory?(s)
143 if !FileTest.exist?("#{script_dir}/#{fname}")
143 if !FileTest.exist?("#{script_dir}/#{fname}")
144 copied << fname
144 copied << fname
145 FileUtils.cp(s, "#{script_dir}", :preserve => true)
145 FileUtils.cp(s, "#{script_dir}", :preserve => true)
146 end
146 end
147 end
147 end
148
148
149 return copied
149 return copied
150 end
150 end
151
151
152 def copy_log_filename(problem_home)
152 def copy_log_filename(problem_home)
153 return File.join(problem_home, '.scripts_copied')
153 return File.join(problem_home, '.scripts_copied')
154 end
154 end
155
155
156 def save_copy_log(problem_home, log)
156 def save_copy_log(problem_home, log)
157 f = File.new(copy_log_filename(problem_home),"w")
157 f = File.new(copy_log_filename(problem_home),"w")
158 log.each do |fname|
158 log.each do |fname|
159 f.write("#{fname}\n")
159 f.write("#{fname}\n")
160 end
160 end
161 f.close
161 f.close
162 end
162 end
163
163
164 def load_copy_log(problem_home)
164 def load_copy_log(problem_home)
165 f = File.new(copy_log_filename(problem_home),"r")
165 f = File.new(copy_log_filename(problem_home),"r")
166 log = []
166 log = []
167 f.readlines.each do |line|
167 f.readlines.each do |line|
168 log << line.strip
168 log << line.strip
169 end
169 end
170 f.close
170 f.close
171 log
171 log
172 end
172 end
173
173
174 def clear_copy_log(problem_home)
174 def clear_copy_log(problem_home)
175 File.delete(copy_log_filename(problem_home))
175 File.delete(copy_log_filename(problem_home))
176 end
176 end
177
177
178 def clear_script(log,problem_home)
178 def clear_script(log,problem_home)
179 log.each do |s|
179 log.each do |s|
180 FileUtils.rm("#{problem_home}/script/#{s}")
180 FileUtils.rm("#{problem_home}/script/#{s}")
181 end
181 end
182 end
182 end
183
183
184 def mkdir_if_does_not_exist(dirname)
184 def mkdir_if_does_not_exist(dirname)
185 Dir.mkdir(dirname) if !FileTest.exist?(dirname)
185 Dir.mkdir(dirname) if !FileTest.exist?(dirname)
186 end
186 end
187
187
188 end
188 end
189
189
190 end
190 end
You need to be logged in to leave comments. Login now