##// END OF EJS Templates
Fixed: files with an apostrophe in their names can't be accessed in the repository...
Jean-Philippe Lang -
r519:98d08439dce6
parent child
Show More
@@ -1,436 +1,436
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 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 'rexml/document'
18 require 'rexml/document'
19 require 'cgi'
19 require 'cgi'
20
20
21 module SvnRepos
21 module SvnRepos
22
22
23 class CommandFailed < StandardError #:nodoc:
23 class CommandFailed < StandardError #:nodoc:
24 end
24 end
25
25
26 class Base
26 class Base
27
27
28 def initialize(url, root_url=nil, login=nil, password=nil)
28 def initialize(url, root_url=nil, login=nil, password=nil)
29 @url = url
29 @url = url
30 @login = login if login && !login.empty?
30 @login = login if login && !login.empty?
31 @password = (password || "") if @login
31 @password = (password || "") if @login
32 @root_url = root_url.blank? ? retrieve_root_url : root_url
32 @root_url = root_url.blank? ? retrieve_root_url : root_url
33 end
33 end
34
34
35 def root_url
35 def root_url
36 @root_url
36 @root_url
37 end
37 end
38
38
39 def url
39 def url
40 @url
40 @url
41 end
41 end
42
42
43 # get info about the svn repository
43 # get info about the svn repository
44 def info
44 def info
45 cmd = "svn info --xml #{target('')}"
45 cmd = "svn info --xml #{target('')}"
46 cmd << " --username #{@login} --password #{@password}" if @login
46 cmd << " --username #{@login} --password #{@password}" if @login
47 info = nil
47 info = nil
48 shellout(cmd) do |io|
48 shellout(cmd) do |io|
49 begin
49 begin
50 doc = REXML::Document.new(io)
50 doc = REXML::Document.new(io)
51 #root_url = doc.elements["info/entry/repository/root"].text
51 #root_url = doc.elements["info/entry/repository/root"].text
52 info = Info.new({:root_url => doc.elements["info/entry/repository/root"].text,
52 info = Info.new({:root_url => doc.elements["info/entry/repository/root"].text,
53 :lastrev => Revision.new({
53 :lastrev => Revision.new({
54 :identifier => doc.elements["info/entry/commit"].attributes['revision'],
54 :identifier => doc.elements["info/entry/commit"].attributes['revision'],
55 :time => Time.parse(doc.elements["info/entry/commit/date"].text),
55 :time => Time.parse(doc.elements["info/entry/commit/date"].text),
56 :author => (doc.elements["info/entry/commit/author"] ? doc.elements["info/entry/commit/author"].text : "")
56 :author => (doc.elements["info/entry/commit/author"] ? doc.elements["info/entry/commit/author"].text : "")
57 })
57 })
58 })
58 })
59 rescue
59 rescue
60 end
60 end
61 end
61 end
62 return nil if $? && $?.exitstatus != 0
62 return nil if $? && $?.exitstatus != 0
63 info
63 info
64 rescue Errno::ENOENT => e
64 rescue Errno::ENOENT => e
65 return nil
65 return nil
66 end
66 end
67
67
68 # Returns the entry identified by path and revision identifier
68 # Returns the entry identified by path and revision identifier
69 # or nil if entry doesn't exist in the repository
69 # or nil if entry doesn't exist in the repository
70 def entry(path=nil, identifier=nil)
70 def entry(path=nil, identifier=nil)
71 e = entries(path, identifier)
71 e = entries(path, identifier)
72 e ? e.first : nil
72 e ? e.first : nil
73 end
73 end
74
74
75 # Returns an Entries collection
75 # Returns an Entries collection
76 # or nil if the given path doesn't exist in the repository
76 # or nil if the given path doesn't exist in the repository
77 def entries(path=nil, identifier=nil)
77 def entries(path=nil, identifier=nil)
78 path ||= ''
78 path ||= ''
79 identifier = 'HEAD' unless identifier and identifier > 0
79 identifier = 'HEAD' unless identifier and identifier > 0
80 entries = Entries.new
80 entries = Entries.new
81 cmd = "svn list --xml #{target(path)}@#{identifier}"
81 cmd = "svn list --xml #{target(path)}@#{identifier}"
82 cmd << " --username #{@login} --password #{@password}" if @login
82 cmd << " --username #{@login} --password #{@password}" if @login
83 shellout(cmd) do |io|
83 shellout(cmd) do |io|
84 begin
84 begin
85 doc = REXML::Document.new(io)
85 doc = REXML::Document.new(io)
86 doc.elements.each("lists/list/entry") do |entry|
86 doc.elements.each("lists/list/entry") do |entry|
87 entries << Entry.new({:name => entry.elements['name'].text,
87 entries << Entry.new({:name => entry.elements['name'].text,
88 :path => ((path.empty? ? "" : "#{path}/") + entry.elements['name'].text),
88 :path => ((path.empty? ? "" : "#{path}/") + entry.elements['name'].text),
89 :kind => entry.attributes['kind'],
89 :kind => entry.attributes['kind'],
90 :size => (entry.elements['size'] and entry.elements['size'].text).to_i,
90 :size => (entry.elements['size'] and entry.elements['size'].text).to_i,
91 :lastrev => Revision.new({
91 :lastrev => Revision.new({
92 :identifier => entry.elements['commit'].attributes['revision'],
92 :identifier => entry.elements['commit'].attributes['revision'],
93 :time => Time.parse(entry.elements['commit'].elements['date'].text),
93 :time => Time.parse(entry.elements['commit'].elements['date'].text),
94 :author => (entry.elements['commit'].elements['author'] ? entry.elements['commit'].elements['author'].text : "")
94 :author => (entry.elements['commit'].elements['author'] ? entry.elements['commit'].elements['author'].text : "")
95 })
95 })
96 })
96 })
97 end
97 end
98 rescue
98 rescue
99 end
99 end
100 end
100 end
101 return nil if $? && $?.exitstatus != 0
101 return nil if $? && $?.exitstatus != 0
102 entries.sort_by_name
102 entries.sort_by_name
103 rescue Errno::ENOENT => e
103 rescue Errno::ENOENT => e
104 raise CommandFailed
104 raise CommandFailed
105 end
105 end
106
106
107 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
107 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
108 path ||= ''
108 path ||= ''
109 identifier_from = 'HEAD' unless identifier_from and identifier_from.to_i > 0
109 identifier_from = 'HEAD' unless identifier_from and identifier_from.to_i > 0
110 identifier_to = 1 unless identifier_to and identifier_to.to_i > 0
110 identifier_to = 1 unless identifier_to and identifier_to.to_i > 0
111 revisions = Revisions.new
111 revisions = Revisions.new
112 cmd = "svn log --xml -r #{identifier_from}:#{identifier_to}"
112 cmd = "svn log --xml -r #{identifier_from}:#{identifier_to}"
113 cmd << " --username #{@login} --password #{@password}" if @login
113 cmd << " --username #{@login} --password #{@password}" if @login
114 cmd << " --verbose " if options[:with_paths]
114 cmd << " --verbose " if options[:with_paths]
115 cmd << target(path)
115 cmd << target(path)
116 shellout(cmd) do |io|
116 shellout(cmd) do |io|
117 begin
117 begin
118 doc = REXML::Document.new(io)
118 doc = REXML::Document.new(io)
119 doc.elements.each("log/logentry") do |logentry|
119 doc.elements.each("log/logentry") do |logentry|
120 paths = []
120 paths = []
121 logentry.elements.each("paths/path") do |path|
121 logentry.elements.each("paths/path") do |path|
122 paths << {:action => path.attributes['action'],
122 paths << {:action => path.attributes['action'],
123 :path => path.text,
123 :path => path.text,
124 :from_path => path.attributes['copyfrom-path'],
124 :from_path => path.attributes['copyfrom-path'],
125 :from_revision => path.attributes['copyfrom-rev']
125 :from_revision => path.attributes['copyfrom-rev']
126 }
126 }
127 end
127 end
128 paths.sort! { |x,y| x[:path] <=> y[:path] }
128 paths.sort! { |x,y| x[:path] <=> y[:path] }
129
129
130 revisions << Revision.new({:identifier => logentry.attributes['revision'],
130 revisions << Revision.new({:identifier => logentry.attributes['revision'],
131 :author => (logentry.elements['author'] ? logentry.elements['author'].text : ""),
131 :author => (logentry.elements['author'] ? logentry.elements['author'].text : ""),
132 :time => Time.parse(logentry.elements['date'].text),
132 :time => Time.parse(logentry.elements['date'].text),
133 :message => logentry.elements['msg'].text,
133 :message => logentry.elements['msg'].text,
134 :paths => paths
134 :paths => paths
135 })
135 })
136 end
136 end
137 rescue
137 rescue
138 end
138 end
139 end
139 end
140 return nil if $? && $?.exitstatus != 0
140 return nil if $? && $?.exitstatus != 0
141 revisions
141 revisions
142 rescue Errno::ENOENT => e
142 rescue Errno::ENOENT => e
143 raise CommandFailed
143 raise CommandFailed
144 end
144 end
145
145
146 def diff(path, identifier_from, identifier_to=nil, type="inline")
146 def diff(path, identifier_from, identifier_to=nil, type="inline")
147 path ||= ''
147 path ||= ''
148 if identifier_to and identifier_to.to_i > 0
148 if identifier_to and identifier_to.to_i > 0
149 identifier_to = identifier_to.to_i
149 identifier_to = identifier_to.to_i
150 else
150 else
151 identifier_to = identifier_from.to_i - 1
151 identifier_to = identifier_from.to_i - 1
152 end
152 end
153 cmd = "svn diff -r "
153 cmd = "svn diff -r "
154 cmd << "#{identifier_to}:"
154 cmd << "#{identifier_to}:"
155 cmd << "#{identifier_from}"
155 cmd << "#{identifier_from}"
156 cmd << "#{target(path)}@#{identifier_from}"
156 cmd << "#{target(path)}@#{identifier_from}"
157 cmd << " --username #{@login} --password #{@password}" if @login
157 cmd << " --username #{@login} --password #{@password}" if @login
158 diff = []
158 diff = []
159 shellout(cmd) do |io|
159 shellout(cmd) do |io|
160 io.each_line do |line|
160 io.each_line do |line|
161 diff << line
161 diff << line
162 end
162 end
163 end
163 end
164 return nil if $? && $?.exitstatus != 0
164 return nil if $? && $?.exitstatus != 0
165 DiffTableList.new diff, type
165 DiffTableList.new diff, type
166
166
167 rescue Errno::ENOENT => e
167 rescue Errno::ENOENT => e
168 raise CommandFailed
168 raise CommandFailed
169 end
169 end
170
170
171 def cat(path, identifier=nil)
171 def cat(path, identifier=nil)
172 identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
172 identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
173 cmd = "svn cat #{target(path)}@#{identifier}"
173 cmd = "svn cat #{target(path)}@#{identifier}"
174 cmd << " --username #{@login} --password #{@password}" if @login
174 cmd << " --username #{@login} --password #{@password}" if @login
175 cat = nil
175 cat = nil
176 shellout(cmd) do |io|
176 shellout(cmd) do |io|
177 io.binmode
177 io.binmode
178 cat = io.read
178 cat = io.read
179 end
179 end
180 return nil if $? && $?.exitstatus != 0
180 return nil if $? && $?.exitstatus != 0
181 cat
181 cat
182 rescue Errno::ENOENT => e
182 rescue Errno::ENOENT => e
183 raise CommandFailed
183 raise CommandFailed
184 end
184 end
185
185
186 private
186 private
187 def retrieve_root_url
187 def retrieve_root_url
188 info = self.info
188 info = self.info
189 info ? info.root_url : nil
189 info ? info.root_url : nil
190 end
190 end
191
191
192 def target(path)
192 def target(path)
193 path ||= ""
193 path ||= ""
194 base = path.match(/^\//) ? root_url : url
194 base = path.match(/^\//) ? root_url : url
195 " \"" << "#{base}/#{path}".gsub(/["'?<>\*]/, '') << "\""
195 " \"" << "#{base}/#{path}".gsub(/["?<>\*]/, '') << "\""
196 end
196 end
197
197
198 def logger
198 def logger
199 RAILS_DEFAULT_LOGGER
199 RAILS_DEFAULT_LOGGER
200 end
200 end
201
201
202 def shellout(cmd, &block)
202 def shellout(cmd, &block)
203 logger.debug "Shelling out: #{cmd}" if logger && logger.debug?
203 logger.debug "Shelling out: #{cmd}" if logger && logger.debug?
204 IO.popen(cmd, "r+") do |io|
204 IO.popen(cmd, "r+") do |io|
205 io.close_write
205 io.close_write
206 block.call(io) if block_given?
206 block.call(io) if block_given?
207 end
207 end
208 end
208 end
209 end
209 end
210
210
211 class Entries < Array
211 class Entries < Array
212 def sort_by_name
212 def sort_by_name
213 sort {|x,y|
213 sort {|x,y|
214 if x.kind == y.kind
214 if x.kind == y.kind
215 x.name <=> y.name
215 x.name <=> y.name
216 else
216 else
217 x.kind <=> y.kind
217 x.kind <=> y.kind
218 end
218 end
219 }
219 }
220 end
220 end
221
221
222 def revisions
222 def revisions
223 revisions ||= Revisions.new(collect{|entry| entry.lastrev})
223 revisions ||= Revisions.new(collect{|entry| entry.lastrev})
224 end
224 end
225 end
225 end
226
226
227 class Info
227 class Info
228 attr_accessor :root_url, :lastrev
228 attr_accessor :root_url, :lastrev
229 def initialize(attributes={})
229 def initialize(attributes={})
230 self.root_url = attributes[:root_url] if attributes[:root_url]
230 self.root_url = attributes[:root_url] if attributes[:root_url]
231 self.lastrev = attributes[:lastrev]
231 self.lastrev = attributes[:lastrev]
232 end
232 end
233 end
233 end
234
234
235 class Entry
235 class Entry
236 attr_accessor :name, :path, :kind, :size, :lastrev
236 attr_accessor :name, :path, :kind, :size, :lastrev
237 def initialize(attributes={})
237 def initialize(attributes={})
238 self.name = attributes[:name] if attributes[:name]
238 self.name = attributes[:name] if attributes[:name]
239 self.path = attributes[:path] if attributes[:path]
239 self.path = attributes[:path] if attributes[:path]
240 self.kind = attributes[:kind] if attributes[:kind]
240 self.kind = attributes[:kind] if attributes[:kind]
241 self.size = attributes[:size].to_i if attributes[:size]
241 self.size = attributes[:size].to_i if attributes[:size]
242 self.lastrev = attributes[:lastrev]
242 self.lastrev = attributes[:lastrev]
243 end
243 end
244
244
245 def is_file?
245 def is_file?
246 'file' == self.kind
246 'file' == self.kind
247 end
247 end
248
248
249 def is_dir?
249 def is_dir?
250 'dir' == self.kind
250 'dir' == self.kind
251 end
251 end
252
252
253 def is_text?
253 def is_text?
254 Redmine::MimeType.is_type?('text', name)
254 Redmine::MimeType.is_type?('text', name)
255 end
255 end
256 end
256 end
257
257
258 class Revisions < Array
258 class Revisions < Array
259 def latest
259 def latest
260 sort {|x,y| x.time <=> y.time}.last
260 sort {|x,y| x.time <=> y.time}.last
261 end
261 end
262 end
262 end
263
263
264 class Revision
264 class Revision
265 attr_accessor :identifier, :author, :time, :message, :paths
265 attr_accessor :identifier, :author, :time, :message, :paths
266 def initialize(attributes={})
266 def initialize(attributes={})
267 self.identifier = attributes[:identifier]
267 self.identifier = attributes[:identifier]
268 self.author = attributes[:author]
268 self.author = attributes[:author]
269 self.time = attributes[:time]
269 self.time = attributes[:time]
270 self.message = attributes[:message] || ""
270 self.message = attributes[:message] || ""
271 self.paths = attributes[:paths]
271 self.paths = attributes[:paths]
272 end
272 end
273
273
274 end
274 end
275
275
276 # A line of Diff
276 # A line of Diff
277 class Diff
277 class Diff
278
278
279 attr_accessor :nb_line_left
279 attr_accessor :nb_line_left
280 attr_accessor :line_left
280 attr_accessor :line_left
281 attr_accessor :nb_line_right
281 attr_accessor :nb_line_right
282 attr_accessor :line_right
282 attr_accessor :line_right
283 attr_accessor :type_diff_right
283 attr_accessor :type_diff_right
284 attr_accessor :type_diff_left
284 attr_accessor :type_diff_left
285
285
286 def initialize ()
286 def initialize ()
287 self.nb_line_left = ''
287 self.nb_line_left = ''
288 self.nb_line_right = ''
288 self.nb_line_right = ''
289 self.line_left = ''
289 self.line_left = ''
290 self.line_right = ''
290 self.line_right = ''
291 self.type_diff_right = ''
291 self.type_diff_right = ''
292 self.type_diff_left = ''
292 self.type_diff_left = ''
293 end
293 end
294
294
295 def inspect
295 def inspect
296 puts '### Start Line Diff ###'
296 puts '### Start Line Diff ###'
297 puts self.nb_line_left
297 puts self.nb_line_left
298 puts self.line_left
298 puts self.line_left
299 puts self.nb_line_right
299 puts self.nb_line_right
300 puts self.line_right
300 puts self.line_right
301 end
301 end
302 end
302 end
303
303
304 class DiffTableList < Array
304 class DiffTableList < Array
305
305
306 def initialize (diff, type="inline")
306 def initialize (diff, type="inline")
307 diff_table = DiffTable.new type
307 diff_table = DiffTable.new type
308 diff.each do |line|
308 diff.each do |line|
309 if line =~ /^Index: (.*)$/
309 if line =~ /^Index: (.*)$/
310 self << diff_table if diff_table.length > 1
310 self << diff_table if diff_table.length > 1
311 diff_table = DiffTable.new type
311 diff_table = DiffTable.new type
312 end
312 end
313 a = diff_table.add_line line
313 a = diff_table.add_line line
314 end
314 end
315 self << diff_table
315 self << diff_table
316 end
316 end
317 end
317 end
318
318
319 # Class for create a Diff
319 # Class for create a Diff
320 class DiffTable < Hash
320 class DiffTable < Hash
321
321
322 attr_reader :file_name, :line_num_l, :line_num_r
322 attr_reader :file_name, :line_num_l, :line_num_r
323
323
324 # Initialize with a Diff file and the type of Diff View
324 # Initialize with a Diff file and the type of Diff View
325 # The type view must be inline or sbs (side_by_side)
325 # The type view must be inline or sbs (side_by_side)
326 def initialize (type="inline")
326 def initialize (type="inline")
327 @parsing = false
327 @parsing = false
328 @nb_line = 1
328 @nb_line = 1
329 @start = false
329 @start = false
330 @before = 'same'
330 @before = 'same'
331 @second = true
331 @second = true
332 @type = type
332 @type = type
333 end
333 end
334
334
335 # Function for add a line of this Diff
335 # Function for add a line of this Diff
336 def add_line(line)
336 def add_line(line)
337 unless @parsing
337 unless @parsing
338 if line =~ /^Index: (.*)$/
338 if line =~ /^Index: (.*)$/
339 @file_name = $1
339 @file_name = $1
340 return false
340 return false
341 elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/
341 elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/
342 @line_num_l = $2.to_i
342 @line_num_l = $2.to_i
343 @line_num_r = $5.to_i
343 @line_num_r = $5.to_i
344 @parsing = true
344 @parsing = true
345 end
345 end
346 else
346 else
347 if line =~ /^_+$/
347 if line =~ /^_+$/
348 self.delete(self.keys.sort.last)
348 self.delete(self.keys.sort.last)
349 @parsing = false
349 @parsing = false
350 return false
350 return false
351 elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/
351 elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/
352 @line_num_l = $2.to_i
352 @line_num_l = $2.to_i
353 @line_num_r = $5.to_i
353 @line_num_r = $5.to_i
354 else
354 else
355 @nb_line += 1 if parse_line(line, @type)
355 @nb_line += 1 if parse_line(line, @type)
356 end
356 end
357 end
357 end
358 return true
358 return true
359 end
359 end
360
360
361 def inspect
361 def inspect
362 puts '### DIFF TABLE ###'
362 puts '### DIFF TABLE ###'
363 puts "file : #{file_name}"
363 puts "file : #{file_name}"
364 self.each do |d|
364 self.each do |d|
365 d.inspect
365 d.inspect
366 end
366 end
367 end
367 end
368
368
369 private
369 private
370
370
371 # Test if is a Side By Side type
371 # Test if is a Side By Side type
372 def sbs?(type, func)
372 def sbs?(type, func)
373 if @start and type == "sbs"
373 if @start and type == "sbs"
374 if @before == func and @second
374 if @before == func and @second
375 tmp_nb_line = @nb_line
375 tmp_nb_line = @nb_line
376 self[tmp_nb_line] = Diff.new
376 self[tmp_nb_line] = Diff.new
377 else
377 else
378 @second = false
378 @second = false
379 tmp_nb_line = @start
379 tmp_nb_line = @start
380 @start += 1
380 @start += 1
381 @nb_line -= 1
381 @nb_line -= 1
382 end
382 end
383 else
383 else
384 tmp_nb_line = @nb_line
384 tmp_nb_line = @nb_line
385 @start = @nb_line
385 @start = @nb_line
386 self[tmp_nb_line] = Diff.new
386 self[tmp_nb_line] = Diff.new
387 @second = true
387 @second = true
388 end
388 end
389 unless self[tmp_nb_line]
389 unless self[tmp_nb_line]
390 @nb_line += 1
390 @nb_line += 1
391 self[tmp_nb_line] = Diff.new
391 self[tmp_nb_line] = Diff.new
392 else
392 else
393 self[tmp_nb_line]
393 self[tmp_nb_line]
394 end
394 end
395 end
395 end
396
396
397 # Escape the HTML for the diff
397 # Escape the HTML for the diff
398 def escapeHTML(line)
398 def escapeHTML(line)
399 CGI.escapeHTML(line).gsub(/\s/, '&nbsp;')
399 CGI.escapeHTML(line).gsub(/\s/, '&nbsp;')
400 end
400 end
401
401
402 def parse_line (line, type="inline")
402 def parse_line (line, type="inline")
403 if line[0, 1] == "+"
403 if line[0, 1] == "+"
404 diff = sbs? type, 'add'
404 diff = sbs? type, 'add'
405 @before = 'add'
405 @before = 'add'
406 diff.line_left = escapeHTML line[1..-1]
406 diff.line_left = escapeHTML line[1..-1]
407 diff.nb_line_left = @line_num_l
407 diff.nb_line_left = @line_num_l
408 diff.type_diff_left = 'diff_in'
408 diff.type_diff_left = 'diff_in'
409 @line_num_l += 1
409 @line_num_l += 1
410 true
410 true
411 elsif line[0, 1] == "-"
411 elsif line[0, 1] == "-"
412 diff = sbs? type, 'remove'
412 diff = sbs? type, 'remove'
413 @before = 'remove'
413 @before = 'remove'
414 diff.line_right = escapeHTML line[1..-1]
414 diff.line_right = escapeHTML line[1..-1]
415 diff.nb_line_right = @line_num_r
415 diff.nb_line_right = @line_num_r
416 diff.type_diff_right = 'diff_out'
416 diff.type_diff_right = 'diff_out'
417 @line_num_r += 1
417 @line_num_r += 1
418 true
418 true
419 elsif line[0, 1] =~ /\s/
419 elsif line[0, 1] =~ /\s/
420 @before = 'same'
420 @before = 'same'
421 @start = false
421 @start = false
422 diff = Diff.new
422 diff = Diff.new
423 diff.line_right = escapeHTML line[1..-1]
423 diff.line_right = escapeHTML line[1..-1]
424 diff.nb_line_right = @line_num_r
424 diff.nb_line_right = @line_num_r
425 diff.line_left = escapeHTML line[1..-1]
425 diff.line_left = escapeHTML line[1..-1]
426 diff.nb_line_left = @line_num_l
426 diff.nb_line_left = @line_num_l
427 self[@nb_line] = diff
427 self[@nb_line] = diff
428 @line_num_l += 1
428 @line_num_l += 1
429 @line_num_r += 1
429 @line_num_r += 1
430 true
430 true
431 else
431 else
432 false
432 false
433 end
433 end
434 end
434 end
435 end
435 end
436 end No newline at end of file
436 end
General Comments 0
You need to be logged in to leave comments. Login now