comparison lib/redmine/scm/adapters/mercurial_adapter.rb @ 441:cbce1fd3b1b7 redmine-1.2

Update to Redmine 1.2-stable branch (Redmine SVN rev 6000)
author Chris Cannam
date Mon, 06 Jun 2011 14:24:13 +0100
parents 051f544170fe
children 753f1380d6bc 0c939c159af4
comparison
equal deleted inserted replaced
245:051f544170fe 441:cbce1fd3b1b7
1 # redMine - project management software 1 # Redmine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang 2 # Copyright (C) 2006-2011 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'
45 def client_version 45 def client_version
46 @@client_version ||= (hgversion || []) 46 @@client_version ||= (hgversion || [])
47 end 47 end
48 48
49 def client_available 49 def client_available
50 !client_version.empty? 50 client_version_above?([0, 9, 5])
51 end 51 end
52 52
53 def hgversion 53 def hgversion
54 # The hg version is expressed either as a 54 # The hg version is expressed either as a
55 # release number (eg 0.9.5 or 1.0) or as a revision 55 # release number (eg 0.9.5 or 1.0) or as a revision
81 end 81 end
82 end 82 end
83 83
84 def initialize(url, root_url=nil, login=nil, password=nil, path_encoding=nil) 84 def initialize(url, root_url=nil, login=nil, password=nil, path_encoding=nil)
85 super 85 super
86 @path_encoding = path_encoding || 'UTF-8' 86 @path_encoding = path_encoding.blank? ? 'UTF-8' : path_encoding
87 end
88
89 def path_encoding
90 @path_encoding
87 end 91 end
88 92
89 def info 93 def info
90 tip = summary['repository']['tip'] 94 tip = summary['repository']['tip']
91 Info.new(:root_url => CGI.unescape(summary['repository']['root']), 95 Info.new(:root_url => CGI.unescape(summary['repository']['root']),
116 end 120 end
117 Hash[*alist.flatten] 121 Hash[*alist.flatten]
118 end 122 end
119 123
120 def summary 124 def summary
121 return @summary if @summary 125 return @summary if @summary
122 hg 'rhsummary' do |io| 126 hg 'rhsummary' do |io|
123 output = io.read 127 output = io.read
124 if output.respond_to?(:force_encoding) 128 if output.respond_to?(:force_encoding)
125 output.force_encoding('UTF-8') 129 output.force_encoding('UTF-8')
126 end 130 end
130 end 134 end
131 end 135 end
132 end 136 end
133 private :summary 137 private :summary
134 138
135 def entries(path=nil, identifier=nil) 139 def entries(path=nil, identifier=nil, options={})
136 p1 = scm_iconv(@path_encoding, 'UTF-8', path) 140 p1 = scm_iconv(@path_encoding, 'UTF-8', path)
137 manifest = hg('rhmanifest', '-r', CGI.escape(hgrev(identifier)), 141 manifest = hg('rhmanifest', '-r', CGI.escape(hgrev(identifier)),
138 CGI.escape(without_leading_slash(p1.to_s))) do |io| 142 CGI.escape(without_leading_slash(p1.to_s))) do |io|
139 output = io.read 143 output = io.read
140 if output.respond_to?(:force_encoding) 144 if output.respond_to?(:force_encoding)
191 # Mercurial < 1.5 does not support footer template for '</log>' 195 # Mercurial < 1.5 does not support footer template for '</log>'
192 ActiveSupport::XmlMini.parse("#{output}</log>")['log'] 196 ActiveSupport::XmlMini.parse("#{output}</log>")['log']
193 rescue 197 rescue
194 end 198 end
195 end 199 end
196
197 as_ary(log['logentry']).each do |le| 200 as_ary(log['logentry']).each do |le|
198 cpalist = as_ary(le['paths']['path-copied']).map do |e| 201 cpalist = as_ary(le['paths']['path-copied']).map do |e|
199 [e['__content__'], e['copyfrom-path']].map { |s| CGI.unescape(s) } 202 [e['__content__'], e['copyfrom-path']].map do |s|
203 scm_iconv('UTF-8', @path_encoding, CGI.unescape(s))
204 end
200 end 205 end
201 cpmap = Hash[*cpalist.flatten] 206 cpmap = Hash[*cpalist.flatten]
202
203 paths = as_ary(le['paths']['path']).map do |e| 207 paths = as_ary(le['paths']['path']).map do |e|
204 p = scm_iconv('UTF-8', @path_encoding, CGI.unescape(e['__content__']) ) 208 p = scm_iconv('UTF-8', @path_encoding, CGI.unescape(e['__content__']) )
205 {:action => e['action'], :path => with_leading_slash(p), 209 {:action => e['action'],
206 :from_path => (cpmap.member?(p) ? with_leading_slash(cpmap[p]) : nil), 210 :path => with_leading_slash(p),
207 :from_revision => (cpmap.member?(p) ? le['revision'] : nil)} 211 :from_path => (cpmap.member?(p) ? with_leading_slash(cpmap[p]) : nil),
212 :from_revision => (cpmap.member?(p) ? le['node'] : nil)}
208 end.sort { |a, b| a[:path] <=> b[:path] } 213 end.sort { |a, b| a[:path] <=> b[:path] }
209
210 yield Revision.new(:revision => le['revision'], 214 yield Revision.new(:revision => le['revision'],
211 :scmid => le['node'], 215 :scmid => le['node'],
212 :author => (le['author']['__content__'] rescue ''), 216 :author => (le['author']['__content__'] rescue ''),
213 :time => Time.parse(le['date']['__content__']).localtime, 217 :time => Time.parse(le['date']['__content__']),
214 :message => le['msg']['__content__'], 218 :message => le['msg']['__content__'],
215 :paths => paths) 219 :paths => paths)
216 end 220 end
217 self 221 self
222 end
223
224 # Returns list of nodes in the specified branch
225 def nodes_in_branch(branch, options={})
226 hg_args = ['rhlog', '--template', '{node|short}\n', '--rhbranch', CGI.escape(branch)]
227 hg_args << '--from' << CGI.escape(branch)
228 hg_args << '--to' << '0'
229 hg_args << '--limit' << options[:limit] if options[:limit]
230 hg(*hg_args) { |io| io.readlines.map { |e| e.chomp } }
218 end 231 end
219 232
220 def diff(path, identifier_from, identifier_to=nil) 233 def diff(path, identifier_from, identifier_to=nil)
221 hg_args = %w|rhdiff| 234 hg_args = %w|rhdiff|
222 if identifier_to 235 if identifier_to
239 nil # means not found 252 nil # means not found
240 end 253 end
241 254
242 def cat(path, identifier=nil) 255 def cat(path, identifier=nil)
243 p = CGI.escape(scm_iconv(@path_encoding, 'UTF-8', path)) 256 p = CGI.escape(scm_iconv(@path_encoding, 'UTF-8', path))
244 hg 'rhcat', '-r', hgrev(identifier), hgtarget(p) do |io| 257 hg 'rhcat', '-r', CGI.escape(hgrev(identifier)), hgtarget(p) do |io|
245 io.binmode 258 io.binmode
246 io.read 259 io.read
247 end 260 end
248 rescue HgCommandAborted 261 rescue HgCommandAborted
249 nil # means not found 262 nil # means not found
250 end 263 end
251 264
252 def annotate(path, identifier=nil) 265 def annotate(path, identifier=nil)
253 p = CGI.escape(scm_iconv(@path_encoding, 'UTF-8', path)) 266 p = CGI.escape(scm_iconv(@path_encoding, 'UTF-8', path))
254 blame = Annotate.new 267 blame = Annotate.new
255 hg 'rhannotate', '-ncu', '-r', hgrev(identifier), hgtarget(p) do |io| 268 hg 'rhannotate', '-ncu', '-r', CGI.escape(hgrev(identifier)), hgtarget(p) do |io|
256 io.each_line do |line| 269 io.each_line do |line|
257 line.force_encoding('ASCII-8BIT') if line.respond_to?(:force_encoding) 270 line.force_encoding('ASCII-8BIT') if line.respond_to?(:force_encoding)
258 next unless line =~ %r{^([^:]+)\s(\d+)\s([0-9a-f]+):\s(.*)$} 271 next unless line =~ %r{^([^:]+)\s(\d+)\s([0-9a-f]+):\s(.*)$}
259 r = Revision.new(:author => $1.strip, :revision => $2, :scmid => $3, 272 r = Revision.new(:author => $1.strip, :revision => $2, :scmid => $3,
260 :identifier => $3) 273 :identifier => $3)