| 
									
										
										
										
											2019-03-17 16:36:34 +00:00
										 |  |  | # frozen_string_literal: true | 
					
						
							| 
									
										
										
										
											2019-03-15 01:32:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  | # redMine - project management software | 
					
						
							| 
									
										
										
										
											2020-03-03 00:24:10 +00:00
										 |  |  | # Copyright (C) 2006-2020  Jean-Philippe Lang | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  | # | 
					
						
							|  |  |  | # This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  | # modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  | # as published by the Free Software Foundation; either version 2 | 
					
						
							|  |  |  | # of the License, or (at your option) any later version. | 
					
						
							| 
									
										
										
										
											2011-04-12 06:53:08 +00:00
										 |  |  | # | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  | # This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  | # GNU General Public License for more details. | 
					
						
							| 
									
										
										
										
											2011-04-12 06:53:08 +00:00
										 |  |  | # | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  | # You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | # along with this program; if not, write to the Free Software | 
					
						
							|  |  |  | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | require 'redmine/scm/adapters/abstract_adapter' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module Redmine | 
					
						
							|  |  |  |   module Scm | 
					
						
							|  |  |  |     module Adapters | 
					
						
							|  |  |  |       class CvsAdapter < AbstractAdapter | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # CVS executable name | 
					
						
							| 
									
										
										
										
											2011-02-04 10:24:10 +00:00
										 |  |  |         CVS_BIN = Redmine::Configuration['scm_cvs_command'] || "cvs" | 
					
						
							| 
									
										
										
										
											2011-02-14 06:14:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         class << self | 
					
						
							|  |  |  |           def client_command | 
					
						
							|  |  |  |             @@bin    ||= CVS_BIN | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           def sq_bin | 
					
						
							| 
									
										
										
										
											2011-07-15 16:30:07 +00:00
										 |  |  |             @@sq_bin ||= shell_quote_command | 
					
						
							| 
									
										
										
										
											2011-02-14 06:14:34 +00:00
										 |  |  |           end | 
					
						
							| 
									
										
										
										
											2011-02-15 08:04:11 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |           def client_version | 
					
						
							|  |  |  |             @@client_version ||= (scm_command_version || []) | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           def client_available | 
					
						
							| 
									
										
										
										
											2011-02-15 11:05:13 +00:00
										 |  |  |             client_version_above?([1, 12]) | 
					
						
							| 
									
										
										
										
											2011-02-15 08:04:11 +00:00
										 |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           def scm_command_version | 
					
						
							| 
									
										
										
										
											2019-03-20 01:36:44 +00:00
										 |  |  |             scm_version = scm_version_from_command_line.b | 
					
						
							| 
									
										
										
										
											2011-02-15 08:04:11 +00:00
										 |  |  |             if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)}m) | 
					
						
							|  |  |  |               m[2].scan(%r{\d+}).collect(&:to_i) | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           def scm_version_from_command_line | 
					
						
							| 
									
										
										
										
											2020-11-20 11:36:14 +00:00
										 |  |  |             shellout("#{sq_bin} --version") {|io| io.read}.to_s | 
					
						
							| 
									
										
										
										
											2011-02-15 08:04:11 +00:00
										 |  |  |           end | 
					
						
							| 
									
										
										
										
											2011-02-14 06:14:34 +00:00
										 |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         # Guidelines for the input: | 
					
						
							| 
									
										
										
										
											2011-04-10 12:27:53 +00:00
										 |  |  |         #  url      -> the project-path, relative to the cvsroot (eg. module name) | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         #  root_url -> the good old, sometimes damned, CVSROOT | 
					
						
							| 
									
										
										
										
											2011-04-10 12:27:53 +00:00
										 |  |  |         #  login    -> unnecessary | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         #  password -> unnecessary too | 
					
						
							| 
									
										
										
										
											2011-02-24 05:58:59 +00:00
										 |  |  |         def initialize(url, root_url=nil, login=nil, password=nil, | 
					
						
							|  |  |  |                        path_encoding=nil) | 
					
						
							| 
									
										
										
										
											2019-09-24 15:41:39 +00:00
										 |  |  |           @path_encoding = path_encoding.presence || 'UTF-8' | 
					
						
							| 
									
										
										
										
											2011-04-10 12:27:53 +00:00
										 |  |  |           @url      = url | 
					
						
							| 
									
										
										
										
											2011-04-10 08:10:57 +00:00
										 |  |  |           # TODO: better Exception here (IllegalArgumentException) | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |           raise CommandFailed if root_url.blank? | 
					
						
							| 
									
										
										
										
											2020-11-30 15:49:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-10 12:27:53 +00:00
										 |  |  |           @root_url  = root_url | 
					
						
							| 
									
										
										
										
											2011-04-12 06:53:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |           # These are unused. | 
					
						
							|  |  |  |           @login    = login if login && !login.empty? | 
					
						
							|  |  |  |           @password = (password || "") if @login | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2011-02-14 06:14:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-21 02:18:53 +00:00
										 |  |  |         def path_encoding | 
					
						
							|  |  |  |           @path_encoding | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         def info | 
					
						
							|  |  |  |           logger.debug "<cvs> info" | 
					
						
							|  |  |  |           Info.new({:root_url => @root_url, :lastrev => nil}) | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2011-02-14 06:14:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         def get_previous_revision(revision) | 
					
						
							|  |  |  |           CvsRevisionHelper.new(revision).prevRev | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2011-02-11 15:29:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         # Returns an Entries collection | 
					
						
							|  |  |  |         # or nil if the given path doesn't exist in the repository | 
					
						
							|  |  |  |         # this method is used by the repository-browser (aka LIST) | 
					
						
							| 
									
										
										
										
											2011-05-04 14:11:25 +00:00
										 |  |  |         def entries(path=nil, identifier=nil, options={}) | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |           logger.debug "<cvs> entries '#{path}' with identifier '#{identifier}'" | 
					
						
							| 
									
										
										
										
											2011-04-15 07:17:26 +00:00
										 |  |  |           path_locale = scm_iconv(@path_encoding, 'UTF-8', path) | 
					
						
							| 
									
										
										
										
											2019-03-20 01:36:44 +00:00
										 |  |  |           path_locale = path_locale.b | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |           entries = Entries.new | 
					
						
							| 
									
										
										
										
											2011-04-11 07:02:13 +00:00
										 |  |  |           cmd_args = %w|-q rls -e| | 
					
						
							| 
									
										
										
										
											2011-03-11 04:19:12 +00:00
										 |  |  |           cmd_args << "-D" << time_to_cvstime_rlog(identifier) if identifier | 
					
						
							| 
									
										
										
										
											2011-04-12 10:31:33 +00:00
										 |  |  |           cmd_args << path_with_proj(path) | 
					
						
							| 
									
										
										
										
											2011-03-11 00:42:59 +00:00
										 |  |  |           scm_cmd(*cmd_args) do |io| | 
					
						
							| 
									
										
										
										
											2011-03-11 01:48:36 +00:00
										 |  |  |             io.each_line() do |line| | 
					
						
							|  |  |  |               fields = line.chop.split('/',-1) | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |               logger.debug(">>InspectLine #{fields.inspect}") | 
					
						
							|  |  |  |               if fields[0]!="D" | 
					
						
							| 
									
										
										
										
											2011-03-11 04:19:33 +00:00
										 |  |  |                 time = nil | 
					
						
							|  |  |  |                 # Thu Dec 13 16:27:22 2007 | 
					
						
							|  |  |  |                 time_l = fields[-3].split(' ') | 
					
						
							|  |  |  |                 if time_l.size == 5 && time_l[4].length == 4
 | 
					
						
							|  |  |  |                   begin | 
					
						
							| 
									
										
										
										
											2020-12-12 15:49:51 +00:00
										 |  |  |                     time = | 
					
						
							|  |  |  |                       Time.parse( | 
					
						
							|  |  |  |                         "#{time_l[1]} #{time_l[2]} #{time_l[3]} GMT #{time_l[4]}" | 
					
						
							|  |  |  |                       ) | 
					
						
							| 
									
										
										
										
											2011-03-11 04:19:33 +00:00
										 |  |  |                   rescue | 
					
						
							|  |  |  |                   end | 
					
						
							|  |  |  |                 end | 
					
						
							| 
									
										
										
										
											2020-12-12 15:49:51 +00:00
										 |  |  |                 entries << | 
					
						
							|  |  |  |                   Entry.new( | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                       :name => scm_iconv('UTF-8', @path_encoding, fields[-5]), | 
					
						
							|  |  |  |                       #:path => fields[-4].include?(path)?fields[-4]:(path + "/"+ fields[-4]), | 
					
						
							|  |  |  |                       :path => scm_iconv('UTF-8', @path_encoding, "#{path_locale}/#{fields[-5]}"), | 
					
						
							|  |  |  |                       :kind => 'file', | 
					
						
							|  |  |  |                       :size => nil, | 
					
						
							|  |  |  |                       :lastrev => | 
					
						
							|  |  |  |                         Revision.new( | 
					
						
							|  |  |  |                           { | 
					
						
							|  |  |  |                             :revision => fields[-4], | 
					
						
							|  |  |  |                             :name     => scm_iconv('UTF-8', @path_encoding, fields[-4]), | 
					
						
							|  |  |  |                             :time     => time, | 
					
						
							|  |  |  |                             :author   => '' | 
					
						
							|  |  |  |                           } | 
					
						
							|  |  |  |                         ) | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                   ) | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |               else | 
					
						
							| 
									
										
										
										
											2020-12-12 15:49:51 +00:00
										 |  |  |                 entries << | 
					
						
							|  |  |  |                   Entry.new( | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                       :name    => scm_iconv('UTF-8', @path_encoding, fields[1]), | 
					
						
							|  |  |  |                       :path    => scm_iconv('UTF-8', @path_encoding, "#{path_locale}/#{fields[1]}"), | 
					
						
							|  |  |  |                       :kind    => 'dir', | 
					
						
							|  |  |  |                       :size    => nil, | 
					
						
							|  |  |  |                       :lastrev => nil | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                   ) | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |               end | 
					
						
							| 
									
										
										
										
											2011-03-11 01:48:36 +00:00
										 |  |  |             end | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |           end | 
					
						
							|  |  |  |           entries.sort_by_name | 
					
						
							| 
									
										
										
										
											2011-03-11 00:42:59 +00:00
										 |  |  |         rescue ScmCommandAborted | 
					
						
							|  |  |  |           nil | 
					
						
							| 
									
										
										
										
											2011-02-11 15:29:56 +00:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         STARTLOG="----------------------------" | 
					
						
							|  |  |  |         ENDLOG  ="=============================================================================" | 
					
						
							| 
									
										
										
										
											2011-02-11 15:29:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         # Returns all revisions found between identifier_from and identifier_to | 
					
						
							|  |  |  |         # in the repository. both identifier have to be dates or nil. | 
					
						
							|  |  |  |         # these method returns nothing but yield every result in block | 
					
						
							|  |  |  |         def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}, &block) | 
					
						
							| 
									
										
										
										
											2011-04-15 07:16:48 +00:00
										 |  |  |           path_with_project_utf8   = path_with_proj(path) | 
					
						
							|  |  |  |           path_with_project_locale = scm_iconv(@path_encoding, 'UTF-8', path_with_project_utf8) | 
					
						
							| 
									
										
										
										
											2011-04-10 12:27:53 +00:00
										 |  |  |           logger.debug "<cvs> revisions path:" + | 
					
						
							|  |  |  |               "'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}" | 
					
						
							| 
									
										
										
										
											2011-04-11 06:51:41 +00:00
										 |  |  |           cmd_args = %w|-q rlog| | 
					
						
							| 
									
										
										
										
											2011-04-12 06:53:08 +00:00
										 |  |  |           cmd_args << "-d" << ">#{time_to_cvstime_rlog(identifier_from)}" if identifier_from | 
					
						
							| 
									
										
										
										
											2011-04-15 07:16:48 +00:00
										 |  |  |           cmd_args << path_with_project_utf8 | 
					
						
							| 
									
										
										
										
											2011-03-11 01:48:18 +00:00
										 |  |  |           scm_cmd(*cmd_args) do |io| | 
					
						
							| 
									
										
										
										
											2011-04-10 08:10:57 +00:00
										 |  |  |             state      = "entry_start" | 
					
						
							| 
									
										
										
										
											2019-03-17 16:36:34 +00:00
										 |  |  |             commit_log = "" | 
					
						
							| 
									
										
										
										
											2011-04-10 08:10:57 +00:00
										 |  |  |             revision   = nil | 
					
						
							|  |  |  |             date       = nil | 
					
						
							|  |  |  |             author     = nil | 
					
						
							|  |  |  |             entry_path = nil | 
					
						
							|  |  |  |             entry_name = nil | 
					
						
							|  |  |  |             file_state = nil | 
					
						
							|  |  |  |             branch_map = nil | 
					
						
							| 
									
										
										
										
											2011-02-11 15:29:56 +00:00
										 |  |  |             io.each_line() do |line| | 
					
						
							| 
									
										
										
										
											2019-03-27 02:15:24 +00:00
										 |  |  |               if state != "revision" && /^#{ENDLOG}/.match?(line) | 
					
						
							| 
									
										
										
										
											2019-03-17 16:36:34 +00:00
										 |  |  |                 commit_log = "" | 
					
						
							| 
									
										
										
										
											2011-04-10 08:10:57 +00:00
										 |  |  |                 revision   = nil | 
					
						
							|  |  |  |                 state      = "entry_start" | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |               end | 
					
						
							| 
									
										
										
										
											2011-04-13 11:54:06 +00:00
										 |  |  |               if state == "entry_start" | 
					
						
							| 
									
										
										
										
											2019-09-24 02:34:32 +00:00
										 |  |  |                 branch_map = {} | 
					
						
							| 
									
										
										
										
											2011-04-15 07:16:48 +00:00
										 |  |  |                 if /^RCS file: #{Regexp.escape(root_url_path)}\/#{Regexp.escape(path_with_project_locale)}(.+),v$/ =~ line | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |                   entry_path = normalize_cvs_path($1) | 
					
						
							|  |  |  |                   entry_name = normalize_path(File.basename($1)) | 
					
						
							|  |  |  |                   logger.debug("Path #{entry_path} <=> Name #{entry_name}") | 
					
						
							|  |  |  |                 elsif /^head: (.+)$/ =~ line | 
					
						
							| 
									
										
										
										
											2019-08-31 05:53:32 +00:00
										 |  |  |                   entry_headRev = $1 | 
					
						
							| 
									
										
										
										
											2019-03-27 02:15:24 +00:00
										 |  |  |                 elsif /^symbolic names:/.match?(line) | 
					
						
							| 
									
										
										
										
											2019-08-31 05:53:32 +00:00
										 |  |  |                   state = "symbolic" | 
					
						
							| 
									
										
										
										
											2019-03-27 02:15:24 +00:00
										 |  |  |                 elsif /^#{STARTLOG}/.match?(line) | 
					
						
							| 
									
										
										
										
											2019-03-17 16:36:34 +00:00
										 |  |  |                   commit_log = "" | 
					
						
							| 
									
										
										
										
											2011-04-10 12:27:53 +00:00
										 |  |  |                   state      = "revision" | 
					
						
							| 
									
										
										
										
											2011-04-12 06:53:08 +00:00
										 |  |  |                 end | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |                 next | 
					
						
							| 
									
										
										
										
											2011-04-13 11:54:06 +00:00
										 |  |  |               elsif state == "symbolic" | 
					
						
							| 
									
										
										
										
											2011-04-12 06:53:08 +00:00
										 |  |  |                 if /^(.*):\s(.*)/ =~ (line.strip) | 
					
						
							| 
									
										
										
										
											2011-04-13 11:54:06 +00:00
										 |  |  |                   branch_map[$1] = $2 | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |                 else | 
					
						
							| 
									
										
										
										
											2011-04-13 11:54:06 +00:00
										 |  |  |                   state = "tags" | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |                   next | 
					
						
							| 
									
										
										
										
											2011-04-12 06:53:08 +00:00
										 |  |  |                 end | 
					
						
							| 
									
										
										
										
											2011-04-13 11:54:06 +00:00
										 |  |  |               elsif state == "tags" | 
					
						
							| 
									
										
										
										
											2020-10-23 00:13:38 +00:00
										 |  |  |                 if /^#{STARTLOG}/.match?(line) | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |                   commit_log = "" | 
					
						
							| 
									
										
										
										
											2011-04-13 11:54:06 +00:00
										 |  |  |                   state = "revision" | 
					
						
							| 
									
										
										
										
											2020-10-23 00:13:38 +00:00
										 |  |  |                 elsif /^#{ENDLOG}/.match?(line) | 
					
						
							| 
									
										
										
										
											2011-04-13 11:54:06 +00:00
										 |  |  |                   state = "head" | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |                 end | 
					
						
							|  |  |  |                 next | 
					
						
							| 
									
										
										
										
											2011-04-13 11:54:06 +00:00
										 |  |  |               elsif state == "revision" | 
					
						
							| 
									
										
										
										
											2011-02-11 15:29:56 +00:00
										 |  |  |                 if /^#{ENDLOG}/ =~ line || /^#{STARTLOG}/ =~ line | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |                   if revision | 
					
						
							| 
									
										
										
										
											2011-04-11 04:18:55 +00:00
										 |  |  |                     revHelper = CvsRevisionHelper.new(revision) | 
					
						
							|  |  |  |                     revBranch = "HEAD" | 
					
						
							| 
									
										
										
										
											2011-04-10 12:27:53 +00:00
										 |  |  |                     branch_map.each() do |branch_name, branch_point| | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |                       if revHelper.is_in_branch_with_symbol(branch_point) | 
					
						
							| 
									
										
										
										
											2011-04-13 11:54:06 +00:00
										 |  |  |                         revBranch = branch_name | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |                       end | 
					
						
							|  |  |  |                     end | 
					
						
							|  |  |  |                     logger.debug("********** YIELD Revision #{revision}::#{revBranch}") | 
					
						
							| 
									
										
										
										
											2020-12-12 15:49:51 +00:00
										 |  |  |                     yield Revision.new( | 
					
						
							|  |  |  |                       { | 
					
						
							|  |  |  |                         :time    => date, | 
					
						
							|  |  |  |                         :author  => author, | 
					
						
							|  |  |  |                         :message => commit_log.chomp, | 
					
						
							|  |  |  |                         :paths => [ | 
					
						
							|  |  |  |                           { | 
					
						
							|  |  |  |                             :revision => revision.dup, | 
					
						
							|  |  |  |                             :branch   => revBranch.dup, | 
					
						
							|  |  |  |                             :path     => scm_iconv('UTF-8', @path_encoding, entry_path), | 
					
						
							|  |  |  |                             :name     => scm_iconv('UTF-8', @path_encoding, entry_name), | 
					
						
							|  |  |  |                             :kind     => 'file', | 
					
						
							|  |  |  |                             :action   => file_state | 
					
						
							|  |  |  |                           } | 
					
						
							|  |  |  |                         ] | 
					
						
							|  |  |  |                       } | 
					
						
							|  |  |  |                     ) | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |                   end | 
					
						
							| 
									
										
										
										
											2019-03-17 16:36:34 +00:00
										 |  |  |                   commit_log = "" | 
					
						
							| 
									
										
										
										
											2011-04-10 12:27:53 +00:00
										 |  |  |                   revision   = nil | 
					
						
							| 
									
										
										
										
											2020-10-23 00:13:38 +00:00
										 |  |  |                   if /^#{ENDLOG}/.match?(line) | 
					
						
							| 
									
										
										
										
											2011-04-11 04:18:55 +00:00
										 |  |  |                     state = "entry_start" | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |                   end | 
					
						
							|  |  |  |                   next | 
					
						
							|  |  |  |                 end | 
					
						
							| 
									
										
										
										
											2011-02-11 15:29:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-23 00:13:38 +00:00
										 |  |  |                 if /^branches: (.+)$/.match?(line) | 
					
						
							| 
									
										
										
										
											2011-04-11 04:18:55 +00:00
										 |  |  |                   # TODO: version.branch = $1 | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |                 elsif /^revision (\d+(?:\.\d+)+).*$/ =~ line | 
					
						
							| 
									
										
										
										
											2011-04-12 06:53:08 +00:00
										 |  |  |                   revision = $1 | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |                 elsif /^date:\s+(\d+.\d+.\d+\s+\d+:\d+:\d+)/ =~ line | 
					
						
							| 
									
										
										
										
											2019-08-31 05:53:42 +00:00
										 |  |  |                   date         = Time.parse($1) | 
					
						
							| 
									
										
										
										
											2011-04-14 15:39:00 +00:00
										 |  |  |                   line_utf8    = scm_iconv('UTF-8', options[:log_encoding], line) | 
					
						
							|  |  |  |                   author_utf8  = /author: ([^;]+)/.match(line_utf8)[1] | 
					
						
							|  |  |  |                   author       = scm_iconv(options[:log_encoding], 'UTF-8', author_utf8) | 
					
						
							|  |  |  |                   file_state   = /state: ([^;]+)/.match(line)[1] | 
					
						
							| 
									
										
										
										
											2019-09-20 17:54:42 +00:00
										 |  |  |                   # TODO: linechanges only available in CVS.... | 
					
						
							|  |  |  |                   #       maybe a feature our SVN implementation. | 
					
						
							|  |  |  |                   #       I'm sure, they are useful for stats or something else | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |                   #                linechanges =/lines: \+(\d+) -(\d+)/.match(line) | 
					
						
							|  |  |  |                   #                unless linechanges.nil? | 
					
						
							|  |  |  |                   #                  version.line_plus  = linechanges[1] | 
					
						
							|  |  |  |                   #                  version.line_minus = linechanges[2] | 
					
						
							|  |  |  |                   #                else | 
					
						
							|  |  |  |                   #                  version.line_plus  = 0 | 
					
						
							| 
									
										
										
										
											2011-02-11 15:29:56 +00:00
										 |  |  |                   #                  version.line_minus = 0 | 
					
						
							|  |  |  |                   #                end | 
					
						
							|  |  |  |                 else | 
					
						
							| 
									
										
										
										
											2020-10-23 00:13:38 +00:00
										 |  |  |                   commit_log += line unless /^\*\*\* empty log message \*\*\*/.match?(line) | 
					
						
							| 
									
										
										
										
											2011-02-11 15:29:56 +00:00
										 |  |  |                 end | 
					
						
							|  |  |  |               end | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |             end | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2011-03-11 01:48:18 +00:00
										 |  |  |         rescue ScmCommandAborted | 
					
						
							|  |  |  |           Revisions.new | 
					
						
							| 
									
										
										
										
											2011-02-11 15:29:56 +00:00
										 |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-08 16:28:42 +00:00
										 |  |  |         def diff(path, identifier_from, identifier_to=nil) | 
					
						
							| 
									
										
										
										
											2011-04-11 04:18:55 +00:00
										 |  |  |           logger.debug "<cvs> diff path:'#{path}'" + | 
					
						
							|  |  |  |               ",identifier_from #{identifier_from}, identifier_to #{identifier_to}" | 
					
						
							| 
									
										
										
										
											2011-04-11 05:53:35 +00:00
										 |  |  |           cmd_args = %w|rdiff -u| | 
					
						
							|  |  |  |           cmd_args << "-r#{identifier_to}" | 
					
						
							|  |  |  |           cmd_args << "-r#{identifier_from}" | 
					
						
							| 
									
										
										
										
											2011-04-12 10:31:33 +00:00
										 |  |  |           cmd_args << path_with_proj(path) | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |           diff = [] | 
					
						
							| 
									
										
										
										
											2011-04-11 05:53:35 +00:00
										 |  |  |           scm_cmd(*cmd_args) do |io| | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |             io.each_line do |line| | 
					
						
							|  |  |  |               diff << line | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2008-06-08 16:28:42 +00:00
										 |  |  |           diff | 
					
						
							| 
									
										
										
										
											2011-04-11 05:53:35 +00:00
										 |  |  |         rescue ScmCommandAborted | 
					
						
							|  |  |  |           nil | 
					
						
							| 
									
										
										
										
											2011-02-11 15:29:56 +00:00
										 |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         def cat(path, identifier=nil) | 
					
						
							|  |  |  |           identifier = (identifier) ? identifier : "HEAD" | 
					
						
							|  |  |  |           logger.debug "<cvs> cat path:'#{path}',identifier #{identifier}" | 
					
						
							| 
									
										
										
										
											2011-04-11 06:30:47 +00:00
										 |  |  |           cmd_args = %w|-q co| | 
					
						
							| 
									
										
										
										
											2011-04-12 10:31:33 +00:00
										 |  |  |           cmd_args << "-D" << time_to_cvstime(identifier) if identifier | 
					
						
							|  |  |  |           cmd_args << "-p" << path_with_proj(path) | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |           cat = nil | 
					
						
							| 
									
										
										
										
											2011-04-11 06:30:07 +00:00
										 |  |  |           scm_cmd(*cmd_args) do |io| | 
					
						
							| 
									
										
										
										
											2011-02-12 09:43:57 +00:00
										 |  |  |             io.binmode | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |             cat = io.read | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |           cat | 
					
						
							| 
									
										
										
										
											2011-04-11 06:30:07 +00:00
										 |  |  |         rescue ScmCommandAborted | 
					
						
							|  |  |  |           nil | 
					
						
							| 
									
										
										
										
											2011-02-11 15:29:56 +00:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2007-12-02 20:58:02 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         def annotate(path, identifier=nil) | 
					
						
							| 
									
										
										
										
											2011-04-11 15:45:20 +00:00
										 |  |  |           identifier = (identifier) ? identifier : "HEAD" | 
					
						
							| 
									
										
										
										
											2007-12-02 20:58:02 +00:00
										 |  |  |           logger.debug "<cvs> annotate path:'#{path}',identifier #{identifier}" | 
					
						
							| 
									
										
										
										
											2011-04-11 15:45:20 +00:00
										 |  |  |           cmd_args = %w|rannotate| | 
					
						
							| 
									
										
										
										
											2011-04-12 10:31:33 +00:00
										 |  |  |           cmd_args << "-D" << time_to_cvstime(identifier) if identifier | 
					
						
							|  |  |  |           cmd_args << path_with_proj(path) | 
					
						
							| 
									
										
										
										
											2007-12-02 20:58:02 +00:00
										 |  |  |           blame = Annotate.new | 
					
						
							| 
									
										
										
										
											2011-04-11 15:45:20 +00:00
										 |  |  |           scm_cmd(*cmd_args) do |io| | 
					
						
							| 
									
										
										
										
											2007-12-02 20:58:02 +00:00
										 |  |  |             io.each_line do |line| | 
					
						
							|  |  |  |               next unless line =~ %r{^([\d\.]+)\s+\(([^\)]+)\s+[^\)]+\):\s(.*)$} | 
					
						
							| 
									
										
										
										
											2020-11-30 15:49:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-11 08:34:18 +00:00
										 |  |  |               blame.add_line( | 
					
						
							| 
									
										
										
										
											2020-11-20 11:35:52 +00:00
										 |  |  |                 $3.rstrip, | 
					
						
							|  |  |  |                 Revision.new( | 
					
						
							|  |  |  |                   :revision   => $1, | 
					
						
							|  |  |  |                   :identifier => nil, | 
					
						
							|  |  |  |                   :author     => $2.strip | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |               ) | 
					
						
							| 
									
										
										
										
											2007-12-02 20:58:02 +00:00
										 |  |  |             end | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |           blame | 
					
						
							| 
									
										
										
										
											2011-04-11 15:45:20 +00:00
										 |  |  |         rescue ScmCommandAborted | 
					
						
							|  |  |  |           Annotate.new | 
					
						
							| 
									
										
										
										
											2007-12-02 20:58:02 +00:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2011-02-11 15:29:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         private | 
					
						
							| 
									
										
										
										
											2011-02-11 15:29:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-06 17:40:54 +00:00
										 |  |  |         # Returns the root url without the connexion string | 
					
						
							|  |  |  |         # :pserver:anonymous@foo.bar:/path => /path | 
					
						
							|  |  |  |         # :ext:cvsservername:/path => /path | 
					
						
							|  |  |  |         def root_url_path | 
					
						
							| 
									
										
										
										
											2013-07-15 21:06:54 +00:00
										 |  |  |           root_url.to_s.gsub(%r{^:.+?(?=/)}, '') | 
					
						
							| 
									
										
										
										
											2008-12-06 17:40:54 +00:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # convert a date/time into the CVS-format | 
					
						
							|  |  |  |         def time_to_cvstime(time) | 
					
						
							|  |  |  |           return nil if time.nil? | 
					
						
							| 
									
										
										
										
											2020-11-30 15:49:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-20 17:54:30 +00:00
										 |  |  |           time = Time.now if (time.is_a?(String) && time == 'HEAD') | 
					
						
							|  |  |  |           unless time.is_a?(Time) | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |             time = Time.parse(time) | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2020-12-12 15:50:21 +00:00
										 |  |  |           time_to_cvstime_rlog(time) | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2011-02-02 13:13:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         def time_to_cvstime_rlog(time) | 
					
						
							|  |  |  |           return nil if time.nil? | 
					
						
							| 
									
										
										
										
											2020-11-30 15:49:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-02 13:13:44 +00:00
										 |  |  |           t1 = time.clone.localtime | 
					
						
							| 
									
										
										
										
											2020-12-12 15:50:21 +00:00
										 |  |  |           t1.strftime("%Y-%m-%d %H:%M:%S") | 
					
						
							| 
									
										
										
										
											2011-02-02 13:13:44 +00:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2011-04-10 08:10:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         def normalize_cvs_path(path) | 
					
						
							|  |  |  |           normalize_path(path.gsub(/Attic\//,'')) | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2011-04-10 08:10:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         def normalize_path(path) | 
					
						
							|  |  |  |           path.sub(/^(\/)*(.*)/,'\2').sub(/(.*)(,v)+/,'\1') | 
					
						
							| 
									
										
										
										
											2011-04-12 06:53:08 +00:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2011-03-11 00:42:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-12 10:31:33 +00:00
										 |  |  |         def path_with_proj(path) | 
					
						
							|  |  |  |           "#{url}#{with_leading_slash(path)}" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |         private :path_with_proj | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-11 08:34:59 +00:00
										 |  |  |         class Revision < Redmine::Scm::Adapters::Revision | 
					
						
							|  |  |  |           # Returns the readable identifier | 
					
						
							|  |  |  |           def format_identifier | 
					
						
							|  |  |  |             revision.to_s | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-11 00:42:40 +00:00
										 |  |  |         def scm_cmd(*args, &block) | 
					
						
							| 
									
										
										
										
											2011-07-15 16:30:38 +00:00
										 |  |  |           full_args = ['-d', root_url] | 
					
						
							| 
									
										
										
										
											2011-03-11 00:42:40 +00:00
										 |  |  |           full_args += args | 
					
						
							| 
									
										
										
										
											2011-04-15 07:16:04 +00:00
										 |  |  |           full_args_locale = [] | 
					
						
							|  |  |  |           full_args.map do |e| | 
					
						
							|  |  |  |             full_args_locale << scm_iconv(@path_encoding, 'UTF-8', e) | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2020-11-20 11:35:52 +00:00
										 |  |  |           ret = | 
					
						
							|  |  |  |             shellout( | 
					
						
							|  |  |  |               self.class.sq_bin + ' ' + | 
					
						
							|  |  |  |                 full_args_locale.map {|e| shell_quote e.to_s}.join(' '), | 
					
						
							|  |  |  |               &block | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2011-03-11 00:42:40 +00:00
										 |  |  |           if $? && $?.exitstatus != 0
 | 
					
						
							|  |  |  |             raise ScmCommandAborted, "cvs exited with non-zero status: #{$?.exitstatus}" | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2020-11-30 15:49:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-11 00:42:40 +00:00
										 |  |  |           ret | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |         private :scm_cmd | 
					
						
							| 
									
										
										
										
											2011-04-12 06:53:08 +00:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2011-03-11 00:42:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |       class CvsRevisionHelper | 
					
						
							|  |  |  |         attr_accessor :complete_rev, :revision, :base, :branchid | 
					
						
							| 
									
										
										
										
											2011-04-12 06:53:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         def initialize(complete_rev) | 
					
						
							|  |  |  |           @complete_rev = complete_rev | 
					
						
							|  |  |  |           parseRevision() | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2011-04-12 06:53:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         def branchVersion | 
					
						
							|  |  |  |           if isBranchRevision | 
					
						
							| 
									
										
										
										
											2020-12-12 15:50:21 +00:00
										 |  |  |             return @base + "." + @branchid | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |           end | 
					
						
							| 
									
										
										
										
											2020-11-30 15:49:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-12 15:50:21 +00:00
										 |  |  |           @base | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2011-04-12 06:53:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         def isBranchRevision | 
					
						
							|  |  |  |           !@branchid.nil? | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2011-04-09 23:23:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         def prevRev | 
					
						
							| 
									
										
										
										
											2011-04-09 23:23:10 +00:00
										 |  |  |           unless @revision == 0
 | 
					
						
							| 
									
										
										
										
											2020-12-12 15:50:21 +00:00
										 |  |  |             return buildRevision(@revision - 1) | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |           end | 
					
						
							| 
									
										
										
										
											2020-11-30 15:49:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-12 15:50:21 +00:00
										 |  |  |           buildRevision(@revision) | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2011-04-09 23:23:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         def is_in_branch_with_symbol(branch_symbol) | 
					
						
							| 
									
										
										
										
											2011-04-09 23:23:10 +00:00
										 |  |  |           bpieces = branch_symbol.split(".") | 
					
						
							|  |  |  |           branch_start = "#{bpieces[0..-3].join(".")}.#{bpieces[-1]}" | 
					
						
							| 
									
										
										
										
											2020-12-12 15:50:21 +00:00
										 |  |  |           (branchVersion == branch_start) | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2011-04-09 23:23:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         private | 
					
						
							| 
									
										
										
										
											2019-08-03 05:34:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         def buildRevision(rev) | 
					
						
							| 
									
										
										
										
											2011-04-10 12:27:53 +00:00
										 |  |  |           if rev == 0
 | 
					
						
							| 
									
										
										
										
											2011-02-24 04:03:43 +00:00
										 |  |  |             if @branchid.nil? | 
					
						
							| 
									
										
										
										
											2011-04-10 12:27:53 +00:00
										 |  |  |               @base + ".0" | 
					
						
							| 
									
										
										
										
											2011-02-24 04:03:43 +00:00
										 |  |  |             else | 
					
						
							|  |  |  |               @base | 
					
						
							|  |  |  |             end | 
					
						
							| 
									
										
										
										
											2011-04-12 06:53:08 +00:00
										 |  |  |           elsif @branchid.nil? | 
					
						
							| 
									
										
										
										
											2011-04-10 12:27:53 +00:00
										 |  |  |             @base + "." + rev.to_s | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |           else | 
					
						
							| 
									
										
										
										
											2011-04-10 12:27:53 +00:00
										 |  |  |             @base + "." + @branchid + "." + rev.to_s | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2011-04-09 23:23:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         # Interpretiert die cvs revisionsnummern wie z.b. 1.14 oder 1.3.0.15 | 
					
						
							| 
									
										
										
										
											2019-06-20 12:15:28 +00:00
										 |  |  |         def parseRevision | 
					
						
							| 
									
										
										
										
											2011-04-09 23:23:10 +00:00
										 |  |  |           pieces = @complete_rev.split(".") | 
					
						
							|  |  |  |           @revision = pieces.last.to_i | 
					
						
							|  |  |  |           baseSize = 1
 | 
					
						
							|  |  |  |           baseSize += (pieces.size / 2) | 
					
						
							|  |  |  |           @base = pieces[0..-baseSize].join(".") | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |           if baseSize > 2
 | 
					
						
							| 
									
										
										
										
											2011-04-09 23:23:10 +00:00
										 |  |  |             @branchid = pieces[-2] | 
					
						
							| 
									
										
										
										
											2011-04-12 06:53:08 +00:00
										 |  |  |           end | 
					
						
							| 
									
										
										
										
											2007-06-12 20:12:05 +00:00
										 |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end |