Changesets can be listed by changeset number.
The Git repository is here.
- Revision:
- 85
- Log:
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.
- Author:
- adh
- Date:
- Sun Oct 15 13:47:21 +0100 2006
- Size:
- 6272 Bytes
1 | # RCVSweb - a Ruby On Rails wrapper around the Perl-based FreeBSD |
2 | # version of the CVSweb and Python-based CVShistory. |
3 | # |
4 | # See "http://www.freebsd.org/projects/cvsweb.html" and |
5 | # "http://www.jamwt.com/CVSHistory/" |
6 | # |
7 | # This wrapper was created for the sole purpose of embedding CVSweb |
8 | # output into a Rails-provided layout. This layout is shared between |
9 | # different Rails applications on one host. Using the wrapper means |
10 | # that it is not necessary to create a derived copy of the layout |
11 | # expressed in a form that CVSweb understands - instead, the layout |
12 | # can be used directly. |
13 | # |
14 | # Later extensions to the application gave it the ability to wrap |
15 | # CVShistory output too. |
16 | |
17 | 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 |
187 | end |