##// END OF EJS Templates
Display svn properties in the browser, svn >= 1.5.0 only (#1581)....
Jean-Philippe Lang -
r1613:12fbd06c02d4
parent child
Show More
@@ -0,0 +1,33
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 require 'mkmf'
19
20 require File.dirname(__FILE__) + '/../test_helper'
21
22 class SubversionAdapterTest < Test::Unit::TestCase
23
24 if find_executable0('svn')
25 def test_client_version
26 v = Redmine::Scm::Adapters::SubversionAdapter.client_version
27 assert v.is_a?(Array)
28 end
29 else
30 puts "Subversion binary NOT FOUND. Skipping unit tests !!!"
31 def test_fake; assert true end
32 end
33 end
@@ -66,6 +66,7 class RepositoriesController < ApplicationController
66 66 @entries ? render(:partial => 'dir_list_content') : render(:nothing => true)
67 67 else
68 68 show_error_not_found and return unless @entries
69 @properties = @repository.properties(@path, @rev)
69 70 render :action => 'browse'
70 71 end
71 72 end
@@ -74,6 +75,7 class RepositoriesController < ApplicationController
74 75 @entry = @repository.entry(@path, @rev)
75 76 show_error_not_found and return unless @entry
76 77 @changesets = @repository.changesets_for_path(@path)
78 @properties = @repository.properties(@path, @rev)
77 79 end
78 80
79 81 def revisions
@@ -106,7 +108,7 class RepositoriesController < ApplicationController
106 108 else
107 109 # Prevent empty lines when displaying a file with Windows style eol
108 110 @content.gsub!("\r\n", "\n")
109 end
111 end
110 112 end
111 113
112 114 def annotate
@@ -22,6 +22,16 module RepositoriesHelper
22 22 txt.to_s[0,8]
23 23 end
24 24
25 def render_properties(properties)
26 unless properties.nil? || properties.empty?
27 content = ''
28 properties.keys.sort.each do |property|
29 content << content_tag('li', "<b>#{h property}</b>: <span>#{h properties[property]}</span>")
30 end
31 content_tag('ul', content, :class => 'properties')
32 end
33 end
34
25 35 def to_path_param(path)
26 36 path.to_s.split(%r{[/\\]}).select {|p| !p.blank?}
27 37 end
@@ -59,6 +59,10 class Repository < ActiveRecord::Base
59 59 scm.entries(path, identifier)
60 60 end
61 61
62 def properties(path, identifier=nil)
63 scm.properties(path, identifier)
64 end
65
62 66 def cat(path, identifier=nil)
63 67 scm.cat(path, identifier)
64 68 end
@@ -7,6 +7,7
7 7 <h2><%= render :partial => 'navigation', :locals => { :path => @path, :kind => 'dir', :revision => @rev } %></h2>
8 8
9 9 <%= render :partial => 'dir_list' %>
10 <%= render_properties(@properties) %>
10 11
11 12 <% content_for :header_tags do %>
12 13 <%= stylesheet_link_tag "scm" %>
@@ -1,7 +1,5
1 1 <h2><%= render :partial => 'navigation', :locals => { :path => @path, :kind => (@entry ? @entry.kind : nil), :revision => @rev } %></h2>
2 2
3 <h3><%=h @entry.name %></h3>
4
5 3 <p>
6 4 <% if @repository.supports_cat? %>
7 5 <%= link_to l(:button_view), {:action => 'entry', :id => @project, :path => to_path_param(@path), :rev => @rev } %> |
@@ -13,6 +11,8
13 11 <%= "(#{number_to_human_size(@entry.size)})" if @entry.size %>
14 12 </p>
15 13
14 <%= render_properties(@properties) %>
15
16 16 <%= render(:partial => 'revisions',
17 17 :locals => {:project => @project, :path => @path, :revisions => @changesets, :entry => @entry }) unless @changesets.empty? %>
18 18
@@ -24,6 +24,20 module Redmine
24 24 end
25 25
26 26 class AbstractAdapter #:nodoc:
27 class << self
28 # Returns the version of the scm client
29 # Eg: [1, 5, 0]
30 def client_version
31 'Unknown version'
32 end
33
34 # Returns the version string of the scm client
35 # Eg: '1.5.0'
36 def client_version_string
37 client_version.is_a?(Array) ? client_version.join('.') : client_version.to_s
38 end
39 end
40
27 41 def initialize(url, root_url=nil, login=nil, password=nil)
28 42 @url = url
29 43 @login = login if login && !login.empty?
@@ -77,6 +91,10 module Redmine
77 91 def entries(path=nil, identifier=nil)
78 92 return nil
79 93 end
94
95 def properties(path, identifier=nil)
96 return nil
97 end
80 98
81 99 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
82 100 return nil
@@ -131,10 +149,18 module Redmine
131 149 end
132 150
133 151 def logger
134 RAILS_DEFAULT_LOGGER
152 self.class.logger
135 153 end
136 154
137 155 def shellout(cmd, &block)
156 self.class.shellout(cmd, &block)
157 end
158
159 def self.logger
160 RAILS_DEFAULT_LOGGER
161 end
162
163 def self.shellout(cmd, &block)
138 164 logger.debug "Shelling out: #{cmd}" if logger && logger.debug?
139 165 begin
140 166 IO.popen(cmd, "r+") do |io|
@@ -26,6 +26,25 module Redmine
26 26 # SVN executable name
27 27 SVN_BIN = "svn"
28 28
29 class << self
30 def client_version
31 @@client_version ||= (svn_binary_version || 'Unknown version')
32 end
33
34 def svn_binary_version
35 cmd = "#{SVN_BIN} --version"
36 version = nil
37 shellout(cmd) do |io|
38 # Read svn version in first returned line
39 if m = io.gets.match(%r{((\d+\.)+\d+)})
40 version = m[0].scan(%r{\d+}).collect(&:to_i)
41 end
42 end
43 return nil if $? && $?.exitstatus != 0
44 version
45 end
46 end
47
29 48 # Get info about the svn repository
30 49 def info
31 50 cmd = "#{SVN_BIN} info --xml #{target('')}"
@@ -87,7 +106,29 module Redmine
87 106 logger.debug("Found #{entries.size} entries in the repository for #{target(path)}") if logger && logger.debug?
88 107 entries.sort_by_name
89 108 end
90
109
110 def properties(path, identifier=nil)
111 # proplist xml output supported in svn 1.5.0 and higher
112 return nil if (self.class.client_version <=> [1, 5, 0]) < 0
113
114 identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
115 cmd = "#{SVN_BIN} proplist --verbose --xml #{target(path)}@#{identifier}"
116 cmd << credentials_string
117 properties = {}
118 shellout(cmd) do |io|
119 output = io.read
120 begin
121 doc = REXML::Document.new(output)
122 doc.elements.each("properties/target/property") do |property|
123 properties[ property.attributes['name'] ] = property.text
124 end
125 rescue
126 end
127 end
128 return nil if $? && $?.exitstatus != 0
129 properties
130 end
131
91 132 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
92 133 path ||= ''
93 134 identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : "HEAD"
@@ -217,6 +217,10 table#time-report tbody tr.last-level { font-style: normal; color: #555; }
217 217 table#time-report tbody tr.total { font-style: normal; font-weight: bold; color: #555; background-color:#EEEEEE; }
218 218 table#time-report .hours-dec { font-size: 0.9em; }
219 219
220 ul.properties {padding:0; font-size: 0.9em; color: #777;}
221 ul.properties li {list-style-type:none;}
222 ul.properties li span {font-style:italic;}
223
220 224 .total-hours { font-size: 110%; font-weight: bold; }
221 225 .total-hours span.hours-int { font-size: 120%; }
222 226
@@ -71,6 +71,19 class RepositoriesSubversionControllerTest < Test::Unit::TestCase
71 71 assert_not_nil assigns(:entries)
72 72 assert_equal ['folder', '.project', 'helloworld.c', 'helloworld.rb', 'textfile.txt'], assigns(:entries).collect(&:name)
73 73 end
74
75 def test_changes
76 get :changes, :id => 1, :path => ['subversion_test', 'folder', 'helloworld.rb' ]
77 assert_response :success
78 assert_template 'changes'
79 # svn properties
80 assert_not_nil assigns(:properties)
81 assert_equal 'native', assigns(:properties)['svn:eol-style']
82 assert_tag :ul,
83 :child => { :tag => 'li',
84 :child => { :tag => 'b', :content => 'svn:eol-style' },
85 :child => { :tag => 'span', :content => 'native' } }
86 end
74 87
75 88 def test_entry
76 89 get :entry, :id => 1, :path => ['subversion_test', 'helloworld.c']
General Comments 0
You need to be logged in to leave comments. Login now