Mercurial > hg > soundsoftware-site
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) |