#!/usr/bin/ruby def talk(str) if TALKATIVE puts str end end def execute(command, error_message="") if not system(command) puts "ERROR: #{error_message}" exit(127) end end def save_source(submission,dir,fname) f = File.open("#{dir}/#{fname}","w") f.write(submission.source) f.close end def call_judge(problem_home,language,problem_out_dir,fname) ENV['PROBLEM_HOME'] = problem_home puts problem_out_dir Dir.chdir problem_out_dir cmd = "#{problem_home}/script/judge #{language} #{fname}" # puts "CMD: #{cmd}" system(cmd) end def read_result(test_result_dir) cmp_msg_fname = "#{test_result_dir}/compiler_message" cmp_file = File.open(cmp_msg_fname) cmp_msg = cmp_file.read cmp_file.close result_fname = "#{test_result_dir}/result" comment_fname = "#{test_result_dir}/comment" if FileTest.exist?(result_fname) result_file = File.open(result_fname) result = result_file.readline.to_i result_file.close comment_file = File.open(comment_fname) comment = comment_file.readline.chomp comment_file.close return {:points => result, :comment => comment, :cmp_msg => cmp_msg} else return {:points => 0, :comment => 'compile error', :cmp_msg => cmp_msg} end end def save_result(submission,result) problem = Problem.find(submission.problem_id) submission.graded_at = Time.now submission.points = result[:points] if submission.points == problem.full_score submission.grader_comment = 'PASSED: ' + report_comment(result[:comment]) else submission.grader_comment = 'FAILED: ' + report_comment(result[:comment]) end submission.compiler_message = result[:cmp_msg] submission.save end def copy_script(problem_home) script_dir = "#{problem_home}/script" std_script_dir = File.dirname(__FILE__) + '/std-script' scripts = Dir[std_script_dir + '/*'] copied = [] scripts.each do |s| fname = File.basename(s) if !FileTest.exist?("#{script_dir}/#{fname}") copied << fname system("cp #{s} #{script_dir}") end end return copied end def clear_script(log,problem_home) log.each do |s| system("rm #{problem_home}/script/#{s}") end end def grade(submission_id) current_dir = `pwd`.chomp sub = Submission.find(submission_id) user = sub.user problem = sub.problem language = sub.language.name lang_ext = sub.language.ext # FIX THIS talk 'some hack on language' if language == 'cpp' language = 'c++' end user_dir = "#{USER_RESULT_DIR}/#{user.login}" Dir.mkdir(user_dir) if !FileTest.exist?(user_dir) problem_out_dir = "#{user_dir}/#{problem.name}" Dir.mkdir(problem_out_dir) if !FileTest.exist?(problem_out_dir) problem_home = "#{PROBLEMS_DIR}/#{problem.name}" source_name = "#{problem.name}.#{lang_ext}" save_source(sub,problem_out_dir,source_name) copy_log = copy_script(problem_home) call_judge(problem_home,language,problem_out_dir,source_name) save_result(sub,read_result("#{problem_out_dir}/test-result")) clear_script(copy_log,problem_home) Dir.chdir(current_dir) end def stop_grader File.open(File.dirname(__FILE__) + '/stop','w').close end def check_stopfile FileTest.exist?(File.dirname(__FILE__) + '/stop') end def clear_stopfile system("rm " + File.dirname(__FILE__) + '/stop') end ######################################### # main program ######################################### # reading environment and options if (ARGV.length >= 1) and (ARGV[0]=='stop') stop_grader puts "stop file created" exit(0) end if check_stopfile puts "stop file exists" clear_stopfile exit(0) end grader_mode = 'queue' if ARGV.length >= 1 GRADER_ENV = ARGV[0] if ARGV.length >=2 grader_mode = ARGV[1] end else GRADER_ENV = 'exam' end puts "environment: #{GRADER_ENV}" require File.dirname(__FILE__) + "/environment.rb" #main program talk 'Reading rails environment' RAILS_ENV = 'development' require RAILS_APP_DIR + '/config/environment' case grader_mode when "queue" talk 'Grader queue' while true if check_stopfile # created by calling grader stop clear_stopfile puts "stopped" exit(0) end task = Task.find(:first, :order => 'created_at') if task!=nil grade(task.submission_id) task.destroy else sleep(1) end end when "prob" prob = Problem.find_by_name(ARGV[2]) if prob==nil puts "cannot find problem: #{ARGV[2]}" exit(0) end users = User.find(:all) users.each do |u| puts "user: #{u.login}" last_sub = Submission.find(:first, :conditions => "user_id = #{u.id} and " + "problem_id = #{prob.id}", :order => 'submitted_at DESC') if last_sub!=nil grade(last_sub.id) end end end