Mercurial > hg > soundsoftware-site
diff lib/redmine/scm/adapters/git_adapter.rb @ 245:051f544170fe
* Update to SVN trunk revision 4993
author | Chris Cannam |
---|---|
date | Thu, 03 Mar 2011 11:42:28 +0000 |
parents | 0579821a129a |
children | cbce1fd3b1b7 |
line wrap: on
line diff
--- a/lib/redmine/scm/adapters/git_adapter.rb Thu Mar 03 11:40:10 2011 +0000 +++ b/lib/redmine/scm/adapters/git_adapter.rb Thu Mar 03 11:42:28 2011 +0000 @@ -19,11 +19,54 @@ module Redmine module Scm - module Adapters + module Adapters class GitAdapter < AbstractAdapter + + SCM_GIT_REPORT_LAST_COMMIT = true + # Git executable name GIT_BIN = Redmine::Configuration['scm_git_command'] || "git" + # raised if scm command exited with error, e.g. unknown revision. + class ScmCommandAborted < CommandFailed; end + + class << self + def client_command + @@bin ||= GIT_BIN + end + + def sq_bin + @@sq_bin ||= shell_quote(GIT_BIN) + end + + def client_version + @@client_version ||= (scm_command_version || []) + end + + def client_available + !client_version.empty? + end + + def scm_command_version + scm_version = scm_version_from_command_line.dup + if scm_version.respond_to?(:force_encoding) + scm_version.force_encoding('ASCII-8BIT') + end + if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)}) + m[2].scan(%r{\d+}).collect(&:to_i) + end + end + + def scm_version_from_command_line + shellout("#{sq_bin} --version --no-color") { |io| io.read }.to_s + end + end + + def initialize(url, root_url=nil, login=nil, password=nil, path_encoding=nil) + super + @flag_report_last_commit = SCM_GIT_REPORT_LAST_COMMIT + end + def info begin Info.new(:root_url => url, :lastrev => lastrev('',nil)) @@ -35,7 +78,7 @@ def branches return @branches if @branches @branches = [] - cmd = "#{GIT_BIN} --git-dir #{target('')} branch --no-color" + cmd = "#{self.class.sq_bin} --git-dir #{target('')} branch --no-color" shellout(cmd) do |io| io.each_line do |line| @branches << line.match('\s*\*?\s*(.*)$')[1] @@ -46,20 +89,20 @@ def tags return @tags if @tags - cmd = "#{GIT_BIN} --git-dir #{target('')} tag" + cmd = "#{self.class.sq_bin} --git-dir #{target('')} tag" shellout(cmd) do |io| @tags = io.readlines.sort!.map{|t| t.strip} end end def default_branch - branches.include?('master') ? 'master' : branches.first + branches.include?('master') ? 'master' : branches.first end - + def entries(path=nil, identifier=nil) path ||= '' entries = Entries.new - cmd = "#{GIT_BIN} --git-dir #{target('')} ls-tree -l " + cmd = "#{self.class.sq_bin} --git-dir #{target('')} ls-tree -l " cmd << shell_quote("HEAD:" + path) if identifier.nil? cmd << shell_quote(identifier + ":" + path) if identifier shellout(cmd) do |io| @@ -75,7 +118,7 @@ :path => full_path, :kind => (type == "tree") ? 'dir' : 'file', :size => (type == "tree") ? nil : size, - :lastrev => lastrev(full_path,identifier) + :lastrev => @flag_report_last_commit ? lastrev(full_path,identifier) : Revision.new }) unless entries.detect{|entry| entry.name == name} end end @@ -84,18 +127,17 @@ entries.sort_by_name end - def lastrev(path,rev) + def lastrev(path, rev) return nil if path.nil? - cmd = "#{GIT_BIN} --git-dir #{target('')} log --no-color --date=iso --pretty=fuller --no-merges -n 1 " - cmd << " #{shell_quote rev} " if rev - cmd << "-- #{shell_quote path} " unless path.empty? + cmd_args = %w|log --no-color --encoding=UTF-8 --date=iso --pretty=fuller --no-merges -n 1| + cmd_args << rev if rev + cmd_args << "--" << path unless path.empty? lines = [] - shellout(cmd) { |io| lines = io.readlines } - return nil if $? && $?.exitstatus != 0 + scm_cmd(*cmd_args) { |io| lines = io.readlines } begin id = lines[0].split[1] author = lines[1].match('Author:\s+(.*)$')[1] - time = Time.parse(lines[4].match('CommitDate:\s+(.*)$')[1]).localtime + time = Time.parse(lines[4].match('CommitDate:\s+(.*)$')[1]) Revision.new({ :identifier => id, @@ -104,26 +146,29 @@ :time => time, :message => nil, :paths => nil - }) + }) rescue NoMethodError => e logger.error("The revision '#{path}' has a wrong format") return nil end + rescue ScmCommandAborted + nil end def revisions(path, identifier_from, identifier_to, options={}) revisions = Revisions.new + cmd_args = %w|log --no-color --encoding=UTF-8 --raw --date=iso --pretty=fuller| + cmd_args << "--reverse" if options[:reverse] + cmd_args << "--all" if options[:all] + cmd_args << "-n" << "#{options[:limit].to_i}" if options[:limit] + from_to = "" + from_to << "#{identifier_from}.." if identifier_from + from_to << "#{identifier_to}" if identifier_to + cmd_args << from_to if !from_to.empty? + cmd_args << "--since=#{options[:since].strftime("%Y-%m-%d %H:%M:%S")}" if options[:since] + cmd_args << "--" << path if path && !path.empty? - cmd = "#{GIT_BIN} --git-dir #{target('')} log --no-color --raw --date=iso --pretty=fuller " - cmd << " --reverse " if options[:reverse] - cmd << " --all " if options[:all] - cmd << " -n #{options[:limit].to_i} " if options[:limit] - cmd << "#{shell_quote(identifier_from + '..')}" if identifier_from - cmd << "#{shell_quote identifier_to}" if identifier_to - cmd << " --since=#{shell_quote(options[:since].strftime("%Y-%m-%d %H:%M:%S"))}" if options[:since] - cmd << " -- #{shell_quote path}" if path && !path.empty? - - shellout(cmd) do |io| + scm_cmd *cmd_args do |io| files=[] changeset = {} parsing_descr = 0 #0: not parsing desc or files, 1: parsing desc, 2: parsing files @@ -200,8 +245,8 @@ end end end - - return nil if $? && $?.exitstatus != 0 + revisions + rescue ScmCommandAborted revisions end @@ -209,9 +254,9 @@ path ||= '' if identifier_to - cmd = "#{GIT_BIN} --git-dir #{target('')} diff --no-color #{shell_quote identifier_to} #{shell_quote identifier_from}" + cmd = "#{self.class.sq_bin} --git-dir #{target('')} diff --no-color #{shell_quote identifier_to} #{shell_quote identifier_from}" else - cmd = "#{GIT_BIN} --git-dir #{target('')} show --no-color #{shell_quote identifier_from}" + cmd = "#{self.class.sq_bin} --git-dir #{target('')} show --no-color #{shell_quote identifier_from}" end cmd << " -- #{shell_quote path}" unless path.empty? @@ -227,7 +272,7 @@ def annotate(path, identifier=nil) identifier = 'HEAD' if identifier.blank? - cmd = "#{GIT_BIN} --git-dir #{target('')} blame -p #{shell_quote identifier} -- #{shell_quote path}" + cmd = "#{self.class.sq_bin} --git-dir #{target('')} blame -p #{shell_quote identifier} -- #{shell_quote path}" blame = Annotate.new content = nil shellout(cmd) { |io| io.binmode; content = io.read } @@ -250,12 +295,12 @@ end blame end - + def cat(path, identifier=nil) if identifier.nil? identifier = 'HEAD' end - cmd = "#{GIT_BIN} --git-dir #{target('')} show --no-color #{shell_quote(identifier + ':' + path)}" + cmd = "#{self.class.sq_bin} --git-dir #{target('')} show --no-color #{shell_quote(identifier + ':' + path)}" cat = nil shellout(cmd) do |io| io.binmode @@ -271,6 +316,18 @@ identifier[0,8] end end + + def scm_cmd(*args, &block) + repo_path = root_url || url + full_args = [GIT_BIN, '--git-dir', repo_path] + full_args += args + ret = shellout(full_args.map { |e| shell_quote e.to_s }.join(' '), &block) + if $? && $?.exitstatus != 0 + raise ScmCommandAborted, "git exited with non-zero status: #{$?.exitstatus}" + end + ret + end + private :scm_cmd end end end