##// END OF EJS Templates
scm: space cleanup of lib/redmine/scm/adapters/abstract_adapter.rb....
Toshi MARUYAMA -
r4741:bd9a3a720cb4
parent child
Show More
@@ -1,356 +1,356
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 'cgi'
19 19
20 20 module Redmine
21 21 module Scm
22 module Adapters
22 module Adapters
23 23 class CommandFailed < StandardError #:nodoc:
24 24 end
25
25
26 26 class AbstractAdapter #:nodoc:
27 27 class << self
28 28 def client_command
29 29 ""
30 30 end
31 31
32 32 # Returns the version of the scm client
33 33 # Eg: [1, 5, 0] or [] if unknown
34 34 def client_version
35 35 []
36 36 end
37 37
38 38 # Returns the version string of the scm client
39 39 # Eg: '1.5.0' or 'Unknown version' if unknown
40 40 def client_version_string
41 41 v = client_version || 'Unknown version'
42 42 v.is_a?(Array) ? v.join('.') : v.to_s
43 43 end
44 44
45 45 # Returns true if the current client version is above
46 46 # or equals the given one
47 47 # If option is :unknown is set to true, it will return
48 48 # true if the client version is unknown
49 49 def client_version_above?(v, options={})
50 50 ((client_version <=> v) >= 0) || (client_version.empty? && options[:unknown])
51 51 end
52 52
53 53 def client_available
54 54 true
55 55 end
56 56
57 57 def shell_quote(str)
58 58 if Redmine::Platform.mswin?
59 59 '"' + str.gsub(/"/, '\\"') + '"'
60 60 else
61 61 "'" + str.gsub(/'/, "'\"'\"'") + "'"
62 62 end
63 63 end
64 64 end
65 65
66 66 def initialize(url, root_url=nil, login=nil, password=nil)
67 67 @url = url
68 68 @login = login if login && !login.empty?
69 69 @password = (password || "") if @login
70 70 @root_url = root_url.blank? ? retrieve_root_url : root_url
71 71 end
72 72
73 73 def adapter_name
74 74 'Abstract'
75 75 end
76 76
77 77 def supports_cat?
78 78 true
79 79 end
80 80
81 81 def supports_annotate?
82 82 respond_to?('annotate')
83 83 end
84 84
85 85 def root_url
86 86 @root_url
87 87 end
88 88
89 89 def url
90 90 @url
91 91 end
92 92
93 93 # get info about the svn repository
94 94 def info
95 95 return nil
96 96 end
97 97
98 98 # Returns the entry identified by path and revision identifier
99 99 # or nil if entry doesn't exist in the repository
100 100 def entry(path=nil, identifier=nil)
101 101 parts = path.to_s.split(%r{[\/\\]}).select {|n| !n.blank?}
102 102 search_path = parts[0..-2].join('/')
103 103 search_name = parts[-1]
104 104 if search_path.blank? && search_name.blank?
105 105 # Root entry
106 106 Entry.new(:path => '', :kind => 'dir')
107 107 else
108 108 # Search for the entry in the parent directory
109 109 es = entries(search_path, identifier)
110 110 es ? es.detect {|e| e.name == search_name} : nil
111 111 end
112 112 end
113 113
114 114 # Returns an Entries collection
115 115 # or nil if the given path doesn't exist in the repository
116 116 def entries(path=nil, identifier=nil)
117 117 return nil
118 118 end
119 119
120 120 def branches
121 121 return nil
122 122 end
123 123
124 124 def tags
125 125 return nil
126 126 end
127 127
128 128 def default_branch
129 129 return nil
130 130 end
131 131
132 132 def properties(path, identifier=nil)
133 133 return nil
134 134 end
135 135
136 136 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
137 137 return nil
138 138 end
139 139
140 140 def diff(path, identifier_from, identifier_to=nil)
141 141 return nil
142 142 end
143 143
144 144 def cat(path, identifier=nil)
145 145 return nil
146 146 end
147 147
148 148 def with_leading_slash(path)
149 149 path ||= ''
150 150 (path[0,1]!="/") ? "/#{path}" : path
151 151 end
152 152
153 153 def with_trailling_slash(path)
154 154 path ||= ''
155 155 (path[-1,1] == "/") ? path : "#{path}/"
156 156 end
157 157
158 158 def without_leading_slash(path)
159 159 path ||= ''
160 160 path.gsub(%r{^/+}, '')
161 161 end
162 162
163 163 def without_trailling_slash(path)
164 164 path ||= ''
165 165 (path[-1,1] == "/") ? path[0..-2] : path
166 166 end
167 167
168 168 def shell_quote(str)
169 169 self.class.shell_quote(str)
170 170 end
171 171
172 172 private
173 173 def retrieve_root_url
174 174 info = self.info
175 175 info ? info.root_url : nil
176 176 end
177 177
178 178 def target(path)
179 179 path ||= ''
180 180 base = path.match(/^\//) ? root_url : url
181 181 shell_quote("#{base}/#{path}".gsub(/[?<>\*]/, ''))
182 182 end
183 183
184 184 def logger
185 185 self.class.logger
186 186 end
187 187
188 188 def shellout(cmd, &block)
189 189 self.class.shellout(cmd, &block)
190 190 end
191
191
192 192 def self.logger
193 193 RAILS_DEFAULT_LOGGER
194 194 end
195
195
196 196 def self.shellout(cmd, &block)
197 197 logger.debug "Shelling out: #{strip_credential(cmd)}" if logger && logger.debug?
198 198 if Rails.env == 'development'
199 199 # Capture stderr when running in dev environment
200 200 cmd = "#{cmd} 2>>#{RAILS_ROOT}/log/scm.stderr.log"
201 201 end
202 202 begin
203 203 IO.popen(cmd, "r+") do |io|
204 204 io.close_write
205 205 block.call(io) if block_given?
206 206 end
207 207 rescue Errno::ENOENT => e
208 208 msg = strip_credential(e.message)
209 209 # The command failed, log it and re-raise
210 210 logger.error("SCM command failed, make sure that your SCM binary (eg. svn) is in PATH (#{ENV['PATH']}): #{strip_credential(cmd)}\n with: #{msg}")
211 211 raise CommandFailed.new(msg)
212 212 end
213 end
214
213 end
214
215 215 # Hides username/password in a given command
216 216 def self.strip_credential(cmd)
217 217 q = (Redmine::Platform.mswin? ? '"' : "'")
218 218 cmd.to_s.gsub(/(\-\-(password|username))\s+(#{q}[^#{q}]+#{q}|[^#{q}]\S+)/, '\\1 xxxx')
219 219 end
220 220
221 221 def strip_credential(cmd)
222 222 self.class.strip_credential(cmd)
223 223 end
224 224 end
225 225
226 226 class Entries < Array
227 227 def sort_by_name
228 228 sort {|x,y|
229 229 if x.kind == y.kind
230 230 x.name.to_s <=> y.name.to_s
231 231 else
232 232 x.kind <=> y.kind
233 233 end
234 }
234 }
235 235 end
236 236
237 237 def revisions
238 238 revisions ||= Revisions.new(collect{|entry| entry.lastrev}.compact)
239 239 end
240 240 end
241 241
242 242 class Info
243 243 attr_accessor :root_url, :lastrev
244 244 def initialize(attributes={})
245 245 self.root_url = attributes[:root_url] if attributes[:root_url]
246 246 self.lastrev = attributes[:lastrev]
247 247 end
248 248 end
249 249
250 250 class Entry
251 251 attr_accessor :name, :path, :kind, :size, :lastrev
252 252 def initialize(attributes={})
253 253 self.name = attributes[:name] if attributes[:name]
254 254 self.path = attributes[:path] if attributes[:path]
255 255 self.kind = attributes[:kind] if attributes[:kind]
256 256 self.size = attributes[:size].to_i if attributes[:size]
257 257 self.lastrev = attributes[:lastrev]
258 258 end
259 259
260 260 def is_file?
261 261 'file' == self.kind
262 262 end
263 263
264 264 def is_dir?
265 265 'dir' == self.kind
266 266 end
267 267
268 268 def is_text?
269 269 Redmine::MimeType.is_type?('text', name)
270 270 end
271 271 end
272 272
273 273 class Revisions < Array
274 274 def latest
275 275 sort {|x,y|
276 276 unless x.time.nil? or y.time.nil?
277 277 x.time <=> y.time
278 278 else
279 279 0
280 280 end
281 281 }.last
282 282 end
283 283 end
284 284
285 285 class Revision
286 286 attr_accessor :scmid, :name, :author, :time, :message, :paths, :revision, :branch
287 287 attr_writer :identifier
288 288
289 289 def initialize(attributes={})
290 290 self.identifier = attributes[:identifier]
291 291 self.scmid = attributes[:scmid]
292 292 self.name = attributes[:name] || self.identifier
293 293 self.author = attributes[:author]
294 294 self.time = attributes[:time]
295 295 self.message = attributes[:message] || ""
296 296 self.paths = attributes[:paths]
297 297 self.revision = attributes[:revision]
298 298 self.branch = attributes[:branch]
299 299 end
300 300
301 301 # Returns the identifier of this revision; see also Changeset model
302 302 def identifier
303 303 (@identifier || revision).to_s
304 304 end
305 305
306 306 # Returns the readable identifier.
307 307 def format_identifier
308 308 identifier
309 309 end
310 310
311 311 def save(repo)
312 312 Changeset.transaction do
313 313 changeset = Changeset.new(
314 314 :repository => repo,
315 315 :revision => identifier,
316 316 :scmid => scmid,
317 317 :committer => author,
318 318 :committed_on => time,
319 319 :comments => message)
320 320
321 321 if changeset.save
322 322 paths.each do |file|
323 323 Change.create(
324 324 :changeset => changeset,
325 325 :action => file[:action],
326 326 :path => file[:path])
327 327 end
328 328 end
329 329 end
330 330 end
331 331 end
332
332
333 333 class Annotate
334 334 attr_reader :lines, :revisions
335 335
336 336 def initialize
337 337 @lines = []
338 338 @revisions = []
339 339 end
340 340
341 341 def add_line(line, revision)
342 342 @lines << line
343 343 @revisions << revision
344 344 end
345 345
346 346 def content
347 347 content = lines.join("\n")
348 348 end
349 349
350 350 def empty?
351 351 lines.empty?
352 352 end
353 353 end
354 354 end
355 355 end
356 356 end
General Comments 0
You need to be logged in to leave comments. Login now