##// END OF EJS Templates
Fixed: Darcs adapter works on Win32 only (wrong quotes in commands #2402)....
Jean-Philippe Lang -
r2229:567c8ed9b01d
parent child
Show More
@@ -1,196 +1,196
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require 'redmine/scm/adapters/abstract_adapter'
19 19 require 'rexml/document'
20 20
21 21 module Redmine
22 22 module Scm
23 23 module Adapters
24 24 class DarcsAdapter < AbstractAdapter
25 25 # Darcs executable name
26 26 DARCS_BIN = "darcs"
27 27
28 28 class << self
29 29 def client_version
30 30 @@client_version ||= (darcs_binary_version || [])
31 31 end
32 32
33 33 def darcs_binary_version
34 34 cmd = "#{DARCS_BIN} --version"
35 35 version = nil
36 36 shellout(cmd) do |io|
37 37 # Read darcs version in first returned line
38 38 if m = io.gets.match(%r{((\d+\.)+\d+)})
39 39 version = m[0].scan(%r{\d+}).collect(&:to_i)
40 40 end
41 41 end
42 42 return nil if $? && $?.exitstatus != 0
43 43 version
44 44 end
45 45 end
46 46
47 47 def initialize(url, root_url=nil, login=nil, password=nil)
48 48 @url = url
49 49 @root_url = url
50 50 end
51 51
52 52 def supports_cat?
53 53 # cat supported in darcs 2.0.0 and higher
54 54 self.class.client_version_above?([2, 0, 0])
55 55 end
56 56
57 57 # Get info about the darcs repository
58 58 def info
59 59 rev = revisions(nil,nil,nil,{:limit => 1})
60 60 rev ? Info.new({:root_url => @url, :lastrev => rev.last}) : nil
61 61 end
62 62
63 63 # Returns an Entries collection
64 64 # or nil if the given path doesn't exist in the repository
65 65 def entries(path=nil, identifier=nil)
66 66 path_prefix = (path.blank? ? '' : "#{path}/")
67 67 path = '.' if path.blank?
68 68 entries = Entries.new
69 69 cmd = "#{DARCS_BIN} annotate --repodir #{@url} --xml-output"
70 cmd << " --match \"hash #{identifier}\"" if identifier
71 cmd << " #{path}"
70 cmd << " --match #{shell_quote("hash #{identifier}")}" if identifier
71 cmd << " #{shell_quote path}"
72 72 shellout(cmd) do |io|
73 73 begin
74 74 doc = REXML::Document.new(io)
75 75 if doc.root.name == 'directory'
76 76 doc.elements.each('directory/*') do |element|
77 77 next unless ['file', 'directory'].include? element.name
78 78 entries << entry_from_xml(element, path_prefix)
79 79 end
80 80 elsif doc.root.name == 'file'
81 81 entries << entry_from_xml(doc.root, path_prefix)
82 82 end
83 83 rescue
84 84 end
85 85 end
86 86 return nil if $? && $?.exitstatus != 0
87 87 entries.compact.sort_by_name
88 88 end
89 89
90 90 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
91 91 path = '.' if path.blank?
92 92 revisions = Revisions.new
93 93 cmd = "#{DARCS_BIN} changes --repodir #{@url} --xml-output"
94 cmd << " --from-match \"hash #{identifier_from}\"" if identifier_from
94 cmd << " --from-match #{shell_quote("hash #{identifier_from}")}" if identifier_from
95 95 cmd << " --last #{options[:limit].to_i}" if options[:limit]
96 96 shellout(cmd) do |io|
97 97 begin
98 98 doc = REXML::Document.new(io)
99 99 doc.elements.each("changelog/patch") do |patch|
100 100 message = patch.elements['name'].text
101 101 message << "\n" + patch.elements['comment'].text.gsub(/\*\*\*END OF DESCRIPTION\*\*\*.*\z/m, '') if patch.elements['comment']
102 102 revisions << Revision.new({:identifier => nil,
103 103 :author => patch.attributes['author'],
104 104 :scmid => patch.attributes['hash'],
105 105 :time => Time.parse(patch.attributes['local_date']),
106 106 :message => message,
107 107 :paths => (options[:with_path] ? get_paths_for_patch(patch.attributes['hash']) : nil)
108 108 })
109 109 end
110 110 rescue
111 111 end
112 112 end
113 113 return nil if $? && $?.exitstatus != 0
114 114 revisions
115 115 end
116 116
117 117 def diff(path, identifier_from, identifier_to=nil)
118 118 path = '*' if path.blank?
119 119 cmd = "#{DARCS_BIN} diff --repodir #{@url}"
120 120 if identifier_to.nil?
121 cmd << " --match \"hash #{identifier_from}\""
121 cmd << " --match #{shell_quote("hash #{identifier_from}")}"
122 122 else
123 cmd << " --to-match \"hash #{identifier_from}\""
124 cmd << " --from-match \"hash #{identifier_to}\""
123 cmd << " --to-match #{shell_quote("hash #{identifier_from}")}"
124 cmd << " --from-match #{shell_quote("hash #{identifier_to}")}"
125 125 end
126 cmd << " -u #{path}"
126 cmd << " -u #{shell_quote path}"
127 127 diff = []
128 128 shellout(cmd) do |io|
129 129 io.each_line do |line|
130 130 diff << line
131 131 end
132 132 end
133 133 return nil if $? && $?.exitstatus != 0
134 134 diff
135 135 end
136 136
137 137 def cat(path, identifier=nil)
138 138 cmd = "#{DARCS_BIN} show content --repodir #{@url}"
139 cmd << " --match \"hash #{identifier}\"" if identifier
139 cmd << " --match #{shell_quote("hash #{identifier}")}" if identifier
140 140 cmd << " #{shell_quote path}"
141 141 cat = nil
142 142 shellout(cmd) do |io|
143 143 io.binmode
144 144 cat = io.read
145 145 end
146 146 return nil if $? && $?.exitstatus != 0
147 147 cat
148 148 end
149 149
150 150 private
151 151
152 152 # Returns an Entry from the given XML element
153 153 # or nil if the entry was deleted
154 154 def entry_from_xml(element, path_prefix)
155 155 modified_element = element.elements['modified']
156 156 if modified_element.elements['modified_how'].text.match(/removed/)
157 157 return nil
158 158 end
159 159
160 160 Entry.new({:name => element.attributes['name'],
161 161 :path => path_prefix + element.attributes['name'],
162 162 :kind => element.name == 'file' ? 'file' : 'dir',
163 163 :size => nil,
164 164 :lastrev => Revision.new({
165 165 :identifier => nil,
166 166 :scmid => modified_element.elements['patch'].attributes['hash']
167 167 })
168 168 })
169 169 end
170 170
171 171 # Retrieve changed paths for a single patch
172 172 def get_paths_for_patch(hash)
173 173 cmd = "#{DARCS_BIN} annotate --repodir #{@url} --summary --xml-output"
174 cmd << " --match \"hash #{hash}\" "
174 cmd << " --match #{shell_quote("hash #{hash}")} "
175 175 paths = []
176 176 shellout(cmd) do |io|
177 177 begin
178 178 # Darcs xml output has multiple root elements in this case (tested with darcs 1.0.7)
179 179 # A root element is added so that REXML doesn't raise an error
180 180 doc = REXML::Document.new("<fake_root>" + io.read + "</fake_root>")
181 181 doc.elements.each('fake_root/summary/*') do |modif|
182 182 paths << {:action => modif.name[0,1].upcase,
183 183 :path => "/" + modif.text.chomp.gsub(/^\s*/, '')
184 184 }
185 185 end
186 186 rescue
187 187 end
188 188 end
189 189 paths
190 190 rescue CommandFailed
191 191 paths
192 192 end
193 193 end
194 194 end
195 195 end
196 196 end
General Comments 0
You need to be logged in to leave comments. Login now