##// END OF EJS Templates
misc scm browser improvements...
Jean-Philippe Lang -
r100:efe31d49f041
parent child
Show More
@@ -6,30 +6,31 class RepositoriesController < ApplicationController
6 end
6 end
7
7
8 def browse
8 def browse
9 @rev = params[:rev].to_i if params[:rev] and params[:rev].to_i > 0
9 @entries = @repository.scm.entries(@path, @rev)
10 redirect_to :action => 'show', :id => @project and return unless @entries
11 end
12
13 def entry_revisions
10 @entry = @repository.scm.entry(@path, @rev)
14 @entry = @repository.scm.entry(@path, @rev)
11 redirect_to :action => 'show', :id => @project and return unless @entry
15 @revisions = @repository.scm.revisions(@path, @rev)
12 if @entry.is_dir?
16 redirect_to :action => 'show', :id => @project and return unless @entry && @revisions
13 # if entry is a dir, shows directory listing
17 end
14 @entries = @repository.scm.entries(@path, @rev)
18
15 redirect_to :action => 'show', :id => @project and return unless @entries
19 def entry
16 else
20 if 'raw' == params[:format]
17 # else, shows file's revisions
21 content = @repository.scm.cat(@path, @rev)
18 @revisions = @repository.scm.revisions(@path, @rev)
22 redirect_to :action => 'show', :id => @project and return unless content
19 redirect_to :action => 'show', :id => @project and return unless @revisions
23 send_data content, :filename => @path.split('/').last
20 render :action => 'entry_revisions'
21 end
24 end
22 end
25 end
23
26
24 def revision
27 def revision
25 @rev = params[:rev].to_i if params[:rev] and params[:rev].to_i > 0
26 @revisions = @repository.scm.revisions '', @rev, @rev, :with_paths => true
28 @revisions = @repository.scm.revisions '', @rev, @rev, :with_paths => true
27 redirect_to :action => 'show', :id => @project and return unless @revisions
29 redirect_to :action => 'show', :id => @project and return unless @revisions
28 @revision = @revisions.first
30 @revision = @revisions.first
29 end
31 end
30
32
31 def diff
33 def diff
32 @rev = params[:rev].to_i if params[:rev] and params[:rev].to_i > 0
33 @rev_to = params[:rev_to] || (@rev-1)
34 @rev_to = params[:rev_to] || (@rev-1)
34 @diff = @repository.scm.diff(params[:path], @rev, @rev_to)
35 @diff = @repository.scm.diff(params[:path], @rev, @rev_to)
35 redirect_to :action => 'show', :id => @project and return unless @diff
36 redirect_to :action => 'show', :id => @project and return unless @diff
@@ -40,5 +41,7 private
40 @project = Project.find(params[:id])
41 @project = Project.find(params[:id])
41 @repository = @project.repository
42 @repository = @project.repository
42 @path = params[:path].squeeze('/').gsub(/^\//, '') if params[:path]
43 @path = params[:path].squeeze('/').gsub(/^\//, '') if params[:path]
44 @path ||= ''
45 @rev = params[:rev].to_i if params[:rev] and params[:rev].to_i > 0
43 end
46 end
44 end
47 end
@@ -9,7 +9,7 module SvnRepos
9 @url = nil
9 @url = nil
10 @login = nil
10 @login = nil
11 @password = nil
11 @password = nil
12
12
13 def initialize(url, login=nil, password=nil)
13 def initialize(url, login=nil, password=nil)
14 @url = url
14 @url = url
15 @login = login if login && !login.empty?
15 @login = login if login && !login.empty?
@@ -19,31 +19,8 module SvnRepos
19 # Returns the entry identified by path and revision identifier
19 # Returns the entry identified by path and revision identifier
20 # or nil if entry doesn't exist in the repository
20 # or nil if entry doesn't exist in the repository
21 def entry(path=nil, identifier=nil)
21 def entry(path=nil, identifier=nil)
22 path ||= ''
22 e = entries(path, identifier)
23 identifier = 'HEAD' unless identifier and identifier > 0
23 e ? e.first : nil
24 entry = nil
25 cmd = "svn info --xml -r #{identifier} #{target(path)}"
26 IO.popen(cmd) do |io|
27 begin
28 doc = REXML::Document.new(io)
29 doc.elements.each("info/entry") do |info|
30 entry = Entry.new({:name => info.attributes['path'],
31 :path => path,
32 :kind => info.attributes['kind'],
33 :lastrev => Revision.new({
34 :identifier => info.elements['commit'].attributes['revision'],
35 :author => info.elements['commit'].elements['author'].text,
36 :time => Time.parse(info.elements['commit'].elements['date'].text)
37 })
38 })
39 end
40 rescue
41 end
42 end
43 return nil if $? && $?.exitstatus != 0
44 entry
45 rescue Errno::ENOENT
46 raise RepositoryCmdFailed
47 end
24 end
48
25
49 # Returns an Entries collection
26 # Returns an Entries collection
@@ -52,8 +29,8 module SvnRepos
52 path ||= ''
29 path ||= ''
53 identifier = 'HEAD' unless identifier and identifier > 0
30 identifier = 'HEAD' unless identifier and identifier > 0
54 entries = Entries.new
31 entries = Entries.new
55 cmd = "svn list --xml -r #{identifier} #{target(path)}"
32 cmd = "svn list --xml #{target(path)}@#{identifier}"
56 IO.popen(cmd) do |io|
33 shellout(cmd) do |io|
57 begin
34 begin
58 doc = REXML::Document.new(io)
35 doc = REXML::Document.new(io)
59 doc.elements.each("lists/list/entry") do |entry|
36 doc.elements.each("lists/list/entry") do |entry|
@@ -85,7 +62,7 module SvnRepos
85 cmd = "svn log --xml -r #{identifier_from}:#{identifier_to} "
62 cmd = "svn log --xml -r #{identifier_from}:#{identifier_to} "
86 cmd << "--verbose " if options[:with_paths]
63 cmd << "--verbose " if options[:with_paths]
87 cmd << target(path)
64 cmd << target(path)
88 IO.popen(cmd) do |io|
65 shellout(cmd) do |io|
89 begin
66 begin
90 doc = REXML::Document.new(io)
67 doc = REXML::Document.new(io)
91 doc.elements.each("log/logentry") do |logentry|
68 doc.elements.each("log/logentry") do |logentry|
@@ -95,6 +72,8 module SvnRepos
95 :path => path.text
72 :path => path.text
96 }
73 }
97 end
74 end
75 paths.sort! { |x,y| x[:path] <=> y[:path] }
76
98 revisions << Revision.new({:identifier => logentry.attributes['revision'],
77 revisions << Revision.new({:identifier => logentry.attributes['revision'],
99 :author => logentry.elements['author'].text,
78 :author => logentry.elements['author'].text,
100 :time => Time.parse(logentry.elements['date'].text),
79 :time => Time.parse(logentry.elements['date'].text),
@@ -121,9 +100,9 module SvnRepos
121 cmd = "svn diff -r "
100 cmd = "svn diff -r "
122 cmd << "#{identifier_to}:"
101 cmd << "#{identifier_to}:"
123 cmd << "#{identifier_from}"
102 cmd << "#{identifier_from}"
124 cmd << target(path)
103 cmd << "#{target(path)}@#{identifier_from}"
125 diff = []
104 diff = []
126 IO.popen(cmd) do |io|
105 shellout(cmd) do |io|
127 io.each_line do |line|
106 io.each_line do |line|
128 diff << line
107 diff << line
129 end
108 end
@@ -133,11 +112,35 module SvnRepos
133 rescue Errno::ENOENT => e
112 rescue Errno::ENOENT => e
134 raise CommandFailed
113 raise CommandFailed
135 end
114 end
115
116 def cat(path, identifier=nil)
117 identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
118 cmd = "svn cat #{target(path)}@#{identifier}"
119 cat = nil
120 shellout(cmd) do |io|
121 cat = io.read
122 end
123 return nil if $? && $?.exitstatus != 0
124 cat
125 rescue Errno::ENOENT => e
126 raise CommandFailed
127 end
136
128
137 private
129 private
138 def target(path)
130 def target(path)
139 " \"" << "#{@url}/#{path}".gsub(/["'<>]/, '') << "\""
131 " \"" << "#{@url}/#{path}".gsub(/["'<>]/, '') << "\""
140 end
132 end
133
134 def logger
135 RAILS_DEFAULT_LOGGER
136 end
137
138 def shellout(cmd, &block)
139 logger.debug "Shelling out: #{cmd}" if logger && logger.debug?
140 IO.popen(cmd) do |io|
141 block.call(io) if block_given?
142 end
143 end
141 end
144 end
142
145
143 class Entries < Array
146 class Entries < Array
@@ -1,9 +1,18
1 <%= link_to 'root', :action => 'browse', :id => @project, :path => '', :rev => @rev %>
1 <%= link_to 'root', :action => 'browse', :id => @project, :path => '', :rev => @rev %>
2 <% link_path = ''
2 <%
3 path.split('/').each do |dir|
3 dirs = path.split('/')
4 if 'file' == kind
5 filename = dirs.pop
6 end
7 link_path = ''
8 dirs.each do |dir|
4 link_path << '/' unless link_path.empty?
9 link_path << '/' unless link_path.empty?
5 link_path << "#{dir}"
10 link_path << "#{dir}"
6 %>
11 %>
7 / <%= link_to h(dir), :action => 'browse', :id => @project, :path => link_path, :rev => @rev %>
12 / <%= link_to h(dir), :action => 'browse', :id => @project, :path => link_path, :rev => @rev %>
8 <% end %>
13 <% end %>
14 <% if filename %>
15 / <%= link_to h(filename), :action => 'entry_revisions', :id => @project, :path => "#{link_path}/#{filename}", :rev => @rev %>
16 <% end %>
17
9 <%= "@ #{revision}" if revision %> No newline at end of file
18 <%= "@ #{revision}" if revision %>
@@ -6,7 +6,7
6 <%= submit_tag 'OK' %>
6 <%= submit_tag 'OK' %>
7 </div>
7 </div>
8
8
9 <h2><%= render :partial => 'navigation', :locals => { :path => @entry.path, :revision => @rev } %></h2>
9 <h2><%= render :partial => 'navigation', :locals => { :path => @path, :kind => 'dir', :revision => @rev } %></h2>
10
10
11 <table class="list">
11 <table class="list">
12 <thead><tr>
12 <thead><tr>
@@ -20,7 +20,7
20 <% total_size = 0
20 <% total_size = 0
21 @entries.each do |entry| %>
21 @entries.each do |entry| %>
22 <tr class="<%= cycle 'odd', 'even' %>">
22 <tr class="<%= cycle 'odd', 'even' %>">
23 <td><%= link_to h(entry.name), { :action => 'browse', :id => @project, :path => entry.path, :rev => @rev }, :class => "icon " + (entry.is_dir? ? 'folder' : 'file') %></td>
23 <td><%= link_to h(entry.name), { :action => (entry.is_dir? ? 'browse' : 'entry_revisions'), :id => @project, :path => entry.path, :rev => @rev }, :class => "icon " + (entry.is_dir? ? 'folder' : 'file') %></td>
24 <td align="right"><%= human_size(entry.size) unless entry.is_dir? %></td>
24 <td align="right"><%= human_size(entry.size) unless entry.is_dir? %></td>
25 <td align="right"><%= link_to entry.lastrev.identifier, :action => 'revision', :id => @project, :rev => entry.lastrev.identifier %></td>
25 <td align="right"><%= link_to entry.lastrev.identifier, :action => 'revision', :id => @project, :rev => entry.lastrev.identifier %></td>
26 <td align="center"><em><%=h entry.lastrev.author %></em></td>
26 <td align="center"><em><%=h entry.lastrev.author %></em></td>
@@ -1,4 +1,4
1 <h2><%= render :partial => 'navigation', :locals => { :path => @path, :revision => @rev } %></h2>
1 <h2><%= render :partial => 'navigation', :locals => { :path => @path, :kind => 'file', :revision => @rev } %></h2>
2
2
3 <%= stylesheet_link_tag "scm" %>
3 <%= stylesheet_link_tag "scm" %>
4
4
@@ -6,10 +6,10
6 <%= submit_tag 'OK' %>
6 <%= submit_tag 'OK' %>
7 </div>
7 </div>
8
8
9 <h2><%= render :partial => 'navigation', :locals => { :path => @entry.path, :revision => @rev } %></h2>
9 <h2><%= render :partial => 'navigation', :locals => { :path => @path, :kind => @entry.kind, :revision => @rev } %></h2>
10
10
11 <h3><%=h @entry.name %></h3>
11 <h3><%=h @entry.name %></h3>
12 <p><%= link_to 'Download', {}, :class => "icon file" %></p>
12 <p><%= link_to 'Download', {:action => 'entry', :id => @project, :path => @path, :rev => @rev, :format => 'raw' }, :class => "icon file" %> (<%= human_size @entry.size %>)</p>
13
13
14 <h3>Revisions</h3>
14 <h3>Revisions</h3>
15
15
@@ -28,7 +28,7
28 <td align="center"><em><%=h revision.author %></em></td>
28 <td align="center"><em><%=h revision.author %></em></td>
29 <td align="center"><%= format_time(revision.time) %></td>
29 <td align="center"><%= format_time(revision.time) %></td>
30 <td width="70%"><%= simple_format(h(revision.message)) %></td>
30 <td width="70%"><%= simple_format(h(revision.message)) %></td>
31 <td><%= link_to 'View diff', :action => 'diff', :id => @project, :path => @entry.path, :rev => revision.identifier %></td>
31 <td align="center"><%= link_to 'Diff', :action => 'diff', :id => @project, :path => @path, :rev => revision.identifier unless revision == @revisions.last %></td>
32 </tr>
32 </tr>
33 <% end %>
33 <% end %>
34 </tbody>
34 </tbody>
@@ -8,9 +8,15
8
8
9 <h2><%= l(:label_revision) %> <%= @revision.identifier %></h2>
9 <h2><%= l(:label_revision) %> <%= @revision.identifier %></h2>
10
10
11 <p><%= l(:field_author) %>: <em><%= @revision.author %></em></p>
11 <p><em><%= @revision.author %>, <%= format_time(@revision.time) %></em></p>
12 <%= simple_format @revision.message %>
12 <%= simple_format @revision.message %>
13
13
14 <div style="float:right;">
15 <div class="square action_A"></div> <div style="float:left;"><%= l(:label_added) %>&nbsp;</div>
16 <div class="square action_M"></div> <div style="float:left;"><%= l(:label_modified) %>&nbsp;</div>
17 <div class="square action_D"></div> <div style="float:left;"><%= l(:label_deleted) %>&nbsp;</div>
18 </div>
19
14 <h3><%= l(:label_attachment_plural) %></h3>
20 <h3><%= l(:label_attachment_plural) %></h3>
15 <table class="list">
21 <table class="list">
16 <tbody>
22 <tbody>
@@ -289,6 +289,9 label_browse: Parcourir
289 label_modification: %d modification
289 label_modification: %d modification
290 label_modification_plural: %d modifications
290 label_modification_plural: %d modifications
291 label_revision: Révision
291 label_revision: Révision
292 label_added: ajouté
293 label_modified: modifié
294 label_deleted: supprimé
292
295
293 button_login: Connexion
296 button_login: Connexion
294 button_submit: Soumettre
297 button_submit: Soumettre
@@ -29,6 +29,7 table.list tbody th {
29 font-weight: normal;
29 font-weight: normal;
30 text-align: center;
30 text-align: center;
31 background: #eed;
31 background: #eed;
32 border: 1px solid #d7d7d7;
32 }
33 }
33
34
34 .icon {
35 .icon {
@@ -42,7 +43,7 table.list tbody th {
42
43
43
44
44
45
45 table.diff tr.spacing {
46 tr.spacing {
46 border: 1px solid #d7d7d7;
47 border: 1px solid #d7d7d7;
47 }
48 }
48
49
General Comments 0
You need to be logged in to leave comments. Login now