svn_record 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +72 -0
  3. data/Rakefile +7 -0
  4. data/app/assets/images/svn_record/file_icon/bullet_add.png +0 -0
  5. data/app/assets/images/svn_record/file_icon/bullet_black.png +0 -0
  6. data/app/assets/images/svn_record/file_icon/bullet_blue.png +0 -0
  7. data/app/assets/images/svn_record/file_icon/bullet_delete.png +0 -0
  8. data/app/assets/images/svn_record/file_icon/bullet_diamond.png +0 -0
  9. data/app/assets/images/svn_record/file_icon/bullet_end.png +0 -0
  10. data/app/assets/images/svn_record/file_icon/bullet_go.png +0 -0
  11. data/app/assets/images/svn_record/file_icon/bullet_orange.png +0 -0
  12. data/app/assets/images/svn_record/file_icon/bullet_purple.png +0 -0
  13. data/app/assets/images/svn_record/file_icon/bullet_toggle_minus.png +0 -0
  14. data/app/assets/images/svn_record/file_icon/bullet_toggle_plus.png +0 -0
  15. data/app/assets/images/svn_record/file_icon/dir.png +0 -0
  16. data/app/assets/images/svn_record/file_icon/file.png +0 -0
  17. data/app/assets/images/svn_record/file_icon/folder.png +0 -0
  18. data/app/assets/images/svn_record/file_icon/folder_open.png +0 -0
  19. data/app/assets/images/svn_record/file_icon/folder_open_add.png +0 -0
  20. data/app/assets/images/svn_record/file_icon/folder_open_orange.png +0 -0
  21. data/app/assets/javascripts/svn_record/application.js +16 -0
  22. data/app/assets/javascripts/svn_record/change.js.coffee +4 -0
  23. data/app/assets/stylesheets/svn_record/application.css +14 -0
  24. data/app/assets/stylesheets/svn_record/site.css +396 -0
  25. data/app/controllers/svn_record/application_controller.rb +3 -0
  26. data/app/controllers/svn_record/repository/application_controller.rb +3 -0
  27. data/app/controllers/svn_record/repository/changes_controller.rb +38 -0
  28. data/app/models/svn_record/repository/change.rb +39 -0
  29. data/app/models/svn_record/repository/file.rb +20 -0
  30. data/app/models/svn_record/repository/user.rb +14 -0
  31. data/app/views/layouts/svn_record/subversion.html.slim +22 -0
  32. data/app/views/svn_record/repository/changes/_changesets_list.slim +29 -0
  33. data/app/views/svn_record/repository/changes/diff.html.slim +30 -0
  34. data/app/views/svn_record/repository/changes/entry.html.slim +18 -0
  35. data/app/views/svn_record/repository/changes/index.html.slim +34 -0
  36. data/app/views/svn_record/repository/changes/list.html.slim +2 -0
  37. data/app/views/svn_record/repository/changes/revisions.html.slim +18 -0
  38. data/config/configuration.yml +5 -0
  39. data/config/routes.rb +17 -0
  40. data/lib/Svn/helper.rb +108 -0
  41. data/lib/Svn/mime_type.rb +492 -0
  42. data/lib/Svn/scm/adapters/subversion.rb +303 -0
  43. data/lib/generators/svn_record/install_generator.rb +16 -0
  44. data/lib/generators/svn_record/templates/create_repository_changes.rb +17 -0
  45. data/lib/generators/svn_record/templates/create_repository_files.rb +21 -0
  46. data/lib/generators/svn_record/templates/create_repository_user.rb +8 -0
  47. data/lib/svn_record/engine.rb +11 -0
  48. data/lib/svn_record/version.rb +3 -0
  49. data/lib/svn_record.rb +4 -0
  50. metadata +161 -0
@@ -0,0 +1,492 @@
1
+ module Svn
2
+ module MimeType
3
+
4
+ MIME_TYPES = {
5
+ 'text/css' => 'css',
6
+ 'text/html' => 'html,htm,xhtml',
7
+ 'text/x-html-template' => 'rhtml',
8
+ 'text/x-ruby' => 'rb,rbw,ruby,rake,erb',
9
+ 'text/x-sh' => 'sh',
10
+ 'text/csv' => 'csv',
11
+ 'image/gif' => 'gif',
12
+ 'image/jpeg' => 'jpg,jpeg,jpe',
13
+ 'image/png' => 'png',
14
+ 'image/tiff' => 'tiff,tif',
15
+ 'image/x-ms-bmp' => 'bmp',
16
+ 'image/x-xpixmap' => 'xpm',
17
+ 'image/svg+xml'=> 'svg',
18
+ 'application/javascript' => 'js',
19
+ 'application/vnd.ms-powerpoint' => 'ppt,pps',
20
+ 'application/x-tar' => 'tar',
21
+ 'application/zip' => 'zip',
22
+ 'application/x-gzip' => 'gz',
23
+ }.freeze
24
+
25
+ EXTENSIONS = MIME_TYPES.inject({}) do |map, (type, exts)|
26
+ exts.split(',').each {|ext| map[ext.strip] = type}
27
+ map
28
+ end
29
+
30
+ # returns mime type for name or nil if unknown
31
+ def self.of(name)
32
+ return nil unless name
33
+ m = name.to_s.match(/(^|\.)([^\.]+)$/)
34
+ EXTENSIONS[m[2].downcase] if m
35
+ end
36
+
37
+ # Returns the css class associated to
38
+ # the mime type of name
39
+ def self.css_class_of(name)
40
+ mime = of(name)
41
+ mime && mime.gsub('/', '-')
42
+ end
43
+
44
+ def self.main_mimetype_of(name)
45
+ mimetype = of(name)
46
+ mimetype.split('/').first if mimetype
47
+ end
48
+
49
+ # return true if mime-type for name is type/*
50
+ # otherwise false
51
+ def self.is_type?(type, name)
52
+ main_mimetype = main_mimetype_of(name)
53
+ type.to_s == main_mimetype
54
+ end
55
+ end
56
+
57
+ module SyntaxHighlighting
58
+
59
+ class << self
60
+ attr_reader :highlighter
61
+ delegate :highlight_by_filename, :highlight_by_language, :to => :highlighter
62
+
63
+ def highlighter=(name)
64
+ if name.is_a?(Module)
65
+ @highlighter = name
66
+ else
67
+ @highlighter = const_get(name)
68
+ end
69
+ end
70
+ end
71
+ module CodeRay
72
+ require 'coderay'
73
+ require 'coderay/helpers/file_type'
74
+ class << self
75
+ # Highlights +text+ as the content of +filename+
76
+ # Should not return line numbers nor outer pre tag
77
+ def highlight_by_filename(text, filename)
78
+ language = ::CodeRay::FileType[filename]
79
+ language ? ::CodeRay.scan(text, language).html(:break_lines => true) : ERB::Util.h(text)
80
+ end
81
+ # Highlights +text+ using +language+ syntax
82
+ # Should not return outer pre tag
83
+ def highlight_by_language(text, language)
84
+ ::CodeRay.scan(text, language).html(:wrap => :span)
85
+ end
86
+ end
87
+ end
88
+ end
89
+ SyntaxHighlighting.highlighter = 'CodeRay'
90
+
91
+ class UnifiedDiff < Array
92
+ attr_reader :diff_type, :diff_style
93
+
94
+ def initialize(diff, options={})
95
+ options.assert_valid_keys(:type, :style, :max_lines)
96
+ diff = diff.split("\n") if diff.is_a?(String)
97
+ @diff_type = options[:type] || 'inline'
98
+ @diff_style = options[:style]
99
+ lines = 0
100
+ @truncated = false
101
+ diff_table = DiffTable.new(diff_type, diff_style)
102
+ diff.each do |line_raw|
103
+ line = Svn::CodesetUtil.to_utf8_by_setting(line_raw)
104
+ unless diff_table.add_line(line)
105
+ self << diff_table if diff_table.length > 0
106
+ diff_table = DiffTable.new(diff_type, diff_style)
107
+ end
108
+ lines += 1
109
+ if options[:max_lines] && lines > options[:max_lines]
110
+ @truncated = true
111
+ break
112
+ end
113
+ end
114
+ self << diff_table unless diff_table.empty?
115
+ self
116
+ end
117
+ def truncated?; @truncated; end
118
+ end
119
+
120
+ # Class that represents a file diff
121
+ class DiffTable < Array
122
+ attr_reader :file_name
123
+ def initialize(type="inline", style=nil)
124
+ @parsing = false
125
+ @added = 0
126
+ @removed = 0
127
+ @type = type
128
+ @style = style
129
+ @file_name = nil
130
+ @git_diff = false
131
+ end
132
+
133
+ def add_line(line)
134
+ unless @parsing
135
+ if line =~ /^(---|\+\+\+) (.*)$/
136
+ self.file_name = $2
137
+ elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/
138
+ @line_num_l = $2.to_i
139
+ @line_num_r = $5.to_i
140
+ @parsing = true
141
+ end
142
+ else
143
+ if line =~ %r{^[^\+\-\s@\\]}
144
+ @parsing = false
145
+ return false
146
+ elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/
147
+ @line_num_l = $2.to_i
148
+ @line_num_r = $5.to_i
149
+ else
150
+ parse_line(line, @type)
151
+ end
152
+ end
153
+ return true
154
+ end
155
+ def each_line
156
+ prev_line_left, prev_line_right = nil, nil
157
+ each do |line|
158
+ spacing = prev_line_left && prev_line_right && (line.nb_line_left != prev_line_left+1) && (line.nb_line_right != prev_line_right+1)
159
+ yield spacing, line
160
+ prev_line_left = line.nb_line_left.to_i if line.nb_line_left.to_i > 0
161
+ prev_line_right = line.nb_line_right.to_i if line.nb_line_right.to_i > 0
162
+ end
163
+ end
164
+
165
+ def inspect
166
+ puts '### DIFF TABLE ###'
167
+ puts "file : #{file_name}"
168
+ self.each do |d|
169
+ d.inspect
170
+ end
171
+ end
172
+
173
+ private
174
+
175
+ def file_name=(arg)
176
+ both_git_diff = false
177
+ if file_name.nil?
178
+ @git_diff = true if arg =~ %r{^(a/|/dev/null)}
179
+ else
180
+ both_git_diff = (@git_diff && arg =~ %r{^(b/|/dev/null)})
181
+ end
182
+ if both_git_diff
183
+ if file_name && arg == "/dev/null"
184
+ # keep the original file name
185
+ @file_name = file_name.sub(%r{^a/}, '')
186
+ else
187
+ # remove leading b/
188
+ @file_name = arg.sub(%r{^b/}, '')
189
+ end
190
+ elsif @style == "Subversion"
191
+ # removing trailing "(revision nn)"
192
+ @file_name = arg.sub(%r{\t+\(.*\)$}, '')
193
+ else
194
+ @file_name = arg
195
+ end
196
+ end
197
+
198
+ def diff_for_added_line
199
+ if @type == 'sbs' && @removed > 0 && @added < @removed
200
+ self[-(@removed - @added)]
201
+ else
202
+ diff = Diff.new
203
+ self << diff
204
+ diff
205
+ end
206
+ end
207
+
208
+ def parse_line(line, type="inline")
209
+ if line[0, 1] == "+"
210
+ diff = diff_for_added_line
211
+ diff.line_right = line[1..-1]
212
+ diff.nb_line_right = @line_num_r
213
+ diff.type_diff_right = 'diff_in'
214
+ @line_num_r += 1
215
+ @added += 1
216
+ true
217
+ elsif line[0, 1] == "-"
218
+ diff = Diff.new
219
+ diff.line_left = line[1..-1]
220
+ diff.nb_line_left = @line_num_l
221
+ diff.type_diff_left = 'diff_out'
222
+ self << diff
223
+ @line_num_l += 1
224
+ @removed += 1
225
+ true
226
+ else
227
+ write_offsets
228
+ if line[0, 1] =~ /\s/
229
+ diff = Diff.new
230
+ diff.line_right = line[1..-1]
231
+ diff.nb_line_right = @line_num_r
232
+ diff.line_left = line[1..-1]
233
+ diff.nb_line_left = @line_num_l
234
+ self << diff
235
+ @line_num_l += 1
236
+ @line_num_r += 1
237
+ true
238
+ elsif line[0, 1] = "\\"
239
+ true
240
+ else
241
+ false
242
+ end
243
+ end
244
+ end
245
+
246
+ def write_offsets
247
+ if @added > 0 && @added == @removed
248
+ @added.times do |i|
249
+ line = self[-(1 + i)]
250
+ removed = (@type == 'sbs') ? line : self[-(1 + @added + i)]
251
+ offsets = offsets(removed.line_left, line.line_right)
252
+ removed.offsets = line.offsets = offsets
253
+ end
254
+ end
255
+ @added = 0
256
+ @removed = 0
257
+ end
258
+
259
+ def offsets(line_left, line_right)
260
+ if line_left.present? && line_right.present? && line_left != line_right
261
+ max = [line_left.size, line_right.size].min
262
+ starting = 0
263
+ while starting < max && line_left[starting] == line_right[starting]
264
+ starting += 1
265
+ end
266
+ while line_left[starting].ord.between?(128, 191) && starting > 0
267
+ starting -= 1
268
+ end
269
+ ending = -1
270
+ while ending >= -(max - starting) && line_left[ending] == line_right[ending]
271
+ ending -= 1
272
+ end
273
+ while line_left[ending].ord.between?(128, 191) && ending > -1
274
+ ending -= 1
275
+ end
276
+ unless starting == 0 && ending == -1
277
+ [starting, ending]
278
+ end
279
+ end
280
+ end
281
+ end
282
+
283
+ # A line of diff
284
+ class Diff
285
+ attr_accessor :nb_line_left
286
+ attr_accessor :line_left
287
+ attr_accessor :nb_line_right
288
+ attr_accessor :line_right
289
+ attr_accessor :type_diff_right
290
+ attr_accessor :type_diff_left
291
+ attr_accessor :offsets
292
+
293
+ def initialize()
294
+ self.nb_line_left = ''
295
+ self.nb_line_right = ''
296
+ self.line_left = ''
297
+ self.line_right = ''
298
+ self.type_diff_right = ''
299
+ self.type_diff_left = ''
300
+ end
301
+
302
+ def type_diff
303
+ type_diff_right == 'diff_in' ? type_diff_right : type_diff_left
304
+ end
305
+
306
+ def line
307
+ type_diff_right == 'diff_in' ? line_right : line_left
308
+ end
309
+
310
+ def html_line_left
311
+ line_to_html(line_left, offsets)
312
+ end
313
+
314
+ def html_line_right
315
+ line_to_html(line_right, offsets)
316
+ end
317
+
318
+ def html_line
319
+ line_to_html(line, offsets)
320
+ end
321
+
322
+ def inspect
323
+ puts '### Start Line Diff ###'
324
+ puts self.nb_line_left
325
+ puts self.line_left
326
+ puts self.nb_line_right
327
+ puts self.line_right
328
+ end
329
+
330
+ private
331
+
332
+ def line_to_html(line, offsets)
333
+ html = line_to_html_raw(line, offsets)
334
+ html.force_encoding('UTF-8') if html.respond_to?(:force_encoding)
335
+ html
336
+ end
337
+
338
+ def line_to_html_raw(line, offsets)
339
+ if offsets
340
+ s = ''
341
+ unless offsets.first == 0
342
+ s << CGI.escapeHTML(line[0..offsets.first-1])
343
+ end
344
+ s << '<span>' + CGI.escapeHTML(line[offsets.first..offsets.last]) + '</span>'
345
+ unless offsets.last == -1
346
+ s << CGI.escapeHTML(line[offsets.last+1..-1])
347
+ end
348
+ s
349
+ else
350
+ CGI.escapeHTML(line)
351
+ end
352
+ end
353
+ end
354
+
355
+ module CodesetUtil
356
+
357
+ def self.replace_invalid_utf8(str)
358
+ return str if str.nil?
359
+ if str.respond_to?(:force_encoding)
360
+ str.force_encoding('UTF-8')
361
+ if ! str.valid_encoding?
362
+ str = str.encode("US-ASCII", :invalid => :replace,
363
+ :undef => :replace, :replace => '?').encode("UTF-8")
364
+ end
365
+ elsif RUBY_PLATFORM == 'java'
366
+ begin
367
+ ic = Iconv.new('UTF-8', 'UTF-8')
368
+ str = ic.iconv(str)
369
+ rescue
370
+ str = str.gsub(%r{[^\r\n\t\x20-\x7e]}, '?')
371
+ end
372
+ else
373
+ ic = Iconv.new('UTF-8', 'UTF-8')
374
+ txtar = ""
375
+ begin
376
+ txtar += ic.iconv(str)
377
+ rescue Iconv::IllegalSequence
378
+ txtar += $!.success
379
+ str = '?' + $!.failed[1,$!.failed.length]
380
+ retry
381
+ rescue
382
+ txtar += $!.success
383
+ end
384
+ str = txtar
385
+ end
386
+ str
387
+ end
388
+
389
+ def self.to_utf8(str, encoding)
390
+ return str if str.nil?
391
+ str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding)
392
+ if str.empty?
393
+ str.force_encoding("UTF-8") if str.respond_to?(:force_encoding)
394
+ return str
395
+ end
396
+ enc = encoding.blank? ? "UTF-8" : encoding
397
+ if str.respond_to?(:force_encoding)
398
+ if enc.upcase != "UTF-8"
399
+ str.force_encoding(enc)
400
+ str = str.encode("UTF-8", :invalid => :replace,
401
+ :undef => :replace, :replace => '?')
402
+ else
403
+ str.force_encoding("UTF-8")
404
+ if ! str.valid_encoding?
405
+ str = str.encode("US-ASCII", :invalid => :replace,
406
+ :undef => :replace, :replace => '?').encode("UTF-8")
407
+ end
408
+ end
409
+ elsif RUBY_PLATFORM == 'java'
410
+ begin
411
+ ic = Iconv.new('UTF-8', enc)
412
+ str = ic.iconv(str)
413
+ rescue
414
+ str = str.gsub(%r{[^\r\n\t\x20-\x7e]}, '?')
415
+ end
416
+ else
417
+ ic = Iconv.new('UTF-8', enc)
418
+ txtar = ""
419
+ begin
420
+ txtar += ic.iconv(str)
421
+ rescue Iconv::IllegalSequence
422
+ txtar += $!.success
423
+ str = '?' + $!.failed[1,$!.failed.length]
424
+ retry
425
+ rescue
426
+ txtar += $!.success
427
+ end
428
+ str = txtar
429
+ end
430
+ str
431
+ end
432
+
433
+ def self.to_utf8_by_setting(str)
434
+ return str if str.nil?
435
+ str = self.to_utf8_by_setting_internal(str)
436
+ if str.respond_to?(:force_encoding)
437
+ str.force_encoding('UTF-8')
438
+ end
439
+ str
440
+ end
441
+
442
+ def self.to_utf8_by_setting_internal(str)
443
+ return str if str.nil?
444
+ if str.respond_to?(:force_encoding)
445
+ str.force_encoding('ASCII-8BIT')
446
+ end
447
+ return str if str.empty?
448
+ return str if /\A[\r\n\t\x20-\x7e]*\Z/n.match(str) # for us-ascii
449
+ if str.respond_to?(:force_encoding)
450
+ str.force_encoding('UTF-8')
451
+ end
452
+ str = self.replace_invalid_utf8(str)
453
+ if str.respond_to?(:force_encoding)
454
+ str.force_encoding('UTF-8')
455
+ end
456
+ str
457
+ end
458
+
459
+ def self.from_utf8(str, encoding)
460
+ str ||= ''
461
+ if str.respond_to?(:force_encoding)
462
+ str.force_encoding('UTF-8')
463
+ if encoding.upcase != 'UTF-8'
464
+ str = str.encode(encoding, :invalid => :replace,
465
+ :undef => :replace, :replace => '?')
466
+ else
467
+ str = self.replace_invalid_utf8(str)
468
+ end
469
+ elsif RUBY_PLATFORM == 'java'
470
+ begin
471
+ ic = Iconv.new(encoding, 'UTF-8')
472
+ str = ic.iconv(str)
473
+ rescue
474
+ str = str.gsub(%r{[^\r\n\t\x20-\x7e]}, '?')
475
+ end
476
+ else
477
+ ic = Iconv.new(encoding, 'UTF-8')
478
+ txtar = ""
479
+ begin
480
+ txtar += ic.iconv(str)
481
+ rescue Iconv::IllegalSequence
482
+ txtar += $!.success
483
+ str = '?' + $!.failed[1, $!.failed.length]
484
+ retry
485
+ rescue
486
+ txtar += $!.success
487
+ end
488
+ str = txtar
489
+ end
490
+ end
491
+ end
492
+ end