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,41 +1,26
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
@@ -129,21 +114,32
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
@@ -6,13 +6,13
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
@@ -24,13 +24,13
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
@@ -74,23 +74,26
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
@@ -100,25 +103,27
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
@@ -126,31 +131,34
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
@@ -159,13 +167,13
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
@@ -21,12 +21,15
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
@@ -1,23 +1,23
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)
@@ -27,30 +27,30
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
@@ -60,13 +60,13
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
@@ -74,13 +74,13
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 += ""
@@ -111,13 +111,13
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])
@@ -137,18 +137,18
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