To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.
root / lib / redmine / scm / adapters / cvs_adapter.rb @ 441:cbce1fd3b1b7
History | View | Annotate | Download (16.4 KB)
| 1 | 0:513646585e45 | Chris | # redMine - project management software
|
|---|---|---|---|
| 2 | # Copyright (C) 2006-2007 Jean-Philippe Lang
|
||
| 3 | #
|
||
| 4 | # This program is free software; you can redistribute it and/or
|
||
| 5 | # modify it under the terms of the GNU General Public License
|
||
| 6 | # as published by the Free Software Foundation; either version 2
|
||
| 7 | # of the License, or (at your option) any later version.
|
||
| 8 | 441:cbce1fd3b1b7 | Chris | #
|
| 9 | 0:513646585e45 | Chris | # This program is distributed in the hope that it will be useful,
|
| 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
| 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
| 12 | # GNU General Public License for more details.
|
||
| 13 | 441:cbce1fd3b1b7 | Chris | #
|
| 14 | 0:513646585e45 | Chris | # You should have received a copy of the GNU General Public License
|
| 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.
|
||
| 17 | |||
| 18 | require 'redmine/scm/adapters/abstract_adapter'
|
||
| 19 | |||
| 20 | module Redmine |
||
| 21 | module Scm |
||
| 22 | module Adapters |
||
| 23 | class CvsAdapter < AbstractAdapter |
||
| 24 | |||
| 25 | # CVS executable name
|
||
| 26 | 210:0579821a129a | Chris | CVS_BIN = Redmine::Configuration['scm_cvs_command'] || "cvs" |
| 27 | 245:051f544170fe | Chris | |
| 28 | 441:cbce1fd3b1b7 | Chris | # raised if scm command exited with error, e.g. unknown revision.
|
| 29 | class ScmCommandAborted < CommandFailed; end |
||
| 30 | |||
| 31 | 245:051f544170fe | Chris | class << self |
| 32 | def client_command |
||
| 33 | @@bin ||= CVS_BIN |
||
| 34 | end
|
||
| 35 | |||
| 36 | def sq_bin |
||
| 37 | @@sq_bin ||= shell_quote(CVS_BIN) |
||
| 38 | end
|
||
| 39 | |||
| 40 | def client_version |
||
| 41 | @@client_version ||= (scm_command_version || [])
|
||
| 42 | end
|
||
| 43 | |||
| 44 | def client_available |
||
| 45 | client_version_above?([1, 12]) |
||
| 46 | end
|
||
| 47 | |||
| 48 | def scm_command_version |
||
| 49 | scm_version = scm_version_from_command_line.dup |
||
| 50 | if scm_version.respond_to?(:force_encoding) |
||
| 51 | scm_version.force_encoding('ASCII-8BIT')
|
||
| 52 | end
|
||
| 53 | if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)}m) |
||
| 54 | m[2].scan(%r{\d+}).collect(&:to_i) |
||
| 55 | end
|
||
| 56 | end
|
||
| 57 | |||
| 58 | def scm_version_from_command_line |
||
| 59 | shellout("#{sq_bin} --version") { |io| io.read }.to_s
|
||
| 60 | end
|
||
| 61 | end
|
||
| 62 | |||
| 63 | 0:513646585e45 | Chris | # Guidelines for the input:
|
| 64 | 441:cbce1fd3b1b7 | Chris | # url -> the project-path, relative to the cvsroot (eg. module name)
|
| 65 | 0:513646585e45 | Chris | # root_url -> the good old, sometimes damned, CVSROOT
|
| 66 | 441:cbce1fd3b1b7 | Chris | # login -> unnecessary
|
| 67 | 0:513646585e45 | Chris | # password -> unnecessary too
|
| 68 | 245:051f544170fe | Chris | def initialize(url, root_url=nil, login=nil, password=nil, |
| 69 | path_encoding=nil)
|
||
| 70 | 441:cbce1fd3b1b7 | Chris | @path_encoding = path_encoding.blank? ? 'UTF-8' : path_encoding |
| 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? |
||
| 78 | 0:513646585e45 | Chris | @password = (password || "") if @login |
| 79 | end
|
||
| 80 | 245:051f544170fe | Chris | |
| 81 | 441:cbce1fd3b1b7 | Chris | def path_encoding |
| 82 | @path_encoding
|
||
| 83 | 0:513646585e45 | Chris | end
|
| 84 | 245:051f544170fe | Chris | |
| 85 | 0:513646585e45 | Chris | def info |
| 86 | logger.debug "<cvs> info"
|
||
| 87 | Info.new({:root_url => @root_url, :lastrev => nil}) |
||
| 88 | end
|
||
| 89 | 245:051f544170fe | Chris | |
| 90 | 0:513646585e45 | Chris | def get_previous_revision(revision) |
| 91 | CvsRevisionHelper.new(revision).prevRev
|
||
| 92 | end
|
||
| 93 | 245:051f544170fe | Chris | |
| 94 | 0:513646585e45 | Chris | # Returns an Entries collection
|
| 95 | # or nil if the given path doesn't exist in the repository
|
||
| 96 | # this method is used by the repository-browser (aka LIST)
|
||
| 97 | 441:cbce1fd3b1b7 | Chris | def entries(path=nil, identifier=nil, options={}) |
| 98 | 0:513646585e45 | Chris | logger.debug "<cvs> entries '#{path}' with identifier '#{identifier}'"
|
| 99 | 441:cbce1fd3b1b7 | Chris | path_locale = scm_iconv(@path_encoding, 'UTF-8', path) |
| 100 | path_locale.force_encoding("ASCII-8BIT") if path_locale.respond_to?(:force_encoding) |
||
| 101 | 0:513646585e45 | Chris | entries = Entries.new
|
| 102 | 441:cbce1fd3b1b7 | Chris | cmd_args = %w|-q rls -e|
|
| 103 | cmd_args << "-D" << time_to_cvstime_rlog(identifier) if identifier |
||
| 104 | cmd_args << path_with_proj(path) |
||
| 105 | scm_cmd(*cmd_args) do |io|
|
||
| 106 | io.each_line() do |line|
|
||
| 107 | fields = line.chop.split('/',-1) |
||
| 108 | 0:513646585e45 | Chris | logger.debug(">>InspectLine #{fields.inspect}")
|
| 109 | if fields[0]!="D" |
||
| 110 | 441:cbce1fd3b1b7 | Chris | 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]), |
||
| 123 | 0:513646585e45 | Chris | #:path => fields[-4].include?(path)?fields[-4]:(path + "/"+ fields[-4]),
|
| 124 | 441:cbce1fd3b1b7 | Chris | :path => scm_iconv('UTF-8', @path_encoding, "#{path_locale}/#{fields[-5]}"), |
| 125 | 0:513646585e45 | Chris | :kind => 'file', |
| 126 | :size => nil, |
||
| 127 | 441:cbce1fd3b1b7 | Chris | :lastrev => Revision.new( |
| 128 | {
|
||
| 129 | :revision => fields[-4], |
||
| 130 | :name => scm_iconv('UTF-8', @path_encoding, fields[-4]), |
||
| 131 | :time => time,
|
||
| 132 | :author => '' |
||
| 133 | }) |
||
| 134 | 0:513646585e45 | Chris | }) |
| 135 | else
|
||
| 136 | 441:cbce1fd3b1b7 | Chris | entries << Entry.new(
|
| 137 | {
|
||
| 138 | :name => scm_iconv('UTF-8', @path_encoding, fields[1]), |
||
| 139 | :path => scm_iconv('UTF-8', @path_encoding, "#{path_locale}/#{fields[1]}"), |
||
| 140 | :kind => 'dir', |
||
| 141 | :size => nil, |
||
| 142 | 0:513646585e45 | Chris | :lastrev => nil |
| 143 | 441:cbce1fd3b1b7 | Chris | }) |
| 144 | 0:513646585e45 | Chris | end
|
| 145 | 441:cbce1fd3b1b7 | Chris | end
|
| 146 | 0:513646585e45 | Chris | end
|
| 147 | entries.sort_by_name |
||
| 148 | 441:cbce1fd3b1b7 | Chris | rescue ScmCommandAborted |
| 149 | nil
|
||
| 150 | 245:051f544170fe | Chris | end
|
| 151 | 0:513646585e45 | Chris | |
| 152 | STARTLOG="----------------------------" |
||
| 153 | ENDLOG ="=============================================================================" |
||
| 154 | 245:051f544170fe | Chris | |
| 155 | 0:513646585e45 | Chris | # Returns all revisions found between identifier_from and identifier_to
|
| 156 | # in the repository. both identifier have to be dates or nil.
|
||
| 157 | # these method returns nothing but yield every result in block
|
||
| 158 | def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}, &block) |
||
| 159 | 441:cbce1fd3b1b7 | Chris | path_with_project_utf8 = path_with_proj(path) |
| 160 | path_with_project_locale = scm_iconv(@path_encoding, 'UTF-8', path_with_project_utf8) |
||
| 161 | logger.debug "<cvs> revisions path:" +
|
||
| 162 | "'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}"
|
||
| 163 | cmd_args = %w|-q rlog|
|
||
| 164 | cmd_args << "-d" << ">#{time_to_cvstime_rlog(identifier_from)}" if identifier_from |
||
| 165 | cmd_args << path_with_project_utf8 |
||
| 166 | scm_cmd(*cmd_args) do |io|
|
||
| 167 | state = "entry_start"
|
||
| 168 | commit_log = String.new
|
||
| 169 | revision = nil
|
||
| 170 | date = nil
|
||
| 171 | author = nil
|
||
| 172 | entry_path = nil
|
||
| 173 | entry_name = nil
|
||
| 174 | file_state = nil
|
||
| 175 | branch_map = nil
|
||
| 176 | 245:051f544170fe | Chris | io.each_line() do |line|
|
| 177 | 441:cbce1fd3b1b7 | Chris | if state != "revision" && /^#{ENDLOG}/ =~ line |
| 178 | commit_log = String.new
|
||
| 179 | revision = nil
|
||
| 180 | state = "entry_start"
|
||
| 181 | 0:513646585e45 | Chris | end
|
| 182 | 441:cbce1fd3b1b7 | Chris | if state == "entry_start" |
| 183 | branch_map = Hash.new
|
||
| 184 | if /^RCS file: #{Regexp.escape(root_url_path)}\/#{Regexp.escape(path_with_project_locale)}(.+),v$/ =~ line |
||
| 185 | 0:513646585e45 | Chris | entry_path = normalize_cvs_path($1)
|
| 186 | entry_name = normalize_path(File.basename($1)) |
||
| 187 | logger.debug("Path #{entry_path} <=> Name #{entry_name}")
|
||
| 188 | elsif /^head: (.+)$/ =~ line |
||
| 189 | entry_headRev = $1 #unless entry.nil? |
||
| 190 | elsif /^symbolic names:/ =~ line |
||
| 191 | 441:cbce1fd3b1b7 | Chris | state = "symbolic" #unless entry.nil? |
| 192 | 0:513646585e45 | Chris | elsif /^#{STARTLOG}/ =~ line |
| 193 | 441:cbce1fd3b1b7 | Chris | commit_log = String.new
|
| 194 | state = "revision"
|
||
| 195 | end
|
||
| 196 | 0:513646585e45 | Chris | next
|
| 197 | 441:cbce1fd3b1b7 | Chris | elsif state == "symbolic" |
| 198 | if /^(.*):\s(.*)/ =~ (line.strip) |
||
| 199 | branch_map[$1] = $2 |
||
| 200 | 0:513646585e45 | Chris | else
|
| 201 | 441:cbce1fd3b1b7 | Chris | state = "tags"
|
| 202 | 0:513646585e45 | Chris | next
|
| 203 | 441:cbce1fd3b1b7 | Chris | end
|
| 204 | elsif state == "tags" |
||
| 205 | 0:513646585e45 | Chris | if /^#{STARTLOG}/ =~ line |
| 206 | commit_log = ""
|
||
| 207 | 441:cbce1fd3b1b7 | Chris | state = "revision"
|
| 208 | 0:513646585e45 | Chris | elsif /^#{ENDLOG}/ =~ line |
| 209 | 441:cbce1fd3b1b7 | Chris | state = "head"
|
| 210 | 0:513646585e45 | Chris | end
|
| 211 | next
|
||
| 212 | 441:cbce1fd3b1b7 | Chris | elsif state == "revision" |
| 213 | 245:051f544170fe | Chris | if /^#{ENDLOG}/ =~ line || /^#{STARTLOG}/ =~ line |
| 214 | 0:513646585e45 | Chris | if revision
|
| 215 | 441:cbce1fd3b1b7 | Chris | revHelper = CvsRevisionHelper.new(revision)
|
| 216 | revBranch = "HEAD"
|
||
| 217 | branch_map.each() do |branch_name, branch_point|
|
||
| 218 | 0:513646585e45 | Chris | if revHelper.is_in_branch_with_symbol(branch_point)
|
| 219 | 441:cbce1fd3b1b7 | Chris | revBranch = branch_name |
| 220 | 0:513646585e45 | Chris | end
|
| 221 | end
|
||
| 222 | logger.debug("********** YIELD Revision #{revision}::#{revBranch}")
|
||
| 223 | 245:051f544170fe | Chris | yield Revision.new({ |
| 224 | 441:cbce1fd3b1b7 | Chris | :time => date,
|
| 225 | :author => author,
|
||
| 226 | :message => commit_log.chomp,
|
||
| 227 | 0:513646585e45 | Chris | :paths => [{
|
| 228 | :revision => revision,
|
||
| 229 | 441:cbce1fd3b1b7 | Chris | :branch => revBranch,
|
| 230 | :path => scm_iconv('UTF-8', @path_encoding, entry_path), |
||
| 231 | :name => scm_iconv('UTF-8', @path_encoding, entry_name), |
||
| 232 | :kind => 'file', |
||
| 233 | :action => file_state
|
||
| 234 | }] |
||
| 235 | }) |
||
| 236 | 0:513646585e45 | Chris | end
|
| 237 | 441:cbce1fd3b1b7 | Chris | commit_log = String.new
|
| 238 | revision = nil
|
||
| 239 | 0:513646585e45 | Chris | if /^#{ENDLOG}/ =~ line |
| 240 | 441:cbce1fd3b1b7 | Chris | state = "entry_start"
|
| 241 | 0:513646585e45 | Chris | end
|
| 242 | next
|
||
| 243 | end
|
||
| 244 | 245:051f544170fe | Chris | |
| 245 | 0:513646585e45 | Chris | if /^branches: (.+)$/ =~ line |
| 246 | 441:cbce1fd3b1b7 | Chris | # TODO: version.branch = $1
|
| 247 | 0:513646585e45 | Chris | elsif /^revision (\d+(?:\.\d+)+).*$/ =~ line |
| 248 | 441:cbce1fd3b1b7 | Chris | revision = $1
|
| 249 | 0:513646585e45 | Chris | elsif /^date:\s+(\d+.\d+.\d+\s+\d+:\d+:\d+)/ =~ line |
| 250 | 441:cbce1fd3b1b7 | Chris | date = Time.parse($1) |
| 251 | line_utf8 = scm_iconv('UTF-8', options[:log_encoding], line) |
||
| 252 | author_utf8 = /author: ([^;]+)/.match(line_utf8)[1] |
||
| 253 | author = scm_iconv(options[:log_encoding], 'UTF-8', author_utf8) |
||
| 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
|
||
| 259 | 0:513646585e45 | Chris | # linechanges =/lines: \+(\d+) -(\d+)/.match(line)
|
| 260 | # unless linechanges.nil?
|
||
| 261 | # version.line_plus = linechanges[1]
|
||
| 262 | # version.line_minus = linechanges[2]
|
||
| 263 | # else
|
||
| 264 | # version.line_plus = 0
|
||
| 265 | 245:051f544170fe | Chris | # version.line_minus = 0
|
| 266 | # end
|
||
| 267 | else
|
||
| 268 | 0:513646585e45 | Chris | commit_log << line unless line =~ /^\*\*\* empty log message \*\*\*/ |
| 269 | 245:051f544170fe | Chris | end
|
| 270 | end
|
||
| 271 | 0:513646585e45 | Chris | end
|
| 272 | end
|
||
| 273 | 441:cbce1fd3b1b7 | Chris | rescue ScmCommandAborted |
| 274 | Revisions.new
|
||
| 275 | 245:051f544170fe | Chris | end
|
| 276 | |||
| 277 | 0:513646585e45 | Chris | def diff(path, identifier_from, identifier_to=nil) |
| 278 | 441:cbce1fd3b1b7 | Chris | logger.debug "<cvs> diff path:'#{path}'" +
|
| 279 | ",identifier_from #{identifier_from}, identifier_to #{identifier_to}"
|
||
| 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) |
||
| 284 | 0:513646585e45 | Chris | diff = [] |
| 285 | 441:cbce1fd3b1b7 | Chris | scm_cmd(*cmd_args) do |io|
|
| 286 | 0:513646585e45 | Chris | io.each_line do |line|
|
| 287 | diff << line |
||
| 288 | end
|
||
| 289 | end
|
||
| 290 | diff |
||
| 291 | 441:cbce1fd3b1b7 | Chris | rescue ScmCommandAborted |
| 292 | nil
|
||
| 293 | 245:051f544170fe | Chris | end
|
| 294 | |||
| 295 | 0:513646585e45 | Chris | def cat(path, identifier=nil) |
| 296 | identifier = (identifier) ? identifier : "HEAD"
|
||
| 297 | logger.debug "<cvs> cat path:'#{path}',identifier #{identifier}"
|
||
| 298 | 441:cbce1fd3b1b7 | Chris | cmd_args = %w|-q co|
|
| 299 | cmd_args << "-D" << time_to_cvstime(identifier) if identifier |
||
| 300 | cmd_args << "-p" << path_with_proj(path)
|
||
| 301 | 0:513646585e45 | Chris | cat = nil
|
| 302 | 441:cbce1fd3b1b7 | Chris | scm_cmd(*cmd_args) do |io|
|
| 303 | 245:051f544170fe | Chris | io.binmode |
| 304 | 0:513646585e45 | Chris | cat = io.read |
| 305 | end
|
||
| 306 | cat |
||
| 307 | 441:cbce1fd3b1b7 | Chris | rescue ScmCommandAborted |
| 308 | nil
|
||
| 309 | 245:051f544170fe | Chris | end
|
| 310 | 0:513646585e45 | Chris | |
| 311 | def annotate(path, identifier=nil) |
||
| 312 | 441:cbce1fd3b1b7 | Chris | identifier = (identifier) ? identifier : "HEAD"
|
| 313 | 0:513646585e45 | Chris | logger.debug "<cvs> annotate path:'#{path}',identifier #{identifier}"
|
| 314 | 441:cbce1fd3b1b7 | Chris | cmd_args = %w|rannotate|
|
| 315 | cmd_args << "-D" << time_to_cvstime(identifier) if identifier |
||
| 316 | cmd_args << path_with_proj(path) |
||
| 317 | 0:513646585e45 | Chris | blame = Annotate.new
|
| 318 | 441:cbce1fd3b1b7 | Chris | scm_cmd(*cmd_args) do |io|
|
| 319 | 0:513646585e45 | Chris | io.each_line do |line|
|
| 320 | next unless line =~ %r{^([\d\.]+)\s+\(([^\)]+)\s+[^\)]+\):\s(.*)$} |
||
| 321 | 441:cbce1fd3b1b7 | Chris | blame.add_line( |
| 322 | $3.rstrip,
|
||
| 323 | Revision.new(
|
||
| 324 | :revision => $1, |
||
| 325 | :identifier => nil, |
||
| 326 | :author => $2.strip |
||
| 327 | )) |
||
| 328 | 0:513646585e45 | Chris | end
|
| 329 | end
|
||
| 330 | blame |
||
| 331 | 441:cbce1fd3b1b7 | Chris | rescue ScmCommandAborted |
| 332 | Annotate.new
|
||
| 333 | 0:513646585e45 | Chris | end
|
| 334 | 245:051f544170fe | Chris | |
| 335 | 0:513646585e45 | Chris | private |
| 336 | 245:051f544170fe | Chris | |
| 337 | 0:513646585e45 | Chris | # Returns the root url without the connexion string
|
| 338 | # :pserver:anonymous@foo.bar:/path => /path
|
||
| 339 | # :ext:cvsservername:/path => /path
|
||
| 340 | def root_url_path |
||
| 341 | root_url.to_s.gsub(/^:.+:\d*/, '') |
||
| 342 | end
|
||
| 343 | |||
| 344 | # convert a date/time into the CVS-format
|
||
| 345 | def time_to_cvstime(time) |
||
| 346 | return nil if time.nil? |
||
| 347 | 441:cbce1fd3b1b7 | Chris | time = Time.now if time == 'HEAD' |
| 348 | |||
| 349 | 0:513646585e45 | Chris | unless time.kind_of? Time |
| 350 | time = Time.parse(time)
|
||
| 351 | end
|
||
| 352 | 441:cbce1fd3b1b7 | Chris | return time_to_cvstime_rlog(time)
|
| 353 | 0:513646585e45 | Chris | end
|
| 354 | 210:0579821a129a | Chris | |
| 355 | def time_to_cvstime_rlog(time) |
||
| 356 | return nil if time.nil? |
||
| 357 | t1 = time.clone.localtime |
||
| 358 | return t1.strftime("%Y-%m-%d %H:%M:%S") |
||
| 359 | end
|
||
| 360 | 441:cbce1fd3b1b7 | Chris | |
| 361 | 0:513646585e45 | Chris | def normalize_cvs_path(path) |
| 362 | normalize_path(path.gsub(/Attic\//,'')) |
||
| 363 | end
|
||
| 364 | 441:cbce1fd3b1b7 | Chris | |
| 365 | 0:513646585e45 | Chris | def normalize_path(path) |
| 366 | path.sub(/^(\/)*(.*)/,'\2').sub(/(.*)(,v)+/,'\1') |
||
| 367 | 441:cbce1fd3b1b7 | Chris | end
|
| 368 | |||
| 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 | |||
| 397 | 0:513646585e45 | Chris | class CvsRevisionHelper |
| 398 | attr_accessor :complete_rev, :revision, :base, :branchid |
||
| 399 | 441:cbce1fd3b1b7 | Chris | |
| 400 | 0:513646585e45 | Chris | def initialize(complete_rev) |
| 401 | @complete_rev = complete_rev
|
||
| 402 | parseRevision() |
||
| 403 | end
|
||
| 404 | 441:cbce1fd3b1b7 | Chris | |
| 405 | 0:513646585e45 | Chris | def branchPoint |
| 406 | return @base |
||
| 407 | end
|
||
| 408 | 441:cbce1fd3b1b7 | Chris | |
| 409 | 0:513646585e45 | Chris | def branchVersion |
| 410 | if isBranchRevision
|
||
| 411 | return @base+"."+@branchid |
||
| 412 | end
|
||
| 413 | return @base |
||
| 414 | end
|
||
| 415 | 441:cbce1fd3b1b7 | Chris | |
| 416 | 0:513646585e45 | Chris | def isBranchRevision |
| 417 | !@branchid.nil?
|
||
| 418 | end
|
||
| 419 | 441:cbce1fd3b1b7 | Chris | |
| 420 | 0:513646585e45 | Chris | def prevRev |
| 421 | 441:cbce1fd3b1b7 | Chris | unless @revision == 0 |
| 422 | return buildRevision( @revision - 1 ) |
||
| 423 | 0:513646585e45 | Chris | end
|
| 424 | 441:cbce1fd3b1b7 | Chris | return buildRevision( @revision ) |
| 425 | 0:513646585e45 | Chris | end
|
| 426 | 441:cbce1fd3b1b7 | Chris | |
| 427 | 0:513646585e45 | Chris | def is_in_branch_with_symbol(branch_symbol) |
| 428 | 441:cbce1fd3b1b7 | Chris | bpieces = branch_symbol.split(".")
|
| 429 | branch_start = "#{bpieces[0..-3].join(".")}.#{bpieces[-1]}"
|
||
| 430 | return ( branchVersion == branch_start )
|
||
| 431 | 0:513646585e45 | Chris | end
|
| 432 | 441:cbce1fd3b1b7 | Chris | |
| 433 | 0:513646585e45 | Chris | private |
| 434 | def buildRevision(rev) |
||
| 435 | 441:cbce1fd3b1b7 | Chris | if rev == 0 |
| 436 | 245:051f544170fe | Chris | if @branchid.nil? |
| 437 | 441:cbce1fd3b1b7 | Chris | @base + ".0" |
| 438 | 245:051f544170fe | Chris | else
|
| 439 | @base
|
||
| 440 | end
|
||
| 441 | 441:cbce1fd3b1b7 | Chris | elsif @branchid.nil? |
| 442 | @base + "." + rev.to_s |
||
| 443 | 0:513646585e45 | Chris | else
|
| 444 | 441:cbce1fd3b1b7 | Chris | @base + "." + @branchid + "." + rev.to_s |
| 445 | 0:513646585e45 | Chris | end
|
| 446 | end
|
||
| 447 | 441:cbce1fd3b1b7 | Chris | |
| 448 | 0:513646585e45 | Chris | # Interpretiert die cvs revisionsnummern wie z.b. 1.14 oder 1.3.0.15
|
| 449 | def parseRevision() |
||
| 450 | 441:cbce1fd3b1b7 | Chris | pieces = @complete_rev.split(".") |
| 451 | @revision = pieces.last.to_i
|
||
| 452 | baseSize = 1
|
||
| 453 | baseSize += (pieces.size / 2)
|
||
| 454 | @base = pieces[0..-baseSize].join(".") |
||
| 455 | 0:513646585e45 | Chris | if baseSize > 2 |
| 456 | 441:cbce1fd3b1b7 | Chris | @branchid = pieces[-2] |
| 457 | end
|
||
| 458 | 0:513646585e45 | Chris | end
|
| 459 | end
|
||
| 460 | end
|
||
| 461 | end
|
||
| 462 | end |