##// END OF EJS Templates
scm: use shell quote for scm command at adapter level (#7517, #4273)....
Toshi MARUYAMA -
r4701:8b98c05879a2
parent child
Show More
@@ -111,7 +111,7 default:
111 # Absolute path (e.g. /usr/local/bin/hg) or command name (e.g. hg.exe, bzr.exe)
111 # Absolute path (e.g. /usr/local/bin/hg) or command name (e.g. hg.exe, bzr.exe)
112 # On Windows, *.cmd, *.bat (e.g. hg.cmd, bzr.bat) does not work.
112 # On Windows, *.cmd, *.bat (e.g. hg.cmd, bzr.bat) does not work.
113 scm_subversion_command: svn # (default: svn)
113 scm_subversion_command: svn # (default: svn)
114 scm_mercurial_command: "\"C:\Program Files\TortoiseHg\hg.exe\"" # (default: hg)
114 scm_mercurial_command: C:\Program Files\TortoiseHg\hg.exe # (default: hg)
115 scm_git_command: /usr/local/bin/git # (default: git)
115 scm_git_command: /usr/local/bin/git # (default: git)
116 scm_cvs_command: cvs # (default: cvs)
116 scm_cvs_command: cvs # (default: cvs)
117 scm_bazaar_command: bzr.exe # (default: bzr)
117 scm_bazaar_command: bzr.exe # (default: bzr)
@@ -25,6 +25,10 module Redmine
25
25
26 class AbstractAdapter #:nodoc:
26 class AbstractAdapter #:nodoc:
27 class << self
27 class << self
28 def client_command
29 ""
30 end
31
28 # Returns the version of the scm client
32 # Returns the version of the scm client
29 # Eg: [1, 5, 0] or [] if unknown
33 # Eg: [1, 5, 0] or [] if unknown
30 def client_version
34 def client_version
@@ -45,8 +49,20 module Redmine
45 def client_version_above?(v, options={})
49 def client_version_above?(v, options={})
46 ((client_version <=> v) >= 0) || (client_version.empty? && options[:unknown])
50 ((client_version <=> v) >= 0) || (client_version.empty? && options[:unknown])
47 end
51 end
52
53 def client_available
54 true
55 end
56
57 def shell_quote(str)
58 if Redmine::Platform.mswin?
59 '"' + str.gsub(/"/, '\\"') + '"'
60 else
61 "'" + str.gsub(/'/, "'\"'\"'") + "'"
62 end
63 end
48 end
64 end
49
65
50 def initialize(url, root_url=nil, login=nil, password=nil)
66 def initialize(url, root_url=nil, login=nil, password=nil)
51 @url = url
67 @url = url
52 @login = login if login && !login.empty?
68 @login = login if login && !login.empty?
@@ -138,7 +154,7 module Redmine
138 path ||= ''
154 path ||= ''
139 (path[-1,1] == "/") ? path : "#{path}/"
155 (path[-1,1] == "/") ? path : "#{path}/"
140 end
156 end
141
157
142 def without_leading_slash(path)
158 def without_leading_slash(path)
143 path ||= ''
159 path ||= ''
144 path.gsub(%r{^/+}, '')
160 path.gsub(%r{^/+}, '')
@@ -148,13 +164,9 module Redmine
148 path ||= ''
164 path ||= ''
149 (path[-1,1] == "/") ? path[0..-2] : path
165 (path[-1,1] == "/") ? path[0..-2] : path
150 end
166 end
151
167
152 def shell_quote(str)
168 def shell_quote(str)
153 if Redmine::Platform.mswin?
169 self.class.shell_quote(str)
154 '"' + str.gsub(/"/, '\\"') + '"'
155 else
156 "'" + str.gsub(/'/, "'\"'\"'") + "'"
157 end
158 end
170 end
159
171
160 private
172 private
@@ -168,11 +180,11 module Redmine
168 base = path.match(/^\//) ? root_url : url
180 base = path.match(/^\//) ? root_url : url
169 shell_quote("#{base}/#{path}".gsub(/[?<>\*]/, ''))
181 shell_quote("#{base}/#{path}".gsub(/[?<>\*]/, ''))
170 end
182 end
171
183
172 def logger
184 def logger
173 self.class.logger
185 self.class.logger
174 end
186 end
175
187
176 def shellout(cmd, &block)
188 def shellout(cmd, &block)
177 self.class.shellout(cmd, &block)
189 self.class.shellout(cmd, &block)
178 end
190 end
@@ -19,15 +19,25 require 'redmine/scm/adapters/abstract_adapter'
19
19
20 module Redmine
20 module Redmine
21 module Scm
21 module Scm
22 module Adapters
22 module Adapters
23 class BazaarAdapter < AbstractAdapter
23 class BazaarAdapter < AbstractAdapter
24
24
25 # Bazaar executable name
25 # Bazaar executable name
26 BZR_BIN = Redmine::Configuration['scm_bazaar_command'] || "bzr"
26 BZR_BIN = Redmine::Configuration['scm_bazaar_command'] || "bzr"
27
27
28 class << self
29 def client_command
30 @@bin ||= BZR_BIN
31 end
32
33 def sq_bin
34 @@sq_bin ||= shell_quote(BZR_BIN)
35 end
36 end
37
28 # Get info about the repository
38 # Get info about the repository
29 def info
39 def info
30 cmd = "#{BZR_BIN} revno #{target('')}"
40 cmd = "#{self.class.sq_bin} revno #{target('')}"
31 info = nil
41 info = nil
32 shellout(cmd) do |io|
42 shellout(cmd) do |io|
33 if io.read =~ %r{^(\d+)\r?$}
43 if io.read =~ %r{^(\d+)\r?$}
@@ -43,13 +53,13 module Redmine
43 rescue CommandFailed
53 rescue CommandFailed
44 return nil
54 return nil
45 end
55 end
46
56
47 # Returns an Entries collection
57 # Returns an Entries collection
48 # or nil if the given path doesn't exist in the repository
58 # or nil if the given path doesn't exist in the repository
49 def entries(path=nil, identifier=nil)
59 def entries(path=nil, identifier=nil)
50 path ||= ''
60 path ||= ''
51 entries = Entries.new
61 entries = Entries.new
52 cmd = "#{BZR_BIN} ls -v --show-ids"
62 cmd = "#{self.class.sq_bin} ls -v --show-ids"
53 identifier = -1 unless identifier && identifier.to_i > 0
63 identifier = -1 unless identifier && identifier.to_i > 0
54 cmd << " -r#{identifier.to_i}"
64 cmd << " -r#{identifier.to_i}"
55 cmd << " #{target(path)}"
65 cmd << " #{target(path)}"
@@ -71,13 +81,13 module Redmine
71 logger.debug("Found #{entries.size} entries in the repository for #{target(path)}") if logger && logger.debug?
81 logger.debug("Found #{entries.size} entries in the repository for #{target(path)}") if logger && logger.debug?
72 entries.sort_by_name
82 entries.sort_by_name
73 end
83 end
74
84
75 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
85 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
76 path ||= ''
86 path ||= ''
77 identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : 'last:1'
87 identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : 'last:1'
78 identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : 1
88 identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : 1
79 revisions = Revisions.new
89 revisions = Revisions.new
80 cmd = "#{BZR_BIN} log -v --show-ids -r#{identifier_to}..#{identifier_from} #{target(path)}"
90 cmd = "#{self.class.sq_bin} log -v --show-ids -r#{identifier_to}..#{identifier_from} #{target(path)}"
81 shellout(cmd) do |io|
91 shellout(cmd) do |io|
82 revision = nil
92 revision = nil
83 parsing = nil
93 parsing = nil
@@ -132,7 +142,7 module Redmine
132 return nil if $? && $?.exitstatus != 0
142 return nil if $? && $?.exitstatus != 0
133 revisions
143 revisions
134 end
144 end
135
145
136 def diff(path, identifier_from, identifier_to=nil)
146 def diff(path, identifier_from, identifier_to=nil)
137 path ||= ''
147 path ||= ''
138 if identifier_to
148 if identifier_to
@@ -143,7 +153,7 module Redmine
143 if identifier_from
153 if identifier_from
144 identifier_from = identifier_from.to_i
154 identifier_from = identifier_from.to_i
145 end
155 end
146 cmd = "#{BZR_BIN} diff -r#{identifier_to}..#{identifier_from} #{target(path)}"
156 cmd = "#{self.class.sq_bin} diff -r#{identifier_to}..#{identifier_from} #{target(path)}"
147 diff = []
157 diff = []
148 shellout(cmd) do |io|
158 shellout(cmd) do |io|
149 io.each_line do |line|
159 io.each_line do |line|
@@ -153,9 +163,9 module Redmine
153 #return nil if $? && $?.exitstatus != 0
163 #return nil if $? && $?.exitstatus != 0
154 diff
164 diff
155 end
165 end
156
166
157 def cat(path, identifier=nil)
167 def cat(path, identifier=nil)
158 cmd = "#{BZR_BIN} cat"
168 cmd = "#{self.class.sq_bin} cat"
159 cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0
169 cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0
160 cmd << " #{target(path)}"
170 cmd << " #{target(path)}"
161 cat = nil
171 cat = nil
@@ -166,9 +176,9 module Redmine
166 return nil if $? && $?.exitstatus != 0
176 return nil if $? && $?.exitstatus != 0
167 cat
177 cat
168 end
178 end
169
179
170 def annotate(path, identifier=nil)
180 def annotate(path, identifier=nil)
171 cmd = "#{BZR_BIN} annotate --all"
181 cmd = "#{self.class.sq_bin} annotate --all"
172 cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0
182 cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0
173 cmd << " #{target(path)}"
183 cmd << " #{target(path)}"
174 blame = Annotate.new
184 blame = Annotate.new
@@ -24,7 +24,17 module Redmine
24
24
25 # CVS executable name
25 # CVS executable name
26 CVS_BIN = Redmine::Configuration['scm_cvs_command'] || "cvs"
26 CVS_BIN = Redmine::Configuration['scm_cvs_command'] || "cvs"
27
27
28 class << self
29 def client_command
30 @@bin ||= CVS_BIN
31 end
32
33 def sq_bin
34 @@sq_bin ||= shell_quote(CVS_BIN)
35 end
36 end
37
28 # Guidelines for the input:
38 # Guidelines for the input:
29 # url -> the project-path, relative to the cvsroot (eg. module name)
39 # url -> the project-path, relative to the cvsroot (eg. module name)
30 # root_url -> the good old, sometimes damned, CVSROOT
40 # root_url -> the good old, sometimes damned, CVSROOT
@@ -38,20 +48,20 module Redmine
38 raise CommandFailed if root_url.blank?
48 raise CommandFailed if root_url.blank?
39 @root_url = root_url
49 @root_url = root_url
40 end
50 end
41
51
42 def root_url
52 def root_url
43 @root_url
53 @root_url
44 end
54 end
45
55
46 def url
56 def url
47 @url
57 @url
48 end
58 end
49
59
50 def info
60 def info
51 logger.debug "<cvs> info"
61 logger.debug "<cvs> info"
52 Info.new({:root_url => @root_url, :lastrev => nil})
62 Info.new({:root_url => @root_url, :lastrev => nil})
53 end
63 end
54
64
55 def get_previous_revision(revision)
65 def get_previous_revision(revision)
56 CvsRevisionHelper.new(revision).prevRev
66 CvsRevisionHelper.new(revision).prevRev
57 end
67 end
@@ -63,7 +73,7 module Redmine
63 logger.debug "<cvs> entries '#{path}' with identifier '#{identifier}'"
73 logger.debug "<cvs> entries '#{path}' with identifier '#{identifier}'"
64 path_with_project="#{url}#{with_leading_slash(path)}"
74 path_with_project="#{url}#{with_leading_slash(path)}"
65 entries = Entries.new
75 entries = Entries.new
66 cmd = "#{CVS_BIN} -d #{shell_quote root_url} rls -e"
76 cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} rls -e"
67 cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier
77 cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier
68 cmd << " #{shell_quote path_with_project}"
78 cmd << " #{shell_quote path_with_project}"
69 shellout(cmd) do |io|
79 shellout(cmd) do |io|
@@ -108,7 +118,7 module Redmine
108 logger.debug "<cvs> revisions path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}"
118 logger.debug "<cvs> revisions path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}"
109
119
110 path_with_project="#{url}#{with_leading_slash(path)}"
120 path_with_project="#{url}#{with_leading_slash(path)}"
111 cmd = "#{CVS_BIN} -d #{shell_quote root_url} rlog"
121 cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} rlog"
112 cmd << " -d\">#{time_to_cvstime_rlog(identifier_from)}\"" if identifier_from
122 cmd << " -d\">#{time_to_cvstime_rlog(identifier_from)}\"" if identifier_from
113 cmd << " #{shell_quote path_with_project}"
123 cmd << " #{shell_quote path_with_project}"
114 shellout(cmd) do |io|
124 shellout(cmd) do |io|
@@ -229,7 +239,7 module Redmine
229 def diff(path, identifier_from, identifier_to=nil)
239 def diff(path, identifier_from, identifier_to=nil)
230 logger.debug "<cvs> diff path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}"
240 logger.debug "<cvs> diff path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}"
231 path_with_project="#{url}#{with_leading_slash(path)}"
241 path_with_project="#{url}#{with_leading_slash(path)}"
232 cmd = "#{CVS_BIN} -d #{shell_quote root_url} rdiff -u -r#{identifier_to} -r#{identifier_from} #{shell_quote path_with_project}"
242 cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} rdiff -u -r#{identifier_to} -r#{identifier_from} #{shell_quote path_with_project}"
233 diff = []
243 diff = []
234 shellout(cmd) do |io|
244 shellout(cmd) do |io|
235 io.each_line do |line|
245 io.each_line do |line|
@@ -244,7 +254,7 module Redmine
244 identifier = (identifier) ? identifier : "HEAD"
254 identifier = (identifier) ? identifier : "HEAD"
245 logger.debug "<cvs> cat path:'#{path}',identifier #{identifier}"
255 logger.debug "<cvs> cat path:'#{path}',identifier #{identifier}"
246 path_with_project="#{url}#{with_leading_slash(path)}"
256 path_with_project="#{url}#{with_leading_slash(path)}"
247 cmd = "#{CVS_BIN} -d #{shell_quote root_url} co"
257 cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} co"
248 cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier
258 cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier
249 cmd << " -p #{shell_quote path_with_project}"
259 cmd << " -p #{shell_quote path_with_project}"
250 cat = nil
260 cat = nil
@@ -260,7 +270,7 module Redmine
260 identifier = (identifier) ? identifier.to_i : "HEAD"
270 identifier = (identifier) ? identifier.to_i : "HEAD"
261 logger.debug "<cvs> annotate path:'#{path}',identifier #{identifier}"
271 logger.debug "<cvs> annotate path:'#{path}',identifier #{identifier}"
262 path_with_project="#{url}#{with_leading_slash(path)}"
272 path_with_project="#{url}#{with_leading_slash(path)}"
263 cmd = "#{CVS_BIN} -d #{shell_quote root_url} rannotate -r#{identifier} #{shell_quote path_with_project}"
273 cmd = "#{self.class.sq_bin} -d #{shell_quote root_url} rannotate -r#{identifier} #{shell_quote path_with_project}"
264 blame = Annotate.new
274 blame = Annotate.new
265 shellout(cmd) do |io|
275 shellout(cmd) do |io|
266 io.each_line do |line|
276 io.each_line do |line|
@@ -20,16 +20,24 require 'rexml/document'
20
20
21 module Redmine
21 module Redmine
22 module Scm
22 module Scm
23 module Adapters
23 module Adapters
24 class DarcsAdapter < AbstractAdapter
24 class DarcsAdapter < AbstractAdapter
25 # Darcs executable name
25 # Darcs executable name
26 DARCS_BIN = Redmine::Configuration['scm_darcs_command'] || "darcs"
26 DARCS_BIN = Redmine::Configuration['scm_darcs_command'] || "darcs"
27
27
28 class << self
28 class << self
29 def client_command
30 @@bin ||= DARCS_BIN
31 end
32
33 def sq_bin
34 @@sq_bin ||= shell_quote(DARCS_BIN)
35 end
36
29 def client_version
37 def client_version
30 @@client_version ||= (darcs_binary_version || [])
38 @@client_version ||= (darcs_binary_version || [])
31 end
39 end
32
40
33 def darcs_binary_version
41 def darcs_binary_version
34 darcsversion = darcs_binary_version_from_command_line
42 darcsversion = darcs_binary_version_from_command_line
35 if m = darcsversion.match(%r{\A(.*?)((\d+\.)+\d+)})
43 if m = darcsversion.match(%r{\A(.*?)((\d+\.)+\d+)})
@@ -38,7 +46,7 module Redmine
38 end
46 end
39
47
40 def darcs_binary_version_from_command_line
48 def darcs_binary_version_from_command_line
41 shellout("#{DARCS_BIN} --version") { |io| io.read }.to_s
49 shellout("#{sq_bin} --version") { |io| io.read }.to_s
42 end
50 end
43 end
51 end
44
52
@@ -57,7 +65,7 module Redmine
57 rev = revisions(nil,nil,nil,{:limit => 1})
65 rev = revisions(nil,nil,nil,{:limit => 1})
58 rev ? Info.new({:root_url => @url, :lastrev => rev.last}) : nil
66 rev ? Info.new({:root_url => @url, :lastrev => rev.last}) : nil
59 end
67 end
60
68
61 # Returns an Entries collection
69 # Returns an Entries collection
62 # or nil if the given path doesn't exist in the repository
70 # or nil if the given path doesn't exist in the repository
63 def entries(path=nil, identifier=nil)
71 def entries(path=nil, identifier=nil)
@@ -66,7 +74,7 module Redmine
66 path = ( self.class.client_version_above?([2, 2, 0]) ? @url : '.' )
74 path = ( self.class.client_version_above?([2, 2, 0]) ? @url : '.' )
67 end
75 end
68 entries = Entries.new
76 entries = Entries.new
69 cmd = "#{DARCS_BIN} annotate --repodir #{shell_quote @url} --xml-output"
77 cmd = "#{self.class.sq_bin} annotate --repodir #{shell_quote @url} --xml-output"
70 cmd << " --match #{shell_quote("hash #{identifier}")}" if identifier
78 cmd << " --match #{shell_quote("hash #{identifier}")}" if identifier
71 cmd << " #{shell_quote path}"
79 cmd << " #{shell_quote path}"
72 shellout(cmd) do |io|
80 shellout(cmd) do |io|
@@ -86,11 +94,11 module Redmine
86 return nil if $? && $?.exitstatus != 0
94 return nil if $? && $?.exitstatus != 0
87 entries.compact.sort_by_name
95 entries.compact.sort_by_name
88 end
96 end
89
97
90 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
98 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
91 path = '.' if path.blank?
99 path = '.' if path.blank?
92 revisions = Revisions.new
100 revisions = Revisions.new
93 cmd = "#{DARCS_BIN} changes --repodir #{shell_quote @url} --xml-output"
101 cmd = "#{self.class.sq_bin} changes --repodir #{shell_quote @url} --xml-output"
94 cmd << " --from-match #{shell_quote("hash #{identifier_from}")}" if identifier_from
102 cmd << " --from-match #{shell_quote("hash #{identifier_from}")}" if identifier_from
95 cmd << " --last #{options[:limit].to_i}" if options[:limit]
103 cmd << " --last #{options[:limit].to_i}" if options[:limit]
96 shellout(cmd) do |io|
104 shellout(cmd) do |io|
@@ -113,10 +121,10 module Redmine
113 return nil if $? && $?.exitstatus != 0
121 return nil if $? && $?.exitstatus != 0
114 revisions
122 revisions
115 end
123 end
116
124
117 def diff(path, identifier_from, identifier_to=nil)
125 def diff(path, identifier_from, identifier_to=nil)
118 path = '*' if path.blank?
126 path = '*' if path.blank?
119 cmd = "#{DARCS_BIN} diff --repodir #{shell_quote @url}"
127 cmd = "#{self.class.sq_bin} diff --repodir #{shell_quote @url}"
120 if identifier_to.nil?
128 if identifier_to.nil?
121 cmd << " --match #{shell_quote("hash #{identifier_from}")}"
129 cmd << " --match #{shell_quote("hash #{identifier_from}")}"
122 else
130 else
@@ -133,9 +141,9 module Redmine
133 return nil if $? && $?.exitstatus != 0
141 return nil if $? && $?.exitstatus != 0
134 diff
142 diff
135 end
143 end
136
144
137 def cat(path, identifier=nil)
145 def cat(path, identifier=nil)
138 cmd = "#{DARCS_BIN} show content --repodir #{shell_quote @url}"
146 cmd = "#{self.class.sq_bin} show content --repodir #{shell_quote @url}"
139 cmd << " --match #{shell_quote("hash #{identifier}")}" if identifier
147 cmd << " --match #{shell_quote("hash #{identifier}")}" if identifier
140 cmd << " #{shell_quote path}"
148 cmd << " #{shell_quote path}"
141 cat = nil
149 cat = nil
@@ -148,7 +156,7 module Redmine
148 end
156 end
149
157
150 private
158 private
151
159
152 # Returns an Entry from the given XML element
160 # Returns an Entry from the given XML element
153 # or nil if the entry was deleted
161 # or nil if the entry was deleted
154 def entry_from_xml(element, path_prefix)
162 def entry_from_xml(element, path_prefix)
@@ -196,10 +204,10 module Redmine
196 end
204 end
197 paths
205 paths
198 end
206 end
199
207
200 # Retrieve changed paths for a single patch
208 # Retrieve changed paths for a single patch
201 def get_paths_for_patch_raw(hash)
209 def get_paths_for_patch_raw(hash)
202 cmd = "#{DARCS_BIN} annotate --repodir #{shell_quote @url} --summary --xml-output"
210 cmd = "#{self.class.sq_bin} annotate --repodir #{shell_quote @url} --summary --xml-output"
203 cmd << " --match #{shell_quote("hash #{hash}")} "
211 cmd << " --match #{shell_quote("hash #{hash}")} "
204 paths = []
212 paths = []
205 shellout(cmd) do |io|
213 shellout(cmd) do |io|
@@ -25,7 +25,12 module Redmine
25 module Scm
25 module Scm
26 module Adapters
26 module Adapters
27 class FilesystemAdapter < AbstractAdapter
27 class FilesystemAdapter < AbstractAdapter
28
28
29 class << self
30 def client_available
31 true
32 end
33 end
29
34
30 def initialize(url, root_url=nil, login=nil, password=nil)
35 def initialize(url, root_url=nil, login=nil, password=nil)
31 @url = with_trailling_slash(url)
36 @url = with_trailling_slash(url)
@@ -19,11 +19,25 require 'redmine/scm/adapters/abstract_adapter'
19
19
20 module Redmine
20 module Redmine
21 module Scm
21 module Scm
22 module Adapters
22 module Adapters
23 class GitAdapter < AbstractAdapter
23 class GitAdapter < AbstractAdapter
24 # Git executable name
24 # Git executable name
25 GIT_BIN = Redmine::Configuration['scm_git_command'] || "git"
25 GIT_BIN = Redmine::Configuration['scm_git_command'] || "git"
26
26
27 class << self
28 def client_command
29 @@bin ||= GIT_BIN
30 end
31
32 def sq_bin
33 @@sq_bin ||= shell_quote(GIT_BIN)
34 end
35
36 def client_available
37 !client_version.empty?
38 end
39 end
40
27 def info
41 def info
28 begin
42 begin
29 Info.new(:root_url => url, :lastrev => lastrev('',nil))
43 Info.new(:root_url => url, :lastrev => lastrev('',nil))
@@ -35,7 +49,7 module Redmine
35 def branches
49 def branches
36 return @branches if @branches
50 return @branches if @branches
37 @branches = []
51 @branches = []
38 cmd = "#{GIT_BIN} --git-dir #{target('')} branch --no-color"
52 cmd = "#{self.class.sq_bin} --git-dir #{target('')} branch --no-color"
39 shellout(cmd) do |io|
53 shellout(cmd) do |io|
40 io.each_line do |line|
54 io.each_line do |line|
41 @branches << line.match('\s*\*?\s*(.*)$')[1]
55 @branches << line.match('\s*\*?\s*(.*)$')[1]
@@ -46,7 +60,7 module Redmine
46
60
47 def tags
61 def tags
48 return @tags if @tags
62 return @tags if @tags
49 cmd = "#{GIT_BIN} --git-dir #{target('')} tag"
63 cmd = "#{self.class.sq_bin} --git-dir #{target('')} tag"
50 shellout(cmd) do |io|
64 shellout(cmd) do |io|
51 @tags = io.readlines.sort!.map{|t| t.strip}
65 @tags = io.readlines.sort!.map{|t| t.strip}
52 end
66 end
@@ -59,7 +73,7 module Redmine
59 def entries(path=nil, identifier=nil)
73 def entries(path=nil, identifier=nil)
60 path ||= ''
74 path ||= ''
61 entries = Entries.new
75 entries = Entries.new
62 cmd = "#{GIT_BIN} --git-dir #{target('')} ls-tree -l "
76 cmd = "#{self.class.sq_bin} --git-dir #{target('')} ls-tree -l "
63 cmd << shell_quote("HEAD:" + path) if identifier.nil?
77 cmd << shell_quote("HEAD:" + path) if identifier.nil?
64 cmd << shell_quote(identifier + ":" + path) if identifier
78 cmd << shell_quote(identifier + ":" + path) if identifier
65 shellout(cmd) do |io|
79 shellout(cmd) do |io|
@@ -86,7 +100,7 module Redmine
86
100
87 def lastrev(path,rev)
101 def lastrev(path,rev)
88 return nil if path.nil?
102 return nil if path.nil?
89 cmd = "#{GIT_BIN} --git-dir #{target('')} log --no-color --date=iso --pretty=fuller --no-merges -n 1 "
103 cmd = "#{self.class.sq_bin} --git-dir #{target('')} log --no-color --date=iso --pretty=fuller --no-merges -n 1 "
90 cmd << " #{shell_quote rev} " if rev
104 cmd << " #{shell_quote rev} " if rev
91 cmd << "-- #{shell_quote path} " unless path.empty?
105 cmd << "-- #{shell_quote path} " unless path.empty?
92 lines = []
106 lines = []
@@ -114,7 +128,7 module Redmine
114 def revisions(path, identifier_from, identifier_to, options={})
128 def revisions(path, identifier_from, identifier_to, options={})
115 revisions = Revisions.new
129 revisions = Revisions.new
116
130
117 cmd = "#{GIT_BIN} --git-dir #{target('')} log --no-color --raw --date=iso --pretty=fuller "
131 cmd = "#{self.class.sq_bin} --git-dir #{target('')} log --no-color --raw --date=iso --pretty=fuller "
118 cmd << " --reverse " if options[:reverse]
132 cmd << " --reverse " if options[:reverse]
119 cmd << " --all " if options[:all]
133 cmd << " --all " if options[:all]
120 cmd << " -n #{options[:limit].to_i} " if options[:limit]
134 cmd << " -n #{options[:limit].to_i} " if options[:limit]
@@ -209,9 +223,9 module Redmine
209 path ||= ''
223 path ||= ''
210
224
211 if identifier_to
225 if identifier_to
212 cmd = "#{GIT_BIN} --git-dir #{target('')} diff --no-color #{shell_quote identifier_to} #{shell_quote identifier_from}"
226 cmd = "#{self.class.sq_bin} --git-dir #{target('')} diff --no-color #{shell_quote identifier_to} #{shell_quote identifier_from}"
213 else
227 else
214 cmd = "#{GIT_BIN} --git-dir #{target('')} show --no-color #{shell_quote identifier_from}"
228 cmd = "#{self.class.sq_bin} --git-dir #{target('')} show --no-color #{shell_quote identifier_from}"
215 end
229 end
216
230
217 cmd << " -- #{shell_quote path}" unless path.empty?
231 cmd << " -- #{shell_quote path}" unless path.empty?
@@ -227,7 +241,7 module Redmine
227
241
228 def annotate(path, identifier=nil)
242 def annotate(path, identifier=nil)
229 identifier = 'HEAD' if identifier.blank?
243 identifier = 'HEAD' if identifier.blank?
230 cmd = "#{GIT_BIN} --git-dir #{target('')} blame -p #{shell_quote identifier} -- #{shell_quote path}"
244 cmd = "#{self.class.sq_bin} --git-dir #{target('')} blame -p #{shell_quote identifier} -- #{shell_quote path}"
231 blame = Annotate.new
245 blame = Annotate.new
232 content = nil
246 content = nil
233 shellout(cmd) { |io| io.binmode; content = io.read }
247 shellout(cmd) { |io| io.binmode; content = io.read }
@@ -255,7 +269,7 module Redmine
255 if identifier.nil?
269 if identifier.nil?
256 identifier = 'HEAD'
270 identifier = 'HEAD'
257 end
271 end
258 cmd = "#{GIT_BIN} --git-dir #{target('')} show --no-color #{shell_quote(identifier + ':' + path)}"
272 cmd = "#{self.class.sq_bin} --git-dir #{target('')} show --no-color #{shell_quote(identifier + ':' + path)}"
259 cat = nil
273 cat = nil
260 shellout(cmd) do |io|
274 shellout(cmd) do |io|
261 io.binmode
275 io.binmode
@@ -20,7 +20,7 require 'cgi'
20
20
21 module Redmine
21 module Redmine
22 module Scm
22 module Scm
23 module Adapters
23 module Adapters
24 class MercurialAdapter < AbstractAdapter
24 class MercurialAdapter < AbstractAdapter
25
25
26 # Mercurial executable name
26 # Mercurial executable name
@@ -30,11 +30,23 module Redmine
30 TEMPLATE_EXTENSION = "tmpl"
30 TEMPLATE_EXTENSION = "tmpl"
31
31
32 class << self
32 class << self
33 def client_command
34 @@bin ||= HG_BIN
35 end
36
37 def sq_bin
38 @@sq_bin ||= shell_quote(HG_BIN)
39 end
40
33 def client_version
41 def client_version
34 @@client_version ||= (hgversion || [])
42 @@client_version ||= (hgversion || [])
35 end
43 end
36
44
37 def hgversion
45 def client_available
46 !client_version.empty?
47 end
48
49 def hgversion
38 # The hg version is expressed either as a
50 # The hg version is expressed either as a
39 # release number (eg 0.9.5 or 1.0) or as a revision
51 # release number (eg 0.9.5 or 1.0) or as a revision
40 # id composed of 12 hexa characters.
52 # id composed of 12 hexa characters.
@@ -45,7 +57,7 module Redmine
45 end
57 end
46
58
47 def hgversion_from_command_line
59 def hgversion_from_command_line
48 shellout("#{HG_BIN} --version") { |io| io.read }.to_s
60 shellout("#{sq_bin} --version") { |io| io.read }.to_s
49 end
61 end
50
62
51 def template_path
63 def template_path
@@ -63,7 +75,7 module Redmine
63 end
75 end
64
76
65 def info
77 def info
66 cmd = "#{HG_BIN} -R #{target('')} root"
78 cmd = "#{self.class.sq_bin} -R #{target('')} root"
67 root_url = nil
79 root_url = nil
68 shellout(cmd) do |io|
80 shellout(cmd) do |io|
69 root_url = io.read
81 root_url = io.read
@@ -80,7 +92,7 module Redmine
80 def entries(path=nil, identifier=nil)
92 def entries(path=nil, identifier=nil)
81 path ||= ''
93 path ||= ''
82 entries = Entries.new
94 entries = Entries.new
83 cmd = "#{HG_BIN} -R #{target('')} --cwd #{target('')} locate"
95 cmd = "#{self.class.sq_bin} -R #{target('')} --cwd #{target('')} locate"
84 cmd << " -r #{hgrev(identifier)}"
96 cmd << " -r #{hgrev(identifier)}"
85 cmd << " " + shell_quote("path:#{path}") unless path.empty?
97 cmd << " " + shell_quote("path:#{path}") unless path.empty?
86 shellout(cmd) do |io|
98 shellout(cmd) do |io|
@@ -106,7 +118,7 module Redmine
106 # makes Mercurial produce a xml output.
118 # makes Mercurial produce a xml output.
107 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
119 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
108 revisions = Revisions.new
120 revisions = Revisions.new
109 cmd = "#{HG_BIN} --debug --encoding utf8 -R #{target('')} log -C --style #{shell_quote self.class.template_path}"
121 cmd = "#{self.class.sq_bin} --debug --encoding utf8 -R #{target('')} log -C --style #{shell_quote self.class.template_path}"
110 if identifier_from && identifier_to
122 if identifier_from && identifier_to
111 cmd << " -r #{hgrev(identifier_from)}:#{hgrev(identifier_to)}"
123 cmd << " -r #{hgrev(identifier_from)}:#{hgrev(identifier_to)}"
112 elsif identifier_from
124 elsif identifier_from
@@ -164,7 +176,7 module Redmine
164 return []
176 return []
165 end
177 end
166 end
178 end
167 cmd = "#{HG_BIN} -R #{target('')} --config diff.git=false diff --nodates #{diff_args}"
179 cmd = "#{self.class.sq_bin} -R #{target('')} --config diff.git=false diff --nodates #{diff_args}"
168 cmd << " -I #{target(path)}" unless path.empty?
180 cmd << " -I #{target(path)}" unless path.empty?
169 shellout(cmd) do |io|
181 shellout(cmd) do |io|
170 io.each_line do |line|
182 io.each_line do |line|
@@ -176,7 +188,7 module Redmine
176 end
188 end
177
189
178 def cat(path, identifier=nil)
190 def cat(path, identifier=nil)
179 cmd = "#{HG_BIN} -R #{target('')} cat"
191 cmd = "#{self.class.sq_bin} -R #{target('')} cat"
180 cmd << " -r #{hgrev(identifier)}"
192 cmd << " -r #{hgrev(identifier)}"
181 cmd << " #{target(path)}"
193 cmd << " #{target(path)}"
182 cat = nil
194 cat = nil
@@ -190,7 +202,7 module Redmine
190
202
191 def annotate(path, identifier=nil)
203 def annotate(path, identifier=nil)
192 path ||= ''
204 path ||= ''
193 cmd = "#{HG_BIN} -R #{target('')}"
205 cmd = "#{self.class.sq_bin} -R #{target('')}"
194 cmd << " annotate -ncu"
206 cmd << " annotate -ncu"
195 cmd << " -r #{hgrev(identifier)}"
207 cmd << " -r #{hgrev(identifier)}"
196 cmd << " #{target(path)}"
208 cmd << " #{target(path)}"
@@ -20,19 +20,27 require 'uri'
20
20
21 module Redmine
21 module Redmine
22 module Scm
22 module Scm
23 module Adapters
23 module Adapters
24 class SubversionAdapter < AbstractAdapter
24 class SubversionAdapter < AbstractAdapter
25
25
26 # SVN executable name
26 # SVN executable name
27 SVN_BIN = Redmine::Configuration['scm_subversion_command'] || "svn"
27 SVN_BIN = Redmine::Configuration['scm_subversion_command'] || "svn"
28
28
29 class << self
29 class << self
30 def client_command
31 @@bin ||= SVN_BIN
32 end
33
34 def sq_bin
35 @@sq_bin ||= shell_quote(SVN_BIN)
36 end
37
30 def client_version
38 def client_version
31 @@client_version ||= (svn_binary_version || [])
39 @@client_version ||= (svn_binary_version || [])
32 end
40 end
33
41
34 def svn_binary_version
42 def svn_binary_version
35 cmd = "#{SVN_BIN} --version"
43 cmd = "#{sq_bin} --version"
36 version = nil
44 version = nil
37 shellout(cmd) do |io|
45 shellout(cmd) do |io|
38 # Read svn version in first returned line
46 # Read svn version in first returned line
@@ -44,10 +52,10 module Redmine
44 version
52 version
45 end
53 end
46 end
54 end
47
55
48 # Get info about the svn repository
56 # Get info about the svn repository
49 def info
57 def info
50 cmd = "#{SVN_BIN} info --xml #{target}"
58 cmd = "#{self.class.sq_bin} info --xml #{target}"
51 cmd << credentials_string
59 cmd << credentials_string
52 info = nil
60 info = nil
53 shellout(cmd) do |io|
61 shellout(cmd) do |io|
@@ -70,14 +78,14 module Redmine
70 rescue CommandFailed
78 rescue CommandFailed
71 return nil
79 return nil
72 end
80 end
73
81
74 # Returns an Entries collection
82 # Returns an Entries collection
75 # or nil if the given path doesn't exist in the repository
83 # or nil if the given path doesn't exist in the repository
76 def entries(path=nil, identifier=nil)
84 def entries(path=nil, identifier=nil)
77 path ||= ''
85 path ||= ''
78 identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
86 identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
79 entries = Entries.new
87 entries = Entries.new
80 cmd = "#{SVN_BIN} list --xml #{target(path)}@#{identifier}"
88 cmd = "#{self.class.sq_bin} list --xml #{target(path)}@#{identifier}"
81 cmd << credentials_string
89 cmd << credentials_string
82 shellout(cmd) do |io|
90 shellout(cmd) do |io|
83 output = io.read
91 output = io.read
@@ -110,13 +118,13 module Redmine
110 logger.debug("Found #{entries.size} entries in the repository for #{target(path)}") if logger && logger.debug?
118 logger.debug("Found #{entries.size} entries in the repository for #{target(path)}") if logger && logger.debug?
111 entries.sort_by_name
119 entries.sort_by_name
112 end
120 end
113
121
114 def properties(path, identifier=nil)
122 def properties(path, identifier=nil)
115 # proplist xml output supported in svn 1.5.0 and higher
123 # proplist xml output supported in svn 1.5.0 and higher
116 return nil unless self.class.client_version_above?([1, 5, 0])
124 return nil unless self.class.client_version_above?([1, 5, 0])
117
125
118 identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
126 identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
119 cmd = "#{SVN_BIN} proplist --verbose --xml #{target(path)}@#{identifier}"
127 cmd = "#{self.class.sq_bin} proplist --verbose --xml #{target(path)}@#{identifier}"
120 cmd << credentials_string
128 cmd << credentials_string
121 properties = {}
129 properties = {}
122 shellout(cmd) do |io|
130 shellout(cmd) do |io|
@@ -132,13 +140,13 module Redmine
132 return nil if $? && $?.exitstatus != 0
140 return nil if $? && $?.exitstatus != 0
133 properties
141 properties
134 end
142 end
135
143
136 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
144 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
137 path ||= ''
145 path ||= ''
138 identifier_from = (identifier_from && identifier_from.to_i > 0) ? identifier_from.to_i : "HEAD"
146 identifier_from = (identifier_from && identifier_from.to_i > 0) ? identifier_from.to_i : "HEAD"
139 identifier_to = (identifier_to && identifier_to.to_i > 0) ? identifier_to.to_i : 1
147 identifier_to = (identifier_to && identifier_to.to_i > 0) ? identifier_to.to_i : 1
140 revisions = Revisions.new
148 revisions = Revisions.new
141 cmd = "#{SVN_BIN} log --xml -r #{identifier_from}:#{identifier_to}"
149 cmd = "#{self.class.sq_bin} log --xml -r #{identifier_from}:#{identifier_to}"
142 cmd << credentials_string
150 cmd << credentials_string
143 cmd << " --verbose " if options[:with_paths]
151 cmd << " --verbose " if options[:with_paths]
144 cmd << " --limit #{options[:limit].to_i}" if options[:limit]
152 cmd << " --limit #{options[:limit].to_i}" if options[:limit]
@@ -171,13 +179,13 module Redmine
171 return nil if $? && $?.exitstatus != 0
179 return nil if $? && $?.exitstatus != 0
172 revisions
180 revisions
173 end
181 end
174
182
175 def diff(path, identifier_from, identifier_to=nil, type="inline")
183 def diff(path, identifier_from, identifier_to=nil, type="inline")
176 path ||= ''
184 path ||= ''
177 identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : ''
185 identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : ''
178 identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : (identifier_from.to_i - 1)
186 identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : (identifier_from.to_i - 1)
179
187
180 cmd = "#{SVN_BIN} diff -r "
188 cmd = "#{self.class.sq_bin} diff -r "
181 cmd << "#{identifier_to}:"
189 cmd << "#{identifier_to}:"
182 cmd << "#{identifier_from}"
190 cmd << "#{identifier_from}"
183 cmd << " #{target(path)}@#{identifier_from}"
191 cmd << " #{target(path)}@#{identifier_from}"
@@ -191,10 +199,10 module Redmine
191 return nil if $? && $?.exitstatus != 0
199 return nil if $? && $?.exitstatus != 0
192 diff
200 diff
193 end
201 end
194
202
195 def cat(path, identifier=nil)
203 def cat(path, identifier=nil)
196 identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
204 identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
197 cmd = "#{SVN_BIN} cat #{target(path)}@#{identifier}"
205 cmd = "#{self.class.sq_bin} cat #{target(path)}@#{identifier}"
198 cmd << credentials_string
206 cmd << credentials_string
199 cat = nil
207 cat = nil
200 shellout(cmd) do |io|
208 shellout(cmd) do |io|
@@ -204,10 +212,10 module Redmine
204 return nil if $? && $?.exitstatus != 0
212 return nil if $? && $?.exitstatus != 0
205 cat
213 cat
206 end
214 end
207
215
208 def annotate(path, identifier=nil)
216 def annotate(path, identifier=nil)
209 identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
217 identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
210 cmd = "#{SVN_BIN} blame #{target(path)}@#{identifier}"
218 cmd = "#{self.class.sq_bin} blame #{target(path)}@#{identifier}"
211 cmd << credentials_string
219 cmd << credentials_string
212 blame = Annotate.new
220 blame = Annotate.new
213 shellout(cmd) do |io|
221 shellout(cmd) do |io|
General Comments 0
You need to be logged in to leave comments. Login now