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.

98 lines
2.4 KiB

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