summaryrefslogtreecommitdiffstats
path: root/lib/redmine/scm/adapters/abstract_adapter.rb
diff options
context:
space:
mode:
authorJean-Philippe Lang <jp_lang@yahoo.fr>2007-06-12 20:12:05 +0000
committerJean-Philippe Lang <jp_lang@yahoo.fr>2007-06-12 20:12:05 +0000
commit438161ad1fd37aadbfa3f5a875540730fd6d70c3 (patch)
treeb396b2379835a6f768023cdc0f7042259f560875 /lib/redmine/scm/adapters/abstract_adapter.rb
parent4dddb606a6d24c7f95e52f08e689464ab6f8b5b8 (diff)
downloadredmine-438161ad1fd37aadbfa3f5a875540730fd6d70c3.tar.gz
redmine-438161ad1fd37aadbfa3f5a875540730fd6d70c3.zip
Added basic support for CVS and Mercurial SCMs.
Browsing, changesets fetching and diff viewing are implemented. Only tested with local repositories. Thanks to Ralph Vater for CVS specific code. git-svn-id: http://redmine.rubyforge.org/svn/trunk@559 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'lib/redmine/scm/adapters/abstract_adapter.rb')
-rw-r--r--lib/redmine/scm/adapters/abstract_adapter.rb341
1 files changed, 341 insertions, 0 deletions
diff --git a/lib/redmine/scm/adapters/abstract_adapter.rb b/lib/redmine/scm/adapters/abstract_adapter.rb
new file mode 100644
index 000000000..b74fa1b18
--- /dev/null
+++ b/lib/redmine/scm/adapters/abstract_adapter.rb
@@ -0,0 +1,341 @@
+# redMine - project management software
+# Copyright (C) 2006-2007 Jean-Philippe Lang
+#
+# 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.
+#
+# 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.
+#
+# 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 'cgi'
+
+module Redmine
+ module Scm
+ module Adapters
+ class CommandFailed < StandardError #:nodoc:
+ end
+
+ class AbstractAdapter #:nodoc:
+ def initialize(url, root_url=nil, login=nil, password=nil)
+ @url = url
+ @login = login if login && !login.empty?
+ @password = (password || "") if @login
+ @root_url = root_url.blank? ? retrieve_root_url : root_url
+ end
+
+ def adapter_name
+ 'Abstract'
+ end
+
+ def root_url
+ @root_url
+ end
+
+ def url
+ @url
+ end
+
+ # get info about the svn repository
+ def info
+ return nil
+ end
+
+ # Returns the entry identified by path and revision identifier
+ # or nil if entry doesn't exist in the repository
+ def entry(path=nil, identifier=nil)
+ e = entries(path, identifier)
+ e ? e.first : nil
+ end
+
+ # Returns an Entries collection
+ # or nil if the given path doesn't exist in the repository
+ def entries(path=nil, identifier=nil)
+ return nil
+ end
+
+ def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
+ return nil
+ end
+
+ def diff(path, identifier_from, identifier_to=nil, type="inline")
+ return nil
+ end
+
+ def cat(path, identifier=nil)
+ return nil
+ end
+
+ def with_leading_slash(path)
+ path ||= ''
+ (path[0,1]!="/") ? "/#{path}" : path
+ end
+
+ private
+ def retrieve_root_url
+ info = self.info
+ info ? info.root_url : nil
+ end
+
+ def target(path)
+ path ||= ""
+ base = path.match(/^\//) ? root_url : url
+ " \"" << "#{base}/#{path}".gsub(/["?<>\*]/, '') << "\""
+ end
+
+ def logger
+ RAILS_DEFAULT_LOGGER
+ end
+
+ def shellout(cmd, &block)
+ logger.debug "Shelling out: #{cmd}" if logger && logger.debug?
+ IO.popen(cmd, "r+") do |io|
+ io.close_write
+ block.call(io) if block_given?
+ end
+ end
+ end
+
+ class Entries < Array
+ def sort_by_name
+ sort {|x,y|
+ if x.kind == y.kind
+ x.name <=> y.name
+ else
+ x.kind <=> y.kind
+ end
+ }
+ end
+
+ def revisions
+ revisions ||= Revisions.new(collect{|entry| entry.lastrev}.compact)
+ end
+ end
+
+ class Info
+ attr_accessor :root_url, :lastrev
+ def initialize(attributes={})
+ self.root_url = attributes[:root_url] if attributes[:root_url]
+ self.lastrev = attributes[:lastrev]
+ end
+ end
+
+ class Entry
+ attr_accessor :name, :path, :kind, :size, :lastrev
+ def initialize(attributes={})
+ self.name = attributes[:name] if attributes[:name]
+ self.path = attributes[:path] if attributes[:path]
+ self.kind = attributes[:kind] if attributes[:kind]
+ self.size = attributes[:size].to_i if attributes[:size]
+ self.lastrev = attributes[:lastrev]
+ end
+
+ def is_file?
+ 'file' == self.kind
+ end
+
+ def is_dir?
+ 'dir' == self.kind
+ end
+
+ def is_text?
+ Redmine::MimeType.is_type?('text', name)
+ end
+ end
+
+ class Revisions < Array
+ def latest
+ sort {|x,y|
+ unless x.time.nil? or y.time.nil?
+ x.time <=> y.time
+ else
+ 0
+ end
+ }.last
+ end
+ end
+
+ class Revision
+ attr_accessor :identifier, :scmid, :name, :author, :time, :message, :paths, :revision, :branch
+ def initialize(attributes={})
+ self.identifier = attributes[:identifier]
+ self.scmid = attributes[:scmid]
+ self.name = attributes[:name] || self.identifier
+ self.author = attributes[:author]
+ self.time = attributes[:time]
+ self.message = attributes[:message] || ""
+ self.paths = attributes[:paths]
+ self.revision = attributes[:revision]
+ self.branch = attributes[:branch]
+ end
+
+ end
+
+ # A line of Diff
+ class Diff
+ attr_accessor :nb_line_left
+ attr_accessor :line_left
+ attr_accessor :nb_line_right
+ attr_accessor :line_right
+ attr_accessor :type_diff_right
+ attr_accessor :type_diff_left
+
+ def initialize ()
+ self.nb_line_left = ''
+ self.nb_line_right = ''
+ self.line_left = ''
+ self.line_right = ''
+ self.type_diff_right = ''
+ self.type_diff_left = ''
+ end
+
+ def inspect
+ puts '### Start Line Diff ###'
+ puts self.nb_line_left
+ puts self.line_left
+ puts self.nb_line_right
+ puts self.line_right
+ end
+ end
+
+ class DiffTableList < Array
+ def initialize (diff, type="inline")
+ diff_table = DiffTable.new type
+ diff.each do |line|
+ if line =~ /^(Index:|diff) (.*)$/
+ self << diff_table if diff_table.length > 1
+ diff_table = DiffTable.new type
+ end
+ a = diff_table.add_line line
+ end
+ self << diff_table
+ end
+ end
+
+ # Class for create a Diff
+ class DiffTable < Hash
+ attr_reader :file_name, :line_num_l, :line_num_r
+
+ # Initialize with a Diff file and the type of Diff View
+ # The type view must be inline or sbs (side_by_side)
+ def initialize (type="inline")
+ @parsing = false
+ @nb_line = 1
+ @start = false
+ @before = 'same'
+ @second = true
+ @type = type
+ end
+
+ # Function for add a line of this Diff
+ def add_line(line)
+ unless @parsing
+ if line =~ /^(Index:|diff) (.*)$/
+ @file_name = $2
+ return false
+ elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/
+ @line_num_l = $5.to_i
+ @line_num_r = $2.to_i
+ @parsing = true
+ end
+ else
+ if line =~ /^[^\+\-\s@\\]/
+ self.delete(self.keys.sort.last)
+ @parsing = false
+ return false
+ elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/
+ @line_num_l = $5.to_i
+ @line_num_r = $2.to_i
+ else
+ @nb_line += 1 if parse_line(line, @type)
+ end
+ end
+ return true
+ end
+
+ def inspect
+ puts '### DIFF TABLE ###'
+ puts "file : #{file_name}"
+ self.each do |d|
+ d.inspect
+ end
+ end
+
+ private
+ # Test if is a Side By Side type
+ def sbs?(type, func)
+ if @start and type == "sbs"
+ if @before == func and @second
+ tmp_nb_line = @nb_line
+ self[tmp_nb_line] = Diff.new
+ else
+ @second = false
+ tmp_nb_line = @start
+ @start += 1
+ @nb_line -= 1
+ end
+ else
+ tmp_nb_line = @nb_line
+ @start = @nb_line
+ self[tmp_nb_line] = Diff.new
+ @second = true
+ end
+ unless self[tmp_nb_line]
+ @nb_line += 1
+ self[tmp_nb_line] = Diff.new
+ else
+ self[tmp_nb_line]
+ end
+ end
+
+ # Escape the HTML for the diff
+ def escapeHTML(line)
+ CGI.escapeHTML(line).gsub(/\s/, '&nbsp;')
+ end
+
+ def parse_line (line, type="inline")
+ if line[0, 1] == "+"
+ diff = sbs? type, 'add'
+ @before = 'add'
+ diff.line_left = escapeHTML line[1..-1]
+ diff.nb_line_left = @line_num_l
+ diff.type_diff_left = 'diff_in'
+ @line_num_l += 1
+ true
+ elsif line[0, 1] == "-"
+ diff = sbs? type, 'remove'
+ @before = 'remove'
+ diff.line_right = escapeHTML line[1..-1]
+ diff.nb_line_right = @line_num_r
+ diff.type_diff_right = 'diff_out'
+ @line_num_r += 1
+ true
+ elsif line[0, 1] =~ /\s/
+ @before = 'same'
+ @start = false
+ diff = Diff.new
+ diff.line_right = escapeHTML line[1..-1]
+ diff.nb_line_right = @line_num_r
+ diff.line_left = escapeHTML line[1..-1]
+ diff.nb_line_left = @line_num_l
+ self[@nb_line] = diff
+ @line_num_l += 1
+ @line_num_r += 1
+ true
+ elsif line[0, 1] = "\\"
+ true
+ else
+ false
+ end
+ end
+ end
+ end
+ end
+end