Description:
- new install script - add comment in grader chain
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r254:8d92eda43960 - - 4 files changed: 48 inserted, 41 deleted

@@ -1,83 +1,68
1 #!/bin/sh
1 #!/bin/sh
2
2
3 + #installation script for cafe-grader, for ubuntu 16.04
4 +
3 echo "This script will install and configure Cafe grader."
5 echo "This script will install and configure Cafe grader."
4
6
5 - RUBY_VERSION=2.1.2
7 + RUBY_VERSION=2.3.7
6 - echo "This will install Ruby $RUBY_VERSION under RVM"
7 -
8 - echo "Installing required apts"
9 -
10 - sudo apt-get update
11 - sudo apt-get install mysql-server mysql-client \
12 - g++ gcc apache2 libmysqlclient20 build-essential \
13 - git-core openssl libreadline6 libreadline6-dev \
14 - zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-dev \
15 - sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev \
16 - ncurses-dev automake libtool bison subversion \
17 - pkg-config curl nodejs unzip pyflakes ruby default-jdk \
18 - libmysqld-dev mercurial python-setuptools python-dev python3-numpy
19 -
20 - echo "Installing RVM"
21 - curl -k -L https://get.rvm.io | bash -s stable
22 - source ~/.rvm/scripts/rvm
23
8
24 echo "Installing Ruby $RUBY_VERSION in RVM"
9 echo "Installing Ruby $RUBY_VERSION in RVM"
25
10
26 rvm install $RUBY_VERSION
11 rvm install $RUBY_VERSION
27 rvm use $RUBY_VERSION
12 rvm use $RUBY_VERSION
28
13
29 echo "Fetching Cafe Grader from Git repositories"
14 echo "Fetching Cafe Grader from Git repositories"
30
15
31 echo "Fetching web interface"
16 echo "Fetching web interface"
32
17
33 mkdir cafe_grader
18 mkdir cafe_grader
34 cd cafe_grader
19 cd cafe_grader
35 - git clone -q git://github.com/jittat/cafe-grader-web.git web
20 + git clone -q git://github.com/cafe-grader-team/cafe-grader-web.git web
36
21
37 echo "Configuring rails app"
22 echo "Configuring rails app"
38
23
39 cp web/config/application.rb.SAMPLE web/config/application.rb
24 cp web/config/application.rb.SAMPLE web/config/application.rb
40 cp web/config/initializers/cafe_grader_config.rb.SAMPLE web/config/initializers/cafe_grader_config.rb
25 cp web/config/initializers/cafe_grader_config.rb.SAMPLE web/config/initializers/cafe_grader_config.rb
41
26
42 #replace UTC in application.rb with the system timezone
27 #replace UTC in application.rb with the system timezone
43 timezone='UTC'
28 timezone='UTC'
44 if [ -f '/etc/timezone' ]; then
29 if [ -f '/etc/timezone' ]; then
45 timezone=\"`cat /etc/timezone`\"
30 timezone=\"`cat /etc/timezone`\"
46 else
31 else
47 if [ -f '/etc/sysconfig/clock' ]; then
32 if [ -f '/etc/sysconfig/clock' ]; then
48 timezone=`grep -e '^TIMEZONE' /etc/sysconfig/clock | grep -o -e '\".*\"'`
33 timezone=`grep -e '^TIMEZONE' /etc/sysconfig/clock | grep -o -e '\".*\"'`
49 fi
34 fi
50 fi
35 fi
51 replace="s!'UTC'!$timezone!g"
36 replace="s!'UTC'!$timezone!g"
52 sed -i $replace web/config/application.rb
37 sed -i $replace web/config/application.rb
53
38
54 echo "At this point we will need MySQL user and database."
39 echo "At this point we will need MySQL user and database."
55 echo "Have you created MySQL user and database for Cafe grader? (Y/N) "
40 echo "Have you created MySQL user and database for Cafe grader? (Y/N) "
56 read ch
41 read ch
57
42
58 if [ "$ch" = "n" -o "$ch" = "N" ]
43 if [ "$ch" = "n" -o "$ch" = "N" ]
59 then
44 then
60 echo "Please open another terminal and create the user and database for Cafe grader."
45 echo "Please open another terminal and create the user and database for Cafe grader."
61 echo "Don't forget to grant access to that database for the user."
46 echo "Don't forget to grant access to that database for the user."
62 echo "Please have username, password, and database name ready before continue."
47 echo "Please have username, password, and database name ready before continue."
63 echo
48 echo
64 echo "The following are instructions:"
49 echo "The following are instructions:"
65 echo "1. Run mysql:"
50 echo "1. Run mysql:"
66 echo
51 echo
67 echo " mysql -u root -p"
52 echo " mysql -u root -p"
68 echo
53 echo
69 echo " if you have just installed mysql, the root password is the one that you have just entered"
54 echo " if you have just installed mysql, the root password is the one that you have just entered"
70 echo "2. Create a new database, a new user, and grant access to grader database:"
55 echo "2. Create a new database, a new user, and grant access to grader database:"
71 echo
56 echo
72 echo " create user 'USERNAME'@'localhost' identified by 'PASSWORD';"
57 echo " create user 'USERNAME'@'localhost' identified by 'PASSWORD';"
73 echo " create database \`DATABASENEME\`;"
58 echo " create database \`DATABASENEME\`;"
74 echo " grant all on \`DATABASENAME\`.* to 'USERNAME'@'localhost';"
59 echo " grant all on \`DATABASENAME\`.* to 'USERNAME'@'localhost';"
75 echo
60 echo
76 echo " Replace USERNAME, PASSWORD, and DATABASENAME accordingly."
61 echo " Replace USERNAME, PASSWORD, and DATABASENAME accordingly."
77 echo
62 echo
78 echo "Hit enter when ready..."
63 echo "Hit enter when ready..."
79 read dummy
64 read dummy
80 fi
65 fi
81
66
82 CAFE_PATH=`pwd`
67 CAFE_PATH=`pwd`
83
68
@@ -87,95 +72,106
87 read database
72 read database
88
73
89 echo "Please provide grader username:"
74 echo "Please provide grader username:"
90 read username
75 read username
91
76
92 echo "Please provide $username password:"
77 echo "Please provide $username password:"
93 read password
78 read password
94
79
95 echo "development:" > config/database.yml
80 echo "development:" > config/database.yml
96 echo " adapter: mysql2" >> config/database.yml
81 echo " adapter: mysql2" >> config/database.yml
97 echo " encoding: utf8" >> config/database.yml
82 echo " encoding: utf8" >> config/database.yml
98 echo " reconnect: false" >> config/database.yml
83 echo " reconnect: false" >> config/database.yml
99 echo " database: $database" >> config/database.yml
84 echo " database: $database" >> config/database.yml
100 echo " pool: 5" >> config/database.yml
85 echo " pool: 5" >> config/database.yml
101 echo " username: $username" >> config/database.yml
86 echo " username: $username" >> config/database.yml
102 echo " password: $password" >> config/database.yml
87 echo " password: $password" >> config/database.yml
103 echo " host: localhost" >> config/database.yml
88 echo " host: localhost" >> config/database.yml
104 echo " socket: /var/run/mysqld/mysqld.sock" >> config/database.yml
89 echo " socket: /var/run/mysqld/mysqld.sock" >> config/database.yml
105 echo "" >> config/database.yml
90 echo "" >> config/database.yml
106 echo "production:" >> config/database.yml
91 echo "production:" >> config/database.yml
107 echo " adapter: mysql2" >> config/database.yml
92 echo " adapter: mysql2" >> config/database.yml
108 echo " encoding: utf8" >> config/database.yml
93 echo " encoding: utf8" >> config/database.yml
109 echo " reconnect: false" >> config/database.yml
94 echo " reconnect: false" >> config/database.yml
110 echo " database: $database" >> config/database.yml
95 echo " database: $database" >> config/database.yml
111 echo " pool: 5" >> config/database.yml
96 echo " pool: 5" >> config/database.yml
112 echo " username: $username" >> config/database.yml
97 echo " username: $username" >> config/database.yml
113 echo " password: $password" >> config/database.yml
98 echo " password: $password" >> config/database.yml
114 echo " host: localhost" >> config/database.yml
99 echo " host: localhost" >> config/database.yml
115 echo " socket: /var/run/mysqld/mysqld.sock" >> config/database.yml
100 echo " socket: /var/run/mysqld/mysqld.sock" >> config/database.yml
116
101
117 echo "Object.instance_eval{remove_const :GRADER_ROOT_DIR}" >> config/initializers/cafe_grader_config.rb
102 echo "Object.instance_eval{remove_const :GRADER_ROOT_DIR}" >> config/initializers/cafe_grader_config.rb
118 echo "Object.instance_eval{remove_const :GRADING_RESULT_DIR}" >> config/initializers/cafe_grader_config.rb
103 echo "Object.instance_eval{remove_const :GRADING_RESULT_DIR}" >> config/initializers/cafe_grader_config.rb
119 echo "GRADER_ROOT_DIR = '$CAFE_PATH/judge'" >> config/initializers/cafe_grader_config.rb
104 echo "GRADER_ROOT_DIR = '$CAFE_PATH/judge'" >> config/initializers/cafe_grader_config.rb
120 echo "GRADING_RESULT_DIR = '$CAFE_PATH/judge/result'" >> config/initializers/cafe_grader_config.rb
105 echo "GRADING_RESULT_DIR = '$CAFE_PATH/judge/result'" >> config/initializers/cafe_grader_config.rb
121
106
122 echo "Installing required gems"
107 echo "Installing required gems"
123 gem install bundler
108 gem install bundler
124 bundle install
109 bundle install
125
110
126 echo "Running rake tasks to initialize database"
111 echo "Running rake tasks to initialize database"
127
112
128 rake db:migrate
113 rake db:migrate
129 rake db:seed
114 rake db:seed
130
115
131 echo "Running rake tasks to precompile the assets"
116 echo "Running rake tasks to precompile the assets"
132
117
133 rake assets:precompile
118 rake assets:precompile
134
119
120 + echo "setup the secret file"
121 + SECRET_A=`rake secret`
122 + SECRET_B=`rake secret`
123 + SECRET_C=`rake secret`
124 + echo "development:" > config/secrets.yml
125 + echo " secret_key_base: '$SECRET_A'" >> config/secrets.yml
126 + echo "test:" >> config/secrets.yml
127 + echo " secret_key_base: '$SECRET_B'" >> config/secrets.yml
128 + echo "production:" >> config/secrets.yml
129 + echo " secret_key_base: '$SECRET_C'" >> config/secrets.yml
130 +
135 echo "Intalling web interface complete..."
131 echo "Intalling web interface complete..."
136 echo
132 echo
137 echo "Fetching grader"
133 echo "Fetching grader"
138
134
139 cd ..
135 cd ..
140
136
141 mkdir judge
137 mkdir judge
142 cd judge
138 cd judge
143 - git clone -q git://github.com/jittat/cafe-grader-judge-scripts.git scripts
139 + git clone -q git://github.com/cafe-grader-team/cafe-grader-judge-scripts.git scripts
144 mkdir raw
140 mkdir raw
145 mkdir ev-exam
141 mkdir ev-exam
146 mkdir ev
142 mkdir ev
147 mkdir result
143 mkdir result
148 mkdir log
144 mkdir log
149
145
150 echo "Configuring grader"
146 echo "Configuring grader"
151
147
152 cp scripts/config/env_exam.rb.SAMPLE scripts/config/env_exam.rb
148 cp scripts/config/env_exam.rb.SAMPLE scripts/config/env_exam.rb
153 cp scripts/config/env_grading.rb.SAMPLE scripts/config/env_grading.rb
149 cp scripts/config/env_grading.rb.SAMPLE scripts/config/env_grading.rb
154
150
155 # create new environment.rb file
151 # create new environment.rb file
156 echo "RAILS_ROOT = '$CAFE_PATH/web'" > scripts/config/environment.rb
152 echo "RAILS_ROOT = '$CAFE_PATH/web'" > scripts/config/environment.rb
157 echo "GRADER_ROOT = '$CAFE_PATH/judge/scripts'" >> scripts/config/environment.rb
153 echo "GRADER_ROOT = '$CAFE_PATH/judge/scripts'" >> scripts/config/environment.rb
158 echo "require File.join(File.dirname(__FILE__),'../lib/boot')" >> scripts/config/environment.rb
154 echo "require File.join(File.dirname(__FILE__),'../lib/boot')" >> scripts/config/environment.rb
159 echo "require File.dirname(__FILE__) + \"/env_#{GRADER_ENV}.rb\"" >> scripts/config/environment.rb
155 echo "require File.dirname(__FILE__) + \"/env_#{GRADER_ENV}.rb\"" >> scripts/config/environment.rb
160
156
161 # compiling box
157 # compiling box
162 MACHINE_TYPE=`uname -m`
158 MACHINE_TYPE=`uname -m`
163 if [ ${MACHINE_TYPE} == 'x86_64' ]; then
159 if [ ${MACHINE_TYPE} == 'x86_64' ]; then
164 gcc -std=c99 -o scripts/std-script/box scripts/std-script/box64-new.c
160 gcc -std=c99 -o scripts/std-script/box scripts/std-script/box64-new.c
165 else
161 else
166 g++ -o scripts/std-script/box scripts/std-script/box.cc
162 g++ -o scripts/std-script/box scripts/std-script/box.cc
167 fi
163 fi
168
164
169
165
170 cd ..
166 cd ..
171
167
172 echo "Now you are ready to run cafe grader...."
168 echo "Now you are ready to run cafe grader...."
173 echo
169 echo
174 echo "Try:"
170 echo "Try:"
175 echo
171 echo
176 echo " cd web"
172 echo " cd web"
177 echo " rails s"
173 echo " rails s"
178 echo
174 echo
179 echo "and access web at http://localhost:3000/"
175 echo "and access web at http://localhost:3000/"
180 echo "The root username is 'root', its password is 'ioionrails'."
176 echo "The root username is 'root', its password is 'ioionrails'."
181
177
@@ -1,192 +1,200
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 begin
39 begin
40 # TODO: will have to create real exception for this
40 # TODO: will have to create real exception for this
41 if user==nil or problem == nil
41 if user==nil or problem == nil
42 @reporter.report_error(submission,"Grading error: problem with submission")
42 @reporter.report_error(submission,"Grading error: problem with submission")
43 raise "engine: user or problem is nil"
43 raise "engine: user or problem is nil"
44 end
44 end
45
45
46 # TODO: this is another hack so that output only task can be judged
46 # TODO: this is another hack so that output only task can be judged
47 if submission.language!=nil
47 if submission.language!=nil
48 language = submission.language.name
48 language = submission.language.name
49 lang_ext = submission.language.ext
49 lang_ext = submission.language.ext
50 else
50 else
51 language = 'c'
51 language = 'c'
52 lang_ext = 'c'
52 lang_ext = 'c'
53 end
53 end
54
54
55 # This is needed because older version of std-scripts/compile
55 # This is needed because older version of std-scripts/compile
56 # only look for c++.
56 # only look for c++.
57 if language == 'cpp'
57 if language == 'cpp'
58 language = 'c++'
58 language = 'c++'
59 end
59 end
60
60
61 # COMMENT: should it be only source.ext?
61 # COMMENT: should it be only source.ext?
62 if problem!=nil
62 if problem!=nil
63 source_name = "#{problem.name}.#{lang_ext}"
63 source_name = "#{problem.name}.#{lang_ext}"
64 else
64 else
65 source_name = "source.#{lang_ext}"
65 source_name = "source.#{lang_ext}"
66 end
66 end
67
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 raise "engine: No test data."
77 raise "engine: No test data."
78 end
78 end
79
79
80 + # copy the source script, using lock
80 dinit = DirInit::Manager.new(problem_home)
81 dinit = DirInit::Manager.new(problem_home)
81
82
83 + # lock the directory and copy the scripts
82 dinit.setup do
84 dinit.setup do
83 copy_log = copy_script(problem_home)
85 copy_log = copy_script(problem_home)
84 save_copy_log(problem_home,copy_log)
86 save_copy_log(problem_home,copy_log)
85 end
87 end
86 -
88 +
87 call_judge(problem_home,language,grading_dir,source_name)
89 call_judge(problem_home,language,grading_dir,source_name)
88
90
89 @reporter.report(submission,"#{grading_dir}/test-result")
91 @reporter.report(submission,"#{grading_dir}/test-result")
90
92
93 + # unlock the directory
91 dinit.teardown do
94 dinit.teardown do
92 copy_log = load_copy_log(problem_home)
95 copy_log = load_copy_log(problem_home)
93 clear_copy_log(problem_home)
96 clear_copy_log(problem_home)
94 clear_script(copy_log,problem_home)
97 clear_script(copy_log,problem_home)
95 end
98 end
96
99
97 rescue RuntimeError => msg
100 rescue RuntimeError => msg
98 @reporter.report_error(submission, msg)
101 @reporter.report_error(submission, msg)
99 puts "ERROR: #{msg}"
102 puts "ERROR: #{msg}"
100
103
101 ensure
104 ensure
102 @room_maker.clean_up(submission)
105 @room_maker.clean_up(submission)
103 Dir.chdir(current_dir) # this is really important
106 Dir.chdir(current_dir) # this is really important
104 end
107 end
105 end
108 end
106 -
109 +
107 protected
110 protected
108 -
111 +
109 def talk(str)
112 def talk(str)
110 if @config.talkative
113 if @config.talkative
111 puts str
114 puts str
112 end
115 end
113 end
116 end
114
117
118 + #change directory to problem_home
119 + #call the "judge" script
115 def call_judge(problem_home,language,grading_dir,fname)
120 def call_judge(problem_home,language,grading_dir,fname)
116 ENV['PROBLEM_HOME'] = problem_home
121 ENV['PROBLEM_HOME'] = problem_home
117 ENV['RUBYOPT'] = ''
122 ENV['RUBYOPT'] = ''
118 -
123 +
119 talk grading_dir
124 talk grading_dir
120 Dir.chdir grading_dir
125 Dir.chdir grading_dir
121 script_name = "#{problem_home}/script/judge"
126 script_name = "#{problem_home}/script/judge"
122 cmd = "#{script_name} #{language} #{fname}"
127 cmd = "#{script_name} #{language} #{fname}"
123 talk "CMD: #{cmd}"
128 talk "CMD: #{cmd}"
124 warn "ERROR: file does not exists #{script_name}" unless File.exists? script_name
129 warn "ERROR: file does not exists #{script_name}" unless File.exists? script_name
125 system(cmd)
130 system(cmd)
126 end
131 end
127
132
128 def get_std_script_dir
133 def get_std_script_dir
129 GRADER_ROOT + '/std-script'
134 GRADER_ROOT + '/std-script'
130 end
135 end
131
136
137 + #copy any script presented in std-script directory that is not in the problem_home
138 + #this allow a problem setter to provide their own version for each script
139 + #in case that they want to hack something
132 def copy_script(problem_home)
140 def copy_script(problem_home)
133 script_dir = "#{problem_home}/script"
141 script_dir = "#{problem_home}/script"
134 std_script_dir = get_std_script_dir
142 std_script_dir = get_std_script_dir
135
143
136 raise "engine: std-script directory not found" if !FileTest.exist?(std_script_dir)
144 raise "engine: std-script directory not found" if !FileTest.exist?(std_script_dir)
137
145
138 scripts = Dir[std_script_dir + '/*']
146 scripts = Dir[std_script_dir + '/*']
139 -
147 +
140 copied = []
148 copied = []
141
149
142 scripts.each do |s|
150 scripts.each do |s|
143 fname = File.basename(s)
151 fname = File.basename(s)
144 next if FileTest.directory?(s)
152 next if FileTest.directory?(s)
145 if !FileTest.exist?("#{script_dir}/#{fname}")
153 if !FileTest.exist?("#{script_dir}/#{fname}")
146 copied << fname
154 copied << fname
147 FileUtils.cp(s, "#{script_dir}", :preserve => true)
155 FileUtils.cp(s, "#{script_dir}", :preserve => true)
148 end
156 end
149 end
157 end
150 -
158 +
151 return copied
159 return copied
152 end
160 end
153
161
154 def copy_log_filename(problem_home)
162 def copy_log_filename(problem_home)
155 return File.join(problem_home, '.scripts_copied')
163 return File.join(problem_home, '.scripts_copied')
156 end
164 end
157
165
158 def save_copy_log(problem_home, log)
166 def save_copy_log(problem_home, log)
159 f = File.new(copy_log_filename(problem_home),"w")
167 f = File.new(copy_log_filename(problem_home),"w")
160 log.each do |fname|
168 log.each do |fname|
161 f.write("#{fname}\n")
169 f.write("#{fname}\n")
162 end
170 end
163 f.close
171 f.close
164 end
172 end
165 -
173 +
166 def load_copy_log(problem_home)
174 def load_copy_log(problem_home)
167 f = File.new(copy_log_filename(problem_home),"r")
175 f = File.new(copy_log_filename(problem_home),"r")
168 log = []
176 log = []
169 f.readlines.each do |line|
177 f.readlines.each do |line|
170 log << line.strip
178 log << line.strip
171 end
179 end
172 f.close
180 f.close
173 log
181 log
174 end
182 end
175
183
176 def clear_copy_log(problem_home)
184 def clear_copy_log(problem_home)
177 File.delete(copy_log_filename(problem_home))
185 File.delete(copy_log_filename(problem_home))
178 end
186 end
179
187
180 def clear_script(log,problem_home)
188 def clear_script(log,problem_home)
181 log.each do |s|
189 log.each do |s|
182 FileUtils.rm("#{problem_home}/script/#{s}")
190 FileUtils.rm("#{problem_home}/script/#{s}")
183 end
191 end
184 end
192 end
185
193
186 def mkdir_if_does_not_exist(dirname)
194 def mkdir_if_does_not_exist(dirname)
187 Dir.mkdir(dirname) if !FileTest.exist?(dirname)
195 Dir.mkdir(dirname) if !FileTest.exist?(dirname)
188 end
196 end
189
197
190 end
198 end
191
199
192 end
200 end
@@ -1,71 +1,74
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 + # grade a specified problem for the latest submission of each user
28 + # optionally, on all submission when options[:all_sub] is set
29 + # optionally, only submission that has error (use when the problem itself has some problem)
27 def grade_problem(problem, options={})
30 def grade_problem(problem, options={})
28 user_index = 0
31 user_index = 0
29 user_count = User.count
32 user_count = User.count
30 User.find_each do |u|
33 User.find_each do |u|
31 puts "user: #{u.login} (#{user_index}/#{user_count})"
34 puts "user: #{u.login} (#{user_index}/#{user_count})"
32 user_index += 1
35 user_index += 1
33 if options[:user_conditions]!=nil
36 if options[:user_conditions]!=nil
34 con_proc = options[:user_conditions]
37 con_proc = options[:user_conditions]
35 next if not con_proc.call(u)
38 next if not con_proc.call(u)
36 end
39 end
37 if options[:all_sub]
40 if options[:all_sub]
38 Submission.where(user_id: u.id,problem_id: problem.id).find_each do |sub|
41 Submission.where(user_id: u.id,problem_id: problem.id).find_each do |sub|
39 next if options[:only_err] and sub.grader_comment != 'error during grading'
42 next if options[:only_err] and sub.grader_comment != 'error during grading'
40 @engine.grade(sub)
43 @engine.grade(sub)
41 end
44 end
42 else
45 else
43 last_sub = Submission.find_last_by_user_and_problem(u.id,problem.id)
46 last_sub = Submission.find_last_by_user_and_problem(u.id,problem.id)
44 if last_sub!=nil
47 if last_sub!=nil
45 @engine.grade(last_sub) unless options[:only_err] and last_sub.grader_comment != 'error during grading'
48 @engine.grade(last_sub) unless options[:only_err] and last_sub.grader_comment != 'error during grading'
46 end
49 end
47 end
50 end
48 end
51 end
49 end
52 end
50
53
51 def grade_submission(submission)
54 def grade_submission(submission)
52 puts "Submission: #{submission.id} by #{submission.try(:user).try(:full_name)}"
55 puts "Submission: #{submission.id} by #{submission.try(:user).try(:full_name)}"
53 @engine.grade(submission)
56 @engine.grade(submission)
54 end
57 end
55
58
56 def grade_oldest_test_request
59 def grade_oldest_test_request
57 test_request = TestRequest.get_inqueue_and_change_status(Task::STATUS_GRADING)
60 test_request = TestRequest.get_inqueue_and_change_status(Task::STATUS_GRADING)
58 if test_request!=nil
61 if test_request!=nil
59 @grader_process.report_active(test_request) if @grader_process!=nil
62 @grader_process.report_active(test_request) if @grader_process!=nil
60
63
61 @engine.grade(test_request)
64 @engine.grade(test_request)
62 test_request.status_complete!
65 test_request.status_complete!
63 @grader_process.report_inactive(test_request) if @grader_process!=nil
66 @grader_process.report_inactive(test_request) if @grader_process!=nil
64 end
67 end
65 return test_request
68 return test_request
66 end
69 end
67
70
68 end
71 end
69
72
70 end
73 end
71
74
@@ -1,154 +1,154
1 module Grader
1 module Grader
2
2
3 class SubmissionRoomMaker
3 class SubmissionRoomMaker
4 def initialize
4 def initialize
5 @config = Grader::Configuration.get_instance
5 @config = Grader::Configuration.get_instance
6 end
6 end
7 -
7 +
8 def produce_grading_room(submission)
8 def produce_grading_room(submission)
9 user = submission.user
9 user = submission.user
10 problem = submission.problem
10 problem = submission.problem
11 grading_room = "#{@config.user_result_dir}/" +
11 grading_room = "#{@config.user_result_dir}/" +
12 "#{user.login}/#{problem.name}/#{submission.id}"
12 "#{user.login}/#{problem.name}/#{submission.id}"
13 -
13 +
14 FileUtils.mkdir_p(grading_room)
14 FileUtils.mkdir_p(grading_room)
15 grading_room
15 grading_room
16 end
16 end
17 -
17 +
18 def find_problem_home(submission)
18 def find_problem_home(submission)
19 problem = submission.problem
19 problem = submission.problem
20 "#{@config.problems_dir}/#{problem.name}"
20 "#{@config.problems_dir}/#{problem.name}"
21 end
21 end
22
22
23 def save_source(submission,source_name)
23 def save_source(submission,source_name)
24 dir = self.produce_grading_room(submission)
24 dir = self.produce_grading_room(submission)
25 f = File.open("#{dir}/#{source_name}","w")
25 f = File.open("#{dir}/#{source_name}","w")
26 f.write(submission.source)
26 f.write(submission.source)
27 f.close
27 f.close
28 end
28 end
29
29
30 def clean_up(submission)
30 def clean_up(submission)
31 end
31 end
32 end
32 end
33 -
33 +
34 class SubmissionReporter
34 class SubmissionReporter
35 def initialize(options={})
35 def initialize(options={})
36 options = {:dry_run => false, :result_collector => nil}.merge(options)
36 options = {:dry_run => false, :result_collector => nil}.merge(options)
37 @config = Grader::Configuration.get_instance
37 @config = Grader::Configuration.get_instance
38 @dry_run = options[:dry_run]
38 @dry_run = options[:dry_run]
39 @result_collector = options[:result_collector]
39 @result_collector = options[:result_collector]
40 end
40 end
41 -
41 +
42 def report(sub,test_result_dir)
42 def report(sub,test_result_dir)
43 result = read_result(test_result_dir)
43 result = read_result(test_result_dir)
44 if @result_collector
44 if @result_collector
45 @result_collector.save(sub,
45 @result_collector.save(sub,
46 result)
46 result)
47 end
47 end
48 save_result(sub,result)
48 save_result(sub,result)
49 end
49 end
50 -
50 +
51 def report_error(sub,msg)
51 def report_error(sub,msg)
52 save_result(sub,{:points => 0,
52 save_result(sub,{:points => 0,
53 :comment => "Grading error: #{msg}" })
53 :comment => "Grading error: #{msg}" })
54 end
54 end
55
55
56 protected
56 protected
57 def read_result(test_result_dir)
57 def read_result(test_result_dir)
58 cmp_msg_fname = "#{test_result_dir}/compiler_message"
58 cmp_msg_fname = "#{test_result_dir}/compiler_message"
59 if FileTest.exist?(cmp_msg_fname)
59 if FileTest.exist?(cmp_msg_fname)
60 cmp_file = File.open(cmp_msg_fname)
60 cmp_file = File.open(cmp_msg_fname)
61 cmp_msg = cmp_file.read
61 cmp_msg = cmp_file.read
62 cmp_file.close
62 cmp_file.close
63 else
63 else
64 cmp_msg = ""
64 cmp_msg = ""
65 end
65 end
66 -
66 +
67 result_fname = "#{test_result_dir}/result"
67 result_fname = "#{test_result_dir}/result"
68 comment_fname = "#{test_result_dir}/comment"
68 comment_fname = "#{test_result_dir}/comment"
69 runstat_fname = "#{test_result_dir}/run_stat"
69 runstat_fname = "#{test_result_dir}/run_stat"
70 if FileTest.exist?(result_fname)
70 if FileTest.exist?(result_fname)
71 comment = ""
71 comment = ""
72 begin
72 begin
73 result_file = File.open(result_fname)
73 result_file = File.open(result_fname)
74 result = result_file.readline.to_i
74 result = result_file.readline.to_i
75 result_file.close
75 result_file.close
76 rescue
76 rescue
77 result = 0
77 result = 0
78 comment = "error reading result file."
78 comment = "error reading result file."
79 end
79 end
80 -
80 +
81 begin
81 begin
82 comment_file = File.open(comment_fname)
82 comment_file = File.open(comment_fname)
83 comment += comment_file.readline.chomp
83 comment += comment_file.readline.chomp
84 comment_file.close
84 comment_file.close
85 rescue
85 rescue
86 comment += ""
86 comment += ""
87 end
87 end
88
88
89 begin
89 begin
90 runstat_file = File.open(runstat_fname)
90 runstat_file = File.open(runstat_fname)
91 max_runtime = runstat_file.readline.to_f
91 max_runtime = runstat_file.readline.to_f
92 peak_memory = runstat_file.readline.to_i
92 peak_memory = runstat_file.readline.to_i
93 rescue
93 rescue
94 max_runtime = -1
94 max_runtime = -1
95 peak_memory = -1
95 peak_memory = -1
96 end
96 end
97
97
98
98
99 return {points: result,
99 return {points: result,
100 comment: comment,
100 comment: comment,
101 cmp_msg: cmp_msg,
101 cmp_msg: cmp_msg,
102 max_runtime: max_runtime,
102 max_runtime: max_runtime,
103 peak_memory: peak_memory
103 peak_memory: peak_memory
104 }
104 }
105 else
105 else
106 if FileTest.exist?("#{test_result_dir}/a.out")
106 if FileTest.exist?("#{test_result_dir}/a.out")
107 return {:points => 0,
107 return {:points => 0,
108 :comment => 'error during grading',
108 :comment => 'error during grading',
109 :cmp_msg => cmp_msg}
109 :cmp_msg => cmp_msg}
110 else
110 else
111 return {:points => 0,
111 return {:points => 0,
112 :comment => 'compilation error',
112 :comment => 'compilation error',
113 :cmp_msg => cmp_msg}
113 :cmp_msg => cmp_msg}
114 end
114 end
115 end
115 end
116 end
116 end
117 -
117 +
118 def save_result(submission,result)
118 def save_result(submission,result)
119 problem = submission.problem
119 problem = submission.problem
120 submission.graded_at = Time.now.gmtime
120 submission.graded_at = Time.now.gmtime
121 points = result[:points]
121 points = result[:points]
122 submission.points = points
122 submission.points = points
123 comment = @config.report_comment(result[:comment])
123 comment = @config.report_comment(result[:comment])
124
124
125 submission.peak_memory = result[:peak_memory]
125 submission.peak_memory = result[:peak_memory]
126 submission.max_runtime = result[:max_runtime]
126 submission.max_runtime = result[:max_runtime]
127 submission.effective_code_length =submission.source.length
127 submission.effective_code_length =submission.source.length
128
128
129 #
129 #
130 # TODO: FIX THIS MESSAGE
130 # TODO: FIX THIS MESSAGE
131 #
131 #
132 if problem == nil
132 if problem == nil
133 submission.grader_comment = 'PASSED: ' + comment + '(problem is nil)'
133 submission.grader_comment = 'PASSED: ' + comment + '(problem is nil)'
134 elsif points == problem.full_score
134 elsif points == problem.full_score
135 #submission.grader_comment = 'PASSED: ' + comment
135 #submission.grader_comment = 'PASSED: ' + comment
136 submission.grader_comment = comment
136 submission.grader_comment = comment
137 elsif result[:comment].chomp =~ /^[\[\]P]+$/
137 elsif result[:comment].chomp =~ /^[\[\]P]+$/
138 submission.grader_comment = 'PASSED: ' + comment + '(inconsistent score)'
138 submission.grader_comment = 'PASSED: ' + comment + '(inconsistent score)'
139 else
139 else
140 #submission.grader_comment = 'FAILED: ' + comment
140 #submission.grader_comment = 'FAILED: ' + comment
141 submission.grader_comment = comment
141 submission.grader_comment = comment
142 end
142 end
143 -
143 +
144 #very lazy trim the string
144 #very lazy trim the string
145 submission.compiler_message = result[:cmp_msg][0..60000] or ''
145 submission.compiler_message = result[:cmp_msg][0..60000] or ''
146
146
147 if not @dry_run
147 if not @dry_run
148 submission.save
148 submission.save
149 end
149 end
150 end
150 end
151 -
151 +
152 end
152 end
153 -
153 +
154 end
154 end
You need to be logged in to leave comments. Login now