Description:
copy working trunk (r383, before major changes to combine judge and to support grader message queue) to trunk git-svn-id: http://theory.cpe.ku.ac.th/grader/web/trunk@396 6386c4cd-e34a-4fa8-8920-d93eb39b512e
Commit status:
[Not Reviewed]
References:
merge default
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r188:0b607f9b89c1 - - 12 files changed: 14 inserted, 400 deleted

@@ -0,0 +1,10
1 + # Rails app directory
2 + RAILS_ROOT = "/home/jittat/web_grader"
3 +
4 + GRADER_ROOT = "/home/jittat/grader/scripts"
5 +
6 + # This load all required codes
7 + require File.join(File.dirname(__FILE__),'../lib/boot')
8 +
9 + # load the required environment file
10 + require File.dirname(__FILE__) + "/env_#{GRADER_ENV}.rb"
@@ -1,206 +1,195
1 # This file is auto-generated from the current state of the database. Instead of editing this file,
1 # This file is auto-generated from the current state of the database. Instead of editing this file,
2 # please use the migrations feature of Active Record to incrementally modify your database, and
2 # please use the migrations feature of Active Record to incrementally modify your database, and
3 # then regenerate this schema definition.
3 # then regenerate this schema definition.
4 #
4 #
5 # Note that this schema.rb definition is the authoritative source for your database schema. If you need
5 # Note that this schema.rb definition is the authoritative source for your database schema. If you need
6 # to create the application database on another system, you should be using db:schema:load, not running
6 # to create the application database on another system, you should be using db:schema:load, not running
7 # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
7 # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
8 # you'll amass, the slower it'll run and the greater likelihood for issues).
8 # you'll amass, the slower it'll run and the greater likelihood for issues).
9 #
9 #
10 # It's strongly recommended to check this file into your version control system.
10 # It's strongly recommended to check this file into your version control system.
11
11
12 - ActiveRecord::Schema.define(:version => 20090429014554) do
12 + ActiveRecord::Schema.define(:version => 20090426131044) do
13
13
14 create_table "announcements", :force => true do |t|
14 create_table "announcements", :force => true do |t|
15 t.string "author"
15 t.string "author"
16 t.text "body"
16 t.text "body"
17 t.boolean "published"
17 t.boolean "published"
18 t.datetime "created_at"
18 t.datetime "created_at"
19 t.datetime "updated_at"
19 t.datetime "updated_at"
20 t.boolean "frontpage", :default => false
20 t.boolean "frontpage", :default => false
21 t.boolean "contest_only", :default => false
21 t.boolean "contest_only", :default => false
22 end
22 end
23
23
24 create_table "configurations", :force => true do |t|
24 create_table "configurations", :force => true do |t|
25 t.string "key"
25 t.string "key"
26 t.string "value_type"
26 t.string "value_type"
27 t.string "value"
27 t.string "value"
28 t.datetime "created_at"
28 t.datetime "created_at"
29 t.datetime "updated_at"
29 t.datetime "updated_at"
30 end
30 end
31
31
32 create_table "countries", :force => true do |t|
32 create_table "countries", :force => true do |t|
33 t.string "name"
33 t.string "name"
34 t.datetime "created_at"
34 t.datetime "created_at"
35 t.datetime "updated_at"
35 t.datetime "updated_at"
36 end
36 end
37
37
38 create_table "descriptions", :force => true do |t|
38 create_table "descriptions", :force => true do |t|
39 t.text "body"
39 t.text "body"
40 t.boolean "markdowned"
40 t.boolean "markdowned"
41 t.datetime "created_at"
41 t.datetime "created_at"
42 t.datetime "updated_at"
42 t.datetime "updated_at"
43 end
43 end
44
44
45 - create_table "grader_messages", :force => true do |t|
46 - t.integer "grader_process_id"
47 - t.integer "command"
48 - t.string "options"
49 - t.integer "target_id"
50 - t.boolean "taken"
51 - t.integer "taken_grader_process_id"
52 - t.datetime "created_at"
53 - t.datetime "updated_at"
54 - end
55 -
56 create_table "grader_processes", :force => true do |t|
45 create_table "grader_processes", :force => true do |t|
57 t.string "host", :limit => 20
46 t.string "host", :limit => 20
58 t.integer "pid"
47 t.integer "pid"
59 t.string "mode"
48 t.string "mode"
60 t.boolean "active"
49 t.boolean "active"
61 t.datetime "created_at"
50 t.datetime "created_at"
62 t.datetime "updated_at"
51 t.datetime "updated_at"
63 t.integer "task_id"
52 t.integer "task_id"
64 t.string "task_type"
53 t.string "task_type"
65 t.boolean "terminated"
54 t.boolean "terminated"
66 end
55 end
67
56
68 add_index "grader_processes", ["host", "pid"], :name => "index_grader_processes_on_ip_and_pid"
57 add_index "grader_processes", ["host", "pid"], :name => "index_grader_processes_on_ip_and_pid"
69
58
70 create_table "languages", :force => true do |t|
59 create_table "languages", :force => true do |t|
71 t.string "name", :limit => 10
60 t.string "name", :limit => 10
72 t.string "pretty_name"
61 t.string "pretty_name"
73 t.string "ext", :limit => 10
62 t.string "ext", :limit => 10
74 t.string "common_ext"
63 t.string "common_ext"
75 end
64 end
76
65
77 create_table "messages", :force => true do |t|
66 create_table "messages", :force => true do |t|
78 t.integer "sender_id"
67 t.integer "sender_id"
79 t.integer "receiver_id"
68 t.integer "receiver_id"
80 t.integer "replying_message_id"
69 t.integer "replying_message_id"
81 t.text "body"
70 t.text "body"
82 t.boolean "replied"
71 t.boolean "replied"
83 t.datetime "created_at"
72 t.datetime "created_at"
84 t.datetime "updated_at"
73 t.datetime "updated_at"
85 end
74 end
86
75
87 create_table "problems", :force => true do |t|
76 create_table "problems", :force => true do |t|
88 t.string "name", :limit => 30
77 t.string "name", :limit => 30
89 t.string "full_name"
78 t.string "full_name"
90 t.integer "full_score"
79 t.integer "full_score"
91 t.date "date_added"
80 t.date "date_added"
92 t.boolean "available"
81 t.boolean "available"
93 t.string "url"
82 t.string "url"
94 t.integer "description_id"
83 t.integer "description_id"
95 t.boolean "test_allowed"
84 t.boolean "test_allowed"
96 t.boolean "output_only"
85 t.boolean "output_only"
97 end
86 end
98
87
99 create_table "rights", :force => true do |t|
88 create_table "rights", :force => true do |t|
100 t.string "name"
89 t.string "name"
101 t.string "controller"
90 t.string "controller"
102 t.string "action"
91 t.string "action"
103 end
92 end
104
93
105 create_table "rights_roles", :id => false, :force => true do |t|
94 create_table "rights_roles", :id => false, :force => true do |t|
106 t.integer "right_id"
95 t.integer "right_id"
107 t.integer "role_id"
96 t.integer "role_id"
108 end
97 end
109
98
110 add_index "rights_roles", ["role_id"], :name => "index_rights_roles_on_role_id"
99 add_index "rights_roles", ["role_id"], :name => "index_rights_roles_on_role_id"
111
100
112 create_table "roles", :force => true do |t|
101 create_table "roles", :force => true do |t|
113 t.string "name"
102 t.string "name"
114 end
103 end
115
104
116 create_table "roles_users", :id => false, :force => true do |t|
105 create_table "roles_users", :id => false, :force => true do |t|
117 t.integer "role_id"
106 t.integer "role_id"
118 t.integer "user_id"
107 t.integer "user_id"
119 end
108 end
120
109
121 add_index "roles_users", ["user_id"], :name => "index_roles_users_on_user_id"
110 add_index "roles_users", ["user_id"], :name => "index_roles_users_on_user_id"
122
111
123 create_table "sessions", :force => true do |t|
112 create_table "sessions", :force => true do |t|
124 t.string "session_id"
113 t.string "session_id"
125 t.text "data"
114 t.text "data"
126 t.datetime "updated_at"
115 t.datetime "updated_at"
127 end
116 end
128
117
129 add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
118 add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
130 add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
119 add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
131
120
132 create_table "sites", :force => true do |t|
121 create_table "sites", :force => true do |t|
133 t.string "name"
122 t.string "name"
134 t.boolean "started"
123 t.boolean "started"
135 t.datetime "start_time"
124 t.datetime "start_time"
136 t.datetime "created_at"
125 t.datetime "created_at"
137 t.datetime "updated_at"
126 t.datetime "updated_at"
138 t.integer "country_id"
127 t.integer "country_id"
139 t.string "password"
128 t.string "password"
140 end
129 end
141
130
142 create_table "submissions", :force => true do |t|
131 create_table "submissions", :force => true do |t|
143 t.integer "user_id"
132 t.integer "user_id"
144 t.integer "problem_id"
133 t.integer "problem_id"
145 t.integer "language_id"
134 t.integer "language_id"
146 t.text "source"
135 t.text "source"
147 t.binary "binary"
136 t.binary "binary"
148 t.datetime "submitted_at"
137 t.datetime "submitted_at"
149 t.datetime "compiled_at"
138 t.datetime "compiled_at"
150 t.text "compiler_message"
139 t.text "compiler_message"
151 t.datetime "graded_at"
140 t.datetime "graded_at"
152 t.integer "points"
141 t.integer "points"
153 t.text "grader_comment"
142 t.text "grader_comment"
154 t.integer "number"
143 t.integer "number"
155 t.string "source_filename"
144 t.string "source_filename"
156 end
145 end
157
146
158 add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true
147 add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true
159 add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id"
148 add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id"
160
149
161 create_table "tasks", :force => true do |t|
150 create_table "tasks", :force => true do |t|
162 t.integer "submission_id"
151 t.integer "submission_id"
163 t.datetime "created_at"
152 t.datetime "created_at"
164 t.integer "status"
153 t.integer "status"
165 t.datetime "updated_at"
154 t.datetime "updated_at"
166 end
155 end
167
156
168 create_table "test_requests", :force => true do |t|
157 create_table "test_requests", :force => true do |t|
169 t.integer "user_id"
158 t.integer "user_id"
170 t.integer "problem_id"
159 t.integer "problem_id"
171 t.integer "submission_id"
160 t.integer "submission_id"
172 t.string "input_file_name"
161 t.string "input_file_name"
173 t.string "output_file_name"
162 t.string "output_file_name"
174 t.string "running_stat"
163 t.string "running_stat"
175 t.integer "status"
164 t.integer "status"
176 t.datetime "updated_at"
165 t.datetime "updated_at"
177 t.datetime "submitted_at"
166 t.datetime "submitted_at"
178 t.datetime "compiled_at"
167 t.datetime "compiled_at"
179 t.text "compiler_message"
168 t.text "compiler_message"
180 t.datetime "graded_at"
169 t.datetime "graded_at"
181 t.string "grader_comment"
170 t.string "grader_comment"
182 t.datetime "created_at"
171 t.datetime "created_at"
183 t.float "running_time"
172 t.float "running_time"
184 t.string "exit_status"
173 t.string "exit_status"
185 t.integer "memory_usage"
174 t.integer "memory_usage"
186 end
175 end
187
176
188 add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id"
177 add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id"
189
178
190 create_table "users", :force => true do |t|
179 create_table "users", :force => true do |t|
191 t.string "login", :limit => 50
180 t.string "login", :limit => 50
192 t.string "full_name"
181 t.string "full_name"
193 t.string "hashed_password"
182 t.string "hashed_password"
194 t.string "salt", :limit => 5
183 t.string "salt", :limit => 5
195 t.string "alias"
184 t.string "alias"
196 t.string "email"
185 t.string "email"
197 t.integer "site_id"
186 t.integer "site_id"
198 t.integer "country_id"
187 t.integer "country_id"
199 t.boolean "activated", :default => false
188 t.boolean "activated", :default => false
200 t.datetime "created_at"
189 t.datetime "created_at"
201 t.datetime "updated_at"
190 t.datetime "updated_at"
202 end
191 end
203
192
204 add_index "users", ["login"], :name => "index_users_on_login", :unique => true
193 add_index "users", ["login"], :name => "index_users_on_login", :unique => true
205
194
206 end
195 end
@@ -1,217 +1,217
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}.#{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 # register exit handler to report inactive, and terminated
131 # register exit handler to report inactive, and terminated
132 at_exit do
132 at_exit do
133 if grader_proc!=nil
133 if grader_proc!=nil
134 grader_proc.report_inactive
134 grader_proc.report_inactive
135 grader_proc.terminate
135 grader_proc.terminate
136 end
136 end
137 end
137 end
138
138
139 #
139 #
140 # MAIN LOOP
140 # MAIN LOOP
141 #
141 #
142
142
143 case grader_mode
143 case grader_mode
144 when "queue", "test_request"
144 when "queue", "test_request"
145 log "Grader: #{grader_mode}"
145 log "Grader: #{grader_mode}"
146 if grader_mode=="queue"
146 if grader_mode=="queue"
147 engine = Grader::Engine.new
147 engine = Grader::Engine.new
148 else
148 else
149 engine = Grader::Engine.new(Grader::TestRequestRoomMaker.new,
149 engine = Grader::Engine.new(Grader::TestRequestRoomMaker.new,
150 Grader::TestRequestReporter.new)
150 Grader::TestRequestReporter.new)
151 end
151 end
152
152
153 runner = Grader::Runner.new(engine, grader_proc)
153 runner = Grader::Runner.new(engine, grader_proc)
154 while true
154 while true
155
155
156 if check_stopfile # created by calling grader stop
156 if check_stopfile # created by calling grader stop
157 clear_stopfile
157 clear_stopfile
158 log "stopped (with stop file)"
158 log "stopped (with stop file)"
159 break
159 break
160 end
160 end
161
161
162 if grader_mode=="queue"
162 if grader_mode=="queue"
163 task = runner.grade_oldest_task
163 task = runner.grade_oldest_task
164 else
164 else
165 task = runner.grade_oldest_test_request
165 task = runner.grade_oldest_test_request
166 end
166 end
167 if task==nil
167 if task==nil
168 sleep(1)
168 sleep(1)
169 end
169 end
170 end
170 end
171
171
172 when "prob"
172 when "prob"
173 engine = Grader::Engine.new
173 engine = Grader::Engine.new
174 runner = Grader::Runner.new(engine, grader_proc)
174 runner = Grader::Runner.new(engine, grader_proc)
175
175
176 grader_proc.report_active if grader_proc!=nil
176 grader_proc.report_active if grader_proc!=nil
177
177
178 ARGV.shift
178 ARGV.shift
179 ARGV.shift
179 ARGV.shift
180
180
181 ARGV.each do |prob_name|
181 ARGV.each do |prob_name|
182 prob = Problem.find_by_name(prob_name)
182 prob = Problem.find_by_name(prob_name)
183 if prob==nil
183 if prob==nil
184 puts "cannot find problem: #{prob_name}"
184 puts "cannot find problem: #{prob_name}"
185 else
185 else
186 runner.grade_problem(prob)
186 runner.grade_problem(prob)
187 end
187 end
188 end
188 end
189
189
190 when "sub"
190 when "sub"
191 engine = Grader::Engine.new
191 engine = Grader::Engine.new
192 runner = Grader::Runner.new(engine, grader_proc)
192 runner = Grader::Runner.new(engine, grader_proc)
193
193
194 grader_proc.report_active if grader_proc!=nil
194 grader_proc.report_active if grader_proc!=nil
195
195
196 ARGV.shift
196 ARGV.shift
197 ARGV.shift
197 ARGV.shift
198
198
199 ARGV.each do |sub_id|
199 ARGV.each do |sub_id|
200 puts "Grading #{sub_id}"
200 puts "Grading #{sub_id}"
201 begin
201 begin
202 submission = Submission.find(sub_id.to_i)
202 submission = Submission.find(sub_id.to_i)
203 rescue ActiveRecord::RecordNotFound
203 rescue ActiveRecord::RecordNotFound
204 puts "Record not found"
204 puts "Record not found"
205 submission = nil
205 submission = nil
206 end
206 end
207
207
208 if submission!=nil
208 if submission!=nil
209 runner.grade_submission(submission)
209 runner.grade_submission(submission)
210 end
210 end
211 end
211 end
212
212
213 else
213 else
214 display_manual
214 display_manual
215 exit(0)
215 exit(0)
216 end
216 end
217
217
@@ -1,175 +1,175
1 require 'fileutils'
1 require 'fileutils'
2 require 'ftools'
2 require 'ftools'
3 require 'lib/dir_init'
3 require 'lib/dir_init'
4
4
5 module Grader
5 module Grader
6
6
7 #
7 #
8 # A grader engine grades a submission, against anything: a test
8 # A grader engine grades a submission, against anything: a test
9 # data, or a user submitted test data. It uses two helpers objects:
9 # data, or a user submitted test data. It uses two helpers objects:
10 # room_maker and reporter.
10 # room_maker and reporter.
11 #
11 #
12 class Engine
12 class Engine
13
13
14 attr_writer :room_maker
14 attr_writer :room_maker
15 attr_writer :reporter
15 attr_writer :reporter
16
16
17 def initialize(room_maker=nil, reporter=nil)
17 def initialize(room_maker=nil, reporter=nil)
18 @config = Grader::Configuration.get_instance
18 @config = Grader::Configuration.get_instance
19
19
20 @room_maker = room_maker || Grader::SubmissionRoomMaker.new
20 @room_maker = room_maker || Grader::SubmissionRoomMaker.new
21 @reporter = reporter || Grader::SubmissionReporter.new
21 @reporter = reporter || Grader::SubmissionReporter.new
22 end
22 end
23
23
24 # takes a submission, asks room_maker to produce grading directories,
24 # takes a submission, asks room_maker to produce grading directories,
25 # calls grader scripts, and asks reporter to save the result
25 # calls grader scripts, and asks reporter to save the result
26 def grade(submission)
26 def grade(submission)
27 current_dir = `pwd`.chomp
27 current_dir = `pwd`.chomp
28
28
29 user = submission.user
29 user = submission.user
30 problem = submission.problem
30 problem = submission.problem
31
31
32 # TODO: will have to create real exception for this
32 # TODO: will have to create real exception for this
33 if user==nil or problem == nil
33 if user==nil or problem == nil
34 @reporter.report_error(submission,"Grading error: problem with submission")
34 @reporter.report_error(submission,"Grading error: problem with submission")
35 #raise "engine: user or problem is nil"
35 #raise "engine: user or problem is nil"
36 end
36 end
37
37
38 # TODO: this is another hack so that output only task can be judged
38 # TODO: this is another hack so that output only task can be judged
39 if submission.language!=nil
39 if submission.language!=nil
40 language = submission.language.name
40 language = submission.language.name
41 lang_ext = submission.language.ext
41 lang_ext = submission.language.ext
42 else
42 else
43 language = 'c'
43 language = 'c'
44 lang_ext = 'c'
44 lang_ext = 'c'
45 end
45 end
46
46
47 # FIX THIS
47 # FIX THIS
48 talk 'some hack on language'
48 talk 'some hack on language'
49 if language == 'cpp'
49 if language == 'cpp'
50 language = 'c++'
50 language = 'c++'
51 end
51 end
52
52
53 # COMMENT: should it be only source.ext?
53 # COMMENT: should it be only source.ext?
54 if problem!=nil
54 if problem!=nil
55 source_name = "#{problem.name}.#{lang_ext}"
55 source_name = "#{problem.name}.#{lang_ext}"
56 else
56 else
57 source_name = "source.#{lang_ext}"
57 source_name = "source.#{lang_ext}"
58 end
58 end
59
59
60 begin
60 begin
61 grading_dir = @room_maker.produce_grading_room(submission)
61 grading_dir = @room_maker.produce_grading_room(submission)
62 @room_maker.save_source(submission,source_name)
62 @room_maker.save_source(submission,source_name)
63 problem_home = @room_maker.find_problem_home(submission)
63 problem_home = @room_maker.find_problem_home(submission)
64
64
65 # puts "GRADING DIR: #{grading_dir}"
65 # puts "GRADING DIR: #{grading_dir}"
66 # puts "PROBLEM DIR: #{problem_home}"
66 # puts "PROBLEM DIR: #{problem_home}"
67
67
68 dinit = DirInit::Manager.new(problem_home)
68 dinit = DirInit::Manager.new(problem_home)
69
69
70 dinit.setup do
70 dinit.setup do
71 copy_log = copy_script(problem_home)
71 copy_log = copy_script(problem_home)
72 save_copy_log(problem_home,copy_log)
72 save_copy_log(problem_home,copy_log)
73 end
73 end
74
74
75 call_judge(problem_home,language,grading_dir,source_name)
75 call_judge(problem_home,language,grading_dir,source_name)
76
76
77 @reporter.report(submission,"#{grading_dir}/test-result")
77 @reporter.report(submission,"#{grading_dir}/test-result")
78
78
79 dinit.teardown do
79 dinit.teardown do
80 copy_log = load_copy_log(problem_home)
80 copy_log = load_copy_log(problem_home)
81 clear_copy_log(problem_home)
81 clear_copy_log(problem_home)
82 clear_script(copy_log,problem_home)
82 clear_script(copy_log,problem_home)
83 end
83 end
84
84
85 rescue RuntimeError => msg
85 rescue RuntimeError => msg
86 @reporter.report_error(submission,"Grading error: #{msg}")
86 @reporter.report_error(submission,"Grading error: #{msg}")
87
87
88 ensure
88 ensure
89 @room_maker.clean_up(submission)
89 @room_maker.clean_up(submission)
90 Dir.chdir(current_dir) # this is really important
90 Dir.chdir(current_dir) # this is really important
91 end
91 end
92 end
92 end
93
93
94 protected
94 protected
95
95
96 def talk(str)
96 def talk(str)
97 if @config.talkative
97 if @config.talkative
98 puts str
98 puts str
99 end
99 end
100 end
100 end
101
101
102 def call_judge(problem_home,language,grading_dir,fname)
102 def call_judge(problem_home,language,grading_dir,fname)
103 ENV['PROBLEM_HOME'] = problem_home
103 ENV['PROBLEM_HOME'] = problem_home
104
104
105 - talk "Grading in #{grading_dir}"
105 + talk grading_dir
106 Dir.chdir grading_dir
106 Dir.chdir grading_dir
107 cmd = "#{problem_home}/script/judge #{language} #{fname}"
107 cmd = "#{problem_home}/script/judge #{language} #{fname}"
108 talk "CMD: #{cmd}"
108 talk "CMD: #{cmd}"
109 system(cmd)
109 system(cmd)
110 end
110 end
111
111
112 def get_std_script_dir
112 def get_std_script_dir
113 GRADER_ROOT + '/std-script'
113 GRADER_ROOT + '/std-script'
114 end
114 end
115
115
116 def copy_script(problem_home)
116 def copy_script(problem_home)
117 script_dir = "#{problem_home}/script"
117 script_dir = "#{problem_home}/script"
118 std_script_dir = get_std_script_dir
118 std_script_dir = get_std_script_dir
119
119
120 raise "std-script directory not found" if !FileTest.exist?(std_script_dir)
120 raise "std-script directory not found" if !FileTest.exist?(std_script_dir)
121
121
122 scripts = Dir[std_script_dir + '/*']
122 scripts = Dir[std_script_dir + '/*']
123
123
124 copied = []
124 copied = []
125
125
126 scripts.each do |s|
126 scripts.each do |s|
127 fname = File.basename(s)
127 fname = File.basename(s)
128 if !FileTest.exist?("#{script_dir}/#{fname}")
128 if !FileTest.exist?("#{script_dir}/#{fname}")
129 copied << fname
129 copied << fname
130 system("cp #{s} #{script_dir}")
130 system("cp #{s} #{script_dir}")
131 end
131 end
132 end
132 end
133
133
134 return copied
134 return copied
135 end
135 end
136
136
137 def copy_log_filename(problem_home)
137 def copy_log_filename(problem_home)
138 return File.join(problem_home, '.scripts_copied')
138 return File.join(problem_home, '.scripts_copied')
139 end
139 end
140
140
141 def save_copy_log(problem_home, log)
141 def save_copy_log(problem_home, log)
142 f = File.new(copy_log_filename(problem_home),"w")
142 f = File.new(copy_log_filename(problem_home),"w")
143 log.each do |fname|
143 log.each do |fname|
144 f.write("#{fname}\n")
144 f.write("#{fname}\n")
145 end
145 end
146 f.close
146 f.close
147 end
147 end
148
148
149 def load_copy_log(problem_home)
149 def load_copy_log(problem_home)
150 f = File.new(copy_log_filename(problem_home),"r")
150 f = File.new(copy_log_filename(problem_home),"r")
151 log = []
151 log = []
152 f.readlines.each do |line|
152 f.readlines.each do |line|
153 log << line.strip
153 log << line.strip
154 end
154 end
155 f.close
155 f.close
156 log
156 log
157 end
157 end
158
158
159 def clear_copy_log(problem_home)
159 def clear_copy_log(problem_home)
160 File.delete(copy_log_filename(problem_home))
160 File.delete(copy_log_filename(problem_home))
161 end
161 end
162
162
163 def clear_script(log,problem_home)
163 def clear_script(log,problem_home)
164 log.each do |s|
164 log.each do |s|
165 system("rm #{problem_home}/script/#{s}")
165 system("rm #{problem_home}/script/#{s}")
166 end
166 end
167 end
167 end
168
168
169 def mkdir_if_does_not_exist(dirname)
169 def mkdir_if_does_not_exist(dirname)
170 Dir.mkdir(dirname) if !FileTest.exist?(dirname)
170 Dir.mkdir(dirname) if !FileTest.exist?(dirname)
171 end
171 end
172
172
173 end
173 end
174
174
175 end
175 end
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
You need to be logged in to leave comments. Login now