Commit 6d0fcf55 authored by Toshi MARUYAMA's avatar Toshi MARUYAMA Committed by Eric Davis

scm: use shell quote for scm command at adapter level (#7517, #4273).

"C:\Program Files\TortoiseHg\hg.exe" can be used in config/configuration.yml.

In Ruby 1.9 IO.popen, if cmd is an Array of String,
it will be used as the subprocess‘s argv bypassing a shell.

See http://www.ruby-doc.org/core/classes/IO.html

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4821 e93f8b46-1217-0410-a6f0-8f06a7374b81
parent 6cd9bc5c
...@@ -25,6 +25,10 @@ module Redmine ...@@ -25,6 +25,10 @@ module Redmine
class AbstractAdapter #:nodoc: class AbstractAdapter #:nodoc:
class << self class << self
def client_command
""
end
# Returns the version of the scm client # Returns the version of the scm client
# Eg: [1, 5, 0] or [] if unknown # Eg: [1, 5, 0] or [] if unknown
def client_version def client_version
...@@ -45,8 +49,20 @@ module Redmine ...@@ -45,8 +49,20 @@ module Redmine
def client_version_above?(v, options={}) def client_version_above?(v, options={})
((client_version <=> v) >= 0) || (client_version.empty? && options[:unknown]) ((client_version <=> v) >= 0) || (client_version.empty? && options[:unknown])
end end
def client_available
true
end
def shell_quote(str)
if Redmine::Platform.mswin?
'"' + str.gsub(/"/, '\\"') + '"'
else
"'" + str.gsub(/'/, "'\"'\"'") + "'"
end
end
end end
def initialize(url, root_url=nil, login=nil, password=nil) def initialize(url, root_url=nil, login=nil, password=nil)
@url = url @url = url
@login = login if login && !login.empty? @login = login if login && !login.empty?
...@@ -138,7 +154,7 @@ module Redmine ...@@ -138,7 +154,7 @@ module Redmine
path ||= '' path ||= ''
(path[-1,1] == "/") ? path : "#{path}/" (path[-1,1] == "/") ? path : "#{path}/"
end end
def without_leading_slash(path) def without_leading_slash(path)
path ||= '' path ||= ''
path.gsub(%r{^/+}, '') path.gsub(%r{^/+}, '')
...@@ -148,13 +164,9 @@ module Redmine ...@@ -148,13 +164,9 @@ module Redmine
path ||= '' path ||= ''
(path[-1,1] == "/") ? path[0..-2] : path (path[-1,1] == "/") ? path[0..-2] : path
end end
def shell_quote(str) def shell_quote(str)
if Redmine::Platform.mswin? self.class.shell_quote(str)
'"' + str.gsub(/"/, '\\"') + '"'
else
"'" + str.gsub(/'/, "'\"'\"'") + "'"
end
end end
private private
...@@ -168,11 +180,11 @@ module Redmine ...@@ -168,11 +180,11 @@ module Redmine
base = path.match(/^\//) ? root_url : url base = path.match(/^\//) ? root_url : url
shell_quote("#{base}/#{path}".gsub(/[?<>\*]/, '')) shell_quote("#{base}/#{path}".gsub(/[?<>\*]/, ''))
end end
def logger def logger
self.class.logger self.class.logger
end end
def shellout(cmd, &block) def shellout(cmd, &block)
self.class.shellout(cmd, &block) self.class.shellout(cmd, &block)
end end
......
...@@ -19,15 +19,25 @@ require 'redmine/scm/adapters/abstract_adapter' ...@@ -19,15 +19,25 @@ require 'redmine/scm/adapters/abstract_adapter'
module Redmine module Redmine
module Scm module Scm
module Adapters module Adapters
class BazaarAdapter < AbstractAdapter class BazaarAdapter < AbstractAdapter
# Bazaar executable name # Bazaar executable name
BZR_BIN = Redmine::Configuration['scm_bazaar_command'] || "bzr" BZR_BIN = Redmine::Configuration['scm_bazaar_command'] || "bzr"
class << self
def client_command
@@bin ||= BZR_BIN
end
def sq_bin
@@sq_bin ||= shell_quote(BZR_BIN)
end
end
# Get info about the repository # Get info about the repository
def info def info
cmd = "#{BZR_BIN} revno #{target('')}" cmd = "#{self.class.sq_bin} revno #{target('')}"
info = nil info = nil
shellout(cmd) do |io| shellout(cmd) do |io|
if io.read =~ %r{^(\d+)\r?$} if io.read =~ %r{^(\d+)\r?$}
...@@ -43,13 +53,13 @@ module Redmine ...@@ -43,13 +53,13 @@ module Redmine
rescue CommandFailed rescue CommandFailed
return nil return nil
end end
# Returns an Entries collection # Returns an Entries collection
# or nil if the given path doesn't exist in the repository # or nil if the given path doesn't exist in the repository
def entries(path=nil, identifier=nil) def entries(path=nil, identifier=nil)
path ||= '' path ||= ''
entries = Entries.new entries = Entries.new
cmd = "#{BZR_BIN} ls -v --show-ids" cmd = "#{self.class.sq_bin} ls -v --show-ids"
identifier = -1 unless identifier && identifier.to_i > 0 identifier = -1 unless identifier && identifier.to_i > 0
cmd << " -r#{identifier.to_i}" cmd << " -r#{identifier.to_i}"
cmd << " #{target(path)}" cmd << " #{target(path)}"
...@@ -71,13 +81,13 @@ module Redmine ...@@ -71,13 +81,13 @@ module Redmine
logger.debug("Found #{entries.size} entries in the repository for #{target(path)}") if logger && logger.debug? logger.debug("Found #{entries.size} entries in the repository for #{target(path)}") if logger && logger.debug?
entries.sort_by_name entries.sort_by_name
end end
def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}) def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
path ||= '' path ||= ''
identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : 'last:1' identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : 'last:1'
identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : 1 identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : 1
revisions = Revisions.new revisions = Revisions.new
cmd = "#{BZR_BIN} log -v --show-ids -r#{identifier_to}..#{identifier_from} #{target(path)}" cmd = "#{self.class.sq_bin} log -v --show-ids -r#{identifier_to}..#{identifier_from} #{target(path)}"
shellout(cmd) do |io| shellout(cmd) do |io|
revision = nil revision = nil
parsing = nil parsing = nil
...@@ -132,7 +142,7 @@ module Redmine ...@@ -132,7 +142,7 @@ module Redmine
return nil if $? && $?.exitstatus != 0 return nil if $? && $?.exitstatus != 0
revisions revisions
end end
def diff(path, identifier_from, identifier_to=nil) def diff(path, identifier_from, identifier_to=nil)
path ||= '' path ||= ''
if identifier_to if identifier_to
...@@ -143,7 +153,7 @@ module Redmine ...@@ -143,7 +153,7 @@ module Redmine
if identifier_from if identifier_from
identifier_from = identifier_from.to_i identifier_from = identifier_from.to_i
end end
cmd = "#{BZR_BIN} diff -r#{identifier_to}..#{identifier_from} #{target(path)}" cmd = "#{self.class.sq_bin} diff -r#{identifier_to}..#{identifier_from} #{target(path)}"
diff = [] diff = []
shellout(cmd) do |io| shellout(cmd) do |io|
io.each_line do |line| io.each_line do |line|
...@@ -153,9 +163,9 @@ module Redmine ...@@ -153,9 +163,9 @@ module Redmine
#return nil if $? && $?.exitstatus != 0 #return nil if $? && $?.exitstatus != 0
diff diff
end end
def cat(path, identifier=nil) def cat(path, identifier=nil)
cmd = "#{BZR_BIN} cat" cmd = "#{self.class.sq_bin} cat"
cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0 cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0
cmd << " #{target(path)}" cmd << " #{target(path)}"
cat = nil cat = nil
...@@ -166,9 +176,9 @@ module Redmine ...@@ -166,9 +176,9 @@ module Redmine
return nil if $? && $?.exitstatus != 0 return nil if $? && $?.exitstatus != 0
cat cat
end end
def annotate(path, identifier=nil) def annotate(path, identifier=nil)
cmd = "#{BZR_BIN} annotate --all" cmd = "#{self.class.sq_bin} annotate --all"
cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0 cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0
cmd << " #{target(path)}" cmd << " #{target(path)}"
blame = Annotate.new blame = Annotate.new
......
...@@ -24,7 +24,17 @@ module Redmine ...@@ -24,7 +24,17 @@ module Redmine
# CVS executable name # CVS executable name
CVS_BIN = Redmine::Configuration['scm_cvs_command'] || "cvs" CVS_BIN = Redmine::Configuration['scm_cvs_command'] || "cvs"
class << self
def client_command
@@bin ||= CVS_BIN
end
def sq_bin
@@sq_bin ||= shell_quote(CVS_BIN)
end
end
# Guidelines for the input: # Guidelines for the input:
# url -> the project-path, relative to the cvsroot (eg. module name) # url -> the project-path, relative to the cvsroot (eg. module name)
# root_url -> the good old, sometimes damned, CVSROOT # root_url -> the good old, sometimes damned, CVSROOT
...@@ -38,20 +48,20 @@ module Redmine ...@@ -38,20 +48,20 @@ module Redmine
raise CommandFailed if root_url.blank? raise CommandFailed if root_url.blank?
@root_url = root_url @root_url = root_url
end end
def root_url def root_url
@root_url @root_url
end end
def url def url
@url @url
end end
def info def info
logger.debug "<cvs> info" logger.debug "<cvs> info"
Info.new({:root_url => @root_url, :lastrev => nil}) Info.new({:root_url => @root_url, :lastrev => nil})
end end
def get_previous_revision(revision) def get_previous_revision(revision)
CvsRevisionHelper.new(revision).prevRev CvsRevisionHelper.new(revision).prevRev
end end
...@@ -63,7 +73,7 @@ module Redmine ...@@ -63,7 +73,7 @@ module Redmine
logger.debug "<cvs> entries '#{path}' with identifier '#{identifier}'" logger.debug "<cvs> entries '#{path}' with identifier '#{identifier}'"
path_with_project="#{url}#{with_leading_slash(path)}" path_with_project="#{url}#{with_leading_slash(path)}"
entries = Entries.new entries = Entries.new
cmd = "#{CVS_BIN} -d #{shell_quote root_url} rls -e" cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} rls -e"
cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier
cmd << " #{shell_quote path_with_project}" cmd << " #{shell_quote path_with_project}"
shellout(cmd) do |io| shellout(cmd) do |io|
...@@ -108,7 +118,7 @@ module Redmine ...@@ -108,7 +118,7 @@ module Redmine
logger.debug "<cvs> revisions path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}" logger.debug "<cvs> revisions path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}"
path_with_project="#{url}#{with_leading_slash(path)}" path_with_project="#{url}#{with_leading_slash(path)}"
cmd = "#{CVS_BIN} -d #{shell_quote root_url} rlog" cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} rlog"
cmd << " -d\">#{time_to_cvstime_rlog(identifier_from)}\"" if identifier_from cmd << " -d\">#{time_to_cvstime_rlog(identifier_from)}\"" if identifier_from
cmd << " #{shell_quote path_with_project}" cmd << " #{shell_quote path_with_project}"
shellout(cmd) do |io| shellout(cmd) do |io|
...@@ -229,7 +239,7 @@ module Redmine ...@@ -229,7 +239,7 @@ module Redmine
def diff(path, identifier_from, identifier_to=nil) def diff(path, identifier_from, identifier_to=nil)
logger.debug "<cvs> diff path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}" logger.debug "<cvs> diff path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}"
path_with_project="#{url}#{with_leading_slash(path)}" path_with_project="#{url}#{with_leading_slash(path)}"
cmd = "#{CVS_BIN} -d #{shell_quote root_url} rdiff -u -r#{identifier_to} -r#{identifier_from} #{shell_quote path_with_project}" cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} rdiff -u -r#{identifier_to} -r#{identifier_from} #{shell_quote path_with_project}"
diff = [] diff = []
shellout(cmd) do |io| shellout(cmd) do |io|
io.each_line do |line| io.each_line do |line|
...@@ -244,7 +254,7 @@ module Redmine ...@@ -244,7 +254,7 @@ module Redmine
identifier = (identifier) ? identifier : "HEAD" identifier = (identifier) ? identifier : "HEAD"
logger.debug "<cvs> cat path:'#{path}',identifier #{identifier}" logger.debug "<cvs> cat path:'#{path}',identifier #{identifier}"
path_with_project="#{url}#{with_leading_slash(path)}" path_with_project="#{url}#{with_leading_slash(path)}"
cmd = "#{CVS_BIN} -d #{shell_quote root_url} co" cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} co"
cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier
cmd << " -p #{shell_quote path_with_project}" cmd << " -p #{shell_quote path_with_project}"
cat = nil cat = nil
...@@ -260,7 +270,7 @@ module Redmine ...@@ -260,7 +270,7 @@ module Redmine
identifier = (identifier) ? identifier.to_i : "HEAD" identifier = (identifier) ? identifier.to_i : "HEAD"
logger.debug "<cvs> annotate path:'#{path}',identifier #{identifier}" logger.debug "<cvs> annotate path:'#{path}',identifier #{identifier}"
path_with_project="#{url}#{with_leading_slash(path)}" path_with_project="#{url}#{with_leading_slash(path)}"
cmd = "#{CVS_BIN} -d #{shell_quote root_url} rannotate -r#{identifier} #{shell_quote path_with_project}" cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} rannotate -r#{identifier} #{shell_quote path_with_project}"
blame = Annotate.new blame = Annotate.new
shellout(cmd) do |io| shellout(cmd) do |io|
io.each_line do |line| io.each_line do |line|
......
...@@ -20,16 +20,24 @@ require 'rexml/document' ...@@ -20,16 +20,24 @@ require 'rexml/document'
module Redmine module Redmine
module Scm module Scm
module Adapters module Adapters
class DarcsAdapter < AbstractAdapter class DarcsAdapter < AbstractAdapter
# Darcs executable name # Darcs executable name
DARCS_BIN = Redmine::Configuration['scm_darcs_command'] || "darcs" DARCS_BIN = Redmine::Configuration['scm_darcs_command'] || "darcs"
class << self class << self
def client_command
@@bin ||= DARCS_BIN
end
def sq_bin
@@sq_bin ||= shell_quote(DARCS_BIN)
end
def client_version def client_version
@@client_version ||= (darcs_binary_version || []) @@client_version ||= (darcs_binary_version || [])
end end
def darcs_binary_version def darcs_binary_version
darcsversion = darcs_binary_version_from_command_line darcsversion = darcs_binary_version_from_command_line
if m = darcsversion.match(%r{\A(.*?)((\d+\.)+\d+)}) if m = darcsversion.match(%r{\A(.*?)((\d+\.)+\d+)})
...@@ -38,7 +46,7 @@ module Redmine ...@@ -38,7 +46,7 @@ module Redmine
end end
def darcs_binary_version_from_command_line def darcs_binary_version_from_command_line
shellout("#{DARCS_BIN} --version") { |io| io.read }.to_s shellout("#{sq_bin} --version") { |io| io.read }.to_s
end end
end end
...@@ -57,7 +65,7 @@ module Redmine ...@@ -57,7 +65,7 @@ module Redmine
rev = revisions(nil,nil,nil,{:limit => 1}) rev = revisions(nil,nil,nil,{:limit => 1})
rev ? Info.new({:root_url => @url, :lastrev => rev.last}) : nil rev ? Info.new({:root_url => @url, :lastrev => rev.last}) : nil
end end
# Returns an Entries collection # Returns an Entries collection
# or nil if the given path doesn't exist in the repository # or nil if the given path doesn't exist in the repository
def entries(path=nil, identifier=nil) def entries(path=nil, identifier=nil)
...@@ -66,7 +74,7 @@ module Redmine ...@@ -66,7 +74,7 @@ module Redmine
path = ( self.class.client_version_above?([2, 2, 0]) ? @url : '.' ) path = ( self.class.client_version_above?([2, 2, 0]) ? @url : '.' )
end end
entries = Entries.new entries = Entries.new
cmd = "#{DARCS_BIN} annotate --repodir #{shell_quote @url} --xml-output" cmd = "#{self.class.sq_bin} annotate --repodir #{shell_quote @url} --xml-output"
cmd << " --match #{shell_quote("hash #{identifier}")}" if identifier cmd << " --match #{shell_quote("hash #{identifier}")}" if identifier
cmd << " #{shell_quote path}" cmd << " #{shell_quote path}"
shellout(cmd) do |io| shellout(cmd) do |io|
...@@ -86,11 +94,11 @@ module Redmine ...@@ -86,11 +94,11 @@ module Redmine
return nil if $? && $?.exitstatus != 0 return nil if $? && $?.exitstatus != 0
entries.compact.sort_by_name entries.compact.sort_by_name
end end
def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}) def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
path = '.' if path.blank? path = '.' if path.blank?
revisions = Revisions.new revisions = Revisions.new
cmd = "#{DARCS_BIN} changes --repodir #{shell_quote @url} --xml-output" cmd = "#{self.class.sq_bin} changes --repodir #{shell_quote @url} --xml-output"
cmd << " --from-match #{shell_quote("hash #{identifier_from}")}" if identifier_from cmd << " --from-match #{shell_quote("hash #{identifier_from}")}" if identifier_from
cmd << " --last #{options[:limit].to_i}" if options[:limit] cmd << " --last #{options[:limit].to_i}" if options[:limit]
shellout(cmd) do |io| shellout(cmd) do |io|
...@@ -113,10 +121,10 @@ module Redmine ...@@ -113,10 +121,10 @@ module Redmine
return nil if $? && $?.exitstatus != 0 return nil if $? && $?.exitstatus != 0
revisions revisions
end end
def diff(path, identifier_from, identifier_to=nil) def diff(path, identifier_from, identifier_to=nil)
path = '*' if path.blank? path = '*' if path.blank?
cmd = "#{DARCS_BIN} diff --repodir #{shell_quote @url}" cmd = "#{self.class.sq_bin} diff --repodir #{shell_quote @url}"
if identifier_to.nil? if identifier_to.nil?
cmd << " --match #{shell_quote("hash #{identifier_from}")}" cmd << " --match #{shell_quote("hash #{identifier_from}")}"
else else
...@@ -133,9 +141,9 @@ module Redmine ...@@ -133,9 +141,9 @@ module Redmine
return nil if $? && $?.exitstatus != 0 return nil if $? && $?.exitstatus != 0
diff diff
end end
def cat(path, identifier=nil) def cat(path, identifier=nil)
cmd = "#{DARCS_BIN} show content --repodir #{shell_quote @url}" cmd = "#{self.class.sq_bin} show content --repodir #{shell_quote @url}"
cmd << " --match #{shell_quote("hash #{identifier}")}" if identifier cmd << " --match #{shell_quote("hash #{identifier}")}" if identifier
cmd << " #{shell_quote path}" cmd << " #{shell_quote path}"
cat = nil cat = nil
...@@ -148,7 +156,7 @@ module Redmine ...@@ -148,7 +156,7 @@ module Redmine
end end
private private
# Returns an Entry from the given XML element # Returns an Entry from the given XML element
# or nil if the entry was deleted # or nil if the entry was deleted
def entry_from_xml(element, path_prefix) def entry_from_xml(element, path_prefix)
...@@ -196,10 +204,10 @@ module Redmine ...@@ -196,10 +204,10 @@ module Redmine
end end
paths paths
end end
# Retrieve changed paths for a single patch # Retrieve changed paths for a single patch
def get_paths_for_patch_raw(hash) def get_paths_for_patch_raw(hash)
cmd = "#{DARCS_BIN} annotate --repodir #{shell_quote @url} --summary --xml-output" cmd = "#{self.class.sq_bin} annotate --repodir #{shell_quote @url} --summary --xml-output"
cmd << " --match #{shell_quote("hash #{hash}")} " cmd << " --match #{shell_quote("hash #{hash}")} "
paths = [] paths = []
shellout(cmd) do |io| shellout(cmd) do |io|
......
...@@ -25,7 +25,12 @@ module Redmine ...@@ -25,7 +25,12 @@ module Redmine
module Scm module Scm
module Adapters module Adapters
class FilesystemAdapter < AbstractAdapter class FilesystemAdapter < AbstractAdapter
class << self
def client_available
true
end
end
def initialize(url, root_url=nil, login=nil, password=nil) def initialize(url, root_url=nil, login=nil, password=nil)
@url = with_trailling_slash(url) @url = with_trailling_slash(url)
......
...@@ -19,11 +19,25 @@ require 'redmine/scm/adapters/abstract_adapter' ...@@ -19,11 +19,25 @@ require 'redmine/scm/adapters/abstract_adapter'
module Redmine module Redmine
module Scm module Scm
module Adapters module Adapters
class GitAdapter < AbstractAdapter class GitAdapter < AbstractAdapter
# Git executable name # Git executable name
GIT_BIN = Redmine::Configuration['scm_git_command'] || "git" GIT_BIN = Redmine::Configuration['scm_git_command'] || "git"
class << self
def client_command
@@bin ||= GIT_BIN
end
def sq_bin
@@sq_bin ||= shell_quote(GIT_BIN)
end
def client_available
!client_version.empty?
end
end
def info def info
begin begin
Info.new(:root_url => url, :lastrev => lastrev('',nil)) Info.new(:root_url => url, :lastrev => lastrev('',nil))
...@@ -35,7 +49,7 @@ module Redmine ...@@ -35,7 +49,7 @@ module Redmine
def branches def branches
return @branches if @branches return @branches if @branches
@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| shellout(cmd) do |io|
io.each_line do |line| io.each_line do |line|
@branches << line.match('\s*\*?\s*(.*)$')[1] @branches << line.match('\s*\*?\s*(.*)$')[1]
...@@ -46,7 +60,7 @@ module Redmine ...@@ -46,7 +60,7 @@ module Redmine
def tags def tags
return @tags if @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| shellout(cmd) do |io|
@tags = io.readlines.sort!.map{|t| t.strip} @tags = io.readlines.sort!.map{|t| t.strip}
end end
...@@ -59,7 +73,7 @@ module Redmine ...@@ -59,7 +73,7 @@ module Redmine
def entries(path=nil, identifier=nil) def entries(path=nil, identifier=nil)
path ||= '' path ||= ''
entries = Entries.new 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("HEAD:" + path) if identifier.nil?
cmd << shell_quote(identifier + ":" + path) if identifier cmd << shell_quote(identifier + ":" + path) if identifier
shellout(cmd) do |io| shellout(cmd) do |io|
...@@ -86,7 +100,7 @@ module Redmine ...@@ -86,7 +100,7 @@ module Redmine
def lastrev(path,rev) def lastrev(path,rev)
return nil if path.nil? return nil if path.nil?
cmd = "#{GIT_BIN} --git-dir #{target('')} log --no-color --date=iso --pretty=fuller --no-merges -n 1 " cmd = "#{self.class.sq_bin} --git-dir #{target('')} log --no-color --date=iso --pretty=fuller --no-merges -n 1 "
cmd << " #{shell_quote rev} " if rev cmd << " #{shell_quote rev} " if rev
cmd << "-- #{shell_quote path} " unless path.empty? cmd << "-- #{shell_quote path} " unless path.empty?
lines = [] lines = []
...@@ -114,7 +128,7 @@ module Redmine ...@@ -114,7 +128,7 @@ module Redmine
def revisions(path, identifier_from, identifier_to, options={}) def revisions(path, identifier_from, identifier_to, options={})
revisions = Revisions.new revisions = Revisions.new
cmd = "#{GIT_BIN} --git-dir #{target('')} log --no-color --raw --date=iso --pretty=fuller " cmd = "#{self.class.sq_bin} --git-dir #{target('')} log --no-color --raw --date=iso --pretty=fuller "
cmd << " --reverse " if options[:reverse] cmd << " --reverse " if options[:reverse]
cmd << " --all " if options[:all] cmd << " --all " if options[:all]
cmd << " -n #{options[:limit].to_i} " if options[:limit] cmd << " -n #{options[:limit].to_i} " if options[:limit]
...@@ -209,9 +223,9 @@ module Redmine ...@@ -209,9 +223,9 @@ module Redmine
path ||= '' path ||= ''
if identifier_to 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 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 end
cmd << " -- #{shell_quote path}" unless path.empty? cmd << " -- #{shell_quote path}" unless path.empty?
...@@ -227,7 +241,7 @@ module Redmine ...@@ -227,7 +241,7 @@ module Redmine
def annotate(path, identifier=nil) def annotate(path, identifier=nil)
identifier = 'HEAD' if identifier.blank? 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 blame = Annotate.new
content = nil content = nil
shellout(cmd) { |io| io.binmode; content = io.read } shellout(cmd) { |io| io.binmode; content = io.read }
...@@ -255,7 +269,7 @@ module Redmine ...@@ -255,7 +269,7 @@ module Redmine
if identifier.nil? if identifier.nil?
identifier = 'HEAD' identifier = 'HEAD'
end 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 cat = nil
shellout(cmd) do |io| shellout(cmd) do |io|
io.binmode io.binmode
......
...@@ -20,7 +20,7 @@ require 'cgi' ...@@ -20,7 +20,7 @@ require 'cgi'
module Redmine module Redmine
module Scm module Scm
module Adapters module Adapters
class MercurialAdapter < AbstractAdapter class MercurialAdapter < AbstractAdapter
# Mercurial executable name # Mercurial executable name
...@@ -30,11 +30,23 @@ module Redmine ...@@ -30,11 +30,23 @@ module Redmine
TEMPLATE_EXTENSION = "tmpl" TEMPLATE_EXTENSION = "tmpl"
class << self class << self
def client_command
@@bin ||= HG_BIN
end
def sq_bin
@@sq_bin ||= shell_quote(HG_BIN)
end
def client_version def client_version
@@client_version ||= (hgversion || []) @@client_version ||= (hgversion || [])
end end
def hgversion def client_available
!client_version.empty?
end
def hgversion
# The hg version is expressed either as a # The hg version is expressed either as a
# release number (eg 0.9.5 or 1.0) or as a revision # release number (eg 0.9.5 or 1.0) or as a revision
# id composed of 12 hexa characters. # id composed of 12 hexa characters.
...@@ -45,7 +57,7 @@ module Redmine ...@@ -45,7 +57,7 @@ module Redmine
end end
def hgversion_from_command_line def hgversion_from_command_line
shellout("#{HG_BIN} --version") { |io| io.read }.to_s shellout("#{sq_bin} --version") { |io| io.read }.to_s
end end
def template_path def template_path
...@@ -63,7 +75,7 @@ module Redmine ...@@ -63,7 +75,7 @@ module Redmine
end end
def info def info
cmd = "#{HG_BIN} -R #{target('')} root" cmd = "#{self.class.sq_bin} -R #{target('')} root"
root_url = nil root_url = nil
shellout(cmd) do |io| shellout(cmd) do |io|
root_url = io.read root_url = io.read
...@@ -80,7 +92,7 @@ module Redmine ...@@ -80,7 +92,7 @@ module Redmine
def entries(path=nil, identifier=nil) def entries(path=nil, identifier=nil)
path ||= '' path ||= ''
entries = Entries.new entries = Entries.new
cmd = "#{HG_BIN} -R #{target('')} --cwd #{target('')} locate" cmd = "#{self.class.sq_bin} -R #{target('')} --cwd #{target('')} locate"
cmd << " -r #{hgrev(identifier)}" cmd << " -r #{hgrev(identifier)}"
cmd << " " + shell_quote("path:#{path}") unless path.empty? cmd << " " + shell_quote("path:#{path}") unless path.empty?
shellout(cmd) do |io| shellout(cmd) do |io|
...@@ -106,7 +118,7 @@ module Redmine ...@@ -106,7 +118,7 @@ module Redmine
# makes Mercurial produce a xml output. # makes Mercurial produce a xml output.
def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}) def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
revisions = Revisions.new revisions = Revisions.new
cmd = "#{HG_BIN} --debug --encoding utf8 -R #{target('')} log -C --style #{shell_quote self.class.template_path}" cmd = "#{self.class.sq_bin} --debug --encoding utf8 -R #{target('')} log -C --style #{shell_quote self.class.template_path}"
if identifier_from && identifier_to if identifier_from && identifier_to
cmd << " -r #{hgrev(identifier_from)}:#{hgrev(identifier_to)}" cmd << " -r #{hgrev(identifier_from)}:#{hgrev(identifier_to)}"
elsif identifier_from elsif identifier_from
...@@ -164,7 +176,7 @@ module Redmine ...@@ -164,7 +176,7 @@ module Redmine
return [] return []
end end
end end
cmd = "#{HG_BIN} -R #{target('')} --config diff.git=false diff --nodates #{diff_args}" cmd = "#{self.class.sq_bin} -R #{target('')} --config diff.git=false diff --nodates #{diff_args}"
cmd << " -I #{target(path)}" unless path.empty? cmd << " -I #{target(path)}" unless path.empty?
shellout(cmd) do |io| shellout(cmd) do |io|
io.each_line do |line| io.each_line do |line|
...@@ -176,7 +188,7 @@ module Redmine ...@@ -176,7 +188,7 @@ module Redmine
end end
def cat(path, identifier=nil) def cat(path, identifier=nil)
cmd = "#{HG_BIN} -R #{target('')} cat" cmd = "#{self.class.sq_bin} -R #{target('')} cat"
cmd << " -r #{hgrev(identifier)}" cmd << " -r #{hgrev(identifier)}"
cmd << " #{target(path)}" cmd << " #{target(path)}"
cat = nil cat = nil
...@@ -190,7 +202,7 @@ module Redmine ...@@ -190,7 +202,7 @@ module Redmine
def annotate(path, identifier=nil) def annotate(path, identifier=nil)
path ||= '' path ||= ''
cmd = "#{HG_BIN} -R #{target('')}" cmd = "#{self.class.sq_bin} -R #{target('')}"
cmd << " annotate -ncu" cmd << " annotate -ncu"
cmd << " -r #{hgrev(identifier)}" cmd << " -r #{hgrev(identifier)}"
cmd << " #{target(path)}" cmd << " #{target(path)}"
......
...@@ -20,19 +20,27 @@ require 'uri' ...@@ -20,19 +20,27 @@ require 'uri'
module Redmine module Redmine
module Scm module Scm
module Adapters module Adapters
class SubversionAdapter < AbstractAdapter class SubversionAdapter < AbstractAdapter
# SVN executable name # SVN executable name
SVN_BIN = Redmine::Configuration['scm_subversion_command'] || "svn" SVN_BIN = Redmine::Configuration['scm_subversion_command'] || "svn"
class << self class << self
def client_command
@@bin ||= SVN_BIN
end
def sq_bin
@@sq_bin ||= shell_quote(SVN_BIN)
end
def client_version def client_version
@@client_version ||= (svn_binary_version || []) @@client_version ||= (svn_binary_version || [])
end end
def svn_binary_version def svn_binary_version
cmd = "#{SVN_BIN} --version" cmd = "#{sq_bin} --version"
version = nil version = nil
shellout(cmd) do |io| shellout(cmd) do |io|
# Read svn version in first returned line # Read svn version in first returned line
...@@ -44,10 +52,10 @@ module Redmine ...@@ -44,10 +52,10 @@ module Redmine
version version
end end
end end
# Get info about the svn repository # Get info about the svn repository
def info def info
cmd = "#{SVN_BIN} info --xml #{target}" cmd = "#{self.class.sq_bin} info --xml #{target}"
cmd << credentials_string cmd << credentials_string
info = nil info = nil
shellout(cmd) do |io| shellout(cmd) do |io|
...@@ -70,14 +78,14 @@ module Redmine ...@@ -70,14 +78,14 @@ module Redmine
rescue CommandFailed rescue CommandFailed
return nil return nil
end end
# Returns an Entries collection # Returns an Entries collection
# or nil if the given path doesn't exist in the repository # or nil if the given path doesn't exist in the repository
def entries(path=nil, identifier=nil) def entries(path=nil, identifier=nil)
path ||= '' path ||= ''
identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD" identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
entries = Entries.new entries = Entries.new
cmd = "#{SVN_BIN} list --xml #{target(path)}@#{identifier}" cmd = "#{self.class.sq_bin} list --xml #{target(path)}@#{identifier}"
cmd << credentials_string cmd << credentials_string
shellout(cmd) do |io| shellout(cmd) do |io|
output = io.read output = io.read
...@@ -110,13 +118,13 @@ module Redmine ...@@ -110,13 +118,13 @@ module Redmine
logger.debug("Found #{entries.size} entries in the repository for #{target(path)}") if logger && logger.debug? logger.debug("Found #{entries.size} entries in the repository for #{target(path)}") if logger && logger.debug?
entries.sort_by_name entries.sort_by_name
end end
def properties(path, identifier=nil) def properties(path, identifier=nil)
# proplist xml output supported in svn 1.5.0 and higher # proplist xml output supported in svn 1.5.0 and higher
return nil unless self.class.client_version_above?([1, 5, 0]) return nil unless self.class.client_version_above?([1, 5, 0])
identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD" identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
cmd = "#{SVN_BIN} proplist --verbose --xml #{target(path)}@#{identifier}" cmd = "#{self.class.sq_bin} proplist --verbose --xml #{target(path)}@#{identifier}"
cmd << credentials_string cmd << credentials_string
properties = {} properties = {}
shellout(cmd) do |io| shellout(cmd) do |io|
...@@ -132,13 +140,13 @@ module Redmine ...@@ -132,13 +140,13 @@ module Redmine
return nil if $? && $?.exitstatus != 0 return nil if $? && $?.exitstatus != 0
properties properties
end end
def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}) def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
path ||= '' path ||= ''
identifier_from = (identifier_from && identifier_from.to_i > 0) ? identifier_from.to_i : "HEAD" identifier_from = (identifier_from && identifier_from.to_i > 0) ? identifier_from.to_i : "HEAD"
identifier_to = (identifier_to && identifier_to.to_i > 0) ? identifier_to.to_i : 1 identifier_to = (identifier_to && identifier_to.to_i > 0) ? identifier_to.to_i : 1
revisions = Revisions.new revisions = Revisions.new
cmd = "#{SVN_BIN} log --xml -r #{identifier_from}:#{identifier_to}" cmd = "#{self.class.sq_bin} log --xml -r #{identifier_from}:#{identifier_to}"
cmd << credentials_string cmd << credentials_string
cmd << " --verbose " if options[:with_paths] cmd << " --verbose " if options[:with_paths]
cmd << " --limit #{options[:limit].to_i}" if options[:limit] cmd << " --limit #{options[:limit].to_i}" if options[:limit]
...@@ -171,13 +179,13 @@ module Redmine ...@@ -171,13 +179,13 @@ module Redmine
return nil if $? && $?.exitstatus != 0 return nil if $? && $?.exitstatus != 0
revisions revisions
end end
def diff(path, identifier_from, identifier_to=nil, type="inline") def diff(path, identifier_from, identifier_to=nil, type="inline")
path ||= '' path ||= ''
identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : '' identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : ''
identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : (identifier_from.to_i - 1) identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : (identifier_from.to_i - 1)
cmd = "#{SVN_BIN} diff -r " cmd = "#{self.class.sq_bin} diff -r "
cmd << "#{identifier_to}:" cmd << "#{identifier_to}:"
cmd << "#{identifier_from}" cmd << "#{identifier_from}"
cmd << " #{target(path)}@#{identifier_from}" cmd << " #{target(path)}@#{identifier_from}"
...@@ -191,10 +199,10 @@ module Redmine ...@@ -191,10 +199,10 @@ module Redmine
return nil if $? && $?.exitstatus != 0 return nil if $? && $?.exitstatus != 0
diff diff
end end
def cat(path, identifier=nil) def cat(path, identifier=nil)
identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD" identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
cmd = "#{SVN_BIN} cat #{target(path)}@#{identifier}" cmd = "#{self.class.sq_bin} cat #{target(path)}@#{identifier}"
cmd << credentials_string cmd << credentials_string
cat = nil cat = nil
shellout(cmd) do |io| shellout(cmd) do |io|
...@@ -204,10 +212,10 @@ module Redmine ...@@ -204,10 +212,10 @@ module Redmine
return nil if $? && $?.exitstatus != 0 return nil if $? && $?.exitstatus != 0
cat cat
end end
def annotate(path, identifier=nil) def annotate(path, identifier=nil)
identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD" identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
cmd = "#{SVN_BIN} blame #{target(path)}@#{identifier}" cmd = "#{self.class.sq_bin} blame #{target(path)}@#{identifier}"
cmd << credentials_string cmd << credentials_string
blame = Annotate.new blame = Annotate.new
shellout(cmd) do |io| shellout(cmd) do |io|
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment