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.

84 lines
2.1 KiB

  1. require 'io/console'
  2. require 'nokogiri'
  3. require 'open3'
  4. module KGrader::Backend
  5. class SVN
  6. def initialize(filesystem, course, config)
  7. @fs = filesystem
  8. @course = course
  9. @config = config
  10. @password = nil
  11. end
  12. def prepare(semester, assignment)
  13. return unless @config['verify']
  14. unless test_okay
  15. print "svn: password: "
  16. @password = STDIN.noecho(&:gets).chomp
  17. print "svn: bad password or other network issues" unless test_okay
  18. end
  19. end
  20. def revision(repo)
  21. xml = Nokogiri::XML run('log', '--xml', '-l', '1', repo).first
  22. xml.css('logentry').attr('revision').value.to_i
  23. end
  24. def clone(repo, semester, assignment, student)
  25. url = get_url semester, assignment, student
  26. run 'checkout', '--ignore-externals', url, repo
  27. end
  28. def update(repo, revision = nil)
  29. args = 'update', '--ignore-externals', '--accept', 'tf'
  30. args.push "-r#{revision}" unless revision.nil?
  31. run *args, repo
  32. end
  33. def log(repo)
  34. xml = Nokogiri::XML run('log', '--xml', repo).first
  35. xml.css('logentry').map do |elem|
  36. { :rev => elem.attr('revision').to_i,
  37. :date => Time.parse(elem.css('date').text) }
  38. end
  39. end
  40. def commit(repo, message, paths = nil)
  41. run 'commit', '-m', message, *paths.map { |fn| File.join repo, fn }
  42. end
  43. def commit_date(repo)
  44. xml = Nokogiri::XML run('log', '--xml', '-l', '1', repo).first
  45. Time.parse xml.css('logentry date').text
  46. end
  47. private
  48. def run(*cmd)
  49. if @password
  50. cmd.unshift @password
  51. cmd.unshift '--password'
  52. end
  53. Open3.capture2e('svn', *cmd)
  54. end
  55. def get_url(semester, assignment, student)
  56. @config['url'] % {
  57. :semester => semester,
  58. :assignment => assignment,
  59. :student => student
  60. }
  61. end
  62. def test_okay
  63. url = @config['verify'] % {
  64. :semester => semester,
  65. :assignment => assignment
  66. }
  67. status = run('list', '--non-interactive', url)[1]
  68. status.exited? && status.exitstatus == 0
  69. end
  70. end
  71. end