Changesets can be listed by changeset number.
The Git repository is here.
Changeset 85
Extensive additions to support SVN-like collections revisions presented
in a similar manner to changesets under Collaboa. Integration with
"Ticket [#]xyz" text in check-in logs - generates links to Collboa tickets
if the text is spotted. Note that revision collation is a little slow and
not perfect; it works on directories, since revisions relate to paths and
unlike changesets are not repository-unique. See lib/revision_parser.rb
for more. Requires a CVShistory installation to function - future versions
might be smart enough to extract the information directly.
- Comitted by: adh
- Date: Sunday October 15 13:47:21 2006 (over 18 years ago)
Affected files:
- rool/rails/rcvsweb/trunk/app/views/rcvshistory/
- rool/rails/rcvsweb/trunk/app/views/revisions/
- rool/rails/rcvsweb/trunk/lib/
- rool/rails/rcvsweb/trunk/public/stylesheets/
- rool/rails/rcvsweb/trunk/test/
- rool/rails/rcvsweb/trunk/test/functional/
- rool/rails/rcvsweb/trunk/app/controllers/rcvshistory_controller.rb
- rool/rails/rcvsweb/trunk/app/controllers/revisions_controller.rb
- rool/rails/rcvsweb/trunk/app/helpers/rcvshistory_helper.rb
- rool/rails/rcvsweb/trunk/app/helpers/revisions_helper.rb
- rool/rails/rcvsweb/trunk/app/views/rcvshistory/run.rhtml
- rool/rails/rcvsweb/trunk/app/views/revisions/list.rhtml
- rool/rails/rcvsweb/trunk/app/views/revisions/show.rhtml
- rool/rails/rcvsweb/trunk/lib/revision_parser.rb
- rool/rails/rcvsweb/trunk/public/stylesheets/rcvsweb.css
- rool/rails/rcvsweb/trunk/test/functional/rcvshistory_controller_test.rb
- rool/rails/rcvsweb/trunk/test/functional/revisions_controller_test.rb
- rool/rails/rcvsweb/trunk/app/controllers/application.rb (diff)
- rool/rails/rcvsweb/trunk/app/controllers/rcvsweb_controller.rb (diff)
- rool/rails/rcvsweb/trunk/app/helpers/application_helper.rb (diff)
- rool/rails/rcvsweb/trunk/app/views/layouts/default.rhtml (diff)
- rool/rails/rcvsweb/trunk/app/views/rcvsweb/run.rhtml (diff)
- rool/rails/rcvsweb/trunk/config/environment.rb (diff)
- rool/rails/rcvsweb/trunk/config/routes.rb (diff)
rool/rails/rcvsweb/trunk/app/controllers/application.rb:
prev. | current | |
# RCVSweb - a Ruby On Rails wrapper around the Perl-based FreeBSD | ||
2 | ||
2 | # version of the CVSweb and Python-based CVShistory. | |
# | ||
4 | ||
4 | # See "http://www.freebsd.org/projects/cvsweb.html" and | |
5 | # "http://www.jamwt.com/CVSHistory/" | |
# | ||
# This wrapper was created for the sole purpose of embedding CVSweb | ||
# output into a Rails-provided layout. This layout is shared between | ||
... | ... | |
# that it is not necessary to create a derived copy of the layout | ||
# expressed in a form that CVSweb understands - instead, the layout | ||
# can be used directly. | ||
13 | # | |
14 | # Later extensions to the application gave it the ability to wrap | |
15 | # CVShistory output too. | |
class ApplicationController < ActionController::Base | ||
18 | ||
19 | session :off | |
20 | ||
21 | # The root URL action. | |
22 | # | |
23 | def index | |
24 | redirect_to url_for(:controller => 'rcvsweb', :action => 'run') | |
25 | end | |
26 | ||
27 | private | |
28 | ||
29 | # Pass the fully qualified pathname of the script that is to be | |
30 | # executed and a path prefix from routing (e.g. "/view"). | |
31 | ||
32 | def capture_script_output(script_location, extra_prefix) | |
33 | # Get the request URI in a way that works for FCGI and regular | |
34 | # CGI, at least for LightTPD. Strip off the PATH_PREFIX (location | |
35 | # of the Rails application) if present. | |
36 | ||
37 | uri = @request.env['REQUEST_URI'].dup | |
38 | uri.slice!(PATH_PREFIX + '/') | |
39 | ||
40 | # Split off the query string section, if there is one. | |
41 | ||
42 | (path_info, query) = uri.split('?') | |
43 | ||
44 | # The CGI script expects certain variables to be set up in a | |
45 | # certain way. "Slow" CGI does this but FastCGI does not because | |
46 | # the script executes under a different process environment | |
47 | # entirely, without the benefit of server-set variables. We must | |
48 | # therefore emulate the required environment by setting system | |
49 | # variables before executing the CVSweb script. | |
50 | ||
51 | command = '' | |
52 | needed = %w( | |
53 | HTTP_USER_AGENT HTTP_ACCEPT_ENCODING | |
54 | MOD_PERL PATH_INFO | |
55 | SCRIPT_NAME SCRIPT_FILENAME | |
56 | QUERY_STRING SERVER_PROTOCOL | |
57 | SERVER_PORT SERVER_NAME | |
58 | ) | |
59 | ||
60 | needed.each do |key| | |
61 | ||
62 | # Override certain items where we know we want a particular | |
63 | # result, else use a server-set value if there is one. | |
64 | ||
65 | case key | |
66 | when 'SCRIPT_NAME' | |
67 | value = PATH_PREFIX + extra_prefix | |
68 | when 'SCRIPT_FILENAME' | |
69 | value = "#{RAILS_ROOT}/public/dispatch.cgi" | |
70 | when 'PATH_INFO' | |
71 | value = path_info || '' | |
72 | value = '/' + value unless (value[0] == '/') | |
73 | value = value[extra_prefix.length..-1] if (value[0..(extra_prefix.length - 1)] == extra_prefix) | |
74 | when 'QUERY_STRING' | |
75 | value = query | |
76 | else | |
77 | value = @request.env[key] || '' | |
78 | end | |
79 | ||
80 | # Add the variable initialisation statement to the command string. | |
81 | ||
82 | command += "#{key}=\"#{value}\" " | |
83 | ||
84 | end # From needed.each | |
85 | ||
86 | # Add the CVSweb command to the command string and execute it. | |
87 | # Return the output of the command. | |
88 | ||
89 | command += "#{script_location}" | |
90 | return `#{command}` | |
91 | end | |
92 | ||
93 | # Parse script output - pass the raw output data from the script and a | |
94 | # filename to use in the event that the output isn't of a recognised type | |
95 | # and has to be sent raw to the client. | |
96 | ||
97 | def parse_script_output(output, filename) | |
98 | # The Views expect to use the @output instance variable, so we operate | |
99 | # on that from the beginning. | |
100 | ||
101 | @output = output | |
102 | ||
103 | # The command should have included HTTP headers; split the two. | |
104 | ||
105 | pos = @output.index("\r\n\r\n") | |
106 | short = true unless pos | |
107 | pos = @output.index("\n\n") unless pos | |
108 | headstr = @output.slice!(0..pos + (short ? 1 : 3)) if pos | |
109 | headers = {} | |
110 | ||
111 | if (headstr) | |
112 | ||
113 | # There are indeed some headers. Create a hash from them. | |
114 | ||
115 | headstr.downcase.split(short ? "\n" : "\r\n").each do |str| | |
116 | pos = str.index(':') | |
117 | headers[str.slice!(0..pos - 1).strip] = str[1..-1].strip if (pos > 1) | |
118 | end | |
119 | ||
120 | # If we find a Status header with a 300-series code, check for a | |
121 | # Location header too. If found, redirect to that location. | |
122 | ||
123 | if (headers['status']) | |
124 | code = headers['status'].to_i | |
125 | ||
126 | if (code >= 300 and code < 400 and headers['location']) | |
127 | redirect_to headers['location'] | |
128 | return | |
129 | end | |
130 | end | |
131 | ||
132 | # For a content type of 'text/html', render within a View. Otherwise | |
133 | # send the data directly without a surrounding template. | |
134 | ||
135 | if ([ 'text/html', 'text/x-html' ].include? headers['content-type']) | |
136 | ||
137 | # Almost there - extract a title if we can, and chop off the header | |
138 | # and footer (HTML prologue and epilogue) to attempt to produce | |
139 | # valid (X)HTML. The version of CVSweb in use at the time of writing | |
140 | # always writes body and title container tags in lower case which | |
141 | # helps save a bit of effort. | |
142 | ||
143 | title_tag = @output.slice(/<title.*\/title>/) | |
144 | title_tag.gsub!(/<title.*?>/, '') | |
145 | @title = title_tag.gsub(/<\/title>/, '') || 'CVS Repository' | |
146 | ||
147 | # Chop everything from the front of the output string up to the end | |
148 | # of the opening body tag, inclusive. | |
149 | ||
150 | body_tag = @output.slice(/<body.*?>/) | |
151 | body_pos = @output.index('<body') | |
152 | ||
153 | if (body_pos && body_tag && body_tag.length > 0) | |
154 | @output.slice!(0..body_pos + body_tag.length - 1) | |
155 | end | |
156 | ||
157 | # Chop off anything after the closing body tag too. | |
158 | ||
159 | body_pos = @output.index('</body') | |
160 | @output.slice!(body_pos..-1) if body_pos | |
161 | ||
162 | # Render the default layout to send the template-based output. | |
163 | ||
164 | render :layout => 'default' | |
165 | ||
166 | else | |
167 | ||
168 | # Apparently, not HTML; send the data directly. | |
169 | ||
170 | type = headers['content-type'] || 'application/octet-stream' | |
171 | send_data @output, | |
172 | :type => type, | |
173 | :disposition => 'inline' | |
174 | end | |
175 | ||
176 | else | |
177 | ||
178 | # CVSweb output had no HTTP header - this is unexpected. We don't | |
179 | # understand its output so just send this to the browser as a | |
180 | # stream of binary data. | |
181 | ||
182 | send_data @output, | |
183 | :filename => filename, | |
184 | :type => 'application/octet-stream' | |
185 | end | |
186 | end | |
end |
rool/rails/rcvsweb/trunk/app/controllers/rcvsweb_controller.rb:
prev. | current | |
class RcvswebController < ApplicationController | ||
3 | | |
4 | | |
3 | # All "/view/*" routes lead to the 'run' method, which invokes CVSweb | |
4 | # based on the request URL and embeds the result in a View. Since the | |
5 | # mechanism for embedding script output is common to CVSweb and | |
6 | # CVShistory, the core code for this is in the application controller. | |
def run | ||
7 | ||
8 | | |
9 | | |
10 | | |
11 | ||
12 | | |
13 | | |
14 | ||
15 | | |
16 | ||
17 | | |
18 | ||
19 | | |
20 | | |
21 | | |
22 | | |
23 | | |
24 | | |
25 | ||
26 | | |
27 | | |
28 | | |
29 | | |
30 | | |
31 | | |
32 | | |
33 | ||
34 | | |
35 | ||
36 | | |
37 | | |
38 | ||
39 | | |
40 | | |
41 | | |
42 | | |
43 | | |
44 | | |
45 | | |
46 | | |
47 | | |
48 | | |
49 | | |
50 | | |
51 | | |
52 | ||
53 | | |
54 | ||
55 | | |
56 | ||
57 | | |
58 | ||
59 | | |
60 | | |
61 | | |
62 | ||
63 | | |
64 | | |
65 | ||
66 | | |
67 | ||
68 | | |
69 | | |
70 | | |
71 | ||
72 | | |
73 | ||
74 | | |
75 | ||
76 | | |
77 | | |
78 | | |
79 | | |
80 | ||
81 | | |
82 | | |
83 | ||
84 | | |
85 | | |
86 | ||
87 | | |
88 | | |
89 | | |
90 | | |
91 | | |
92 | ||
93 | | |
94 | | |
95 | ||
96 | | |
97 | ||
98 | | |
99 | | |
100 | | |
101 | | |
102 | | |
103 | ||
104 | | |
105 | | |
106 | | |
107 | ||
108 | | |
109 | | |
110 | ||
111 | | |
112 | | |
113 | ||
114 | | |
115 | | |
116 | | |
117 | ||
118 | | |
119 | ||
120 | | |
121 | | |
122 | ||
123 | | |
124 | ||
125 | | |
126 | ||
127 | | |
128 | ||
129 | | |
130 | ||
131 | | |
132 | | |
133 | | |
134 | | |
135 | | |
136 | ||
137 | | |
138 | ||
139 | | |
140 | | |
141 | | |
142 | ||
143 | | |
144 | | |
145 | | |
146 | | |
9 | parse_script_output(capture_script_output(CVSWEB_LOCATION, '/view'), 'view_data.dat') | |
end | ||
end |
rool/rails/rcvsweb/trunk/app/helpers/application_helper.rb:
prev. | current | |
# Methods added to this helper will be available to all templates in the application. | ||
module ApplicationHelper | ||
3 | ||
4 | # Run simple_format on the given input text, then scan for "Ticket #xxx" strings | |
5 | # and replace them with Collaboa ticket display links. | |
6 | # | |
7 | def format_with_collaboa_links(text) | |
8 | simple_format(text).gsub(/([Tt]icket *#*)([0-9]*)/, '<a href="/rails/collaboa/tickets/\2">\1\2</a>') | |
9 | end | |
end |
rool/rails/rcvsweb/trunk/app/views/layouts/default.rhtml:
prev. | current | |
<meta name="generator" content="FreeBSD-CVSweb 3.0.6" /> | ||
<link rel="stylesheet" type="text/css" href="/css/risc_os_open.css" /> | ||
10 | | |
10 | <%= stylesheet_link_tag '/stylesheets/rcvsweb.css' %> | |
</head> | ||
<body> | ||
<%= render 'shared/fixed_header' %> | ||
15 | | |
15 | <!-- CVSweb contents table --> | |
<p /> | ||
18 | | |
19 | ||
20 | | |
21 | | |
18 | <table width="85%" cellspacing="0" cellpadding="0" align="center"> | |
19 | <tr valign="top" align="left"> | |
20 | <td width="75%"> | |
21 | <%= '<h2 align="left" class="notice">' + flash[:notice] + '</h2><p>' if (flash[:notice]) %><%= '<h2 align="left" class="attention">' + flash[:attention] + '</h2><p>' if (flash[:attention]) %><%= '<h2 align="left" class="alert">' + flash[:alert] + '</h2><p>' if (flash[:alert]) %> | |
22 | <div id="content"> | |
<%= @content_for_layout %> | ||
23 | | |
24 | </div> | |
25 | </td> | |
25 | | |
27 | <td> </td> | |
28 | <td bgcolor="#bbbbbb" class="column_divider"><img src="/images/utilities/blank.gif" width="1" height="1" alt="." border="0" /></td> | |
29 | <td> </td> | |
30 | ||
31 | <td width="25%"> | |
32 | <div class="sidebar"> | |
33 | <div class="sidebar-node"> | |
34 | <h3>Search for CVS module</h3> | |
35 | ||
36 | <p /> | |
37 | <div class="sidebar_static"> | |
38 | <%= form_tag( {}, :method => 'get') %> | |
39 | <input type="text" id="mpath" name="path" value="" size="15" /> | |
40 | <input type="submit" value="Go" /> | |
41 | <%= end_form_tag %> | |
42 | </div> | |
43 | </div> | |
44 | ||
45 | <%= render 'shared/fixed_sidebar' %> | |
46 | ||
47 | <p /> | |
48 | <div class="sidebar-node"> | |
49 | ||
50 | <h3>Options</h3> | |
51 | ||
52 | <p /> | |
53 | <ul> | |
54 | <li><a href="/rails/collaboa/">Tickets</a></li> | |
55 | <li><a href="/rails/collaboa/milestones">Milestones</a></li> | |
56 | <li>Subversion: <a href="/rails/collaboa/repository/changesets">Changesets</a></li> | |
57 | <li>Subversion: <a href="/rails/collaboa/repository/browse">Browse</a></li> | |
58 | <li>CVS: <%= link_to 'Revisions', { :controller => 'revisions', :action => 'list' } %></li> | |
59 | <li>CVS: <%= link_to 'Browse', { :controller => 'rcvsweb', :action => 'run' } %></li> | |
60 | </ul> | |
61 | </div> | |
62 | </div> | |
63 | </td> | |
64 | </tr> | |
65 | </table> | |
66 | ||
<%= render 'shared/fixed_footer' %> | ||
</body> | ||
</html> |
rool/rails/rcvsweb/trunk/app/views/rcvsweb/run.rhtml:
prev. | current | |
1 | ||
1 | You are currently browsing the <b>CVS</b> repository.<br /> | |
2 | The Subversion repository is <a href="/rails/collaboa/repository/browse">here</a>. | |
3 | <hr /> | |
4 | ||
5 | <%= @output %> | |
rool/rails/rcvsweb/trunk/config/environment.rb:
prev. | current | |
# ENV['RAILS_ENV'] ||= 'production' | ||
# Specifies gem version of Rails to use when vendor/rails is not present | ||
8 | ||
8 | #RAILS_GEM_VERSION = '1.1.5' | |
# Bootstrap the Rails environment, frameworks, and default configuration | ||
require File.join(File.dirname(__FILE__), 'boot') | ||
... | ... | |
# Location of application relative to document root in terms of | ||
# URLs (i.e. according to the web server configuration, not the | ||
# filesystem location) and location in the filesystem, rather than | ||
16 | ||
16 | # according to the Web server, of the CVSweb and CVShistory scripts. | |
18 | ||
19 | ||
18 | PATH_PREFIX = '/rails/rcvsweb' | |
19 | CVSWEB_LOCATION = '/home/adh/perl/cvsweb/cvsweb.cgi' | |
20 | CVSHISTORY_LOCATION = '/home/adh/python/cvshistory/cvshistory.cgi' | |
Rails::Initializer.run do |config| | ||
# We don't run in the document root, so images etc. must come from | ||
... | ... | |
end | ||
# Allow multiple Rails applications by giving the session cookie a | ||
39 | ||
40 | # unique prefix. In this application the ApplicationController class | |
41 | # turns sessions off (at the time of writing, 22-Aug-2006) anyway, | |
42 | # but in future sessions may be used again in which case the line | |
43 | # below will be important. | |
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:session_key] = 'rcvswebapp_session_id' |
rool/rails/rcvsweb/trunk/config/routes.rb:
prev. | current | |
ActionController::Routing::Routes.draw do |map| | ||
3 | | |
4 | | |
3 | # Root | |
4 | map.connect PATH_PREFIX + '/', :controller => 'application', :action => 'index' | |
6 | # CVSweb: Route through the 'rcvsweb' controller's 'run' action | |
7 | map.connect PATH_PREFIX + '/view/*url', :controller => 'rcvsweb', :action => 'run' | |
8 | ||
9 | # CVShistory: Route through the 'rcvshistory' controller's 'run' action | |
10 | map.connect PATH_PREFIX + '/history/*url', :controller => 'rcvshistory', :action => 'run' | |
11 | ||
12 | # Revision list | |
13 | map.connect PATH_PREFIX + '/revisions/', :controller => 'revisions', :action => 'list' | |
14 | map.connect PATH_PREFIX + '/revisions/:action', :controller => 'revisions' | |
15 | ||
end |