##// END OF EJS Templates
Quote subversion username and password in svn commands....
Jean-Philippe Lang -
r839:ecfc40629f1e
parent child
Show More
@@ -1,345 +1,353
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require 'cgi'
18 require 'cgi'
19
19
20 module Redmine
20 module Redmine
21 module Scm
21 module Scm
22 module Adapters
22 module Adapters
23 class CommandFailed < StandardError #:nodoc:
23 class CommandFailed < StandardError #:nodoc:
24 end
24 end
25
25
26 class AbstractAdapter #:nodoc:
26 class AbstractAdapter #:nodoc:
27 def initialize(url, root_url=nil, login=nil, password=nil)
27 def initialize(url, root_url=nil, login=nil, password=nil)
28 @url = url
28 @url = url
29 @login = login if login && !login.empty?
29 @login = login if login && !login.empty?
30 @password = (password || "") if @login
30 @password = (password || "") if @login
31 @root_url = root_url.blank? ? retrieve_root_url : root_url
31 @root_url = root_url.blank? ? retrieve_root_url : root_url
32 end
32 end
33
33
34 def adapter_name
34 def adapter_name
35 'Abstract'
35 'Abstract'
36 end
36 end
37
37
38 def supports_cat?
38 def supports_cat?
39 true
39 true
40 end
40 end
41
41
42 def root_url
42 def root_url
43 @root_url
43 @root_url
44 end
44 end
45
45
46 def url
46 def url
47 @url
47 @url
48 end
48 end
49
49
50 # get info about the svn repository
50 # get info about the svn repository
51 def info
51 def info
52 return nil
52 return nil
53 end
53 end
54
54
55 # Returns the entry identified by path and revision identifier
55 # Returns the entry identified by path and revision identifier
56 # or nil if entry doesn't exist in the repository
56 # or nil if entry doesn't exist in the repository
57 def entry(path=nil, identifier=nil)
57 def entry(path=nil, identifier=nil)
58 e = entries(path, identifier)
58 e = entries(path, identifier)
59 e ? e.first : nil
59 e ? e.first : nil
60 end
60 end
61
61
62 # Returns an Entries collection
62 # Returns an Entries collection
63 # or nil if the given path doesn't exist in the repository
63 # or nil if the given path doesn't exist in the repository
64 def entries(path=nil, identifier=nil)
64 def entries(path=nil, identifier=nil)
65 return nil
65 return nil
66 end
66 end
67
67
68 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
68 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
69 return nil
69 return nil
70 end
70 end
71
71
72 def diff(path, identifier_from, identifier_to=nil, type="inline")
72 def diff(path, identifier_from, identifier_to=nil, type="inline")
73 return nil
73 return nil
74 end
74 end
75
75
76 def cat(path, identifier=nil)
76 def cat(path, identifier=nil)
77 return nil
77 return nil
78 end
78 end
79
79
80 def with_leading_slash(path)
80 def with_leading_slash(path)
81 path ||= ''
81 path ||= ''
82 (path[0,1]!="/") ? "/#{path}" : path
82 (path[0,1]!="/") ? "/#{path}" : path
83 end
83 end
84
85 def shell_quote(str)
86 if RUBY_PLATFORM =~ /mswin/
87 '"' + str.gsub(/"/, '\\"') + '"'
88 else
89 "'" + str.gsub(/'/, "'\"'\"'") + "'"
90 end
91 end
84
92
85 private
93 private
86 def retrieve_root_url
94 def retrieve_root_url
87 info = self.info
95 info = self.info
88 info ? info.root_url : nil
96 info ? info.root_url : nil
89 end
97 end
90
98
91 def target(path)
99 def target(path)
92 path ||= ""
100 path ||= ""
93 base = path.match(/^\//) ? root_url : url
101 base = path.match(/^\//) ? root_url : url
94 " \"" << "#{base}/#{path}".gsub(/["?<>\*]/, '') << "\""
102 " \"" << "#{base}/#{path}".gsub(/["?<>\*]/, '') << "\""
95 end
103 end
96
104
97 def logger
105 def logger
98 RAILS_DEFAULT_LOGGER
106 RAILS_DEFAULT_LOGGER
99 end
107 end
100
108
101 def shellout(cmd, &block)
109 def shellout(cmd, &block)
102 logger.debug "Shelling out: #{cmd}" if logger && logger.debug?
110 logger.debug "Shelling out: #{cmd}" if logger && logger.debug?
103 IO.popen(cmd, "r+") do |io|
111 IO.popen(cmd, "r+") do |io|
104 io.close_write
112 io.close_write
105 block.call(io) if block_given?
113 block.call(io) if block_given?
106 end
114 end
107 end
115 end
108 end
116 end
109
117
110 class Entries < Array
118 class Entries < Array
111 def sort_by_name
119 def sort_by_name
112 sort {|x,y|
120 sort {|x,y|
113 if x.kind == y.kind
121 if x.kind == y.kind
114 x.name <=> y.name
122 x.name <=> y.name
115 else
123 else
116 x.kind <=> y.kind
124 x.kind <=> y.kind
117 end
125 end
118 }
126 }
119 end
127 end
120
128
121 def revisions
129 def revisions
122 revisions ||= Revisions.new(collect{|entry| entry.lastrev}.compact)
130 revisions ||= Revisions.new(collect{|entry| entry.lastrev}.compact)
123 end
131 end
124 end
132 end
125
133
126 class Info
134 class Info
127 attr_accessor :root_url, :lastrev
135 attr_accessor :root_url, :lastrev
128 def initialize(attributes={})
136 def initialize(attributes={})
129 self.root_url = attributes[:root_url] if attributes[:root_url]
137 self.root_url = attributes[:root_url] if attributes[:root_url]
130 self.lastrev = attributes[:lastrev]
138 self.lastrev = attributes[:lastrev]
131 end
139 end
132 end
140 end
133
141
134 class Entry
142 class Entry
135 attr_accessor :name, :path, :kind, :size, :lastrev
143 attr_accessor :name, :path, :kind, :size, :lastrev
136 def initialize(attributes={})
144 def initialize(attributes={})
137 self.name = attributes[:name] if attributes[:name]
145 self.name = attributes[:name] if attributes[:name]
138 self.path = attributes[:path] if attributes[:path]
146 self.path = attributes[:path] if attributes[:path]
139 self.kind = attributes[:kind] if attributes[:kind]
147 self.kind = attributes[:kind] if attributes[:kind]
140 self.size = attributes[:size].to_i if attributes[:size]
148 self.size = attributes[:size].to_i if attributes[:size]
141 self.lastrev = attributes[:lastrev]
149 self.lastrev = attributes[:lastrev]
142 end
150 end
143
151
144 def is_file?
152 def is_file?
145 'file' == self.kind
153 'file' == self.kind
146 end
154 end
147
155
148 def is_dir?
156 def is_dir?
149 'dir' == self.kind
157 'dir' == self.kind
150 end
158 end
151
159
152 def is_text?
160 def is_text?
153 Redmine::MimeType.is_type?('text', name)
161 Redmine::MimeType.is_type?('text', name)
154 end
162 end
155 end
163 end
156
164
157 class Revisions < Array
165 class Revisions < Array
158 def latest
166 def latest
159 sort {|x,y|
167 sort {|x,y|
160 unless x.time.nil? or y.time.nil?
168 unless x.time.nil? or y.time.nil?
161 x.time <=> y.time
169 x.time <=> y.time
162 else
170 else
163 0
171 0
164 end
172 end
165 }.last
173 }.last
166 end
174 end
167 end
175 end
168
176
169 class Revision
177 class Revision
170 attr_accessor :identifier, :scmid, :name, :author, :time, :message, :paths, :revision, :branch
178 attr_accessor :identifier, :scmid, :name, :author, :time, :message, :paths, :revision, :branch
171 def initialize(attributes={})
179 def initialize(attributes={})
172 self.identifier = attributes[:identifier]
180 self.identifier = attributes[:identifier]
173 self.scmid = attributes[:scmid]
181 self.scmid = attributes[:scmid]
174 self.name = attributes[:name] || self.identifier
182 self.name = attributes[:name] || self.identifier
175 self.author = attributes[:author]
183 self.author = attributes[:author]
176 self.time = attributes[:time]
184 self.time = attributes[:time]
177 self.message = attributes[:message] || ""
185 self.message = attributes[:message] || ""
178 self.paths = attributes[:paths]
186 self.paths = attributes[:paths]
179 self.revision = attributes[:revision]
187 self.revision = attributes[:revision]
180 self.branch = attributes[:branch]
188 self.branch = attributes[:branch]
181 end
189 end
182
190
183 end
191 end
184
192
185 # A line of Diff
193 # A line of Diff
186 class Diff
194 class Diff
187 attr_accessor :nb_line_left
195 attr_accessor :nb_line_left
188 attr_accessor :line_left
196 attr_accessor :line_left
189 attr_accessor :nb_line_right
197 attr_accessor :nb_line_right
190 attr_accessor :line_right
198 attr_accessor :line_right
191 attr_accessor :type_diff_right
199 attr_accessor :type_diff_right
192 attr_accessor :type_diff_left
200 attr_accessor :type_diff_left
193
201
194 def initialize ()
202 def initialize ()
195 self.nb_line_left = ''
203 self.nb_line_left = ''
196 self.nb_line_right = ''
204 self.nb_line_right = ''
197 self.line_left = ''
205 self.line_left = ''
198 self.line_right = ''
206 self.line_right = ''
199 self.type_diff_right = ''
207 self.type_diff_right = ''
200 self.type_diff_left = ''
208 self.type_diff_left = ''
201 end
209 end
202
210
203 def inspect
211 def inspect
204 puts '### Start Line Diff ###'
212 puts '### Start Line Diff ###'
205 puts self.nb_line_left
213 puts self.nb_line_left
206 puts self.line_left
214 puts self.line_left
207 puts self.nb_line_right
215 puts self.nb_line_right
208 puts self.line_right
216 puts self.line_right
209 end
217 end
210 end
218 end
211
219
212 class DiffTableList < Array
220 class DiffTableList < Array
213 def initialize (diff, type="inline")
221 def initialize (diff, type="inline")
214 diff_table = DiffTable.new type
222 diff_table = DiffTable.new type
215 diff.each do |line|
223 diff.each do |line|
216 if line =~ /^(---|\+\+\+) (.*)$/
224 if line =~ /^(---|\+\+\+) (.*)$/
217 self << diff_table if diff_table.length > 1
225 self << diff_table if diff_table.length > 1
218 diff_table = DiffTable.new type
226 diff_table = DiffTable.new type
219 end
227 end
220 a = diff_table.add_line line
228 a = diff_table.add_line line
221 end
229 end
222 self << diff_table
230 self << diff_table
223 end
231 end
224 end
232 end
225
233
226 # Class for create a Diff
234 # Class for create a Diff
227 class DiffTable < Hash
235 class DiffTable < Hash
228 attr_reader :file_name, :line_num_l, :line_num_r
236 attr_reader :file_name, :line_num_l, :line_num_r
229
237
230 # Initialize with a Diff file and the type of Diff View
238 # Initialize with a Diff file and the type of Diff View
231 # The type view must be inline or sbs (side_by_side)
239 # The type view must be inline or sbs (side_by_side)
232 def initialize (type="inline")
240 def initialize (type="inline")
233 @parsing = false
241 @parsing = false
234 @nb_line = 1
242 @nb_line = 1
235 @start = false
243 @start = false
236 @before = 'same'
244 @before = 'same'
237 @second = true
245 @second = true
238 @type = type
246 @type = type
239 end
247 end
240
248
241 # Function for add a line of this Diff
249 # Function for add a line of this Diff
242 def add_line(line)
250 def add_line(line)
243 unless @parsing
251 unless @parsing
244 if line =~ /^(---|\+\+\+) (.*)$/
252 if line =~ /^(---|\+\+\+) (.*)$/
245 @file_name = $2
253 @file_name = $2
246 return false
254 return false
247 elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/
255 elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/
248 @line_num_l = $5.to_i
256 @line_num_l = $5.to_i
249 @line_num_r = $2.to_i
257 @line_num_r = $2.to_i
250 @parsing = true
258 @parsing = true
251 end
259 end
252 else
260 else
253 if line =~ /^[^\+\-\s@\\]/
261 if line =~ /^[^\+\-\s@\\]/
254 self.delete(self.keys.sort.last)
262 self.delete(self.keys.sort.last)
255 @parsing = false
263 @parsing = false
256 return false
264 return false
257 elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/
265 elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/
258 @line_num_l = $5.to_i
266 @line_num_l = $5.to_i
259 @line_num_r = $2.to_i
267 @line_num_r = $2.to_i
260 else
268 else
261 @nb_line += 1 if parse_line(line, @type)
269 @nb_line += 1 if parse_line(line, @type)
262 end
270 end
263 end
271 end
264 return true
272 return true
265 end
273 end
266
274
267 def inspect
275 def inspect
268 puts '### DIFF TABLE ###'
276 puts '### DIFF TABLE ###'
269 puts "file : #{file_name}"
277 puts "file : #{file_name}"
270 self.each do |d|
278 self.each do |d|
271 d.inspect
279 d.inspect
272 end
280 end
273 end
281 end
274
282
275 private
283 private
276 # Test if is a Side By Side type
284 # Test if is a Side By Side type
277 def sbs?(type, func)
285 def sbs?(type, func)
278 if @start and type == "sbs"
286 if @start and type == "sbs"
279 if @before == func and @second
287 if @before == func and @second
280 tmp_nb_line = @nb_line
288 tmp_nb_line = @nb_line
281 self[tmp_nb_line] = Diff.new
289 self[tmp_nb_line] = Diff.new
282 else
290 else
283 @second = false
291 @second = false
284 tmp_nb_line = @start
292 tmp_nb_line = @start
285 @start += 1
293 @start += 1
286 @nb_line -= 1
294 @nb_line -= 1
287 end
295 end
288 else
296 else
289 tmp_nb_line = @nb_line
297 tmp_nb_line = @nb_line
290 @start = @nb_line
298 @start = @nb_line
291 self[tmp_nb_line] = Diff.new
299 self[tmp_nb_line] = Diff.new
292 @second = true
300 @second = true
293 end
301 end
294 unless self[tmp_nb_line]
302 unless self[tmp_nb_line]
295 @nb_line += 1
303 @nb_line += 1
296 self[tmp_nb_line] = Diff.new
304 self[tmp_nb_line] = Diff.new
297 else
305 else
298 self[tmp_nb_line]
306 self[tmp_nb_line]
299 end
307 end
300 end
308 end
301
309
302 # Escape the HTML for the diff
310 # Escape the HTML for the diff
303 def escapeHTML(line)
311 def escapeHTML(line)
304 CGI.escapeHTML(line)
312 CGI.escapeHTML(line)
305 end
313 end
306
314
307 def parse_line (line, type="inline")
315 def parse_line (line, type="inline")
308 if line[0, 1] == "+"
316 if line[0, 1] == "+"
309 diff = sbs? type, 'add'
317 diff = sbs? type, 'add'
310 @before = 'add'
318 @before = 'add'
311 diff.line_left = escapeHTML line[1..-1]
319 diff.line_left = escapeHTML line[1..-1]
312 diff.nb_line_left = @line_num_l
320 diff.nb_line_left = @line_num_l
313 diff.type_diff_left = 'diff_in'
321 diff.type_diff_left = 'diff_in'
314 @line_num_l += 1
322 @line_num_l += 1
315 true
323 true
316 elsif line[0, 1] == "-"
324 elsif line[0, 1] == "-"
317 diff = sbs? type, 'remove'
325 diff = sbs? type, 'remove'
318 @before = 'remove'
326 @before = 'remove'
319 diff.line_right = escapeHTML line[1..-1]
327 diff.line_right = escapeHTML line[1..-1]
320 diff.nb_line_right = @line_num_r
328 diff.nb_line_right = @line_num_r
321 diff.type_diff_right = 'diff_out'
329 diff.type_diff_right = 'diff_out'
322 @line_num_r += 1
330 @line_num_r += 1
323 true
331 true
324 elsif line[0, 1] =~ /\s/
332 elsif line[0, 1] =~ /\s/
325 @before = 'same'
333 @before = 'same'
326 @start = false
334 @start = false
327 diff = Diff.new
335 diff = Diff.new
328 diff.line_right = escapeHTML line[1..-1]
336 diff.line_right = escapeHTML line[1..-1]
329 diff.nb_line_right = @line_num_r
337 diff.nb_line_right = @line_num_r
330 diff.line_left = escapeHTML line[1..-1]
338 diff.line_left = escapeHTML line[1..-1]
331 diff.nb_line_left = @line_num_l
339 diff.nb_line_left = @line_num_l
332 self[@nb_line] = diff
340 self[@nb_line] = diff
333 @line_num_l += 1
341 @line_num_l += 1
334 @line_num_r += 1
342 @line_num_r += 1
335 true
343 true
336 elsif line[0, 1] = "\\"
344 elsif line[0, 1] = "\\"
337 true
345 true
338 else
346 else
339 false
347 false
340 end
348 end
341 end
349 end
342 end
350 end
343 end
351 end
344 end
352 end
345 end
353 end
@@ -1,178 +1,187
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require 'redmine/scm/adapters/abstract_adapter'
18 require 'redmine/scm/adapters/abstract_adapter'
19 require 'rexml/document'
19 require 'rexml/document'
20
20
21 module Redmine
21 module Redmine
22 module Scm
22 module Scm
23 module Adapters
23 module Adapters
24 class SubversionAdapter < AbstractAdapter
24 class SubversionAdapter < AbstractAdapter
25
25
26 # SVN executable name
26 # SVN executable name
27 SVN_BIN = "svn"
27 SVN_BIN = "svn"
28
28
29 # Get info about the svn repository
29 # Get info about the svn repository
30 def info
30 def info
31 cmd = "#{SVN_BIN} info --xml #{target('')}"
31 cmd = "#{SVN_BIN} info --xml #{target('')}"
32 cmd << " --username #{@login} --password #{@password}" if @login
32 cmd << credentials_string
33 info = nil
33 info = nil
34 shellout(cmd) do |io|
34 shellout(cmd) do |io|
35 begin
35 begin
36 doc = REXML::Document.new(io)
36 doc = REXML::Document.new(io)
37 #root_url = doc.elements["info/entry/repository/root"].text
37 #root_url = doc.elements["info/entry/repository/root"].text
38 info = Info.new({:root_url => doc.elements["info/entry/repository/root"].text,
38 info = Info.new({:root_url => doc.elements["info/entry/repository/root"].text,
39 :lastrev => Revision.new({
39 :lastrev => Revision.new({
40 :identifier => doc.elements["info/entry/commit"].attributes['revision'],
40 :identifier => doc.elements["info/entry/commit"].attributes['revision'],
41 :time => Time.parse(doc.elements["info/entry/commit/date"].text).localtime,
41 :time => Time.parse(doc.elements["info/entry/commit/date"].text).localtime,
42 :author => (doc.elements["info/entry/commit/author"] ? doc.elements["info/entry/commit/author"].text : "")
42 :author => (doc.elements["info/entry/commit/author"] ? doc.elements["info/entry/commit/author"].text : "")
43 })
43 })
44 })
44 })
45 rescue
45 rescue
46 end
46 end
47 end
47 end
48 return nil if $? && $?.exitstatus != 0
48 return nil if $? && $?.exitstatus != 0
49 info
49 info
50 rescue Errno::ENOENT => e
50 rescue Errno::ENOENT => e
51 return nil
51 return nil
52 end
52 end
53
53
54 # Returns the entry identified by path and revision identifier
54 # Returns the entry identified by path and revision identifier
55 # or nil if entry doesn't exist in the repository
55 # or nil if entry doesn't exist in the repository
56 def entry(path=nil, identifier=nil)
56 def entry(path=nil, identifier=nil)
57 e = entries(path, identifier)
57 e = entries(path, identifier)
58 e ? e.first : nil
58 e ? e.first : nil
59 end
59 end
60
60
61 # Returns an Entries collection
61 # Returns an Entries collection
62 # or nil if the given path doesn't exist in the repository
62 # or nil if the given path doesn't exist in the repository
63 def entries(path=nil, identifier=nil)
63 def entries(path=nil, identifier=nil)
64 path ||= ''
64 path ||= ''
65 identifier = 'HEAD' unless identifier and identifier > 0
65 identifier = 'HEAD' unless identifier and identifier > 0
66 entries = Entries.new
66 entries = Entries.new
67 cmd = "#{SVN_BIN} list --xml #{target(path)}@#{identifier}"
67 cmd = "#{SVN_BIN} list --xml #{target(path)}@#{identifier}"
68 cmd << " --username #{@login} --password #{@password}" if @login
68 cmd << credentials_string
69 cmd << " 2>&1"
69 cmd << " 2>&1"
70 shellout(cmd) do |io|
70 shellout(cmd) do |io|
71 output = io.read
71 output = io.read
72 begin
72 begin
73 doc = REXML::Document.new(output)
73 doc = REXML::Document.new(output)
74 doc.elements.each("lists/list/entry") do |entry|
74 doc.elements.each("lists/list/entry") do |entry|
75 entries << Entry.new({:name => entry.elements['name'].text,
75 entries << Entry.new({:name => entry.elements['name'].text,
76 :path => ((path.empty? ? "" : "#{path}/") + entry.elements['name'].text),
76 :path => ((path.empty? ? "" : "#{path}/") + entry.elements['name'].text),
77 :kind => entry.attributes['kind'],
77 :kind => entry.attributes['kind'],
78 :size => (entry.elements['size'] and entry.elements['size'].text).to_i,
78 :size => (entry.elements['size'] and entry.elements['size'].text).to_i,
79 :lastrev => Revision.new({
79 :lastrev => Revision.new({
80 :identifier => entry.elements['commit'].attributes['revision'],
80 :identifier => entry.elements['commit'].attributes['revision'],
81 :time => Time.parse(entry.elements['commit'].elements['date'].text).localtime,
81 :time => Time.parse(entry.elements['commit'].elements['date'].text).localtime,
82 :author => (entry.elements['commit'].elements['author'] ? entry.elements['commit'].elements['author'].text : "")
82 :author => (entry.elements['commit'].elements['author'] ? entry.elements['commit'].elements['author'].text : "")
83 })
83 })
84 })
84 })
85 end
85 end
86 rescue Exception => e
86 rescue Exception => e
87 logger.error("Error parsing svn output: #{e.message}")
87 logger.error("Error parsing svn output: #{e.message}")
88 logger.error("Output was:\n #{output}")
88 logger.error("Output was:\n #{output}")
89 end
89 end
90 end
90 end
91 return nil if $? && $?.exitstatus != 0
91 return nil if $? && $?.exitstatus != 0
92 logger.debug("Found #{entries.size} entries in the repository for #{target(path)}") if logger && logger.debug?
92 logger.debug("Found #{entries.size} entries in the repository for #{target(path)}") if logger && logger.debug?
93 entries.sort_by_name
93 entries.sort_by_name
94 rescue Errno::ENOENT => e
94 rescue Errno::ENOENT => e
95 raise CommandFailed
95 raise CommandFailed
96 end
96 end
97
97
98 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
98 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
99 path ||= ''
99 path ||= ''
100 identifier_from = 'HEAD' unless identifier_from and identifier_from.to_i > 0
100 identifier_from = 'HEAD' unless identifier_from and identifier_from.to_i > 0
101 identifier_to = 1 unless identifier_to and identifier_to.to_i > 0
101 identifier_to = 1 unless identifier_to and identifier_to.to_i > 0
102 revisions = Revisions.new
102 revisions = Revisions.new
103 cmd = "#{SVN_BIN} log --xml -r #{identifier_from}:#{identifier_to}"
103 cmd = "#{SVN_BIN} log --xml -r #{identifier_from}:#{identifier_to}"
104 cmd << " --username #{@login} --password #{@password}" if @login
104 cmd << credentials_string
105 cmd << " --verbose " if options[:with_paths]
105 cmd << " --verbose " if options[:with_paths]
106 cmd << target(path)
106 cmd << target(path)
107 shellout(cmd) do |io|
107 shellout(cmd) do |io|
108 begin
108 begin
109 doc = REXML::Document.new(io)
109 doc = REXML::Document.new(io)
110 doc.elements.each("log/logentry") do |logentry|
110 doc.elements.each("log/logentry") do |logentry|
111 paths = []
111 paths = []
112 logentry.elements.each("paths/path") do |path|
112 logentry.elements.each("paths/path") do |path|
113 paths << {:action => path.attributes['action'],
113 paths << {:action => path.attributes['action'],
114 :path => path.text,
114 :path => path.text,
115 :from_path => path.attributes['copyfrom-path'],
115 :from_path => path.attributes['copyfrom-path'],
116 :from_revision => path.attributes['copyfrom-rev']
116 :from_revision => path.attributes['copyfrom-rev']
117 }
117 }
118 end
118 end
119 paths.sort! { |x,y| x[:path] <=> y[:path] }
119 paths.sort! { |x,y| x[:path] <=> y[:path] }
120
120
121 revisions << Revision.new({:identifier => logentry.attributes['revision'],
121 revisions << Revision.new({:identifier => logentry.attributes['revision'],
122 :author => (logentry.elements['author'] ? logentry.elements['author'].text : ""),
122 :author => (logentry.elements['author'] ? logentry.elements['author'].text : ""),
123 :time => Time.parse(logentry.elements['date'].text).localtime,
123 :time => Time.parse(logentry.elements['date'].text).localtime,
124 :message => logentry.elements['msg'].text,
124 :message => logentry.elements['msg'].text,
125 :paths => paths
125 :paths => paths
126 })
126 })
127 end
127 end
128 rescue
128 rescue
129 end
129 end
130 end
130 end
131 return nil if $? && $?.exitstatus != 0
131 return nil if $? && $?.exitstatus != 0
132 revisions
132 revisions
133 rescue Errno::ENOENT => e
133 rescue Errno::ENOENT => e
134 raise CommandFailed
134 raise CommandFailed
135 end
135 end
136
136
137 def diff(path, identifier_from, identifier_to=nil, type="inline")
137 def diff(path, identifier_from, identifier_to=nil, type="inline")
138 path ||= ''
138 path ||= ''
139 if identifier_to and identifier_to.to_i > 0
139 if identifier_to and identifier_to.to_i > 0
140 identifier_to = identifier_to.to_i
140 identifier_to = identifier_to.to_i
141 else
141 else
142 identifier_to = identifier_from.to_i - 1
142 identifier_to = identifier_from.to_i - 1
143 end
143 end
144 cmd = "#{SVN_BIN} diff -r "
144 cmd = "#{SVN_BIN} diff -r "
145 cmd << "#{identifier_to}:"
145 cmd << "#{identifier_to}:"
146 cmd << "#{identifier_from}"
146 cmd << "#{identifier_from}"
147 cmd << "#{target(path)}@#{identifier_from}"
147 cmd << "#{target(path)}@#{identifier_from}"
148 cmd << " --username #{@login} --password #{@password}" if @login
148 cmd << credentials_string
149 diff = []
149 diff = []
150 shellout(cmd) do |io|
150 shellout(cmd) do |io|
151 io.each_line do |line|
151 io.each_line do |line|
152 diff << line
152 diff << line
153 end
153 end
154 end
154 end
155 return nil if $? && $?.exitstatus != 0
155 return nil if $? && $?.exitstatus != 0
156 DiffTableList.new diff, type
156 DiffTableList.new diff, type
157 rescue Errno::ENOENT => e
157 rescue Errno::ENOENT => e
158 raise CommandFailed
158 raise CommandFailed
159 end
159 end
160
160
161 def cat(path, identifier=nil)
161 def cat(path, identifier=nil)
162 identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
162 identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
163 cmd = "#{SVN_BIN} cat #{target(path)}@#{identifier}"
163 cmd = "#{SVN_BIN} cat #{target(path)}@#{identifier}"
164 cmd << " --username #{@login} --password #{@password}" if @login
164 cmd << credentials_string
165 cat = nil
165 cat = nil
166 shellout(cmd) do |io|
166 shellout(cmd) do |io|
167 io.binmode
167 io.binmode
168 cat = io.read
168 cat = io.read
169 end
169 end
170 return nil if $? && $?.exitstatus != 0
170 return nil if $? && $?.exitstatus != 0
171 cat
171 cat
172 rescue Errno::ENOENT => e
172 rescue Errno::ENOENT => e
173 raise CommandFailed
173 raise CommandFailed
174 end
174 end
175
176 private
177
178 def credentials_string
179 str = ''
180 str << " --username #{shell_quote(@login)}" unless @login.blank?
181 str << " --password #{shell_quote(@password)}" unless @login.blank? || @password.blank?
182 str
183 end
175 end
184 end
176 end
185 end
177 end
186 end
178 end
187 end
General Comments 0
You need to be logged in to leave comments. Login now