svn_record 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +72 -0
- data/Rakefile +7 -0
- data/app/assets/images/svn_record/file_icon/bullet_add.png +0 -0
- data/app/assets/images/svn_record/file_icon/bullet_black.png +0 -0
- data/app/assets/images/svn_record/file_icon/bullet_blue.png +0 -0
- data/app/assets/images/svn_record/file_icon/bullet_delete.png +0 -0
- data/app/assets/images/svn_record/file_icon/bullet_diamond.png +0 -0
- data/app/assets/images/svn_record/file_icon/bullet_end.png +0 -0
- data/app/assets/images/svn_record/file_icon/bullet_go.png +0 -0
- data/app/assets/images/svn_record/file_icon/bullet_orange.png +0 -0
- data/app/assets/images/svn_record/file_icon/bullet_purple.png +0 -0
- data/app/assets/images/svn_record/file_icon/bullet_toggle_minus.png +0 -0
- data/app/assets/images/svn_record/file_icon/bullet_toggle_plus.png +0 -0
- data/app/assets/images/svn_record/file_icon/dir.png +0 -0
- data/app/assets/images/svn_record/file_icon/file.png +0 -0
- data/app/assets/images/svn_record/file_icon/folder.png +0 -0
- data/app/assets/images/svn_record/file_icon/folder_open.png +0 -0
- data/app/assets/images/svn_record/file_icon/folder_open_add.png +0 -0
- data/app/assets/images/svn_record/file_icon/folder_open_orange.png +0 -0
- data/app/assets/javascripts/svn_record/application.js +16 -0
- data/app/assets/javascripts/svn_record/change.js.coffee +4 -0
- data/app/assets/stylesheets/svn_record/application.css +14 -0
- data/app/assets/stylesheets/svn_record/site.css +396 -0
- data/app/controllers/svn_record/application_controller.rb +3 -0
- data/app/controllers/svn_record/repository/application_controller.rb +3 -0
- data/app/controllers/svn_record/repository/changes_controller.rb +38 -0
- data/app/models/svn_record/repository/change.rb +39 -0
- data/app/models/svn_record/repository/file.rb +20 -0
- data/app/models/svn_record/repository/user.rb +14 -0
- data/app/views/layouts/svn_record/subversion.html.slim +22 -0
- data/app/views/svn_record/repository/changes/_changesets_list.slim +29 -0
- data/app/views/svn_record/repository/changes/diff.html.slim +30 -0
- data/app/views/svn_record/repository/changes/entry.html.slim +18 -0
- data/app/views/svn_record/repository/changes/index.html.slim +34 -0
- data/app/views/svn_record/repository/changes/list.html.slim +2 -0
- data/app/views/svn_record/repository/changes/revisions.html.slim +18 -0
- data/config/configuration.yml +5 -0
- data/config/routes.rb +17 -0
- data/lib/Svn/helper.rb +108 -0
- data/lib/Svn/mime_type.rb +492 -0
- data/lib/Svn/scm/adapters/subversion.rb +303 -0
- data/lib/generators/svn_record/install_generator.rb +16 -0
- data/lib/generators/svn_record/templates/create_repository_changes.rb +17 -0
- data/lib/generators/svn_record/templates/create_repository_files.rb +21 -0
- data/lib/generators/svn_record/templates/create_repository_user.rb +8 -0
- data/lib/svn_record/engine.rb +11 -0
- data/lib/svn_record/version.rb +3 -0
- data/lib/svn_record.rb +4 -0
- metadata +161 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
doctype html
|
2
|
+
html
|
3
|
+
head
|
4
|
+
title SVN版本管理
|
5
|
+
meta name="key_words" content="template languagea"
|
6
|
+
= stylesheet_link_tag "application", media: "all"
|
7
|
+
= javascript_include_tag 'application'
|
8
|
+
= csrf_meta_tags
|
9
|
+
body.controller-projects.action-show
|
10
|
+
#wrapper
|
11
|
+
#wrapper2
|
12
|
+
#wrapper3
|
13
|
+
#header
|
14
|
+
h1 SVN版本管理
|
15
|
+
#main-menu
|
16
|
+
ul
|
17
|
+
li = link_to '版本库', repository_changes_path, class: 'overview seelected'
|
18
|
+
= yield
|
19
|
+
#footer
|
20
|
+
#bgl
|
21
|
+
.bgr
|
22
|
+
Powered by <a href="" target="_blank"> 北京胖子很忙 © 2013-2026
|
@@ -0,0 +1,29 @@
|
|
1
|
+
h2 最近的修订版本#{link_to ' (查看更多)', list_repository_changes_path(path: @path), id: 'changes_more' if action_name == 'index' && changesets.size > 10 }
|
2
|
+
= form_tag(diff_repository_changes_path, method: :get) do
|
3
|
+
table.list.entries#browser
|
4
|
+
thead
|
5
|
+
tr id="root"
|
6
|
+
th 用户ID
|
7
|
+
th
|
8
|
+
th 修订
|
9
|
+
th 提交时间
|
10
|
+
th 提交人
|
11
|
+
th 注释
|
12
|
+
tbody
|
13
|
+
- line_num = 1
|
14
|
+
- changesets.each_with_index do |ele, index|
|
15
|
+
tr
|
16
|
+
td = ele.user_id
|
17
|
+
td class="radio_span"
|
18
|
+
-if index < changesets.size - 1
|
19
|
+
span class="float-left"
|
20
|
+
= radio_button_tag 'rev', ele.revision, (line_num==1), id: "cb-#{line_num}"
|
21
|
+
- if index >= 1
|
22
|
+
span class="float_right"
|
23
|
+
= radio_button_tag 'rev_to', ele.revision, (line_num==2), id: "cbto-#{line_num}"
|
24
|
+
td class="revision" = link_to ele.revision, revisions_repository_change_path(ele.revision)
|
25
|
+
td class="age" = ele.committed_at
|
26
|
+
td class="author" = ele.committer
|
27
|
+
td class="comments" = ele.comment
|
28
|
+
- line_num +=1
|
29
|
+
= submit_tag('查看差别') if changesets.length > 1
|
@@ -0,0 +1,30 @@
|
|
1
|
+
- diff = Svn::UnifiedDiff.new(@diff, type: 'inline', max_lines: 3000, style: "")
|
2
|
+
h3 修订: "#{params[:rev]}:#{params[:rev_to]}"
|
3
|
+
h2 = menu_node(params[:path])
|
4
|
+
- if diff.blank?
|
5
|
+
p style="text-indet: 2em"
|
6
|
+
| 空
|
7
|
+
- diff.each do |table_file|
|
8
|
+
.autoscroll
|
9
|
+
table.filecontent
|
10
|
+
thead
|
11
|
+
tr
|
12
|
+
th.filename colspan="4"
|
13
|
+
= table_file.file_name
|
14
|
+
tbody
|
15
|
+
- table_file.each_line do |spacing, line|
|
16
|
+
- if spacing
|
17
|
+
tr
|
18
|
+
th.line-num
|
19
|
+
td
|
20
|
+
th.line-num
|
21
|
+
td
|
22
|
+
tr
|
23
|
+
th.line-num
|
24
|
+
= line.nb_line_left
|
25
|
+
td class="line-code #{line.type_diff_left}"
|
26
|
+
pre = line.html_line_left.html_safe
|
27
|
+
th.line-num
|
28
|
+
= line.nb_line_left
|
29
|
+
td class="line-code #{line.type_diff_right}"
|
30
|
+
pre = line.html_line_right.html_safe
|
@@ -0,0 +1,18 @@
|
|
1
|
+
div.nosidebar#main
|
2
|
+
div#content
|
3
|
+
div.contextual
|
4
|
+
h2 = menu_node(params[:path])
|
5
|
+
p
|
6
|
+
= link_to '显示/隐藏代码', "", class: 'toggle_code'
|
7
|
+
div.autoscroll
|
8
|
+
table.filecontent.syntaxhl
|
9
|
+
tbody
|
10
|
+
- line_num = 1
|
11
|
+
- syntax_highlight_lines(params[:path], Svn::CodesetUtil.to_utf8_by_setting(@content)).each do |line|
|
12
|
+
tr
|
13
|
+
th.line-num id="L#{line_num}"
|
14
|
+
a href="#L#{line_num}" = line_num
|
15
|
+
td.line-code
|
16
|
+
pre = line.html_safe
|
17
|
+
- line_num += 1
|
18
|
+
= render(partial: "/svn_record/repository/changes/changesets_list", locals: {changesets: @changesets, path:@path })
|
@@ -0,0 +1,34 @@
|
|
1
|
+
div#main.nosidebar
|
2
|
+
div#content
|
3
|
+
h2 = menu_node(@path)
|
4
|
+
table.list.entries#browser
|
5
|
+
thead
|
6
|
+
tr#root
|
7
|
+
th 名称
|
8
|
+
th 大小
|
9
|
+
th 修订
|
10
|
+
th 提交时间
|
11
|
+
th 作者
|
12
|
+
th 注释
|
13
|
+
tbody
|
14
|
+
- @entries.each do |element|
|
15
|
+
tr.entry.dir
|
16
|
+
td.filename style="padding-left: 0px;width:400px"
|
17
|
+
span.expander
|
18
|
+
|
|
19
|
+
= image_tag("svn_record/file_icon/#{element.kind}.png")
|
20
|
+
- if element.kind.present? && 'dir' == element.kind.to_s.strip
|
21
|
+
= link_to element.name, repository_changes_path(path: element.path)
|
22
|
+
- else
|
23
|
+
= link_to element.name, entry_repository_changes_path(path: element.path, rev: element.lastrev.name)
|
24
|
+
td.size style="width: 100px"
|
25
|
+
= element.size ? number_to_human_size(element.size) : ""
|
26
|
+
td.revision
|
27
|
+
= link_to element.lastrev.name, revisions_repository_change_path(element.lastrev.name), title: element.name
|
28
|
+
td.age style="width: 100px"
|
29
|
+
= distance_of_date_in_words(element.lastrev.time, Time.now)
|
30
|
+
td.author
|
31
|
+
= element.lastrev.author
|
32
|
+
td.comments
|
33
|
+
= element.lastrev.message
|
34
|
+
= render partial: '/svn_record/repository/changes/changesets_list', locals: { changesets: @changesets, path: @path }
|
@@ -0,0 +1,18 @@
|
|
1
|
+
div.nosidebar#main
|
2
|
+
div#content
|
3
|
+
h2 = "修订#{@changeset.revision}"
|
4
|
+
p
|
5
|
+
span.author
|
6
|
+
= "由#{@changeset.committer} 在 #{distance_of_date_in_words(@changeset.committed_at, Time.now)} 之前添加"
|
7
|
+
p = "#{@changeset.comment}"
|
8
|
+
div#related-issues
|
9
|
+
h3 相关的文件
|
10
|
+
ul#changes-legend
|
11
|
+
li.change.change-A 已添加
|
12
|
+
li.change.change-M 已修改
|
13
|
+
li.change.change-C 已复制
|
14
|
+
li.change.change-R 已重命名
|
15
|
+
li.change.change-D 已删除
|
16
|
+
div.changeset-changes
|
17
|
+
= render_changeset_changes
|
18
|
+
div style="clear:both;"
|
data/config/routes.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
SvnRecord::Engine.routes.draw do
|
2
|
+
namespace :repository do
|
3
|
+
resources :changes, only: [:index] do
|
4
|
+
collection do
|
5
|
+
get :diff
|
6
|
+
get :list
|
7
|
+
get :entry
|
8
|
+
end
|
9
|
+
member do
|
10
|
+
get :revisions
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
Rails.application.routes.draw do
|
16
|
+
mount SvnRecord::Engine => ""
|
17
|
+
end
|
data/lib/Svn/helper.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
module ActionView
|
2
|
+
module Helpers
|
3
|
+
module DateHelper
|
4
|
+
def distance_of_date_in_words(from_date, to_date = 0, options = {})
|
5
|
+
from_date = from_date.to_date if from_date.respond_to?(:to_date)
|
6
|
+
to_date = to_date.to_date if to_date.respond_to?(:to_date)
|
7
|
+
distance_in_days = (to_date - from_date).abs
|
8
|
+
|
9
|
+
I18n.with_options :locale => options[:locale], :scope => :'datetime.distance_in_words' do |locale|
|
10
|
+
case distance_in_days
|
11
|
+
when 0..60 then locale.t :x_days, :count => distance_in_days.round
|
12
|
+
when 61..720 then locale.t :about_x_months, :count => (distance_in_days / 30).round
|
13
|
+
else locale.t :over_x_years, :count => (distance_in_days / 365).floor
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_path_param(path)
|
19
|
+
str = path.to_s.split(%r{[/\\]}).select{|p| p.present?} #.join("/")
|
20
|
+
str.shift if str.length > 1
|
21
|
+
str = str.compact.join("/")
|
22
|
+
str.blank? ? nil : str
|
23
|
+
end
|
24
|
+
|
25
|
+
def render_changeset_changes
|
26
|
+
changes = @changeset.files.limit(1000).reorder('path').all.collect do |change|
|
27
|
+
case change.action
|
28
|
+
when 'A'
|
29
|
+
# Detects moved/copied files
|
30
|
+
if !change.from_path.blank?
|
31
|
+
change.action =
|
32
|
+
@changeset.files.detect {|c| c.action == 'D' && c.path == change.from_path} ? 'R' : 'C'
|
33
|
+
end
|
34
|
+
change
|
35
|
+
when 'D'
|
36
|
+
@changeset.files.detect {|c| c.from_path == change.path} ? nil : change
|
37
|
+
else
|
38
|
+
change
|
39
|
+
end
|
40
|
+
end.compact
|
41
|
+
|
42
|
+
tree = {}
|
43
|
+
changes.each do |change|
|
44
|
+
p = tree
|
45
|
+
dirs = change.path.to_s.split('/').select {|d| !d.blank?}
|
46
|
+
path = ''
|
47
|
+
dirs.each do |dir|
|
48
|
+
path += '/' + dir
|
49
|
+
p[:s] ||= {}
|
50
|
+
p = p[:s]
|
51
|
+
p[path] ||= {}
|
52
|
+
p = p[path]
|
53
|
+
end
|
54
|
+
p[:c] = change
|
55
|
+
end
|
56
|
+
render_changes_tree(tree[:s])
|
57
|
+
end
|
58
|
+
|
59
|
+
def render_changes_tree(tree)
|
60
|
+
return '' if tree.nil?
|
61
|
+
output = ''
|
62
|
+
output << '<ul>'
|
63
|
+
tree.keys.sort.each do |file|
|
64
|
+
style = 'change'
|
65
|
+
text = File.basename(h(file))
|
66
|
+
if s = tree[file][:s]
|
67
|
+
style << ' folder'
|
68
|
+
path_param = to_path_param(file)
|
69
|
+
text = link_to(h(text), repository_changes_path(path: path_param))
|
70
|
+
output << "<li class='#{style}'>#{text}"
|
71
|
+
output << render_changes_tree(s)
|
72
|
+
output << "</li>"
|
73
|
+
elsif c = tree[file][:c]
|
74
|
+
style << " change-#{c.action}"
|
75
|
+
path_param = to_path_param(c.path)
|
76
|
+
text = link_to(h(text), entry_repository_changes_path(path: path_param)) unless c.action == 'D'
|
77
|
+
text << " - #{h(c.revision)}" unless c.revision.blank?
|
78
|
+
text << ' '.html_safe + content_tag('span', h(c.from_path), :class => 'copied-from') unless c.from_path.blank?
|
79
|
+
output << "<li class='#{style}'>#{text}</li>"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
output << '</ul>'
|
83
|
+
output.html_safe
|
84
|
+
end
|
85
|
+
|
86
|
+
def syntax_highlight_lines(name, content)
|
87
|
+
lines = []
|
88
|
+
syntax_highlight(name, content).each_line { |line| lines << line }
|
89
|
+
lines
|
90
|
+
end
|
91
|
+
|
92
|
+
def syntax_highlight(name, content)
|
93
|
+
Svn::SyntaxHighlighting.highlight_by_filename(content, name)
|
94
|
+
end
|
95
|
+
|
96
|
+
def menu_node(path,array = [])
|
97
|
+
link_root = link_to @root_name, repository_changes_path
|
98
|
+
return raw(link_root) unless path.present?
|
99
|
+
paths = path.split('/').map do |p|
|
100
|
+
array << p
|
101
|
+
p == path.split('/').last ? p : link_to(p, repository_changes_path(path: array.join('/')))
|
102
|
+
end
|
103
|
+
paths.unshift(link_root)
|
104
|
+
raw paths.join("/")
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|