| @@ -9,7 +9,9 @@ module KGrader | |||||
| @root = @fs.assignment @course.name, @name | @root = @fs.assignment @course.name, @name | ||||
| @config = @fs.load @fs.assignment_config(@course.name, @name) | @config = @fs.load @fs.assignment_config(@course.name, @name) | ||||
| @manifest = build_manifest | |||||
| verify_config | |||||
| @manifest = get_manifest | |||||
| rescue FilesystemError | rescue FilesystemError | ||||
| raise AssignmentError, "unknown assignment: #{name}" | raise AssignmentError, "unknown assignment: #{name}" | ||||
| end | end | ||||
| @@ -18,22 +20,44 @@ module KGrader | |||||
| @config['id'] || @name | @config['id'] || @name | ||||
| end | end | ||||
| def build_manifest | |||||
| unless @config.include? 'manifest' | |||||
| raise AssignmentError, "missing manifest: #{@name}" | |||||
| def build_steps | |||||
| @config['build'] | |||||
| end | |||||
| def tests | |||||
| @config['grade'] | |||||
| end | |||||
| def report | |||||
| @config['commit']['report'] || "report.txt" | |||||
| end | |||||
| def commit_message(student) | |||||
| default = "adding grade report for #{name}: {student}" | |||||
| template = @config['commit']['message'].clone || default | |||||
| template['{student}'] = student | |||||
| template | |||||
| end | |||||
| private | |||||
| def verify_config | |||||
| %w(stage build grade).each do |key| | |||||
| unless @config.include? key | |||||
| raise AssignmentError, "missing #{key} section in config: #{@name}" | |||||
| end | |||||
| end | end | ||||
| end | |||||
| def get_manifest | |||||
| stage = @config['stage'] | |||||
| raise AssignmentError, "chroot is not supported yet" if stage['chroot'] | |||||
| manifest = @config['manifest'] | |||||
| provided = manifest['provided'].map do |fn| | |||||
| provided = stage['provided'].map do |fn| | |||||
| { :name => fn, :path => File.join(@root, 'provided', fn) } | { :name => fn, :path => File.join(@root, 'provided', fn) } | ||||
| end | end | ||||
| graded = manifest['graded'].map { |fn| { :name => fn } } | |||||
| graded = stage['graded'].map { |fn| { :name => fn } } | |||||
| { | |||||
| :provided => provided, | |||||
| :graded => graded, | |||||
| :report => manifest['report'] | |||||
| } | |||||
| { :provided => provided, :graded => graded } | |||||
| end | end | ||||
| end | end | ||||
| end | end | ||||
| @@ -5,16 +5,25 @@ module KGrader | |||||
| @root = root | @root = root | ||||
| end | end | ||||
| def reset | |||||
| FileUtils.rm_rf @root | |||||
| end | |||||
| def init | def init | ||||
| FileUtils.mkdir_p @root | FileUtils.mkdir_p @root | ||||
| end | end | ||||
| def reset | |||||
| FileUtils.rm_rf @root | |||||
| def stage(source, target) | |||||
| FileUtils.cp source, File.join(@root, target) | |||||
| end | end | ||||
| def stage(source, target) | |||||
| puts "[chroot::stage] #{source} -> (jail)/#{target}" | |||||
| def exec(command) | |||||
| pid = Process.fork do | |||||
| Dir.chdir @root | |||||
| # TODO: rlimit in exec, umask? | |||||
| Process.exec command | |||||
| end | |||||
| Process.waitpid pid, 0 | |||||
| end | end | ||||
| end | end | ||||
| end | end | ||||
| @@ -48,30 +48,24 @@ module KGrader | |||||
| end | end | ||||
| def grade | def grade | ||||
| # TODO: | |||||
| # self.status = :ungraded | |||||
| self.status = :ungraded | |||||
| stage | stage | ||||
| # [grade the stuff] | |||||
| # [save report to gradefile] | |||||
| # @fs.jail.reset | |||||
| # FileUtils.touch pendingfile | |||||
| # self.status = :graded | |||||
| # return grade summary string | |||||
| sleep rand / 2 | |||||
| '100%' | |||||
| build | |||||
| test | |||||
| save | |||||
| # self.status = :graded # UNCOMMENT | |||||
| # @fs.jail.reset # UNCOMMENT | |||||
| # TODO: return grade summary string | |||||
| end | end | ||||
| def commit | def commit | ||||
| # TODO: | |||||
| # if status == :graded && File.exists? pendingfile | |||||
| # [copy gradefile to repo] | |||||
| # @course.backend.commit repo, <message>, <gradefile path> | |||||
| # FileUtils.rm pendingfile | |||||
| # end | |||||
| sleep rand / 2 | |||||
| nil | |||||
| if status == :graded && File.exists?(pendingfile) | |||||
| target = File.join(repo, @assignment.report) | |||||
| message = @assignment.commit_message @student | |||||
| FileUtils.cp gradefile, target | |||||
| @course.backend.commit repo, message, target | |||||
| FileUtils.rm pendingfile | |||||
| end | |||||
| end | end | ||||
| private | private | ||||
| @@ -118,5 +112,22 @@ module KGrader | |||||
| @fs.jail.stage File.join(repo, entry[:name]), entry[:name] | @fs.jail.stage File.join(repo, entry[:name]), entry[:name] | ||||
| end | end | ||||
| end | end | ||||
| def build | |||||
| @assignment.build_steps.each do |command| | |||||
| @fs.jail.exec command | |||||
| end | |||||
| end | |||||
| def test | |||||
| @assignment.tests.each do |script| | |||||
| # TODO: execute script in jail | |||||
| end | |||||
| end | |||||
| def save | |||||
| # TODO: save gradefile | |||||
| FileUtils.touch pendingfile | |||||
| end | |||||
| end | end | ||||
| end | end | ||||
| @@ -1 +1 @@ | |||||
| Subproject commit 438e509e4c9097894f275dd66a5ae37bbcb62c24 | |||||
| Subproject commit f9cb0aabbe48368ef7a8db6c43e7d81e71d2c4fa | |||||