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