Description:
added problem import git-svn-id: http://theory.cpe.ku.ac.th/grader/web/trunk@435 6386c4cd-e34a-4fa8-8920-d93eb39b512e
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r204:ffd23bd6817d - - 9 files changed: 267 inserted, 17 deleted

@@ -0,0 +1,20
1 + - content_for :head do
2 + = stylesheet_link_tag 'problems'
3 + = javascript_include_tag :defaults
4 +
5 + %h1 Import problems: successful
6 +
7 + %p
8 + %b Problem:
9 + = "#{@problem.full_name} (#{@problem.name})"
10 + %br/
11 + Note that the full score has be assigned to the default value, 100.
12 + You should change it to the correct full score.
13 +
14 + %p
15 + = link_to '[Back to problem list]', :action => 'list'
16 + = link_to '[Import other problems]', :action => 'import'
17 +
18 + %h3 Import log
19 + %pre.import-log
20 + = @log
@@ -0,0 +1,43
1 + - content_for :head do
2 + = stylesheet_link_tag 'problems'
3 + = javascript_include_tag :defaults
4 +
5 + %h1 Import problems
6 +
7 + %p= link_to '[Back to problem list]', :action => 'list'
8 +
9 + - if @problem and @problem.errors
10 + =error_messages_for 'problem'
11 +
12 + - form_tag({:action => 'do_import'}, :multipart => true) do
13 + .submitbox
14 + %table
15 + %tr
16 + %td Name:
17 + %td= text_field_tag 'name'
18 + %tr
19 + %td Full name:
20 + %td
21 + = text_field_tag 'full_name'
22 + %span{:class => 'help'} Leave blank to use the same value as the name above.
23 + %tr
24 + %td Testdata file:
25 + %td= file_field_tag 'file'
26 + %tr
27 + %td Time limit:
28 + %td
29 + = text_field_tag 'time_limit'
30 + %span{:class => 'help'} In seconds. Leave blank to use 1 sec.
31 + %tr
32 + %td Memory limit:
33 + %td
34 + = text_field_tag 'memory_limit'
35 + %span{:class => 'help'} In MB. Leave blank to use 32MB.
36 + %tr
37 + %td
38 + %td= submit_tag 'Import problem'
39 +
40 + - if @log
41 + %h3 Import log
42 + %pre.import-log
43 + = @log
@@ -0,0 +1,76
1 + require 'tmpdir'
2 +
3 + class TestdataImporter
4 +
5 + attr :log_msg
6 +
7 + def import_from_file(problem_name,
8 + tempfile,
9 + time_limit,
10 + memory_limit)
11 +
12 + dirname = TestdataImporter.extract(problem_name, tempfile)
13 + return false if not dirname
14 + @log_msg = GraderScript.call_import_problem(problem_name,
15 + dirname,
16 + time_limit,
17 + memory_limit)
18 + return true
19 + end
20 +
21 + protected
22 +
23 + def self.long_ext(filename)
24 + i = filename.index('.')
25 + len = filename.length
26 + return filename.slice(i..len)
27 + end
28 +
29 + def self.extract(problem_name, tempfile)
30 + testdata_filename = TestdataImporter.save_testdata_file(problem_name,
31 + tempfile)
32 + ext = TestdataImporter.long_ext(tempfile.original_filename)
33 +
34 + extract_dir = File.join(GraderScript.raw_dir, problem_name)
35 + begin
36 + Dir.mkdir extract_dir
37 + rescue Errno::EEXIST
38 + end
39 +
40 + if ext=='.tar.gz' or ext=='.tgz'
41 + cmd = "tar -zxvf #{testdata_filename} -C #{extract_dir}"
42 + elsif ext=='.tar'
43 + cmd = "tar -xvf #{testdata_filename} -C #{extract_dir}"
44 + elsif ext=='.zip'
45 + cmd = "unzip #{testdata_filename} -d #{extract_dir}"
46 + else
47 + return nil
48 + end
49 +
50 + system(cmd)
51 +
52 + files = Dir["#{extract_dir}/**/1*.in"]
53 + return nil if files.length==0
54 +
55 + return File.dirname(files[0])
56 + end
57 +
58 + def self.save_testdata_file(problem_name, tempfile)
59 + ext = TestdataImporter.long_ext(tempfile.original_filename)
60 + testdata_filename = File.join(Dir.tmpdir,"#{problem_name}#{ext}")
61 +
62 + return nil if tempfile==""
63 +
64 + if tempfile.instance_of?(Tempfile)
65 + tempfile.close
66 + FileUtils.move(tempfile.path,testdata_filename)
67 + else
68 + File.open(testdata_filename, "wb") do |f|
69 + f.write(tempfile.read)
70 + end
71 + end
72 +
73 + return testdata_filename
74 + end
75 +
76 + end
@@ -15,6 +15,7
15 15 verify :method => :post, :only => [ :destroy,
16 16 :create, :quick_create,
17 17 :do_manage,
18 + :do_import,
18 19 :update ],
19 20 :redirect_to => { :action => :list }
20 21
@@ -145,6 +146,20
145 146 redirect_to :action => 'manage'
146 147 end
147 148
149 + def import
150 + end
151 +
152 + def do_import
153 + @problem, import_log = Problem.new_from_import_form_params(params)
154 +
155 + if @problem.errors.length != 0
156 + render :action => 'import' and return
157 + end
158 +
159 + @problem.save
160 + @log = import_log
161 + end
162 +
148 163 ##################################
149 164 protected
150 165
@@ -9,4 +9,68
9 9 find(:all, :conditions => {:available => true}, :order => "date_added DESC")
10 10 end
11 11
12 + def self.new_from_import_form_params(params)
13 + problem = Problem.new
14 +
15 + # form error checking
16 +
17 + time_limit_s = params[:time_limit]
18 + memory_limit_s = params[:memory_limit]
19 +
20 + time_limit_s = '1' if time_limit_s==''
21 + memory_limit_s = '32' if memory_limit_s==''
22 +
23 + time_limit = time_limit_s.to_i
24 + memory_limit = memory_limit_s.to_i
25 +
26 + if time_limit==0 and time_limit_s!='0'
27 + problem.errors.add_to_base('Time limit format errors.')
28 + elsif time_limit<=0 or time_limit >60
29 + problem.errors.add_to_base('Time limit out of range.')
30 + end
31 +
32 + if memory_limit==0 and memory_limit_s!='0'
33 + problem.errors.add_to_base('Memory limit format errors.')
34 + elsif memory_limit<=0 or memory_limit >512
35 + problem.errors.add_to_base('Memory limit out of range.')
36 + end
37 +
38 + if params[:file]==nil or params[:file]==''
39 + problem.errors.add_to_base('No testdata file.')
40 + end
41 +
42 + file = params[:file]
43 +
44 + if problem.errors.length!=0
45 + return problem
46 + end
47 +
48 + problem.name = params[:name]
49 + if params[:full_name]!=''
50 + problem.full_name = params[:full_name]
51 + else
52 + problem.full_name = params[:name]
53 + end
54 +
55 + if not problem.valid?
56 + return problem
57 + end
58 +
59 + importer = TestdataImporter.new
60 +
61 + if not importer.import_from_file(problem.name,
62 + file,
63 + time_limit,
64 + memory_limit)
65 + problem.errors.add_to_base('Import error.')
66 + end
67 +
68 + problem.full_score = 100
69 + problem.date_added = Time.new
70 + problem.test_allowed = true
71 + problem.output_only = false
72 + problem.available = false
73 + return problem, importer.log_msg
74 + end
75 +
12 76 end
@@ -8,6 +8,7
8 8 <p>
9 9 <%= link_to '[New problem]', :action => 'new' %>
10 10 <%= link_to '[Manage problems]', :action => 'manage' %>
11 + <%= link_to '[Import problems]', :action => 'import' %>
11 12 <%= link_to '[Turn off all problems]', :action => 'turn_all_off' %>
12 13 <%= link_to '[Turn on all problems]', :action => 'turn_all_on' %>
13 14 </p>
@@ -54,4 +55,4
54 55
55 56 <br />
56 57
57 - <%= link_to 'New problem', :action => 'new' %>
58 + <%= link_to '[New problem]', :action => 'new' %>
@@ -74,8 +74,10
74 74 # Include your application configuration below
75 75
76 76 # If you want to manage graders through web interface, set the path to
77 - # script directory below
78 - GRADER_SCRIPT_DIR = ''
77 + # the grader directory below. This dir is where raw, ev, ev-exam,
78 + # scripts reside. All grader scripts will be in
79 + # #{GRADER_ROOT_DIR}/scripts.
80 + GRADER_ROOT_DIR = ''
79 81
80 82 # These are where inputs and outputs of test requests are stored
81 83 TEST_REQUEST_INPUT_FILE_DIR = RAILS_ROOT + '/data/test_request/input'
@@ -1,35 +1,58
1 1 module GraderScript
2 2
3 3 def self.grader_control_enabled?
4 - if defined? GRADER_SCRIPT_DIR
5 - GRADER_SCRIPT_DIR != ''
4 + if defined? GRADER_ROOT_DIR
5 + GRADER_ROOT_DIR != ''
6 6 else
7 7 false
8 8 end
9 9 end
10 10
11 - def self.stop_grader(pid)
11 + def self.raw_dir
12 + File.join GRADER_ROOT_DIR, "raw"
13 + end
14 +
15 + def self.call_grader(params)
12 16 if GraderScript.grader_control_enabled?
13 - cmd = "#{GRADER_SCRIPT_DIR}/grader stop #{pid}"
17 + cmd = File.join(GRADER_ROOT_DIR, "scripts/grader") + " " + params
14 18 system(cmd)
15 19 end
16 20 end
17 21
22 + def self.stop_grader(pid)
23 + GraderScript.call_grader "stop #{pid}"
24 + end
25 +
18 26 def self.stop_graders(pids)
19 - if GraderScript.grader_control_enabled?
20 - pid_str = (pids.map { |process| process.pid.to_a }).join ' '
21 - cmd = "#{GRADER_SCRIPT_DIR}/grader stop " + pid_str
22 - system(cmd)
23 - end
27 + pid_str = (pids.map { |process| process.pid.to_a }).join ' '
28 + GraderScript.call_grader "stop #{pid_str}"
24 29 end
25 30
26 31 def self.start_grader(env)
32 + GraderScript.call_grader "#{env} queue &"
33 + GraderScript.call_grader "#{env} test_request &"
34 + end
35 +
36 + def self.call_import_problem(problem_name,
37 + problem_dir,
38 + time_limit=1,
39 + memory_limit=32,
40 + checker_name='text')
27 41 if GraderScript.grader_control_enabled?
28 - cmd = "#{GRADER_SCRIPT_DIR}/grader #{env} queue &"
29 - system(cmd)
30 - cmd = "#{GRADER_SCRIPT_DIR}/grader #{env} test_request &"
31 - system(cmd)
32 - end
42 + cur_dir = `pwd`.chomp
43 + Dir.chdir(GRADER_ROOT_DIR)
44 +
45 + script_name = File.join(GRADER_ROOT_DIR, "scripts/import_problem")
46 + cmd = "#{script_name} #{problem_name} #{problem_dir} #{checker_name}" +
47 + " -t #{time_limit} -m #{memory_limit}"
48 +
49 + output = `#{cmd}`
50 +
51 + Dir.chdir(cur_dir)
52 +
53 + return output
54 + end
55 + return ''
33 56 end
34 57
35 58 end
@@ -6,3 +6,9
6 6 tr.not-available {
7 7 background: #ffc0c0;
8 8 }
9 +
10 + .import-log {
11 + background: lightgray;
12 + border: solid black 1px;
13 + padding: 10px;
14 + } No newline at end of file
You need to be logged in to leave comments. Login now