Mercurial > hg > soundsoftware-site
comparison lib/redmine/scm/adapters/abstract_adapter.rb @ 245:051f544170fe
* Update to SVN trunk revision 4993
author | Chris Cannam |
---|---|
date | Thu, 03 Mar 2011 11:42:28 +0000 |
parents | 8661b858af72 |
children | eeebe205a056 cbce1fd3b1b7 |
comparison
equal
deleted
inserted
replaced
244:8972b600f4fb | 245:051f544170fe |
---|---|
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 class << self | 27 class << self |
28 def client_command | |
29 "" | |
30 end | |
31 | |
28 # Returns the version of the scm client | 32 # Returns the version of the scm client |
29 # Eg: [1, 5, 0] or [] if unknown | 33 # Eg: [1, 5, 0] or [] if unknown |
30 def client_version | 34 def client_version |
31 [] | 35 [] |
32 end | 36 end |
33 | 37 |
34 # Returns the version string of the scm client | 38 # Returns the version string of the scm client |
35 # Eg: '1.5.0' or 'Unknown version' if unknown | 39 # Eg: '1.5.0' or 'Unknown version' if unknown |
36 def client_version_string | 40 def client_version_string |
37 v = client_version || 'Unknown version' | 41 v = client_version || 'Unknown version' |
38 v.is_a?(Array) ? v.join('.') : v.to_s | 42 v.is_a?(Array) ? v.join('.') : v.to_s |
39 end | 43 end |
40 | 44 |
41 # Returns true if the current client version is above | 45 # Returns true if the current client version is above |
42 # or equals the given one | 46 # or equals the given one |
43 # If option is :unknown is set to true, it will return | 47 # If option is :unknown is set to true, it will return |
44 # true if the client version is unknown | 48 # true if the client version is unknown |
45 def client_version_above?(v, options={}) | 49 def client_version_above?(v, options={}) |
46 ((client_version <=> v) >= 0) || (client_version.empty? && options[:unknown]) | 50 ((client_version <=> v) >= 0) || (client_version.empty? && options[:unknown]) |
47 end | 51 end |
48 end | 52 |
49 | 53 def client_available |
50 def initialize(url, root_url=nil, login=nil, password=nil) | 54 true |
55 end | |
56 | |
57 def shell_quote(str) | |
58 if Redmine::Platform.mswin? | |
59 '"' + str.gsub(/"/, '\\"') + '"' | |
60 else | |
61 "'" + str.gsub(/'/, "'\"'\"'") + "'" | |
62 end | |
63 end | |
64 end | |
65 | |
66 def initialize(url, root_url=nil, login=nil, password=nil, | |
67 path_encoding=nil) | |
51 @url = url | 68 @url = url |
52 @login = login if login && !login.empty? | 69 @login = login if login && !login.empty? |
53 @password = (password || "") if @login | 70 @password = (password || "") if @login |
54 @root_url = root_url.blank? ? retrieve_root_url : root_url | 71 @root_url = root_url.blank? ? retrieve_root_url : root_url |
55 end | 72 end |
56 | 73 |
57 def adapter_name | 74 def adapter_name |
58 'Abstract' | 75 'Abstract' |
59 end | 76 end |
60 | 77 |
61 def supports_cat? | 78 def supports_cat? |
62 true | 79 true |
63 end | 80 end |
64 | 81 |
65 def supports_annotate? | 82 def supports_annotate? |
66 respond_to?('annotate') | 83 respond_to?('annotate') |
67 end | 84 end |
68 | 85 |
69 def root_url | 86 def root_url |
70 @root_url | 87 @root_url |
71 end | 88 end |
72 | 89 |
73 def url | 90 def url |
74 @url | 91 @url |
75 end | 92 end |
76 | 93 |
77 # get info about the svn repository | 94 # get info about the svn repository |
136 | 153 |
137 def with_trailling_slash(path) | 154 def with_trailling_slash(path) |
138 path ||= '' | 155 path ||= '' |
139 (path[-1,1] == "/") ? path : "#{path}/" | 156 (path[-1,1] == "/") ? path : "#{path}/" |
140 end | 157 end |
141 | 158 |
142 def without_leading_slash(path) | 159 def without_leading_slash(path) |
143 path ||= '' | 160 path ||= '' |
144 path.gsub(%r{^/+}, '') | 161 path.gsub(%r{^/+}, '') |
145 end | 162 end |
146 | 163 |
147 def without_trailling_slash(path) | 164 def without_trailling_slash(path) |
148 path ||= '' | 165 path ||= '' |
149 (path[-1,1] == "/") ? path[0..-2] : path | 166 (path[-1,1] == "/") ? path[0..-2] : path |
150 end | 167 end |
151 | 168 |
152 def shell_quote(str) | 169 def shell_quote(str) |
153 if Redmine::Platform.mswin? | 170 self.class.shell_quote(str) |
154 '"' + str.gsub(/"/, '\\"') + '"' | |
155 else | |
156 "'" + str.gsub(/'/, "'\"'\"'") + "'" | |
157 end | |
158 end | 171 end |
159 | 172 |
160 private | 173 private |
161 def retrieve_root_url | 174 def retrieve_root_url |
162 info = self.info | 175 info = self.info |
166 def target(path) | 179 def target(path) |
167 path ||= '' | 180 path ||= '' |
168 base = path.match(/^\//) ? root_url : url | 181 base = path.match(/^\//) ? root_url : url |
169 shell_quote("#{base}/#{path}".gsub(/[?<>\*]/, '')) | 182 shell_quote("#{base}/#{path}".gsub(/[?<>\*]/, '')) |
170 end | 183 end |
171 | 184 |
172 def logger | 185 def logger |
173 self.class.logger | 186 self.class.logger |
174 end | 187 end |
175 | 188 |
176 def shellout(cmd, &block) | 189 def shellout(cmd, &block) |
177 self.class.shellout(cmd, &block) | 190 self.class.shellout(cmd, &block) |
178 end | 191 end |
179 | 192 |
180 def self.logger | 193 def self.logger |
181 RAILS_DEFAULT_LOGGER | 194 RAILS_DEFAULT_LOGGER |
182 end | 195 end |
183 | 196 |
184 def self.shellout(cmd, &block) | 197 def self.shellout(cmd, &block) |
185 logger.debug "Shelling out: #{strip_credential(cmd)}" if logger && logger.debug? | 198 logger.debug "Shelling out: #{strip_credential(cmd)}" if logger && logger.debug? |
186 if Rails.env == 'development' | 199 if Rails.env == 'development' |
187 # Capture stderr when running in dev environment | 200 # Capture stderr when running in dev environment |
188 cmd = "#{cmd} 2>>#{RAILS_ROOT}/log/scm.stderr.log" | 201 cmd = "#{cmd} 2>>#{RAILS_ROOT}/log/scm.stderr.log" |
189 end | 202 end |
190 begin | 203 begin |
191 IO.popen(cmd, "r+") do |io| | 204 if RUBY_VERSION < '1.9' |
205 mode = "r+" | |
206 else | |
207 mode = "r+:ASCII-8BIT" | |
208 end | |
209 IO.popen(cmd, mode) do |io| | |
192 io.close_write | 210 io.close_write |
193 block.call(io) if block_given? | 211 block.call(io) if block_given? |
194 end | 212 end |
195 rescue Errno::ENOENT => e | 213 rescue Errno::ENOENT => e |
196 msg = strip_credential(e.message) | 214 msg = strip_credential(e.message) |
197 # The command failed, log it and re-raise | 215 # The command failed, log it and re-raise |
198 logger.error("SCM command failed, make sure that your SCM binary (eg. svn) is in PATH (#{ENV['PATH']}): #{strip_credential(cmd)}\n with: #{msg}") | 216 logger.error("SCM command failed, make sure that your SCM binary (eg. svn) is in PATH (#{ENV['PATH']}): #{strip_credential(cmd)}\n with: #{msg}") |
199 raise CommandFailed.new(msg) | 217 raise CommandFailed.new(msg) |
200 end | 218 end |
201 end | 219 end |
202 | 220 |
203 # Hides username/password in a given command | 221 # Hides username/password in a given command |
204 def self.strip_credential(cmd) | 222 def self.strip_credential(cmd) |
205 q = (Redmine::Platform.mswin? ? '"' : "'") | 223 q = (Redmine::Platform.mswin? ? '"' : "'") |
206 cmd.to_s.gsub(/(\-\-(password|username))\s+(#{q}[^#{q}]+#{q}|[^#{q}]\S+)/, '\\1 xxxx') | 224 cmd.to_s.gsub(/(\-\-(password|username))\s+(#{q}[^#{q}]+#{q}|[^#{q}]\S+)/, '\\1 xxxx') |
207 end | 225 end |
208 | 226 |
209 def strip_credential(cmd) | 227 def strip_credential(cmd) |
210 self.class.strip_credential(cmd) | 228 self.class.strip_credential(cmd) |
211 end | 229 end |
212 end | 230 |
213 | 231 def scm_iconv(to, from, str) |
232 return nil if str.nil? | |
233 return str if to == from | |
234 begin | |
235 Iconv.conv(to, from, str) | |
236 rescue Iconv::Failure => err | |
237 logger.error("failed to convert from #{from} to #{to}. #{err}") | |
238 nil | |
239 end | |
240 end | |
241 end | |
242 | |
214 class Entries < Array | 243 class Entries < Array |
215 def sort_by_name | 244 def sort_by_name |
216 sort {|x,y| | 245 sort {|x,y| |
217 if x.kind == y.kind | 246 if x.kind == y.kind |
218 x.name.to_s <=> y.name.to_s | 247 x.name.to_s <=> y.name.to_s |
219 else | 248 else |
220 x.kind <=> y.kind | 249 x.kind <=> y.kind |
221 end | 250 end |
222 } | 251 } |
223 end | 252 end |
224 | 253 |
225 def revisions | 254 def revisions |
226 revisions ||= Revisions.new(collect{|entry| entry.lastrev}.compact) | 255 revisions ||= Revisions.new(collect{|entry| entry.lastrev}.compact) |
227 end | 256 end |
293 | 322 |
294 # Returns the readable identifier. | 323 # Returns the readable identifier. |
295 def format_identifier | 324 def format_identifier |
296 identifier | 325 identifier |
297 end | 326 end |
298 | 327 end |
299 def save(repo) | 328 |
300 Changeset.transaction do | |
301 changeset = Changeset.new( | |
302 :repository => repo, | |
303 :revision => identifier, | |
304 :scmid => scmid, | |
305 :committer => author, | |
306 :committed_on => time, | |
307 :comments => message) | |
308 | |
309 if changeset.save | |
310 paths.each do |file| | |
311 Change.create( | |
312 :changeset => changeset, | |
313 :action => file[:action], | |
314 :path => file[:path]) | |
315 end | |
316 end | |
317 end | |
318 end | |
319 end | |
320 | |
321 class Annotate | 329 class Annotate |
322 attr_reader :lines, :revisions | 330 attr_reader :lines, :revisions |
323 | 331 |
324 def initialize | 332 def initialize |
325 @lines = [] | 333 @lines = [] |