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