##// END OF EJS Templates
Move unified diff parser out of the scm abstract adapter so it can be reused for viewing attached diffs (#1403)....
Jean-Philippe Lang -
r1499:ec0525d4975b
parent child
Show More
@@ -0,0 +1,178
1 # redMine - project management software
2 # Copyright (C) 2006-2008 Jean-Philippe Lang
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
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
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18 module Redmine
19 # Class used to parse unified diffs
20 class UnifiedDiff < Array
21 def initialize(diff, type="inline")
22 diff_table = DiffTable.new type
23 diff.each do |line|
24 if line =~ /^(---|\+\+\+) (.*)$/
25 self << diff_table if diff_table.length > 1
26 diff_table = DiffTable.new type
27 end
28 a = diff_table.add_line line
29 end
30 self << diff_table unless diff_table.empty?
31 self
32 end
33 end
34
35 # Class that represents a file diff
36 class DiffTable < Hash
37 attr_reader :file_name, :line_num_l, :line_num_r
38
39 # Initialize with a Diff file and the type of Diff View
40 # The type view must be inline or sbs (side_by_side)
41 def initialize(type="inline")
42 @parsing = false
43 @nb_line = 1
44 @start = false
45 @before = 'same'
46 @second = true
47 @type = type
48 end
49
50 # Function for add a line of this Diff
51 def add_line(line)
52 unless @parsing
53 if line =~ /^(---|\+\+\+) (.*)$/
54 @file_name = $2
55 return false
56 elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/
57 @line_num_l = $5.to_i
58 @line_num_r = $2.to_i
59 @parsing = true
60 end
61 else
62 if line =~ /^[^\+\-\s@\\]/
63 @parsing = false
64 return false
65 elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/
66 @line_num_l = $5.to_i
67 @line_num_r = $2.to_i
68 else
69 @nb_line += 1 if parse_line(line, @type)
70 end
71 end
72 return true
73 end
74
75 def inspect
76 puts '### DIFF TABLE ###'
77 puts "file : #{file_name}"
78 self.each do |d|
79 d.inspect
80 end
81 end
82
83 private
84 # Test if is a Side By Side type
85 def sbs?(type, func)
86 if @start and type == "sbs"
87 if @before == func and @second
88 tmp_nb_line = @nb_line
89 self[tmp_nb_line] = Diff.new
90 else
91 @second = false
92 tmp_nb_line = @start
93 @start += 1
94 @nb_line -= 1
95 end
96 else
97 tmp_nb_line = @nb_line
98 @start = @nb_line
99 self[tmp_nb_line] = Diff.new
100 @second = true
101 end
102 unless self[tmp_nb_line]
103 @nb_line += 1
104 self[tmp_nb_line] = Diff.new
105 else
106 self[tmp_nb_line]
107 end
108 end
109
110 # Escape the HTML for the diff
111 def escapeHTML(line)
112 CGI.escapeHTML(line)
113 end
114
115 def parse_line(line, type="inline")
116 if line[0, 1] == "+"
117 diff = sbs? type, 'add'
118 @before = 'add'
119 diff.line_left = escapeHTML line[1..-1]
120 diff.nb_line_left = @line_num_l
121 diff.type_diff_left = 'diff_in'
122 @line_num_l += 1
123 true
124 elsif line[0, 1] == "-"
125 diff = sbs? type, 'remove'
126 @before = 'remove'
127 diff.line_right = escapeHTML line[1..-1]
128 diff.nb_line_right = @line_num_r
129 diff.type_diff_right = 'diff_out'
130 @line_num_r += 1
131 true
132 elsif line[0, 1] =~ /\s/
133 @before = 'same'
134 @start = false
135 diff = Diff.new
136 diff.line_right = escapeHTML line[1..-1]
137 diff.nb_line_right = @line_num_r
138 diff.line_left = escapeHTML line[1..-1]
139 diff.nb_line_left = @line_num_l
140 self[@nb_line] = diff
141 @line_num_l += 1
142 @line_num_r += 1
143 true
144 elsif line[0, 1] = "\\"
145 true
146 else
147 false
148 end
149 end
150 end
151
152 # A line of diff
153 class Diff
154 attr_accessor :nb_line_left
155 attr_accessor :line_left
156 attr_accessor :nb_line_right
157 attr_accessor :line_right
158 attr_accessor :type_diff_right
159 attr_accessor :type_diff_left
160
161 def initialize()
162 self.nb_line_left = ''
163 self.nb_line_right = ''
164 self.line_left = ''
165 self.line_right = ''
166 self.type_diff_right = ''
167 self.type_diff_left = ''
168 end
169
170 def inspect
171 puts '### Start Line Diff ###'
172 puts self.nb_line_left
173 puts self.line_left
174 puts self.nb_line_right
175 puts self.line_right
176 end
177 end
178 end
@@ -153,7 +153,7 class RepositoriesController < ApplicationController
153 153
154 154 @cache_key = "repositories/diff/#{@repository.id}/" + Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}")
155 155 unless read_fragment(@cache_key)
156 @diff = @repository.diff(@path, @rev, @rev_to, @diff_type)
156 @diff = @repository.diff(@path, @rev, @rev_to)
157 157 show_error_not_found unless @diff
158 158 end
159 159 rescue Redmine::Scm::Adapters::CommandFailed => e
@@ -55,8 +55,8 class Repository < ActiveRecord::Base
55 55 scm.entries(path, identifier)
56 56 end
57 57
58 def diff(path, rev, rev_to, type)
59 scm.diff(path, rev, rev_to, type)
58 def diff(path, rev, rev_to)
59 scm.diff(path, rev, rev_to)
60 60 end
61 61
62 62 # Default behaviour: we search in cached changesets
@@ -53,7 +53,7 class Repository::Cvs < Repository
53 53 entries
54 54 end
55 55
56 def diff(path, rev, rev_to, type)
56 def diff(path, rev, rev_to)
57 57 #convert rev to revision. CVS can't handle changesets here
58 58 diff=[]
59 59 changeset_from=changesets.find_by_revision(rev)
@@ -76,7 +76,7 class Repository::Cvs < Repository
76 76 unless revision_to
77 77 revision_to=scm.get_previous_revision(revision_from)
78 78 end
79 diff=diff+scm.diff(change_from.path, revision_from, revision_to, type)
79 diff=diff+scm.diff(change_from.path, revision_from, revision_to)
80 80 end
81 81 end
82 82 return diff
@@ -46,14 +46,14 class Repository::Darcs < Repository
46 46 entries
47 47 end
48 48
49 def diff(path, rev, rev_to, type)
49 def diff(path, rev, rev_to)
50 50 patch_from = changesets.find_by_revision(rev)
51 51 return nil if patch_from.nil?
52 52 patch_to = changesets.find_by_revision(rev_to) if rev_to
53 53 if path.blank?
54 54 path = patch_from.changes.collect{|change| change.path}.join(' ')
55 55 end
56 patch_from ? scm.diff(path, patch_from.scmid, patch_to ? patch_to.scmid : nil, type) : nil
56 patch_from ? scm.diff(path, patch_from.scmid, patch_to ? patch_to.scmid : nil) : nil
57 57 end
58 58
59 59 def fetch_changesets
@@ -12,7 +12,7
12 12 <% end %>
13 13
14 14 <% cache(@cache_key) do -%>
15 <% @diff.each do |table_file| -%>
15 <% Redmine::UnifiedDiff.new(@diff, @diff_type).each do |table_file| -%>
16 16 <div class="autoscroll">
17 17 <% if @diff_type == 'sbs' -%>
18 18 <table class="filecontent CodeRay">
@@ -82,7 +82,7 module Redmine
82 82 return nil
83 83 end
84 84
85 def diff(path, identifier_from, identifier_to=nil, type="inline")
85 def diff(path, identifier_from, identifier_to=nil)
86 86 return nil
87 87 end
88 88
@@ -234,166 +234,7 module Redmine
234 234 end
235 235
236 236 end
237
238 # A line of Diff
239 class Diff
240 attr_accessor :nb_line_left
241 attr_accessor :line_left
242 attr_accessor :nb_line_right
243 attr_accessor :line_right
244 attr_accessor :type_diff_right
245 attr_accessor :type_diff_left
246 237
247 def initialize ()
248 self.nb_line_left = ''
249 self.nb_line_right = ''
250 self.line_left = ''
251 self.line_right = ''
252 self.type_diff_right = ''
253 self.type_diff_left = ''
254 end
255
256 def inspect
257 puts '### Start Line Diff ###'
258 puts self.nb_line_left
259 puts self.line_left
260 puts self.nb_line_right
261 puts self.line_right
262 end
263 end
264
265 class DiffTableList < Array
266 def initialize (diff, type="inline")
267 diff_table = DiffTable.new type
268 diff.each do |line|
269 if line =~ /^(---|\+\+\+) (.*)$/
270 self << diff_table if diff_table.length > 1
271 diff_table = DiffTable.new type
272 end
273 a = diff_table.add_line line
274 end
275 self << diff_table unless diff_table.empty?
276 self
277 end
278 end
279
280 # Class for create a Diff
281 class DiffTable < Hash
282 attr_reader :file_name, :line_num_l, :line_num_r
283
284 # Initialize with a Diff file and the type of Diff View
285 # The type view must be inline or sbs (side_by_side)
286 def initialize(type="inline")
287 @parsing = false
288 @nb_line = 1
289 @start = false
290 @before = 'same'
291 @second = true
292 @type = type
293 end
294
295 # Function for add a line of this Diff
296 def add_line(line)
297 unless @parsing
298 if line =~ /^(---|\+\+\+) (.*)$/
299 @file_name = $2
300 return false
301 elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/
302 @line_num_l = $5.to_i
303 @line_num_r = $2.to_i
304 @parsing = true
305 end
306 else
307 if line =~ /^[^\+\-\s@\\]/
308 @parsing = false
309 return false
310 elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/
311 @line_num_l = $5.to_i
312 @line_num_r = $2.to_i
313 else
314 @nb_line += 1 if parse_line(line, @type)
315 end
316 end
317 return true
318 end
319
320 def inspect
321 puts '### DIFF TABLE ###'
322 puts "file : #{file_name}"
323 self.each do |d|
324 d.inspect
325 end
326 end
327
328 private
329 # Test if is a Side By Side type
330 def sbs?(type, func)
331 if @start and type == "sbs"
332 if @before == func and @second
333 tmp_nb_line = @nb_line
334 self[tmp_nb_line] = Diff.new
335 else
336 @second = false
337 tmp_nb_line = @start
338 @start += 1
339 @nb_line -= 1
340 end
341 else
342 tmp_nb_line = @nb_line
343 @start = @nb_line
344 self[tmp_nb_line] = Diff.new
345 @second = true
346 end
347 unless self[tmp_nb_line]
348 @nb_line += 1
349 self[tmp_nb_line] = Diff.new
350 else
351 self[tmp_nb_line]
352 end
353 end
354
355 # Escape the HTML for the diff
356 def escapeHTML(line)
357 CGI.escapeHTML(line)
358 end
359
360 def parse_line(line, type="inline")
361 if line[0, 1] == "+"
362 diff = sbs? type, 'add'
363 @before = 'add'
364 diff.line_left = escapeHTML line[1..-1]
365 diff.nb_line_left = @line_num_l
366 diff.type_diff_left = 'diff_in'
367 @line_num_l += 1
368 true
369 elsif line[0, 1] == "-"
370 diff = sbs? type, 'remove'
371 @before = 'remove'
372 diff.line_right = escapeHTML line[1..-1]
373 diff.nb_line_right = @line_num_r
374 diff.type_diff_right = 'diff_out'
375 @line_num_r += 1
376 true
377 elsif line[0, 1] =~ /\s/
378 @before = 'same'
379 @start = false
380 diff = Diff.new
381 diff.line_right = escapeHTML line[1..-1]
382 diff.nb_line_right = @line_num_r
383 diff.line_left = escapeHTML line[1..-1]
384 diff.nb_line_left = @line_num_l
385 self[@nb_line] = diff
386 @line_num_l += 1
387 @line_num_r += 1
388 true
389 elsif line[0, 1] = "\\"
390 true
391 else
392 false
393 end
394 end
395 end
396
397 238 class Annotate
398 239 attr_reader :lines, :revisions
399 240
@@ -132,7 +132,7 module Redmine
132 132 revisions
133 133 end
134 134
135 def diff(path, identifier_from, identifier_to=nil, type="inline")
135 def diff(path, identifier_from, identifier_to=nil)
136 136 path ||= ''
137 137 if identifier_to
138 138 identifier_to = identifier_to.to_i
@@ -147,7 +147,7 module Redmine
147 147 end
148 148 end
149 149 #return nil if $? && $?.exitstatus != 0
150 DiffTableList.new diff, type
150 diff
151 151 end
152 152
153 153 def cat(path, identifier=nil)
@@ -227,7 +227,7 module Redmine
227 227 end
228 228 end
229 229
230 def diff(path, identifier_from, identifier_to=nil, type="inline")
230 def diff(path, identifier_from, identifier_to=nil)
231 231 logger.debug "<cvs> diff path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}"
232 232 path_with_project="#{url}#{with_leading_slash(path)}"
233 233 cmd = "#{CVS_BIN} -d #{root_url} rdiff -u -r#{identifier_to} -r#{identifier_from} #{path_with_project}"
@@ -238,7 +238,7 module Redmine
238 238 end
239 239 end
240 240 return nil if $? && $?.exitstatus != 0
241 DiffTableList.new diff, type
241 diff
242 242 end
243 243
244 244 def cat(path, identifier=nil)
@@ -94,7 +94,7 module Redmine
94 94 revisions
95 95 end
96 96
97 def diff(path, identifier_from, identifier_to=nil, type="inline")
97 def diff(path, identifier_from, identifier_to=nil)
98 98 path = '*' if path.blank?
99 99 cmd = "#{DARCS_BIN} diff --repodir #{@url}"
100 100 if identifier_to.nil?
@@ -111,7 +111,7 module Redmine
111 111 end
112 112 end
113 113 return nil if $? && $?.exitstatus != 0
114 DiffTableList.new diff, type
114 diff
115 115 end
116 116
117 117 private
@@ -204,7 +204,7 module Redmine
204 204 revisions
205 205 end
206 206
207 def diff(path, identifier_from, identifier_to=nil, type="inline")
207 def diff(path, identifier_from, identifier_to=nil)
208 208 path ||= ''
209 209 if !identifier_to
210 210 identifier_to = nil
@@ -220,7 +220,7 module Redmine
220 220 end
221 221 end
222 222 return nil if $? && $?.exitstatus != 0
223 DiffTableList.new diff, type
223 diff
224 224 end
225 225
226 226 def annotate(path, identifier=nil)
@@ -117,7 +117,7 module Redmine
117 117 revisions
118 118 end
119 119
120 def diff(path, identifier_from, identifier_to=nil, type="inline")
120 def diff(path, identifier_from, identifier_to=nil)
121 121 path ||= ''
122 122 if identifier_to
123 123 identifier_to = identifier_to.to_i
@@ -133,7 +133,7 module Redmine
133 133 end
134 134 end
135 135 return nil if $? && $?.exitstatus != 0
136 DiffTableList.new diff, type
136 diff
137 137 end
138 138
139 139 def cat(path, identifier=nil)
@@ -142,7 +142,7 module Redmine
142 142 end
143 143 end
144 144 return nil if $? && $?.exitstatus != 0
145 DiffTableList.new diff, type
145 diff
146 146 end
147 147
148 148 def cat(path, identifier=nil)
General Comments 0
You need to be logged in to leave comments. Login now