From ea3e2b1121800ebd4ea8bae40d3142d0c13d44f4 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sat, 13 Feb 2010 13:58:05 +0000 Subject: [PATCH] Changes SubversionAdapter to use ActiveSupport::XmlMini API for XML parsing. This allows easy switching to one of the faster XML parsers supported by XmlMini (eg. libxml-ruby). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@3424 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- .../scm/adapters/subversion_adapter.rb | 83 +++++++++++-------- 1 file changed, 49 insertions(+), 34 deletions(-) diff --git a/lib/redmine/scm/adapters/subversion_adapter.rb b/lib/redmine/scm/adapters/subversion_adapter.rb index dccb39fe..73814f93 100644 --- a/lib/redmine/scm/adapters/subversion_adapter.rb +++ b/lib/redmine/scm/adapters/subversion_adapter.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2010 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -16,7 +16,6 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. require 'redmine/scm/adapters/abstract_adapter' -require 'rexml/document' require 'uri' module Redmine @@ -52,14 +51,15 @@ module Redmine cmd << credentials_string info = nil shellout(cmd) do |io| + output = io.read begin - doc = REXML::Document.new(io) + doc = ActiveSupport::XmlMini.parse(output) #root_url = doc.elements["info/entry/repository/root"].text - info = Info.new({:root_url => doc.elements["info/entry/repository/root"].text, + info = Info.new({:root_url => doc['info']['entry']['repository']['root']['__content__'], :lastrev => Revision.new({ - :identifier => doc.elements["info/entry/commit"].attributes['revision'], - :time => Time.parse(doc.elements["info/entry/commit/date"].text).localtime, - :author => (doc.elements["info/entry/commit/author"] ? doc.elements["info/entry/commit/author"].text : "") + :identifier => doc['info']['entry']['commit']['revision'], + :time => Time.parse(doc['info']['entry']['commit']['date']['__content__']).localtime, + :author => (doc['info']['entry']['commit']['author'] ? doc['info']['entry']['commit']['author']['__content__'] : "") }) }) rescue @@ -82,22 +82,22 @@ module Redmine shellout(cmd) do |io| output = io.read begin - doc = REXML::Document.new(output) - doc.elements.each("lists/list/entry") do |entry| - commit = entry.elements['commit'] - commit_date = commit.elements['date'] + doc = ActiveSupport::XmlMini.parse(output) + each_xml_element(doc['lists']['list'], 'entry') do |entry| + commit = entry['commit'] + commit_date = commit['date'] # Skip directory if there is no commit date (usually that # means that we don't have read access to it) - next if entry.attributes['kind'] == 'dir' && commit_date.nil? - name = entry.elements['name'].text + next if entry['kind'] == 'dir' && commit_date.nil? + name = entry['name']['__content__'] entries << Entry.new({:name => URI.unescape(name), :path => ((path.empty? ? "" : "#{path}/") + name), - :kind => entry.attributes['kind'], - :size => ((s = entry.elements['size']) ? s.text.to_i : nil), + :kind => entry['kind'], + :size => ((s = entry['size']) ? s['__content__'].to_i : nil), :lastrev => Revision.new({ - :identifier => commit.attributes['revision'], - :time => Time.parse(commit_date.text).localtime, - :author => ((a = commit.elements['author']) ? a.text : nil) + :identifier => commit['revision'], + :time => Time.parse(commit_date['__content__'].to_s).localtime, + :author => ((a = commit['author']) ? a['__content__'] : nil) }) }) end @@ -122,9 +122,9 @@ module Redmine shellout(cmd) do |io| output = io.read begin - doc = REXML::Document.new(output) - doc.elements.each("properties/target/property") do |property| - properties[ property.attributes['name'] ] = property.text + doc = ActiveSupport::XmlMini.parse(output) + each_xml_element(doc['properties']['target'], 'property') do |property| + properties[ property['name'] ] = property['__content__'].to_s end rescue end @@ -144,23 +144,24 @@ module Redmine cmd << " --limit #{options[:limit].to_i}" if options[:limit] cmd << ' ' + target(URI.escape(path)) shellout(cmd) do |io| + output = io.read begin - doc = REXML::Document.new(io) - doc.elements.each("log/logentry") do |logentry| + doc = ActiveSupport::XmlMini.parse(output) + each_xml_element(doc['log'], 'logentry') do |logentry| paths = [] - logentry.elements.each("paths/path") do |path| - paths << {:action => path.attributes['action'], - :path => path.text, - :from_path => path.attributes['copyfrom-path'], - :from_revision => path.attributes['copyfrom-rev'] + each_xml_element(logentry['paths'], 'path') do |path| + paths << {:action => path['action'], + :path => path['__content__'], + :from_path => path['copyfrom-path'], + :from_revision => path['copyfrom-rev'] } - end + end if logentry['paths'] && logentry['paths']['path'] paths.sort! { |x,y| x[:path] <=> y[:path] } - revisions << Revision.new({:identifier => logentry.attributes['revision'], - :author => (logentry.elements['author'] ? logentry.elements['author'].text : ""), - :time => Time.parse(logentry.elements['date'].text).localtime, - :message => logentry.elements['msg'].text, + revisions << Revision.new({:identifier => logentry['revision'], + :author => (logentry['author'] ? logentry['author']['__content__'] : ""), + :time => Time.parse(logentry['date']['__content__'].to_s).localtime, + :message => logentry['msg']['__content__'], :paths => paths }) end @@ -228,6 +229,20 @@ module Redmine str << " --no-auth-cache --non-interactive" str end + + # Helper that iterates over the child elements of a xml node + # MiniXml returns a hash when a single child is found or an array of hashes for multiple children + def each_xml_element(node, name) + if node && node[name] + if node[name].is_a?(Hash) + yield node[name] + else + node[name].each do |element| + yield element + end + end + end + end end end end