A code autograder for student homework submissions
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123 lines
2.6 KiB

  1. module KGrader
  2. class Submission
  3. attr_reader :course, :semester, :assignment, :student
  4. def initialize(filesystem, course, semester, assignment, student)
  5. @fs = filesystem
  6. @course = course
  7. @semester = semester
  8. @assignment = assignment
  9. @student = student
  10. @root = @fs.submission @course.name, @semester, @assignment.name, student
  11. @status = nil
  12. end
  13. def status
  14. @status ||= @fs.load(statusfile).to_sym
  15. end
  16. def status=(new_status)
  17. File.write statusfile, new_status
  18. @status = new_status
  19. end
  20. def exists?
  21. File.exists? statusfile
  22. end
  23. def create
  24. FileUtils.mkdir_p @root
  25. self.status = :init
  26. nil
  27. end
  28. def fetch(due)
  29. if status == :init
  30. @course.backend.clone repo, @semester, @assignment.id, @student
  31. rewind due
  32. self.status = :ungraded
  33. else
  34. oldrev = revision if status == :graded
  35. self.status = :fetching
  36. @course.backend.update repo
  37. newrev = rewind due
  38. self.status = newrev == oldrev ? :graded : :ungraded
  39. end
  40. nil
  41. end
  42. def grade
  43. # TODO:
  44. # self.status = :ungraded
  45. stage
  46. # [grade the stuff]
  47. # [save report to gradefile]
  48. # @fs.jail.reset
  49. # FileUtils.touch pendingfile
  50. # self.status = :graded
  51. # return grade summary string
  52. sleep rand / 2
  53. '100%'
  54. end
  55. def commit
  56. # TODO:
  57. # if status == :graded && File.exists? pendingfile
  58. # [copy gradefile to repo]
  59. # @course.backend.commit repo, <message>, <gradefile path>
  60. # FileUtils.rm pendingfile
  61. # end
  62. sleep rand / 2
  63. nil
  64. end
  65. private
  66. def repo
  67. File.join @root, 'repo'
  68. end
  69. def statusfile
  70. File.join @root, 'status.txt'
  71. end
  72. def gradefile
  73. File.join @root, 'grade.txt'
  74. end
  75. def pendingfile
  76. File.join @root, 'pending'
  77. end
  78. def revision
  79. @course.backend.revision repo
  80. end
  81. def rewind(date)
  82. log = @course.backend.log repo
  83. target = log.find { |commit| commit[:date] <= date }
  84. if target.nil?
  85. raise SubmissionError, "no commits before due date: #{student}"
  86. end
  87. rev = target[:rev]
  88. @course.backend.update repo, rev
  89. rev
  90. end
  91. def stage
  92. @fs.jail.reset
  93. @fs.jail.init
  94. @assignment.manifest[:provided].each do |entry|
  95. @fs.jail.stage entry[:path], entry[:name]
  96. end
  97. @assignment.manifest[:graded].each do |entry|
  98. @fs.jail.stage File.join(repo, entry[:name]), entry[:name]
  99. end
  100. end
  101. end
  102. end