@@ -5,5 +5,6 @@ require_relative 'kgrader/course' | |||
require_relative 'kgrader/errors' | |||
require_relative 'kgrader/filesystem' | |||
require_relative 'kgrader/roster' | |||
require_relative 'kgrader/submission' | |||
require_relative 'kgrader/task' | |||
require_relative 'kgrader/util' |
@@ -1,17 +1,39 @@ | |||
require 'open3' | |||
module KGrader::Backend | |||
class SVN | |||
def initialize(filesystem, config) | |||
def initialize(filesystem, course, config) | |||
@fs = filesystem | |||
@course = course | |||
@config = config | |||
end | |||
def fetch(semester, assignment, student) | |||
url = @config['url'] % { | |||
:semester => semester, :assignment => assignment, :student => student } | |||
def revision(repo) | |||
# TODO | |||
puts "[fetching #{student}: #{url}]" | |||
-1 | |||
end | |||
def clone(repo, semester, assignment, student) | |||
url = get_url semester, assignment, student | |||
run 'checkout', '--ignore-externals', url, repo | |||
end | |||
def update(repo) | |||
run 'update', '--ignore-externals', '--accept', 'tf', repo | |||
end | |||
private | |||
def run(*cmd) | |||
Open3.capture2e('svn', *cmd) | |||
end | |||
def get_url(semester, assignment, student) | |||
@config['url'] % { | |||
:semester => semester, | |||
:assignment => assignment, | |||
:student => student | |||
} | |||
end | |||
end | |||
end |
@@ -8,7 +8,7 @@ module KGrader | |||
@config = @fs.load @fs.course_config(@name) | |||
type = @config['backend'] | |||
@backend = KGrader::backend(type).new self, @config[type] | |||
@backend = KGrader::backend(type).new @fs, self, @config[type] | |||
@rosters = {} | |||
@assignments = {} | |||
rescue FilesystemError | |||
@@ -1,3 +1,4 @@ | |||
require 'json' | |||
require 'yaml' | |||
module KGrader | |||
@@ -37,6 +38,10 @@ module KGrader | |||
File.join desk, courseid, semester, '_roster.csv' | |||
end | |||
def submission(courseid, semester, assignment, student) | |||
File.join desk, courseid, semester, assignment, student | |||
end | |||
# ------------------------------------------------------------------------- | |||
def courses | |||
@@ -44,7 +49,7 @@ module KGrader | |||
end | |||
def assignments(courseid) | |||
Dir[assignment courseid '*'].map! { |fn| File.basename File.dirname fn } | |||
Dir[assignment courseid, '*'].map! { |fn| File.basename File.dirname fn } | |||
end | |||
def semesters(courseid) | |||
@@ -55,6 +60,10 @@ module KGrader | |||
def load(path) | |||
case File.extname path | |||
when '.txt' | |||
File.read path | |||
when '.json' | |||
JSON.parse File.read(path) | |||
when '.yml', '.yaml' | |||
YAML.load File.read(path) | |||
when '.csv' | |||
@@ -0,0 +1,70 @@ | |||
module KGrader | |||
class Submission | |||
attr_reader :course, :semester, :assignment, :student | |||
def initialize(filesystem, course, semester, assignment, student) | |||
@fs = filesystem | |||
@course = course | |||
@semester = semester | |||
@assignment = assignment | |||
@student = student | |||
@root = @fs.submission @course.name, @semester, @assignment.name, student | |||
@status = nil | |||
end | |||
def status | |||
@status ||= @fs.load(statusfile).to_sym | |||
end | |||
def status=(new_status) | |||
File.write statusfile, new_status | |||
@status = new_status | |||
end | |||
def exists? | |||
File.exists? statusfile | |||
end | |||
def create | |||
FileUtils.mkdir_p @root | |||
self.status = :init | |||
end | |||
def fetch(due) | |||
if status == :init | |||
@course.backend.clone repo, @semester, @assignment.id, @student | |||
rewind due | |||
self.status = :ungraded | |||
else | |||
oldrev = revision if status == :graded | |||
self.status = :fetching | |||
@course.backend.update repo | |||
rewind due | |||
self.status = revision == oldrev ? :graded : :ungraded | |||
end | |||
end | |||
def grade | |||
# TODO | |||
# self.status = :graded | |||
end | |||
private | |||
def statusfile | |||
File.join @root, "status.txt" | |||
end | |||
def repo | |||
File.join @root, "repo" | |||
end | |||
def revision | |||
@course.backend.revision repo | |||
end | |||
def rewind(date) | |||
# TODO | |||
end | |||
end | |||
end |
@@ -2,52 +2,62 @@ module KGrader | |||
class Task | |||
def initialize(filesystem, course, semester, assignment) | |||
@fs = filesystem | |||
@course = course | |||
@semester = semester | |||
@fs = filesystem | |||
@course = course | |||
@semester = semester | |||
@assignment = @course.assignment assignment | |||
@students = @course.roster(@semester).students | |||
@students = @course.roster(@semester).students | |||
end | |||
def grade(options = {}) | |||
students = @students | |||
students &= options[:students] unless options[:students].nil? | |||
submissions = get_submissions options[:students] | |||
due = options.fetch(:due, Time.now) | |||
fetch = options.fetch(:fetch, true) | |||
regrade = options.fetch(:regrade, false) | |||
# TODO | |||
puts "[grading]" | |||
puts "course => #{@course.name}" | |||
puts "semester => #{@semester}" | |||
puts "assignment => #{@assignment.name}" | |||
puts "students => #{students.join ', '}" | |||
puts "due => #{due}" | |||
puts "fetch => #{fetch}" | |||
puts "regrade => #{regrade}" | |||
puts | |||
count = submissions.count | |||
puts "[grading #{count} student#{'s' if count != 1}]" | |||
fetch_students students if fetch | |||
submissions.each do |sub| | |||
unless sub.exists? | |||
puts "[init #{sub.student}]" | |||
sub.create | |||
end | |||
end | |||
if fetch | |||
submissions.each do |sub| | |||
puts "[fetch #{sub.student}]" | |||
sub.fetch due | |||
end | |||
end | |||
submissions.each do |sub| | |||
sub.status = :ungraded if regrade | |||
if sub.status == :ungraded | |||
puts "[grade #{sub.student}]" | |||
sub.grade | |||
end | |||
end | |||
end | |||
def commit(options = {}) | |||
students = @students | |||
students &= options[:students] unless options[:students].nil? | |||
submissions = get_submissions options[:students] | |||
# TODO | |||
puts "[committing]" | |||
puts "course => #{@course.name}" | |||
puts "semester => #{@semester}" | |||
puts "assignment => #{@assignment.name}" | |||
puts "students => #{students.join ', '}" | |||
puts "students => #{submissions.map { |sub| sub.student }.join ', '}" | |||
end | |||
private | |||
def fetch_students(students) | |||
students.each do |student| | |||
@course.backend.fetch @semester, @assignment.id, student | |||
def get_submissions(students) | |||
students.nil? ? (students = @students) : (students &= @students) | |||
students.map do |student| | |||
Submission.new @fs, @course, @semester, @assignment, student | |||
end | |||
end | |||
end | |||