##// END OF EJS Templates
scm: bazaar: add @path_encoding instance value and set it UTF-8 at adapter initialize method (#11834)...
Toshi MARUYAMA -
r10232:f230ffbd543f
parent child
Show More
@@ -1,315 +1,320
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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 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
28 class << self
29 def client_command
29 def client_command
30 @@bin ||= BZR_BIN
30 @@bin ||= BZR_BIN
31 end
31 end
32
32
33 def sq_bin
33 def sq_bin
34 @@sq_bin ||= shell_quote_command
34 @@sq_bin ||= shell_quote_command
35 end
35 end
36
36
37 def client_version
37 def client_version
38 @@client_version ||= (scm_command_version || [])
38 @@client_version ||= (scm_command_version || [])
39 end
39 end
40
40
41 def client_available
41 def client_available
42 !client_version.empty?
42 !client_version.empty?
43 end
43 end
44
44
45 def scm_command_version
45 def scm_command_version
46 scm_version = scm_version_from_command_line.dup
46 scm_version = scm_version_from_command_line.dup
47 if scm_version.respond_to?(:force_encoding)
47 if scm_version.respond_to?(:force_encoding)
48 scm_version.force_encoding('ASCII-8BIT')
48 scm_version.force_encoding('ASCII-8BIT')
49 end
49 end
50 if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)})
50 if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)})
51 m[2].scan(%r{\d+}).collect(&:to_i)
51 m[2].scan(%r{\d+}).collect(&:to_i)
52 end
52 end
53 end
53 end
54
54
55 def scm_version_from_command_line
55 def scm_version_from_command_line
56 shellout("#{sq_bin} --version") { |io| io.read }.to_s
56 shellout("#{sq_bin} --version") { |io| io.read }.to_s
57 end
57 end
58 end
58 end
59
59
60 def initialize(url, root_url=nil, login=nil, password=nil, path_encoding=nil)
61 @path_encoding = 'UTF-8'
62 super
63 end
64
60 # Get info about the repository
65 # Get info about the repository
61 def info
66 def info
62 cmd_args = %w|revno|
67 cmd_args = %w|revno|
63 cmd_args << bzr_target('')
68 cmd_args << bzr_target('')
64 info = nil
69 info = nil
65 scm_cmd(*cmd_args) do |io|
70 scm_cmd(*cmd_args) do |io|
66 if io.read =~ %r{^(\d+)\r?$}
71 if io.read =~ %r{^(\d+)\r?$}
67 info = Info.new({:root_url => url,
72 info = Info.new({:root_url => url,
68 :lastrev => Revision.new({
73 :lastrev => Revision.new({
69 :identifier => $1
74 :identifier => $1
70 })
75 })
71 })
76 })
72 end
77 end
73 end
78 end
74 info
79 info
75 rescue ScmCommandAborted
80 rescue ScmCommandAborted
76 return nil
81 return nil
77 end
82 end
78
83
79 # Returns an Entries collection
84 # Returns an Entries collection
80 # or nil if the given path doesn't exist in the repository
85 # or nil if the given path doesn't exist in the repository
81 def entries(path=nil, identifier=nil, options={})
86 def entries(path=nil, identifier=nil, options={})
82 path ||= ''
87 path ||= ''
83 entries = Entries.new
88 entries = Entries.new
84 identifier = -1 unless identifier && identifier.to_i > 0
89 identifier = -1 unless identifier && identifier.to_i > 0
85 cmd_args = %w|ls -v --show-ids|
90 cmd_args = %w|ls -v --show-ids|
86 cmd_args << "-r#{identifier.to_i}"
91 cmd_args << "-r#{identifier.to_i}"
87 cmd_args << bzr_target(path)
92 cmd_args << bzr_target(path)
88 scm_cmd(*cmd_args) do |io|
93 scm_cmd(*cmd_args) do |io|
89 prefix = "#{url}/#{path}".gsub('\\', '/')
94 prefix = "#{url}/#{path}".gsub('\\', '/')
90 logger.debug "PREFIX: #{prefix}"
95 logger.debug "PREFIX: #{prefix}"
91 re = %r{^V\s+(#{Regexp.escape(prefix)})?(\/?)([^\/]+)(\/?)\s+(\S+)\r?$}
96 re = %r{^V\s+(#{Regexp.escape(prefix)})?(\/?)([^\/]+)(\/?)\s+(\S+)\r?$}
92 io.each_line do |line|
97 io.each_line do |line|
93 next unless line =~ re
98 next unless line =~ re
94 entries << Entry.new({:name => $3.strip,
99 entries << Entry.new({:name => $3.strip,
95 :path => ((path.empty? ? "" : "#{path}/") + $3.strip),
100 :path => ((path.empty? ? "" : "#{path}/") + $3.strip),
96 :kind => ($4.blank? ? 'file' : 'dir'),
101 :kind => ($4.blank? ? 'file' : 'dir'),
97 :size => nil,
102 :size => nil,
98 :lastrev => Revision.new(:revision => $5.strip)
103 :lastrev => Revision.new(:revision => $5.strip)
99 })
104 })
100 end
105 end
101 end
106 end
102 if logger && logger.debug?
107 if logger && logger.debug?
103 logger.debug("Found #{entries.size} entries in the repository for #{target(path)}")
108 logger.debug("Found #{entries.size} entries in the repository for #{target(path)}")
104 end
109 end
105 entries.sort_by_name
110 entries.sort_by_name
106 rescue ScmCommandAborted
111 rescue ScmCommandAborted
107 return nil
112 return nil
108 end
113 end
109
114
110 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
115 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
111 path ||= ''
116 path ||= ''
112 identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : 'last:1'
117 identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : 'last:1'
113 identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : 1
118 identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : 1
114 revisions = Revisions.new
119 revisions = Revisions.new
115 cmd_args = %w|log -v --show-ids|
120 cmd_args = %w|log -v --show-ids|
116 cmd_args << "-r#{identifier_to}..#{identifier_from}"
121 cmd_args << "-r#{identifier_to}..#{identifier_from}"
117 cmd_args << bzr_target(path)
122 cmd_args << bzr_target(path)
118 scm_cmd(*cmd_args) do |io|
123 scm_cmd(*cmd_args) do |io|
119 revision = nil
124 revision = nil
120 parsing = nil
125 parsing = nil
121 io.each_line do |line|
126 io.each_line do |line|
122 if line =~ /^----/
127 if line =~ /^----/
123 revisions << revision if revision
128 revisions << revision if revision
124 revision = Revision.new(:paths => [], :message => '')
129 revision = Revision.new(:paths => [], :message => '')
125 parsing = nil
130 parsing = nil
126 else
131 else
127 next unless revision
132 next unless revision
128 if line =~ /^revno: (\d+)($|\s\[merge\]$)/
133 if line =~ /^revno: (\d+)($|\s\[merge\]$)/
129 revision.identifier = $1.to_i
134 revision.identifier = $1.to_i
130 elsif line =~ /^committer: (.+)$/
135 elsif line =~ /^committer: (.+)$/
131 revision.author = $1.strip
136 revision.author = $1.strip
132 elsif line =~ /^revision-id:(.+)$/
137 elsif line =~ /^revision-id:(.+)$/
133 revision.scmid = $1.strip
138 revision.scmid = $1.strip
134 elsif line =~ /^timestamp: (.+)$/
139 elsif line =~ /^timestamp: (.+)$/
135 revision.time = Time.parse($1).localtime
140 revision.time = Time.parse($1).localtime
136 elsif line =~ /^ -----/
141 elsif line =~ /^ -----/
137 # partial revisions
142 # partial revisions
138 parsing = nil unless parsing == 'message'
143 parsing = nil unless parsing == 'message'
139 elsif line =~ /^(message|added|modified|removed|renamed):/
144 elsif line =~ /^(message|added|modified|removed|renamed):/
140 parsing = $1
145 parsing = $1
141 elsif line =~ /^ (.*)$/
146 elsif line =~ /^ (.*)$/
142 if parsing == 'message'
147 if parsing == 'message'
143 revision.message << "#{$1}\n"
148 revision.message << "#{$1}\n"
144 else
149 else
145 if $1 =~ /^(.*)\s+(\S+)$/
150 if $1 =~ /^(.*)\s+(\S+)$/
146 path = $1.strip
151 path = $1.strip
147 revid = $2
152 revid = $2
148 case parsing
153 case parsing
149 when 'added'
154 when 'added'
150 revision.paths << {:action => 'A', :path => "/#{path}", :revision => revid}
155 revision.paths << {:action => 'A', :path => "/#{path}", :revision => revid}
151 when 'modified'
156 when 'modified'
152 revision.paths << {:action => 'M', :path => "/#{path}", :revision => revid}
157 revision.paths << {:action => 'M', :path => "/#{path}", :revision => revid}
153 when 'removed'
158 when 'removed'
154 revision.paths << {:action => 'D', :path => "/#{path}", :revision => revid}
159 revision.paths << {:action => 'D', :path => "/#{path}", :revision => revid}
155 when 'renamed'
160 when 'renamed'
156 new_path = path.split('=>').last
161 new_path = path.split('=>').last
157 if new_path
162 if new_path
158 revision.paths << {:action => 'M', :path => "/#{new_path.strip}",
163 revision.paths << {:action => 'M', :path => "/#{new_path.strip}",
159 :revision => revid}
164 :revision => revid}
160 end
165 end
161 end
166 end
162 end
167 end
163 end
168 end
164 else
169 else
165 parsing = nil
170 parsing = nil
166 end
171 end
167 end
172 end
168 end
173 end
169 revisions << revision if revision
174 revisions << revision if revision
170 end
175 end
171 revisions
176 revisions
172 rescue ScmCommandAborted
177 rescue ScmCommandAborted
173 return nil
178 return nil
174 end
179 end
175
180
176 def diff(path, identifier_from, identifier_to=nil)
181 def diff(path, identifier_from, identifier_to=nil)
177 path ||= ''
182 path ||= ''
178 if identifier_to
183 if identifier_to
179 identifier_to = identifier_to.to_i
184 identifier_to = identifier_to.to_i
180 else
185 else
181 identifier_to = identifier_from.to_i - 1
186 identifier_to = identifier_from.to_i - 1
182 end
187 end
183 if identifier_from
188 if identifier_from
184 identifier_from = identifier_from.to_i
189 identifier_from = identifier_from.to_i
185 end
190 end
186 diff = []
191 diff = []
187 cmd_args = %w|diff|
192 cmd_args = %w|diff|
188 cmd_args << "-r#{identifier_to}..#{identifier_from}"
193 cmd_args << "-r#{identifier_to}..#{identifier_from}"
189 cmd_args << bzr_target(path)
194 cmd_args << bzr_target(path)
190 scm_cmd_no_raise(*cmd_args) do |io|
195 scm_cmd_no_raise(*cmd_args) do |io|
191 io.each_line do |line|
196 io.each_line do |line|
192 diff << line
197 diff << line
193 end
198 end
194 end
199 end
195 diff
200 diff
196 end
201 end
197
202
198 def cat(path, identifier=nil)
203 def cat(path, identifier=nil)
199 cat = nil
204 cat = nil
200 cmd_args = %w|cat|
205 cmd_args = %w|cat|
201 cmd_args << "-r#{identifier.to_i}" if identifier && identifier.to_i > 0
206 cmd_args << "-r#{identifier.to_i}" if identifier && identifier.to_i > 0
202 cmd_args << bzr_target(path)
207 cmd_args << bzr_target(path)
203 scm_cmd(*cmd_args) do |io|
208 scm_cmd(*cmd_args) do |io|
204 io.binmode
209 io.binmode
205 cat = io.read
210 cat = io.read
206 end
211 end
207 cat
212 cat
208 rescue ScmCommandAborted
213 rescue ScmCommandAborted
209 return nil
214 return nil
210 end
215 end
211
216
212 def annotate(path, identifier=nil)
217 def annotate(path, identifier=nil)
213 blame = Annotate.new
218 blame = Annotate.new
214 cmd_args = %w|annotate -q --all|
219 cmd_args = %w|annotate -q --all|
215 cmd_args << "-r#{identifier.to_i}" if identifier && identifier.to_i > 0
220 cmd_args << "-r#{identifier.to_i}" if identifier && identifier.to_i > 0
216 cmd_args << bzr_target(path)
221 cmd_args << bzr_target(path)
217 scm_cmd(*cmd_args) do |io|
222 scm_cmd(*cmd_args) do |io|
218 author = nil
223 author = nil
219 identifier = nil
224 identifier = nil
220 io.each_line do |line|
225 io.each_line do |line|
221 next unless line =~ %r{^(\d+) ([^|]+)\| (.*)$}
226 next unless line =~ %r{^(\d+) ([^|]+)\| (.*)$}
222 rev = $1
227 rev = $1
223 blame.add_line($3.rstrip,
228 blame.add_line($3.rstrip,
224 Revision.new(
229 Revision.new(
225 :identifier => rev,
230 :identifier => rev,
226 :revision => rev,
231 :revision => rev,
227 :author => $2.strip
232 :author => $2.strip
228 ))
233 ))
229 end
234 end
230 end
235 end
231 blame
236 blame
232 rescue ScmCommandAborted
237 rescue ScmCommandAborted
233 return nil
238 return nil
234 end
239 end
235
240
236 def self.branch_conf_path(path)
241 def self.branch_conf_path(path)
237 bcp = nil
242 bcp = nil
238 m = path.match(%r{^(.*[/\\])\.bzr.*$})
243 m = path.match(%r{^(.*[/\\])\.bzr.*$})
239 if m
244 if m
240 bcp = m[1]
245 bcp = m[1]
241 else
246 else
242 bcp = path
247 bcp = path
243 end
248 end
244 bcp.gsub!(%r{[\/\\]$}, "")
249 bcp.gsub!(%r{[\/\\]$}, "")
245 if bcp
250 if bcp
246 bcp = File.join(bcp, ".bzr", "branch", "branch.conf")
251 bcp = File.join(bcp, ".bzr", "branch", "branch.conf")
247 end
252 end
248 bcp
253 bcp
249 end
254 end
250
255
251 def append_revisions_only
256 def append_revisions_only
252 return @aro if ! @aro.nil?
257 return @aro if ! @aro.nil?
253 @aro = false
258 @aro = false
254 bcp = self.class.branch_conf_path(url)
259 bcp = self.class.branch_conf_path(url)
255 if bcp && File.exist?(bcp)
260 if bcp && File.exist?(bcp)
256 begin
261 begin
257 f = File::open(bcp, "r")
262 f = File::open(bcp, "r")
258 cnt = 0
263 cnt = 0
259 f.each_line do |line|
264 f.each_line do |line|
260 l = line.chomp.to_s
265 l = line.chomp.to_s
261 if l =~ /^\s*append_revisions_only\s*=\s*(\w+)\s*$/
266 if l =~ /^\s*append_revisions_only\s*=\s*(\w+)\s*$/
262 str_aro = $1
267 str_aro = $1
263 if str_aro.upcase == "TRUE"
268 if str_aro.upcase == "TRUE"
264 @aro = true
269 @aro = true
265 cnt += 1
270 cnt += 1
266 elsif str_aro.upcase == "FALSE"
271 elsif str_aro.upcase == "FALSE"
267 @aro = false
272 @aro = false
268 cnt += 1
273 cnt += 1
269 end
274 end
270 if cnt > 1
275 if cnt > 1
271 @aro = false
276 @aro = false
272 break
277 break
273 end
278 end
274 end
279 end
275 end
280 end
276 ensure
281 ensure
277 f.close
282 f.close
278 end
283 end
279 end
284 end
280 @aro
285 @aro
281 end
286 end
282
287
283 def scm_cmd(*args, &block)
288 def scm_cmd(*args, &block)
284 full_args = []
289 full_args = []
285 full_args += args
290 full_args += args
286 ret = shellout(
291 ret = shellout(
287 self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '),
292 self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '),
288 &block
293 &block
289 )
294 )
290 if $? && $?.exitstatus != 0
295 if $? && $?.exitstatus != 0
291 raise ScmCommandAborted, "bzr exited with non-zero status: #{$?.exitstatus}"
296 raise ScmCommandAborted, "bzr exited with non-zero status: #{$?.exitstatus}"
292 end
297 end
293 ret
298 ret
294 end
299 end
295 private :scm_cmd
300 private :scm_cmd
296
301
297 def scm_cmd_no_raise(*args, &block)
302 def scm_cmd_no_raise(*args, &block)
298 full_args = []
303 full_args = []
299 full_args += args
304 full_args += args
300 ret = shellout(
305 ret = shellout(
301 self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '),
306 self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '),
302 &block
307 &block
303 )
308 )
304 ret
309 ret
305 end
310 end
306 private :scm_cmd_no_raise
311 private :scm_cmd_no_raise
307
312
308 def bzr_target(path)
313 def bzr_target(path)
309 target(path, false)
314 target(path, false)
310 end
315 end
311 private :bzr_target
316 private :bzr_target
312 end
317 end
313 end
318 end
314 end
319 end
315 end
320 end
General Comments 0
You need to be logged in to leave comments. Login now