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.

96 lines
2.4 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. url = @config['verify'] % {
  15. :semester => semester,
  16. :assignment => assignment
  17. }
  18. unless test_okay url
  19. print "svn: password: "
  20. @password = STDIN.noecho(&:gets).chomp
  21. puts
  22. unless test_okay url
  23. raise SVNError, "bad password or other network issues"
  24. end
  25. end
  26. end
  27. def revision(repo)
  28. xml = Nokogiri::XML run('log', '--xml', '-l', '1', repo).first
  29. xml.css('logentry').attr('revision').value.to_i
  30. end
  31. def clone(repo, semester, assignment, student)
  32. url = get_url semester, assignment, student
  33. run 'checkout', '--ignore-externals', url, repo
  34. end
  35. def update(repo, revision = nil)
  36. args = 'update', '--ignore-externals', '--accept', 'tf'
  37. args.push "-r#{revision}" unless revision.nil?
  38. run *args, repo
  39. end
  40. def log(repo)
  41. xml = Nokogiri::XML run('log', '--xml', repo).first
  42. xml.css('logentry').map do |elem|
  43. { :rev => elem.attr('revision').to_i,
  44. :date => Time.parse(elem.css('date').text) }
  45. end
  46. end
  47. def commit(repo, message, *paths)
  48. fullpaths = paths.map { |fn| File.join repo, fn }
  49. run 'add', *fullpaths
  50. run 'commit', '-m', message, *fullpaths
  51. end
  52. def commit_date(repo)
  53. xml = Nokogiri::XML run('log', '--xml', '-l', '1', repo).first
  54. Time.parse xml.css('logentry date').text
  55. end
  56. private
  57. def run(*cmd)
  58. if @password
  59. temp = '.svn_temp_' + rand(1000000000).to_s
  60. begin
  61. File.write temp, @password
  62. Open3.capture2e("cat #{temp} | xargs svn #{cmd.join ' '} --password")
  63. ensure
  64. File.unlink temp
  65. end
  66. else
  67. Open3.capture2e('svn', *cmd)
  68. end
  69. end
  70. def get_url(semester, assignment, student)
  71. @config['url'] % {
  72. :semester => semester,
  73. :assignment => assignment,
  74. :student => student
  75. }
  76. end
  77. def test_okay(url)
  78. status = run('list', '--non-interactive', url)[1]
  79. status.exited? && status.exitstatus == 0
  80. end
  81. end
  82. end