##// END OF EJS Templates
scm: git: branches return cache too when there is no branch (#18923)...
Toshi MARUYAMA -
r13545:6097e247f4a6
parent child
Show More
@@ -1,408 +1,408
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require 'redmine/scm/adapters/abstract_adapter'
18 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
24
25 # Git executable name
25 # Git executable name
26 GIT_BIN = Redmine::Configuration['scm_git_command'] || "git"
26 GIT_BIN = Redmine::Configuration['scm_git_command'] || "git"
27
27
28 class GitBranch < Branch
28 class GitBranch < Branch
29 attr_accessor :is_default
29 attr_accessor :is_default
30 end
30 end
31
31
32 class << self
32 class << self
33 def client_command
33 def client_command
34 @@bin ||= GIT_BIN
34 @@bin ||= GIT_BIN
35 end
35 end
36
36
37 def sq_bin
37 def sq_bin
38 @@sq_bin ||= shell_quote_command
38 @@sq_bin ||= shell_quote_command
39 end
39 end
40
40
41 def client_version
41 def client_version
42 @@client_version ||= (scm_command_version || [])
42 @@client_version ||= (scm_command_version || [])
43 end
43 end
44
44
45 def client_available
45 def client_available
46 !client_version.empty?
46 !client_version.empty?
47 end
47 end
48
48
49 def scm_command_version
49 def scm_command_version
50 scm_version = scm_version_from_command_line.dup.force_encoding('ASCII-8BIT')
50 scm_version = scm_version_from_command_line.dup.force_encoding('ASCII-8BIT')
51 if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)})
51 if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)})
52 m[2].scan(%r{\d+}).collect(&:to_i)
52 m[2].scan(%r{\d+}).collect(&:to_i)
53 end
53 end
54 end
54 end
55
55
56 def scm_version_from_command_line
56 def scm_version_from_command_line
57 shellout("#{sq_bin} --version --no-color") { |io| io.read }.to_s
57 shellout("#{sq_bin} --version --no-color") { |io| io.read }.to_s
58 end
58 end
59 end
59 end
60
60
61 def initialize(url, root_url=nil, login=nil, password=nil, path_encoding=nil)
61 def initialize(url, root_url=nil, login=nil, password=nil, path_encoding=nil)
62 super
62 super
63 @path_encoding = path_encoding.blank? ? 'UTF-8' : path_encoding
63 @path_encoding = path_encoding.blank? ? 'UTF-8' : path_encoding
64 end
64 end
65
65
66 def path_encoding
66 def path_encoding
67 @path_encoding
67 @path_encoding
68 end
68 end
69
69
70 def info
70 def info
71 begin
71 begin
72 Info.new(:root_url => url, :lastrev => lastrev('',nil))
72 Info.new(:root_url => url, :lastrev => lastrev('',nil))
73 rescue
73 rescue
74 nil
74 nil
75 end
75 end
76 end
76 end
77
77
78 def branches
78 def branches
79 return @branches if @branches
79 return @branches if !@branches.nil?
80 @branches = []
80 @branches = []
81 cmd_args = %w|branch --no-color --verbose --no-abbrev|
81 cmd_args = %w|branch --no-color --verbose --no-abbrev|
82 git_cmd(cmd_args) do |io|
82 git_cmd(cmd_args) do |io|
83 io.each_line do |line|
83 io.each_line do |line|
84 branch_rev = line.match('\s*(\*?)\s*(.*?)\s*([0-9a-f]{40}).*$')
84 branch_rev = line.match('\s*(\*?)\s*(.*?)\s*([0-9a-f]{40}).*$')
85 bran = GitBranch.new(branch_rev[2])
85 bran = GitBranch.new(branch_rev[2])
86 bran.revision = branch_rev[3]
86 bran.revision = branch_rev[3]
87 bran.scmid = branch_rev[3]
87 bran.scmid = branch_rev[3]
88 bran.is_default = ( branch_rev[1] == '*' )
88 bran.is_default = ( branch_rev[1] == '*' )
89 @branches << bran
89 @branches << bran
90 end
90 end
91 end
91 end
92 @branches.sort!
92 @branches.sort!
93 rescue ScmCommandAborted
93 rescue ScmCommandAborted
94 nil
94 nil
95 end
95 end
96
96
97 def tags
97 def tags
98 return @tags if !@tags.nil?
98 return @tags if !@tags.nil?
99 @tags = []
99 @tags = []
100 cmd_args = %w|tag|
100 cmd_args = %w|tag|
101 git_cmd(cmd_args) do |io|
101 git_cmd(cmd_args) do |io|
102 @tags = io.readlines.sort!.map{|t| t.strip}
102 @tags = io.readlines.sort!.map{|t| t.strip}
103 end
103 end
104 @tags
104 @tags
105 rescue ScmCommandAborted
105 rescue ScmCommandAborted
106 nil
106 nil
107 end
107 end
108
108
109 def default_branch
109 def default_branch
110 bras = self.branches
110 bras = self.branches
111 return nil if bras.nil?
111 return nil if bras.nil?
112 default_bras = bras.select{|x| x.is_default == true}
112 default_bras = bras.select{|x| x.is_default == true}
113 return default_bras.first.to_s if ! default_bras.empty?
113 return default_bras.first.to_s if ! default_bras.empty?
114 master_bras = bras.select{|x| x.to_s == 'master'}
114 master_bras = bras.select{|x| x.to_s == 'master'}
115 master_bras.empty? ? bras.first.to_s : 'master'
115 master_bras.empty? ? bras.first.to_s : 'master'
116 end
116 end
117
117
118 def entry(path=nil, identifier=nil)
118 def entry(path=nil, identifier=nil)
119 parts = path.to_s.split(%r{[\/\\]}).select {|n| !n.blank?}
119 parts = path.to_s.split(%r{[\/\\]}).select {|n| !n.blank?}
120 search_path = parts[0..-2].join('/')
120 search_path = parts[0..-2].join('/')
121 search_name = parts[-1]
121 search_name = parts[-1]
122 if search_path.blank? && search_name.blank?
122 if search_path.blank? && search_name.blank?
123 # Root entry
123 # Root entry
124 Entry.new(:path => '', :kind => 'dir')
124 Entry.new(:path => '', :kind => 'dir')
125 else
125 else
126 # Search for the entry in the parent directory
126 # Search for the entry in the parent directory
127 es = entries(search_path, identifier,
127 es = entries(search_path, identifier,
128 options = {:report_last_commit => false})
128 options = {:report_last_commit => false})
129 es ? es.detect {|e| e.name == search_name} : nil
129 es ? es.detect {|e| e.name == search_name} : nil
130 end
130 end
131 end
131 end
132
132
133 def entries(path=nil, identifier=nil, options={})
133 def entries(path=nil, identifier=nil, options={})
134 path ||= ''
134 path ||= ''
135 p = scm_iconv(@path_encoding, 'UTF-8', path)
135 p = scm_iconv(@path_encoding, 'UTF-8', path)
136 entries = Entries.new
136 entries = Entries.new
137 cmd_args = %w|ls-tree -l|
137 cmd_args = %w|ls-tree -l|
138 cmd_args << "HEAD:#{p}" if identifier.nil?
138 cmd_args << "HEAD:#{p}" if identifier.nil?
139 cmd_args << "#{identifier}:#{p}" if identifier
139 cmd_args << "#{identifier}:#{p}" if identifier
140 git_cmd(cmd_args) do |io|
140 git_cmd(cmd_args) do |io|
141 io.each_line do |line|
141 io.each_line do |line|
142 e = line.chomp.to_s
142 e = line.chomp.to_s
143 if e =~ /^\d+\s+(\w+)\s+([0-9a-f]{40})\s+([0-9-]+)\t(.+)$/
143 if e =~ /^\d+\s+(\w+)\s+([0-9a-f]{40})\s+([0-9-]+)\t(.+)$/
144 type = $1
144 type = $1
145 sha = $2
145 sha = $2
146 size = $3
146 size = $3
147 name = $4.force_encoding(@path_encoding)
147 name = $4.force_encoding(@path_encoding)
148 full_path = p.empty? ? name : "#{p}/#{name}"
148 full_path = p.empty? ? name : "#{p}/#{name}"
149 n = scm_iconv('UTF-8', @path_encoding, name)
149 n = scm_iconv('UTF-8', @path_encoding, name)
150 full_p = scm_iconv('UTF-8', @path_encoding, full_path)
150 full_p = scm_iconv('UTF-8', @path_encoding, full_path)
151 entries << Entry.new({:name => n,
151 entries << Entry.new({:name => n,
152 :path => full_p,
152 :path => full_p,
153 :kind => (type == "tree") ? 'dir' : 'file',
153 :kind => (type == "tree") ? 'dir' : 'file',
154 :size => (type == "tree") ? nil : size,
154 :size => (type == "tree") ? nil : size,
155 :lastrev => options[:report_last_commit] ?
155 :lastrev => options[:report_last_commit] ?
156 lastrev(full_path, identifier) : Revision.new
156 lastrev(full_path, identifier) : Revision.new
157 }) unless entries.detect{|entry| entry.name == name}
157 }) unless entries.detect{|entry| entry.name == name}
158 end
158 end
159 end
159 end
160 end
160 end
161 entries.sort_by_name
161 entries.sort_by_name
162 rescue ScmCommandAborted
162 rescue ScmCommandAborted
163 nil
163 nil
164 end
164 end
165
165
166 def lastrev(path, rev)
166 def lastrev(path, rev)
167 return nil if path.nil?
167 return nil if path.nil?
168 cmd_args = %w|log --no-color --encoding=UTF-8 --date=iso --pretty=fuller --no-merges -n 1|
168 cmd_args = %w|log --no-color --encoding=UTF-8 --date=iso --pretty=fuller --no-merges -n 1|
169 cmd_args << rev if rev
169 cmd_args << rev if rev
170 cmd_args << "--" << path unless path.empty?
170 cmd_args << "--" << path unless path.empty?
171 lines = []
171 lines = []
172 git_cmd(cmd_args) { |io| lines = io.readlines }
172 git_cmd(cmd_args) { |io| lines = io.readlines }
173 begin
173 begin
174 id = lines[0].split[1]
174 id = lines[0].split[1]
175 author = lines[1].match('Author:\s+(.*)$')[1]
175 author = lines[1].match('Author:\s+(.*)$')[1]
176 time = Time.parse(lines[4].match('CommitDate:\s+(.*)$')[1])
176 time = Time.parse(lines[4].match('CommitDate:\s+(.*)$')[1])
177
177
178 Revision.new({
178 Revision.new({
179 :identifier => id,
179 :identifier => id,
180 :scmid => id,
180 :scmid => id,
181 :author => author,
181 :author => author,
182 :time => time,
182 :time => time,
183 :message => nil,
183 :message => nil,
184 :paths => nil
184 :paths => nil
185 })
185 })
186 rescue NoMethodError => e
186 rescue NoMethodError => e
187 logger.error("The revision '#{path}' has a wrong format")
187 logger.error("The revision '#{path}' has a wrong format")
188 return nil
188 return nil
189 end
189 end
190 rescue ScmCommandAborted
190 rescue ScmCommandAborted
191 nil
191 nil
192 end
192 end
193
193
194 def revisions(path, identifier_from, identifier_to, options={})
194 def revisions(path, identifier_from, identifier_to, options={})
195 revs = Revisions.new
195 revs = Revisions.new
196 cmd_args = %w|log --no-color --encoding=UTF-8 --raw --date=iso --pretty=fuller --parents --stdin|
196 cmd_args = %w|log --no-color --encoding=UTF-8 --raw --date=iso --pretty=fuller --parents --stdin|
197 cmd_args << "--reverse" if options[:reverse]
197 cmd_args << "--reverse" if options[:reverse]
198 cmd_args << "-n" << "#{options[:limit].to_i}" if options[:limit]
198 cmd_args << "-n" << "#{options[:limit].to_i}" if options[:limit]
199 cmd_args << "--" << scm_iconv(@path_encoding, 'UTF-8', path) if path && !path.empty?
199 cmd_args << "--" << scm_iconv(@path_encoding, 'UTF-8', path) if path && !path.empty?
200 revisions = []
200 revisions = []
201 if identifier_from || identifier_to
201 if identifier_from || identifier_to
202 revisions << ""
202 revisions << ""
203 revisions[0] << "#{identifier_from}.." if identifier_from
203 revisions[0] << "#{identifier_from}.." if identifier_from
204 revisions[0] << "#{identifier_to}" if identifier_to
204 revisions[0] << "#{identifier_to}" if identifier_to
205 else
205 else
206 unless options[:includes].blank?
206 unless options[:includes].blank?
207 revisions += options[:includes]
207 revisions += options[:includes]
208 end
208 end
209 unless options[:excludes].blank?
209 unless options[:excludes].blank?
210 revisions += options[:excludes].map{|r| "^#{r}"}
210 revisions += options[:excludes].map{|r| "^#{r}"}
211 end
211 end
212 end
212 end
213
213
214 git_cmd(cmd_args, {:write_stdin => true}) do |io|
214 git_cmd(cmd_args, {:write_stdin => true}) do |io|
215 io.binmode
215 io.binmode
216 io.puts(revisions.join("\n"))
216 io.puts(revisions.join("\n"))
217 io.close_write
217 io.close_write
218 files=[]
218 files=[]
219 changeset = {}
219 changeset = {}
220 parsing_descr = 0 #0: not parsing desc or files, 1: parsing desc, 2: parsing files
220 parsing_descr = 0 #0: not parsing desc or files, 1: parsing desc, 2: parsing files
221
221
222 io.each_line do |line|
222 io.each_line do |line|
223 if line =~ /^commit ([0-9a-f]{40})(( [0-9a-f]{40})*)$/
223 if line =~ /^commit ([0-9a-f]{40})(( [0-9a-f]{40})*)$/
224 key = "commit"
224 key = "commit"
225 value = $1
225 value = $1
226 parents_str = $2
226 parents_str = $2
227 if (parsing_descr == 1 || parsing_descr == 2)
227 if (parsing_descr == 1 || parsing_descr == 2)
228 parsing_descr = 0
228 parsing_descr = 0
229 revision = Revision.new({
229 revision = Revision.new({
230 :identifier => changeset[:commit],
230 :identifier => changeset[:commit],
231 :scmid => changeset[:commit],
231 :scmid => changeset[:commit],
232 :author => changeset[:author],
232 :author => changeset[:author],
233 :time => Time.parse(changeset[:date]),
233 :time => Time.parse(changeset[:date]),
234 :message => changeset[:description],
234 :message => changeset[:description],
235 :paths => files,
235 :paths => files,
236 :parents => changeset[:parents]
236 :parents => changeset[:parents]
237 })
237 })
238 if block_given?
238 if block_given?
239 yield revision
239 yield revision
240 else
240 else
241 revs << revision
241 revs << revision
242 end
242 end
243 changeset = {}
243 changeset = {}
244 files = []
244 files = []
245 end
245 end
246 changeset[:commit] = $1
246 changeset[:commit] = $1
247 unless parents_str.nil? or parents_str == ""
247 unless parents_str.nil? or parents_str == ""
248 changeset[:parents] = parents_str.strip.split(' ')
248 changeset[:parents] = parents_str.strip.split(' ')
249 end
249 end
250 elsif (parsing_descr == 0) && line =~ /^(\w+):\s*(.*)$/
250 elsif (parsing_descr == 0) && line =~ /^(\w+):\s*(.*)$/
251 key = $1
251 key = $1
252 value = $2
252 value = $2
253 if key == "Author"
253 if key == "Author"
254 changeset[:author] = value
254 changeset[:author] = value
255 elsif key == "CommitDate"
255 elsif key == "CommitDate"
256 changeset[:date] = value
256 changeset[:date] = value
257 end
257 end
258 elsif (parsing_descr == 0) && line.chomp.to_s == ""
258 elsif (parsing_descr == 0) && line.chomp.to_s == ""
259 parsing_descr = 1
259 parsing_descr = 1
260 changeset[:description] = ""
260 changeset[:description] = ""
261 elsif (parsing_descr == 1 || parsing_descr == 2) \
261 elsif (parsing_descr == 1 || parsing_descr == 2) \
262 && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\t(.+)$/
262 && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\t(.+)$/
263 parsing_descr = 2
263 parsing_descr = 2
264 fileaction = $1
264 fileaction = $1
265 filepath = $2
265 filepath = $2
266 p = scm_iconv('UTF-8', @path_encoding, filepath)
266 p = scm_iconv('UTF-8', @path_encoding, filepath)
267 files << {:action => fileaction, :path => p}
267 files << {:action => fileaction, :path => p}
268 elsif (parsing_descr == 1 || parsing_descr == 2) \
268 elsif (parsing_descr == 1 || parsing_descr == 2) \
269 && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\d+\s+(\S+)\t(.+)$/
269 && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\d+\s+(\S+)\t(.+)$/
270 parsing_descr = 2
270 parsing_descr = 2
271 fileaction = $1
271 fileaction = $1
272 filepath = $3
272 filepath = $3
273 p = scm_iconv('UTF-8', @path_encoding, filepath)
273 p = scm_iconv('UTF-8', @path_encoding, filepath)
274 files << {:action => fileaction, :path => p}
274 files << {:action => fileaction, :path => p}
275 elsif (parsing_descr == 1) && line.chomp.to_s == ""
275 elsif (parsing_descr == 1) && line.chomp.to_s == ""
276 parsing_descr = 2
276 parsing_descr = 2
277 elsif (parsing_descr == 1)
277 elsif (parsing_descr == 1)
278 changeset[:description] << line[4..-1]
278 changeset[:description] << line[4..-1]
279 end
279 end
280 end
280 end
281
281
282 if changeset[:commit]
282 if changeset[:commit]
283 revision = Revision.new({
283 revision = Revision.new({
284 :identifier => changeset[:commit],
284 :identifier => changeset[:commit],
285 :scmid => changeset[:commit],
285 :scmid => changeset[:commit],
286 :author => changeset[:author],
286 :author => changeset[:author],
287 :time => Time.parse(changeset[:date]),
287 :time => Time.parse(changeset[:date]),
288 :message => changeset[:description],
288 :message => changeset[:description],
289 :paths => files,
289 :paths => files,
290 :parents => changeset[:parents]
290 :parents => changeset[:parents]
291 })
291 })
292 if block_given?
292 if block_given?
293 yield revision
293 yield revision
294 else
294 else
295 revs << revision
295 revs << revision
296 end
296 end
297 end
297 end
298 end
298 end
299 revs
299 revs
300 rescue ScmCommandAborted => e
300 rescue ScmCommandAborted => e
301 err_msg = "git log error: #{e.message}"
301 err_msg = "git log error: #{e.message}"
302 logger.error(err_msg)
302 logger.error(err_msg)
303 if block_given?
303 if block_given?
304 raise CommandFailed, err_msg
304 raise CommandFailed, err_msg
305 else
305 else
306 revs
306 revs
307 end
307 end
308 end
308 end
309
309
310 def diff(path, identifier_from, identifier_to=nil)
310 def diff(path, identifier_from, identifier_to=nil)
311 path ||= ''
311 path ||= ''
312 cmd_args = []
312 cmd_args = []
313 if identifier_to
313 if identifier_to
314 cmd_args << "diff" << "--no-color" << identifier_to << identifier_from
314 cmd_args << "diff" << "--no-color" << identifier_to << identifier_from
315 else
315 else
316 cmd_args << "show" << "--no-color" << identifier_from
316 cmd_args << "show" << "--no-color" << identifier_from
317 end
317 end
318 cmd_args << "--" << scm_iconv(@path_encoding, 'UTF-8', path) unless path.empty?
318 cmd_args << "--" << scm_iconv(@path_encoding, 'UTF-8', path) unless path.empty?
319 diff = []
319 diff = []
320 git_cmd(cmd_args) do |io|
320 git_cmd(cmd_args) do |io|
321 io.each_line do |line|
321 io.each_line do |line|
322 diff << line
322 diff << line
323 end
323 end
324 end
324 end
325 diff
325 diff
326 rescue ScmCommandAborted
326 rescue ScmCommandAborted
327 nil
327 nil
328 end
328 end
329
329
330 def annotate(path, identifier=nil)
330 def annotate(path, identifier=nil)
331 identifier = 'HEAD' if identifier.blank?
331 identifier = 'HEAD' if identifier.blank?
332 cmd_args = %w|blame --encoding=UTF-8|
332 cmd_args = %w|blame --encoding=UTF-8|
333 cmd_args << "-p" << identifier << "--" << scm_iconv(@path_encoding, 'UTF-8', path)
333 cmd_args << "-p" << identifier << "--" << scm_iconv(@path_encoding, 'UTF-8', path)
334 blame = Annotate.new
334 blame = Annotate.new
335 content = nil
335 content = nil
336 git_cmd(cmd_args) { |io| io.binmode; content = io.read }
336 git_cmd(cmd_args) { |io| io.binmode; content = io.read }
337 # git annotates binary files
337 # git annotates binary files
338 return nil if content.is_binary_data?
338 return nil if content.is_binary_data?
339 identifier = ''
339 identifier = ''
340 # git shows commit author on the first occurrence only
340 # git shows commit author on the first occurrence only
341 authors_by_commit = {}
341 authors_by_commit = {}
342 content.split("\n").each do |line|
342 content.split("\n").each do |line|
343 if line =~ /^([0-9a-f]{39,40})\s.*/
343 if line =~ /^([0-9a-f]{39,40})\s.*/
344 identifier = $1
344 identifier = $1
345 elsif line =~ /^author (.+)/
345 elsif line =~ /^author (.+)/
346 authors_by_commit[identifier] = $1.strip
346 authors_by_commit[identifier] = $1.strip
347 elsif line =~ /^\t(.*)/
347 elsif line =~ /^\t(.*)/
348 blame.add_line($1, Revision.new(
348 blame.add_line($1, Revision.new(
349 :identifier => identifier,
349 :identifier => identifier,
350 :revision => identifier,
350 :revision => identifier,
351 :scmid => identifier,
351 :scmid => identifier,
352 :author => authors_by_commit[identifier]
352 :author => authors_by_commit[identifier]
353 ))
353 ))
354 identifier = ''
354 identifier = ''
355 author = ''
355 author = ''
356 end
356 end
357 end
357 end
358 blame
358 blame
359 rescue ScmCommandAborted
359 rescue ScmCommandAborted
360 nil
360 nil
361 end
361 end
362
362
363 def cat(path, identifier=nil)
363 def cat(path, identifier=nil)
364 if identifier.nil?
364 if identifier.nil?
365 identifier = 'HEAD'
365 identifier = 'HEAD'
366 end
366 end
367 cmd_args = %w|show --no-color|
367 cmd_args = %w|show --no-color|
368 cmd_args << "#{identifier}:#{scm_iconv(@path_encoding, 'UTF-8', path)}"
368 cmd_args << "#{identifier}:#{scm_iconv(@path_encoding, 'UTF-8', path)}"
369 cat = nil
369 cat = nil
370 git_cmd(cmd_args) do |io|
370 git_cmd(cmd_args) do |io|
371 io.binmode
371 io.binmode
372 cat = io.read
372 cat = io.read
373 end
373 end
374 cat
374 cat
375 rescue ScmCommandAborted
375 rescue ScmCommandAborted
376 nil
376 nil
377 end
377 end
378
378
379 class Revision < Redmine::Scm::Adapters::Revision
379 class Revision < Redmine::Scm::Adapters::Revision
380 # Returns the readable identifier
380 # Returns the readable identifier
381 def format_identifier
381 def format_identifier
382 identifier[0,8]
382 identifier[0,8]
383 end
383 end
384 end
384 end
385
385
386 def git_cmd(args, options = {}, &block)
386 def git_cmd(args, options = {}, &block)
387 repo_path = root_url || url
387 repo_path = root_url || url
388 full_args = ['--git-dir', repo_path]
388 full_args = ['--git-dir', repo_path]
389 if self.class.client_version_above?([1, 7, 2])
389 if self.class.client_version_above?([1, 7, 2])
390 full_args << '-c' << 'core.quotepath=false'
390 full_args << '-c' << 'core.quotepath=false'
391 full_args << '-c' << 'log.decorate=no'
391 full_args << '-c' << 'log.decorate=no'
392 end
392 end
393 full_args += args
393 full_args += args
394 ret = shellout(
394 ret = shellout(
395 self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '),
395 self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '),
396 options,
396 options,
397 &block
397 &block
398 )
398 )
399 if $? && $?.exitstatus != 0
399 if $? && $?.exitstatus != 0
400 raise ScmCommandAborted, "git exited with non-zero status: #{$?.exitstatus}"
400 raise ScmCommandAborted, "git exited with non-zero status: #{$?.exitstatus}"
401 end
401 end
402 ret
402 ret
403 end
403 end
404 private :git_cmd
404 private :git_cmd
405 end
405 end
406 end
406 end
407 end
407 end
408 end
408 end
General Comments 0
You need to be logged in to leave comments. Login now