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