Mercurial > hg > soundsoftware-site
comparison lib/redmine/scm/adapters/.svn/text-base/cvs_adapter.rb.svn-base @ 441:cbce1fd3b1b7 redmine-1.2
Update to Redmine 1.2-stable branch (Redmine SVN rev 6000)
author | Chris Cannam |
---|---|
date | Mon, 06 Jun 2011 14:24:13 +0100 |
parents | 051f544170fe |
children | 753f1380d6bc |
comparison
equal
deleted
inserted
replaced
245:051f544170fe | 441:cbce1fd3b1b7 |
---|---|
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' |
23 class CvsAdapter < AbstractAdapter | 23 class CvsAdapter < AbstractAdapter |
24 | 24 |
25 # CVS executable name | 25 # CVS executable name |
26 CVS_BIN = Redmine::Configuration['scm_cvs_command'] || "cvs" | 26 CVS_BIN = Redmine::Configuration['scm_cvs_command'] || "cvs" |
27 | 27 |
28 # raised if scm command exited with error, e.g. unknown revision. | |
29 class ScmCommandAborted < CommandFailed; end | |
30 | |
28 class << self | 31 class << self |
29 def client_command | 32 def client_command |
30 @@bin ||= CVS_BIN | 33 @@bin ||= CVS_BIN |
31 end | 34 end |
32 | 35 |
56 shellout("#{sq_bin} --version") { |io| io.read }.to_s | 59 shellout("#{sq_bin} --version") { |io| io.read }.to_s |
57 end | 60 end |
58 end | 61 end |
59 | 62 |
60 # Guidelines for the input: | 63 # Guidelines for the input: |
61 # url -> the project-path, relative to the cvsroot (eg. module name) | 64 # url -> the project-path, relative to the cvsroot (eg. module name) |
62 # root_url -> the good old, sometimes damned, CVSROOT | 65 # root_url -> the good old, sometimes damned, CVSROOT |
63 # login -> unnecessary | 66 # login -> unnecessary |
64 # password -> unnecessary too | 67 # password -> unnecessary too |
65 def initialize(url, root_url=nil, login=nil, password=nil, | 68 def initialize(url, root_url=nil, login=nil, password=nil, |
66 path_encoding=nil) | 69 path_encoding=nil) |
67 @url = url | 70 @path_encoding = path_encoding.blank? ? 'UTF-8' : path_encoding |
68 @login = login if login && !login.empty? | 71 @url = url |
72 # TODO: better Exception here (IllegalArgumentException) | |
73 raise CommandFailed if root_url.blank? | |
74 @root_url = root_url | |
75 | |
76 # These are unused. | |
77 @login = login if login && !login.empty? | |
69 @password = (password || "") if @login | 78 @password = (password || "") if @login |
70 #TODO: better Exception here (IllegalArgumentException) | 79 end |
71 raise CommandFailed if root_url.blank? | 80 |
72 @root_url = root_url | 81 def path_encoding |
73 end | 82 @path_encoding |
74 | |
75 def root_url | |
76 @root_url | |
77 end | |
78 | |
79 def url | |
80 @url | |
81 end | 83 end |
82 | 84 |
83 def info | 85 def info |
84 logger.debug "<cvs> info" | 86 logger.debug "<cvs> info" |
85 Info.new({:root_url => @root_url, :lastrev => nil}) | 87 Info.new({:root_url => @root_url, :lastrev => nil}) |
90 end | 92 end |
91 | 93 |
92 # Returns an Entries collection | 94 # Returns an Entries collection |
93 # or nil if the given path doesn't exist in the repository | 95 # or nil if the given path doesn't exist in the repository |
94 # this method is used by the repository-browser (aka LIST) | 96 # this method is used by the repository-browser (aka LIST) |
95 def entries(path=nil, identifier=nil) | 97 def entries(path=nil, identifier=nil, options={}) |
96 logger.debug "<cvs> entries '#{path}' with identifier '#{identifier}'" | 98 logger.debug "<cvs> entries '#{path}' with identifier '#{identifier}'" |
97 path_with_project="#{url}#{with_leading_slash(path)}" | 99 path_locale = scm_iconv(@path_encoding, 'UTF-8', path) |
100 path_locale.force_encoding("ASCII-8BIT") if path_locale.respond_to?(:force_encoding) | |
98 entries = Entries.new | 101 entries = Entries.new |
99 cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} rls -e" | 102 cmd_args = %w|-q rls -e| |
100 cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier | 103 cmd_args << "-D" << time_to_cvstime_rlog(identifier) if identifier |
101 cmd << " #{shell_quote path_with_project}" | 104 cmd_args << path_with_proj(path) |
102 shellout(cmd) do |io| | 105 scm_cmd(*cmd_args) do |io| |
103 io.each_line(){|line| | 106 io.each_line() do |line| |
104 fields=line.chop.split('/',-1) | 107 fields = line.chop.split('/',-1) |
105 logger.debug(">>InspectLine #{fields.inspect}") | 108 logger.debug(">>InspectLine #{fields.inspect}") |
106 | |
107 if fields[0]!="D" | 109 if fields[0]!="D" |
108 entries << Entry.new({:name => fields[-5], | 110 time = nil |
111 # Thu Dec 13 16:27:22 2007 | |
112 time_l = fields[-3].split(' ') | |
113 if time_l.size == 5 && time_l[4].length == 4 | |
114 begin | |
115 time = Time.parse( | |
116 "#{time_l[1]} #{time_l[2]} #{time_l[3]} GMT #{time_l[4]}") | |
117 rescue | |
118 end | |
119 end | |
120 entries << Entry.new( | |
121 { | |
122 :name => scm_iconv('UTF-8', @path_encoding, fields[-5]), | |
109 #:path => fields[-4].include?(path)?fields[-4]:(path + "/"+ fields[-4]), | 123 #:path => fields[-4].include?(path)?fields[-4]:(path + "/"+ fields[-4]), |
110 :path => "#{path}/#{fields[-5]}", | 124 :path => scm_iconv('UTF-8', @path_encoding, "#{path_locale}/#{fields[-5]}"), |
111 :kind => 'file', | 125 :kind => 'file', |
112 :size => nil, | 126 :size => nil, |
113 :lastrev => Revision.new({ | 127 :lastrev => Revision.new( |
114 :revision => fields[-4], | 128 { |
115 :name => fields[-4], | 129 :revision => fields[-4], |
116 :time => Time.parse(fields[-3]), | 130 :name => scm_iconv('UTF-8', @path_encoding, fields[-4]), |
117 :author => '' | 131 :time => time, |
132 :author => '' | |
133 }) | |
118 }) | 134 }) |
119 }) | |
120 else | 135 else |
121 entries << Entry.new({:name => fields[1], | 136 entries << Entry.new( |
122 :path => "#{path}/#{fields[1]}", | 137 { |
123 :kind => 'dir', | 138 :name => scm_iconv('UTF-8', @path_encoding, fields[1]), |
124 :size => nil, | 139 :path => scm_iconv('UTF-8', @path_encoding, "#{path_locale}/#{fields[1]}"), |
140 :kind => 'dir', | |
141 :size => nil, | |
125 :lastrev => nil | 142 :lastrev => nil |
126 }) | 143 }) |
127 end | 144 end |
128 } | 145 end |
129 end | 146 end |
130 return nil if $? && $?.exitstatus != 0 | |
131 entries.sort_by_name | 147 entries.sort_by_name |
148 rescue ScmCommandAborted | |
149 nil | |
132 end | 150 end |
133 | 151 |
134 STARTLOG="----------------------------" | 152 STARTLOG="----------------------------" |
135 ENDLOG ="=============================================================================" | 153 ENDLOG ="=============================================================================" |
136 | 154 |
137 # Returns all revisions found between identifier_from and identifier_to | 155 # Returns all revisions found between identifier_from and identifier_to |
138 # in the repository. both identifier have to be dates or nil. | 156 # in the repository. both identifier have to be dates or nil. |
139 # these method returns nothing but yield every result in block | 157 # these method returns nothing but yield every result in block |
140 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}, &block) | 158 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}, &block) |
141 logger.debug "<cvs> revisions path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}" | 159 path_with_project_utf8 = path_with_proj(path) |
142 | 160 path_with_project_locale = scm_iconv(@path_encoding, 'UTF-8', path_with_project_utf8) |
143 path_with_project="#{url}#{with_leading_slash(path)}" | 161 logger.debug "<cvs> revisions path:" + |
144 cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} rlog" | 162 "'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}" |
145 cmd << " -d\">#{time_to_cvstime_rlog(identifier_from)}\"" if identifier_from | 163 cmd_args = %w|-q rlog| |
146 cmd << " #{shell_quote path_with_project}" | 164 cmd_args << "-d" << ">#{time_to_cvstime_rlog(identifier_from)}" if identifier_from |
147 shellout(cmd) do |io| | 165 cmd_args << path_with_project_utf8 |
148 state="entry_start" | 166 scm_cmd(*cmd_args) do |io| |
149 | 167 state = "entry_start" |
150 commit_log=String.new | 168 commit_log = String.new |
151 revision=nil | 169 revision = nil |
152 date=nil | 170 date = nil |
153 author=nil | 171 author = nil |
154 entry_path=nil | 172 entry_path = nil |
155 entry_name=nil | 173 entry_name = nil |
156 file_state=nil | 174 file_state = nil |
157 branch_map=nil | 175 branch_map = nil |
158 | |
159 io.each_line() do |line| | 176 io.each_line() do |line| |
160 | 177 if state != "revision" && /^#{ENDLOG}/ =~ line |
161 if state!="revision" && /^#{ENDLOG}/ =~ line | 178 commit_log = String.new |
162 commit_log=String.new | 179 revision = nil |
163 revision=nil | 180 state = "entry_start" |
164 state="entry_start" | |
165 end | 181 end |
166 | 182 if state == "entry_start" |
167 if state=="entry_start" | 183 branch_map = Hash.new |
168 branch_map=Hash.new | 184 if /^RCS file: #{Regexp.escape(root_url_path)}\/#{Regexp.escape(path_with_project_locale)}(.+),v$/ =~ line |
169 if /^RCS file: #{Regexp.escape(root_url_path)}\/#{Regexp.escape(path_with_project)}(.+),v$/ =~ line | |
170 entry_path = normalize_cvs_path($1) | 185 entry_path = normalize_cvs_path($1) |
171 entry_name = normalize_path(File.basename($1)) | 186 entry_name = normalize_path(File.basename($1)) |
172 logger.debug("Path #{entry_path} <=> Name #{entry_name}") | 187 logger.debug("Path #{entry_path} <=> Name #{entry_name}") |
173 elsif /^head: (.+)$/ =~ line | 188 elsif /^head: (.+)$/ =~ line |
174 entry_headRev = $1 #unless entry.nil? | 189 entry_headRev = $1 #unless entry.nil? |
175 elsif /^symbolic names:/ =~ line | 190 elsif /^symbolic names:/ =~ line |
176 state="symbolic" #unless entry.nil? | 191 state = "symbolic" #unless entry.nil? |
177 elsif /^#{STARTLOG}/ =~ line | 192 elsif /^#{STARTLOG}/ =~ line |
178 commit_log=String.new | 193 commit_log = String.new |
179 state="revision" | 194 state = "revision" |
180 end | 195 end |
181 next | 196 next |
182 elsif state=="symbolic" | 197 elsif state == "symbolic" |
183 if /^(.*):\s(.*)/ =~ (line.strip) | 198 if /^(.*):\s(.*)/ =~ (line.strip) |
184 branch_map[$1]=$2 | 199 branch_map[$1] = $2 |
185 else | 200 else |
186 state="tags" | 201 state = "tags" |
187 next | 202 next |
188 end | 203 end |
189 elsif state=="tags" | 204 elsif state == "tags" |
190 if /^#{STARTLOG}/ =~ line | 205 if /^#{STARTLOG}/ =~ line |
191 commit_log = "" | 206 commit_log = "" |
192 state="revision" | 207 state = "revision" |
193 elsif /^#{ENDLOG}/ =~ line | 208 elsif /^#{ENDLOG}/ =~ line |
194 state="head" | 209 state = "head" |
195 end | 210 end |
196 next | 211 next |
197 elsif state=="revision" | 212 elsif state == "revision" |
198 if /^#{ENDLOG}/ =~ line || /^#{STARTLOG}/ =~ line | 213 if /^#{ENDLOG}/ =~ line || /^#{STARTLOG}/ =~ line |
199 if revision | 214 if revision |
200 | 215 revHelper = CvsRevisionHelper.new(revision) |
201 revHelper=CvsRevisionHelper.new(revision) | 216 revBranch = "HEAD" |
202 revBranch="HEAD" | 217 branch_map.each() do |branch_name, branch_point| |
203 | |
204 branch_map.each() do |branch_name,branch_point| | |
205 if revHelper.is_in_branch_with_symbol(branch_point) | 218 if revHelper.is_in_branch_with_symbol(branch_point) |
206 revBranch=branch_name | 219 revBranch = branch_name |
207 end | 220 end |
208 end | 221 end |
209 | |
210 logger.debug("********** YIELD Revision #{revision}::#{revBranch}") | 222 logger.debug("********** YIELD Revision #{revision}::#{revBranch}") |
211 | |
212 yield Revision.new({ | 223 yield Revision.new({ |
213 :time => date, | 224 :time => date, |
214 :author => author, | 225 :author => author, |
215 :message=>commit_log.chomp, | 226 :message => commit_log.chomp, |
216 :paths => [{ | 227 :paths => [{ |
217 :revision => revision, | 228 :revision => revision, |
218 :branch=> revBranch, | 229 :branch => revBranch, |
219 :path=>entry_path, | 230 :path => scm_iconv('UTF-8', @path_encoding, entry_path), |
220 :name=>entry_name, | 231 :name => scm_iconv('UTF-8', @path_encoding, entry_name), |
221 :kind=>'file', | 232 :kind => 'file', |
222 :action=>file_state | 233 :action => file_state |
223 }] | 234 }] |
224 }) | 235 }) |
225 end | 236 end |
226 | 237 commit_log = String.new |
227 commit_log=String.new | 238 revision = nil |
228 revision=nil | |
229 | |
230 if /^#{ENDLOG}/ =~ line | 239 if /^#{ENDLOG}/ =~ line |
231 state="entry_start" | 240 state = "entry_start" |
232 end | 241 end |
233 next | 242 next |
234 end | 243 end |
235 | 244 |
236 if /^branches: (.+)$/ =~ line | 245 if /^branches: (.+)$/ =~ line |
237 #TODO: version.branch = $1 | 246 # TODO: version.branch = $1 |
238 elsif /^revision (\d+(?:\.\d+)+).*$/ =~ line | 247 elsif /^revision (\d+(?:\.\d+)+).*$/ =~ line |
239 revision = $1 | 248 revision = $1 |
240 elsif /^date:\s+(\d+.\d+.\d+\s+\d+:\d+:\d+)/ =~ line | 249 elsif /^date:\s+(\d+.\d+.\d+\s+\d+:\d+:\d+)/ =~ line |
241 date = Time.parse($1) | 250 date = Time.parse($1) |
242 author = /author: ([^;]+)/.match(line)[1] | 251 line_utf8 = scm_iconv('UTF-8', options[:log_encoding], line) |
243 file_state = /state: ([^;]+)/.match(line)[1] | 252 author_utf8 = /author: ([^;]+)/.match(line_utf8)[1] |
244 #TODO: linechanges only available in CVS.... maybe a feature our SVN implementation. i'm sure, they are | 253 author = scm_iconv(options[:log_encoding], 'UTF-8', author_utf8) |
245 # useful for stats or something else | 254 file_state = /state: ([^;]+)/.match(line)[1] |
255 # TODO: | |
256 # linechanges only available in CVS.... | |
257 # maybe a feature our SVN implementation. | |
258 # I'm sure, they are useful for stats or something else | |
246 # linechanges =/lines: \+(\d+) -(\d+)/.match(line) | 259 # linechanges =/lines: \+(\d+) -(\d+)/.match(line) |
247 # unless linechanges.nil? | 260 # unless linechanges.nil? |
248 # version.line_plus = linechanges[1] | 261 # version.line_plus = linechanges[1] |
249 # version.line_minus = linechanges[2] | 262 # version.line_minus = linechanges[2] |
250 # else | 263 # else |
255 commit_log << line unless line =~ /^\*\*\* empty log message \*\*\*/ | 268 commit_log << line unless line =~ /^\*\*\* empty log message \*\*\*/ |
256 end | 269 end |
257 end | 270 end |
258 end | 271 end |
259 end | 272 end |
273 rescue ScmCommandAborted | |
274 Revisions.new | |
260 end | 275 end |
261 | 276 |
262 def diff(path, identifier_from, identifier_to=nil) | 277 def diff(path, identifier_from, identifier_to=nil) |
263 logger.debug "<cvs> diff path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}" | 278 logger.debug "<cvs> diff path:'#{path}'" + |
264 path_with_project="#{url}#{with_leading_slash(path)}" | 279 ",identifier_from #{identifier_from}, identifier_to #{identifier_to}" |
265 cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} rdiff -u -r#{identifier_to} -r#{identifier_from} #{shell_quote path_with_project}" | 280 cmd_args = %w|rdiff -u| |
281 cmd_args << "-r#{identifier_to}" | |
282 cmd_args << "-r#{identifier_from}" | |
283 cmd_args << path_with_proj(path) | |
266 diff = [] | 284 diff = [] |
267 shellout(cmd) do |io| | 285 scm_cmd(*cmd_args) do |io| |
268 io.each_line do |line| | 286 io.each_line do |line| |
269 diff << line | 287 diff << line |
270 end | 288 end |
271 end | 289 end |
272 return nil if $? && $?.exitstatus != 0 | |
273 diff | 290 diff |
291 rescue ScmCommandAborted | |
292 nil | |
274 end | 293 end |
275 | 294 |
276 def cat(path, identifier=nil) | 295 def cat(path, identifier=nil) |
277 identifier = (identifier) ? identifier : "HEAD" | 296 identifier = (identifier) ? identifier : "HEAD" |
278 logger.debug "<cvs> cat path:'#{path}',identifier #{identifier}" | 297 logger.debug "<cvs> cat path:'#{path}',identifier #{identifier}" |
279 path_with_project="#{url}#{with_leading_slash(path)}" | 298 cmd_args = %w|-q co| |
280 cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} co" | 299 cmd_args << "-D" << time_to_cvstime(identifier) if identifier |
281 cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier | 300 cmd_args << "-p" << path_with_proj(path) |
282 cmd << " -p #{shell_quote path_with_project}" | |
283 cat = nil | 301 cat = nil |
284 shellout(cmd) do |io| | 302 scm_cmd(*cmd_args) do |io| |
285 io.binmode | 303 io.binmode |
286 cat = io.read | 304 cat = io.read |
287 end | 305 end |
288 return nil if $? && $?.exitstatus != 0 | |
289 cat | 306 cat |
307 rescue ScmCommandAborted | |
308 nil | |
290 end | 309 end |
291 | 310 |
292 def annotate(path, identifier=nil) | 311 def annotate(path, identifier=nil) |
293 identifier = (identifier) ? identifier.to_i : "HEAD" | 312 identifier = (identifier) ? identifier : "HEAD" |
294 logger.debug "<cvs> annotate path:'#{path}',identifier #{identifier}" | 313 logger.debug "<cvs> annotate path:'#{path}',identifier #{identifier}" |
295 path_with_project="#{url}#{with_leading_slash(path)}" | 314 cmd_args = %w|rannotate| |
296 cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} rannotate -r#{identifier} #{shell_quote path_with_project}" | 315 cmd_args << "-D" << time_to_cvstime(identifier) if identifier |
316 cmd_args << path_with_proj(path) | |
297 blame = Annotate.new | 317 blame = Annotate.new |
298 shellout(cmd) do |io| | 318 scm_cmd(*cmd_args) do |io| |
299 io.each_line do |line| | 319 io.each_line do |line| |
300 next unless line =~ %r{^([\d\.]+)\s+\(([^\)]+)\s+[^\)]+\):\s(.*)$} | 320 next unless line =~ %r{^([\d\.]+)\s+\(([^\)]+)\s+[^\)]+\):\s(.*)$} |
301 blame.add_line($3.rstrip, Revision.new(:revision => $1, :author => $2.strip)) | 321 blame.add_line( |
302 end | 322 $3.rstrip, |
303 end | 323 Revision.new( |
304 return nil if $? && $?.exitstatus != 0 | 324 :revision => $1, |
325 :identifier => nil, | |
326 :author => $2.strip | |
327 )) | |
328 end | |
329 end | |
305 blame | 330 blame |
331 rescue ScmCommandAborted | |
332 Annotate.new | |
306 end | 333 end |
307 | 334 |
308 private | 335 private |
309 | 336 |
310 # Returns the root url without the connexion string | 337 # Returns the root url without the connexion string |
315 end | 342 end |
316 | 343 |
317 # convert a date/time into the CVS-format | 344 # convert a date/time into the CVS-format |
318 def time_to_cvstime(time) | 345 def time_to_cvstime(time) |
319 return nil if time.nil? | 346 return nil if time.nil? |
320 return Time.now if time == 'HEAD' | 347 time = Time.now if time == 'HEAD' |
321 | 348 |
322 unless time.kind_of? Time | 349 unless time.kind_of? Time |
323 time = Time.parse(time) | 350 time = Time.parse(time) |
324 end | 351 end |
325 return time.strftime("%Y-%m-%d %H:%M:%S") | 352 return time_to_cvstime_rlog(time) |
326 end | 353 end |
327 | 354 |
328 def time_to_cvstime_rlog(time) | 355 def time_to_cvstime_rlog(time) |
329 return nil if time.nil? | 356 return nil if time.nil? |
330 t1 = time.clone.localtime | 357 t1 = time.clone.localtime |
331 return t1.strftime("%Y-%m-%d %H:%M:%S") | 358 return t1.strftime("%Y-%m-%d %H:%M:%S") |
332 end | 359 end |
333 | 360 |
334 def normalize_cvs_path(path) | 361 def normalize_cvs_path(path) |
335 normalize_path(path.gsub(/Attic\//,'')) | 362 normalize_path(path.gsub(/Attic\//,'')) |
336 end | 363 end |
337 | 364 |
338 def normalize_path(path) | 365 def normalize_path(path) |
339 path.sub(/^(\/)*(.*)/,'\2').sub(/(.*)(,v)+/,'\1') | 366 path.sub(/^(\/)*(.*)/,'\2').sub(/(.*)(,v)+/,'\1') |
340 end | 367 end |
341 end | 368 |
342 | 369 def path_with_proj(path) |
370 "#{url}#{with_leading_slash(path)}" | |
371 end | |
372 private :path_with_proj | |
373 | |
374 class Revision < Redmine::Scm::Adapters::Revision | |
375 # Returns the readable identifier | |
376 def format_identifier | |
377 revision.to_s | |
378 end | |
379 end | |
380 | |
381 def scm_cmd(*args, &block) | |
382 full_args = [CVS_BIN, '-d', root_url] | |
383 full_args += args | |
384 full_args_locale = [] | |
385 full_args.map do |e| | |
386 full_args_locale << scm_iconv(@path_encoding, 'UTF-8', e) | |
387 end | |
388 ret = shellout(full_args_locale.map { |e| shell_quote e.to_s }.join(' '), &block) | |
389 if $? && $?.exitstatus != 0 | |
390 raise ScmCommandAborted, "cvs exited with non-zero status: #{$?.exitstatus}" | |
391 end | |
392 ret | |
393 end | |
394 private :scm_cmd | |
395 end | |
396 | |
343 class CvsRevisionHelper | 397 class CvsRevisionHelper |
344 attr_accessor :complete_rev, :revision, :base, :branchid | 398 attr_accessor :complete_rev, :revision, :base, :branchid |
345 | 399 |
346 def initialize(complete_rev) | 400 def initialize(complete_rev) |
347 @complete_rev = complete_rev | 401 @complete_rev = complete_rev |
348 parseRevision() | 402 parseRevision() |
349 end | 403 end |
350 | 404 |
351 def branchPoint | 405 def branchPoint |
352 return @base | 406 return @base |
353 end | 407 end |
354 | 408 |
355 def branchVersion | 409 def branchVersion |
356 if isBranchRevision | 410 if isBranchRevision |
357 return @base+"."+@branchid | 411 return @base+"."+@branchid |
358 end | 412 end |
359 return @base | 413 return @base |
360 end | 414 end |
361 | 415 |
362 def isBranchRevision | 416 def isBranchRevision |
363 !@branchid.nil? | 417 !@branchid.nil? |
364 end | 418 end |
365 | 419 |
366 def prevRev | 420 def prevRev |
367 unless @revision==0 | 421 unless @revision == 0 |
368 return buildRevision(@revision-1) | 422 return buildRevision( @revision - 1 ) |
369 end | 423 end |
370 return buildRevision(@revision) | 424 return buildRevision( @revision ) |
371 end | 425 end |
372 | 426 |
373 def is_in_branch_with_symbol(branch_symbol) | 427 def is_in_branch_with_symbol(branch_symbol) |
374 bpieces=branch_symbol.split(".") | 428 bpieces = branch_symbol.split(".") |
375 branch_start="#{bpieces[0..-3].join(".")}.#{bpieces[-1]}" | 429 branch_start = "#{bpieces[0..-3].join(".")}.#{bpieces[-1]}" |
376 return (branchVersion==branch_start) | 430 return ( branchVersion == branch_start ) |
377 end | 431 end |
378 | 432 |
379 private | 433 private |
380 def buildRevision(rev) | 434 def buildRevision(rev) |
381 if rev== 0 | 435 if rev == 0 |
382 if @branchid.nil? | 436 if @branchid.nil? |
383 @base+".0" | 437 @base + ".0" |
384 else | 438 else |
385 @base | 439 @base |
386 end | 440 end |
387 elsif @branchid.nil? | 441 elsif @branchid.nil? |
388 @base+"."+rev.to_s | 442 @base + "." + rev.to_s |
389 else | 443 else |
390 @base+"."+@branchid+"."+rev.to_s | 444 @base + "." + @branchid + "." + rev.to_s |
391 end | 445 end |
392 end | 446 end |
393 | 447 |
394 # Interpretiert die cvs revisionsnummern wie z.b. 1.14 oder 1.3.0.15 | 448 # Interpretiert die cvs revisionsnummern wie z.b. 1.14 oder 1.3.0.15 |
395 def parseRevision() | 449 def parseRevision() |
396 pieces=@complete_rev.split(".") | 450 pieces = @complete_rev.split(".") |
397 @revision=pieces.last.to_i | 451 @revision = pieces.last.to_i |
398 baseSize=1 | 452 baseSize = 1 |
399 baseSize+=(pieces.size/2) | 453 baseSize += (pieces.size / 2) |
400 @base=pieces[0..-baseSize].join(".") | 454 @base = pieces[0..-baseSize].join(".") |
401 if baseSize > 2 | 455 if baseSize > 2 |
402 @branchid=pieces[-2] | 456 @branchid = pieces[-2] |
403 end | 457 end |
404 end | 458 end |
405 end | 459 end |
406 end | 460 end |
407 end | 461 end |
408 end | 462 end |