##// END OF EJS Templates
scm: cvs: code clean up lib/redmine/scm/adapters/cvs_adapter.rb....
Toshi MARUYAMA -
r5257:740051b769ef
parent child
Show More
@@ -1,439 +1,439
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_rlog(identifier) if identifier
103 cmd_args << "-D" << time_to_cvstime_rlog(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() do |line|
106 io.each_line() do |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 if fields[0]!="D"
109 if fields[0]!="D"
110 time = nil
110 time = nil
111 # Thu Dec 13 16:27:22 2007
111 # Thu Dec 13 16:27:22 2007
112 time_l = fields[-3].split(' ')
112 time_l = fields[-3].split(' ')
113 if time_l.size == 5 && time_l[4].length == 4
113 if time_l.size == 5 && time_l[4].length == 4
114 begin
114 begin
115 time = Time.parse(
115 time = Time.parse(
116 "#{time_l[1]} #{time_l[2]} #{time_l[3]} GMT #{time_l[4]}")
116 "#{time_l[1]} #{time_l[2]} #{time_l[3]} GMT #{time_l[4]}")
117 rescue
117 rescue
118 end
118 end
119 end
119 end
120 entries << Entry.new(
120 entries << Entry.new(
121 {
121 {
122 :name => fields[-5],
122 :name => fields[-5],
123 #:path => fields[-4].include?(path)?fields[-4]:(path + "/"+ fields[-4]),
123 #:path => fields[-4].include?(path)?fields[-4]:(path + "/"+ fields[-4]),
124 :path => "#{path}/#{fields[-5]}",
124 :path => "#{path}/#{fields[-5]}",
125 :kind => 'file',
125 :kind => 'file',
126 :size => nil,
126 :size => nil,
127 :lastrev => Revision.new(
127 :lastrev => Revision.new(
128 {
128 {
129 :revision => fields[-4],
129 :revision => fields[-4],
130 :name => fields[-4],
130 :name => fields[-4],
131 :time => time,
131 :time => time,
132 :author => ''
132 :author => ''
133 })
133 })
134 })
134 })
135 else
135 else
136 entries << Entry.new(
136 entries << Entry.new(
137 {
137 {
138 :name => fields[1],
138 :name => fields[1],
139 :path => "#{path}/#{fields[1]}",
139 :path => "#{path}/#{fields[1]}",
140 :kind => 'dir',
140 :kind => 'dir',
141 :size => nil,
141 :size => nil,
142 :lastrev => nil
142 :lastrev => nil
143 })
143 })
144 end
144 end
145 end
145 end
146 end
146 end
147 entries.sort_by_name
147 entries.sort_by_name
148 rescue ScmCommandAborted
148 rescue ScmCommandAborted
149 nil
149 nil
150 end
150 end
151
151
152 STARTLOG="----------------------------"
152 STARTLOG="----------------------------"
153 ENDLOG ="============================================================================="
153 ENDLOG ="============================================================================="
154
154
155 # Returns all revisions found between identifier_from and identifier_to
155 # Returns all revisions found between identifier_from and identifier_to
156 # in the repository. both identifier have to be dates or nil.
156 # in the repository. both identifier have to be dates or nil.
157 # these method returns nothing but yield every result in block
157 # these method returns nothing but yield every result in block
158 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)
159 logger.debug "<cvs> revisions path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}"
159 logger.debug "<cvs> revisions path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}"
160
160
161 path_with_project="#{url}#{with_leading_slash(path)}"
161 path_with_project="#{url}#{with_leading_slash(path)}"
162 cmd_args = %w|rlog|
162 cmd_args = %w|rlog|
163 cmd_args << "-d" << ">#{time_to_cvstime_rlog(identifier_from)}" if identifier_from
163 cmd_args << "-d" << ">#{time_to_cvstime_rlog(identifier_from)}" if identifier_from
164 cmd_args << path_with_project
164 cmd_args << path_with_project
165 scm_cmd(*cmd_args) do |io|
165 scm_cmd(*cmd_args) do |io|
166 state="entry_start"
166 state="entry_start"
167
167
168 commit_log=String.new
168 commit_log=String.new
169 revision=nil
169 revision=nil
170 date=nil
170 date=nil
171 author=nil
171 author=nil
172 entry_path=nil
172 entry_path=nil
173 entry_name=nil
173 entry_name=nil
174 file_state=nil
174 file_state=nil
175 branch_map=nil
175 branch_map=nil
176
176
177 io.each_line() do |line|
177 io.each_line() do |line|
178
178
179 if state!="revision" && /^#{ENDLOG}/ =~ line
179 if state!="revision" && /^#{ENDLOG}/ =~ line
180 commit_log=String.new
180 commit_log=String.new
181 revision=nil
181 revision=nil
182 state="entry_start"
182 state="entry_start"
183 end
183 end
184
184
185 if state=="entry_start"
185 if state=="entry_start"
186 branch_map=Hash.new
186 branch_map=Hash.new
187 if /^RCS file: #{Regexp.escape(root_url_path)}\/#{Regexp.escape(path_with_project)}(.+),v$/ =~ line
187 if /^RCS file: #{Regexp.escape(root_url_path)}\/#{Regexp.escape(path_with_project)}(.+),v$/ =~ line
188 entry_path = normalize_cvs_path($1)
188 entry_path = normalize_cvs_path($1)
189 entry_name = normalize_path(File.basename($1))
189 entry_name = normalize_path(File.basename($1))
190 logger.debug("Path #{entry_path} <=> Name #{entry_name}")
190 logger.debug("Path #{entry_path} <=> Name #{entry_name}")
191 elsif /^head: (.+)$/ =~ line
191 elsif /^head: (.+)$/ =~ line
192 entry_headRev = $1 #unless entry.nil?
192 entry_headRev = $1 #unless entry.nil?
193 elsif /^symbolic names:/ =~ line
193 elsif /^symbolic names:/ =~ line
194 state="symbolic" #unless entry.nil?
194 state="symbolic" #unless entry.nil?
195 elsif /^#{STARTLOG}/ =~ line
195 elsif /^#{STARTLOG}/ =~ line
196 commit_log=String.new
196 commit_log=String.new
197 state="revision"
197 state="revision"
198 end
198 end
199 next
199 next
200 elsif state=="symbolic"
200 elsif state=="symbolic"
201 if /^(.*):\s(.*)/ =~ (line.strip)
201 if /^(.*):\s(.*)/ =~ (line.strip)
202 branch_map[$1]=$2
202 branch_map[$1]=$2
203 else
203 else
204 state="tags"
204 state="tags"
205 next
205 next
206 end
206 end
207 elsif state=="tags"
207 elsif state=="tags"
208 if /^#{STARTLOG}/ =~ line
208 if /^#{STARTLOG}/ =~ line
209 commit_log = ""
209 commit_log = ""
210 state="revision"
210 state="revision"
211 elsif /^#{ENDLOG}/ =~ line
211 elsif /^#{ENDLOG}/ =~ line
212 state="head"
212 state="head"
213 end
213 end
214 next
214 next
215 elsif state=="revision"
215 elsif state=="revision"
216 if /^#{ENDLOG}/ =~ line || /^#{STARTLOG}/ =~ line
216 if /^#{ENDLOG}/ =~ line || /^#{STARTLOG}/ =~ line
217 if revision
217 if revision
218
218
219 revHelper=CvsRevisionHelper.new(revision)
219 revHelper=CvsRevisionHelper.new(revision)
220 revBranch="HEAD"
220 revBranch="HEAD"
221
221
222 branch_map.each() do |branch_name,branch_point|
222 branch_map.each() do |branch_name,branch_point|
223 if revHelper.is_in_branch_with_symbol(branch_point)
223 if revHelper.is_in_branch_with_symbol(branch_point)
224 revBranch=branch_name
224 revBranch=branch_name
225 end
225 end
226 end
226 end
227
227
228 logger.debug("********** YIELD Revision #{revision}::#{revBranch}")
228 logger.debug("********** YIELD Revision #{revision}::#{revBranch}")
229
229
230 yield Revision.new({
230 yield Revision.new({
231 :time => date,
231 :time => date,
232 :author => author,
232 :author => author,
233 :message=>commit_log.chomp,
233 :message=>commit_log.chomp,
234 :paths => [{
234 :paths => [{
235 :revision => revision,
235 :revision => revision,
236 :branch=> revBranch,
236 :branch=> revBranch,
237 :path=>entry_path,
237 :path=>entry_path,
238 :name=>entry_name,
238 :name=>entry_name,
239 :kind=>'file',
239 :kind=>'file',
240 :action=>file_state
240 :action=>file_state
241 }]
241 }]
242 })
242 })
243 end
243 end
244
244
245 commit_log=String.new
245 commit_log=String.new
246 revision=nil
246 revision=nil
247
247
248 if /^#{ENDLOG}/ =~ line
248 if /^#{ENDLOG}/ =~ line
249 state="entry_start"
249 state="entry_start"
250 end
250 end
251 next
251 next
252 end
252 end
253
253
254 if /^branches: (.+)$/ =~ line
254 if /^branches: (.+)$/ =~ line
255 #TODO: version.branch = $1
255 #TODO: version.branch = $1
256 elsif /^revision (\d+(?:\.\d+)+).*$/ =~ line
256 elsif /^revision (\d+(?:\.\d+)+).*$/ =~ line
257 revision = $1
257 revision = $1
258 elsif /^date:\s+(\d+.\d+.\d+\s+\d+:\d+:\d+)/ =~ line
258 elsif /^date:\s+(\d+.\d+.\d+\s+\d+:\d+:\d+)/ =~ line
259 date = Time.parse($1)
259 date = Time.parse($1)
260 author = /author: ([^;]+)/.match(line)[1]
260 author = /author: ([^;]+)/.match(line)[1]
261 file_state = /state: ([^;]+)/.match(line)[1]
261 file_state = /state: ([^;]+)/.match(line)[1]
262 #TODO: linechanges only available in CVS.... maybe a feature our SVN implementation. i'm sure, they are
262 #TODO: linechanges only available in CVS.... maybe a feature our SVN implementation. i'm sure, they are
263 # useful for stats or something else
263 # useful for stats or something else
264 # linechanges =/lines: \+(\d+) -(\d+)/.match(line)
264 # linechanges =/lines: \+(\d+) -(\d+)/.match(line)
265 # unless linechanges.nil?
265 # unless linechanges.nil?
266 # version.line_plus = linechanges[1]
266 # version.line_plus = linechanges[1]
267 # version.line_minus = linechanges[2]
267 # version.line_minus = linechanges[2]
268 # else
268 # else
269 # version.line_plus = 0
269 # version.line_plus = 0
270 # version.line_minus = 0
270 # version.line_minus = 0
271 # end
271 # end
272 else
272 else
273 commit_log << line unless line =~ /^\*\*\* empty log message \*\*\*/
273 commit_log << line unless line =~ /^\*\*\* empty log message \*\*\*/
274 end
274 end
275 end
275 end
276 end
276 end
277 end
277 end
278 rescue ScmCommandAborted
278 rescue ScmCommandAborted
279 Revisions.new
279 Revisions.new
280 end
280 end
281
281
282 def diff(path, identifier_from, identifier_to=nil)
282 def diff(path, identifier_from, identifier_to=nil)
283 logger.debug "<cvs> diff path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}"
283 logger.debug "<cvs> diff path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}"
284 path_with_project="#{url}#{with_leading_slash(path)}"
284 path_with_project="#{url}#{with_leading_slash(path)}"
285 cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} rdiff -u -r#{identifier_to} -r#{identifier_from} #{shell_quote path_with_project}"
285 cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} rdiff -u -r#{identifier_to} -r#{identifier_from} #{shell_quote path_with_project}"
286 diff = []
286 diff = []
287 shellout(cmd) do |io|
287 shellout(cmd) do |io|
288 io.each_line do |line|
288 io.each_line do |line|
289 diff << line
289 diff << line
290 end
290 end
291 end
291 end
292 return nil if $? && $?.exitstatus != 0
292 return nil if $? && $?.exitstatus != 0
293 diff
293 diff
294 end
294 end
295
295
296 def cat(path, identifier=nil)
296 def cat(path, identifier=nil)
297 identifier = (identifier) ? identifier : "HEAD"
297 identifier = (identifier) ? identifier : "HEAD"
298 logger.debug "<cvs> cat path:'#{path}',identifier #{identifier}"
298 logger.debug "<cvs> cat path:'#{path}',identifier #{identifier}"
299 path_with_project="#{url}#{with_leading_slash(path)}"
299 path_with_project="#{url}#{with_leading_slash(path)}"
300 cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} co"
300 cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} co"
301 cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier
301 cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier
302 cmd << " -p #{shell_quote path_with_project}"
302 cmd << " -p #{shell_quote path_with_project}"
303 cat = nil
303 cat = nil
304 shellout(cmd) do |io|
304 shellout(cmd) do |io|
305 io.binmode
305 io.binmode
306 cat = io.read
306 cat = io.read
307 end
307 end
308 return nil if $? && $?.exitstatus != 0
308 return nil if $? && $?.exitstatus != 0
309 cat
309 cat
310 end
310 end
311
311
312 def annotate(path, identifier=nil)
312 def annotate(path, identifier=nil)
313 identifier = (identifier) ? identifier.to_i : "HEAD"
313 identifier = (identifier) ? identifier.to_i : "HEAD"
314 logger.debug "<cvs> annotate path:'#{path}',identifier #{identifier}"
314 logger.debug "<cvs> annotate path:'#{path}',identifier #{identifier}"
315 path_with_project="#{url}#{with_leading_slash(path)}"
315 path_with_project="#{url}#{with_leading_slash(path)}"
316 cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} rannotate -r#{identifier} #{shell_quote path_with_project}"
316 cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} rannotate -r#{identifier} #{shell_quote path_with_project}"
317 blame = Annotate.new
317 blame = Annotate.new
318 shellout(cmd) do |io|
318 shellout(cmd) do |io|
319 io.each_line do |line|
319 io.each_line do |line|
320 next unless line =~ %r{^([\d\.]+)\s+\(([^\)]+)\s+[^\)]+\):\s(.*)$}
320 next unless line =~ %r{^([\d\.]+)\s+\(([^\)]+)\s+[^\)]+\):\s(.*)$}
321 blame.add_line($3.rstrip, Revision.new(:revision => $1, :author => $2.strip))
321 blame.add_line($3.rstrip, Revision.new(:revision => $1, :author => $2.strip))
322 end
322 end
323 end
323 end
324 return nil if $? && $?.exitstatus != 0
324 return nil if $? && $?.exitstatus != 0
325 blame
325 blame
326 end
326 end
327
327
328 private
328 private
329
329
330 # Returns the root url without the connexion string
330 # Returns the root url without the connexion string
331 # :pserver:anonymous@foo.bar:/path => /path
331 # :pserver:anonymous@foo.bar:/path => /path
332 # :ext:cvsservername:/path => /path
332 # :ext:cvsservername:/path => /path
333 def root_url_path
333 def root_url_path
334 root_url.to_s.gsub(/^:.+:\d*/, '')
334 root_url.to_s.gsub(/^:.+:\d*/, '')
335 end
335 end
336
336
337 # convert a date/time into the CVS-format
337 # convert a date/time into the CVS-format
338 def time_to_cvstime(time)
338 def time_to_cvstime(time)
339 return nil if time.nil?
339 return nil if time.nil?
340 return Time.now if time == 'HEAD'
340 return Time.now if time == 'HEAD'
341
341
342 unless time.kind_of? Time
342 unless time.kind_of? Time
343 time = Time.parse(time)
343 time = Time.parse(time)
344 end
344 end
345 return time.strftime("%Y-%m-%d %H:%M:%S")
345 return time.strftime("%Y-%m-%d %H:%M:%S")
346 end
346 end
347
347
348 def time_to_cvstime_rlog(time)
348 def time_to_cvstime_rlog(time)
349 return nil if time.nil?
349 return nil if time.nil?
350 t1 = time.clone.localtime
350 t1 = time.clone.localtime
351 return t1.strftime("%Y-%m-%d %H:%M:%S")
351 return t1.strftime("%Y-%m-%d %H:%M:%S")
352 end
352 end
353
353
354 def normalize_cvs_path(path)
354 def normalize_cvs_path(path)
355 normalize_path(path.gsub(/Attic\//,''))
355 normalize_path(path.gsub(/Attic\//,''))
356 end
356 end
357
357
358 def normalize_path(path)
358 def normalize_path(path)
359 path.sub(/^(\/)*(.*)/,'\2').sub(/(.*)(,v)+/,'\1')
359 path.sub(/^(\/)*(.*)/,'\2').sub(/(.*)(,v)+/,'\1')
360 end
360 end
361
361
362 def scm_cmd(*args, &block)
362 def scm_cmd(*args, &block)
363 full_args = [CVS_BIN, '-d', root_url]
363 full_args = [CVS_BIN, '-d', root_url]
364 full_args += args
364 full_args += args
365 ret = shellout(full_args.map { |e| shell_quote e.to_s }.join(' '), &block)
365 ret = shellout(full_args.map { |e| shell_quote e.to_s }.join(' '), &block)
366 if $? && $?.exitstatus != 0
366 if $? && $?.exitstatus != 0
367 raise ScmCommandAborted, "cvs exited with non-zero status: #{$?.exitstatus}"
367 raise ScmCommandAborted, "cvs exited with non-zero status: #{$?.exitstatus}"
368 end
368 end
369 ret
369 ret
370 end
370 end
371 private :scm_cmd
371 private :scm_cmd
372 end
372 end
373
373
374 class CvsRevisionHelper
374 class CvsRevisionHelper
375 attr_accessor :complete_rev, :revision, :base, :branchid
375 attr_accessor :complete_rev, :revision, :base, :branchid
376
376
377 def initialize(complete_rev)
377 def initialize(complete_rev)
378 @complete_rev = complete_rev
378 @complete_rev = complete_rev
379 parseRevision()
379 parseRevision()
380 end
380 end
381
381
382 def branchPoint
382 def branchPoint
383 return @base
383 return @base
384 end
384 end
385
385
386 def branchVersion
386 def branchVersion
387 if isBranchRevision
387 if isBranchRevision
388 return @base+"."+@branchid
388 return @base+"."+@branchid
389 end
389 end
390 return @base
390 return @base
391 end
391 end
392
392
393 def isBranchRevision
393 def isBranchRevision
394 !@branchid.nil?
394 !@branchid.nil?
395 end
395 end
396
396
397 def prevRev
397 def prevRev
398 unless @revision==0
398 unless @revision == 0
399 return buildRevision(@revision-1)
399 return buildRevision( @revision - 1 )
400 end
400 end
401 return buildRevision(@revision)
401 return buildRevision( @revision )
402 end
402 end
403
403
404 def is_in_branch_with_symbol(branch_symbol)
404 def is_in_branch_with_symbol(branch_symbol)
405 bpieces=branch_symbol.split(".")
405 bpieces = branch_symbol.split(".")
406 branch_start="#{bpieces[0..-3].join(".")}.#{bpieces[-1]}"
406 branch_start = "#{bpieces[0..-3].join(".")}.#{bpieces[-1]}"
407 return (branchVersion==branch_start)
407 return ( branchVersion == branch_start )
408 end
408 end
409
409
410 private
410 private
411 def buildRevision(rev)
411 def buildRevision(rev)
412 if rev== 0
412 if rev== 0
413 if @branchid.nil?
413 if @branchid.nil?
414 @base+".0"
414 @base+".0"
415 else
415 else
416 @base
416 @base
417 end
417 end
418 elsif @branchid.nil?
418 elsif @branchid.nil?
419 @base+"."+rev.to_s
419 @base+"."+rev.to_s
420 else
420 else
421 @base+"."+@branchid+"."+rev.to_s
421 @base+"."+@branchid+"."+rev.to_s
422 end
422 end
423 end
423 end
424
424
425 # Interpretiert die cvs revisionsnummern wie z.b. 1.14 oder 1.3.0.15
425 # Interpretiert die cvs revisionsnummern wie z.b. 1.14 oder 1.3.0.15
426 def parseRevision()
426 def parseRevision()
427 pieces=@complete_rev.split(".")
427 pieces = @complete_rev.split(".")
428 @revision=pieces.last.to_i
428 @revision = pieces.last.to_i
429 baseSize=1
429 baseSize = 1
430 baseSize+=(pieces.size/2)
430 baseSize += (pieces.size / 2)
431 @base=pieces[0..-baseSize].join(".")
431 @base = pieces[0..-baseSize].join(".")
432 if baseSize > 2
432 if baseSize > 2
433 @branchid=pieces[-2]
433 @branchid = pieces[-2]
434 end
434 end
435 end
435 end
436 end
436 end
437 end
437 end
438 end
438 end
439 end
439 end
General Comments 0
You need to be logged in to leave comments. Login now