##// END OF EJS Templates
Fixed: cvs diff broken by r4539 (#7176)....
Jean-Philippe Lang -
r4463:0025a6620087
parent child
Show More
@@ -1,362 +1,362
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
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
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.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require 'redmine/scm/adapters/abstract_adapter'
18 require 'redmine/scm/adapters/abstract_adapter'
19
19
20 module Redmine
20 module Redmine
21 module Scm
21 module Scm
22 module Adapters
22 module Adapters
23 class CvsAdapter < AbstractAdapter
23 class CvsAdapter < AbstractAdapter
24
24
25 # CVS executable name
25 # CVS executable name
26 CVS_BIN = "cvs"
26 CVS_BIN = "cvs"
27
27
28 # Guidelines for the input:
28 # Guidelines for the input:
29 # url -> the project-path, relative to the cvsroot (eg. module name)
29 # url -> the project-path, relative to the cvsroot (eg. module name)
30 # root_url -> the good old, sometimes damned, CVSROOT
30 # root_url -> the good old, sometimes damned, CVSROOT
31 # login -> unnecessary
31 # login -> unnecessary
32 # password -> unnecessary too
32 # password -> unnecessary too
33 def initialize(url, root_url=nil, login=nil, password=nil)
33 def initialize(url, root_url=nil, login=nil, password=nil)
34 @url = url
34 @url = url
35 @login = login if login && !login.empty?
35 @login = login if login && !login.empty?
36 @password = (password || "") if @login
36 @password = (password || "") if @login
37 #TODO: better Exception here (IllegalArgumentException)
37 #TODO: better Exception here (IllegalArgumentException)
38 raise CommandFailed if root_url.blank?
38 raise CommandFailed if root_url.blank?
39 @root_url = root_url
39 @root_url = root_url
40 end
40 end
41
41
42 def root_url
42 def root_url
43 @root_url
43 @root_url
44 end
44 end
45
45
46 def url
46 def url
47 @url
47 @url
48 end
48 end
49
49
50 def info
50 def info
51 logger.debug "<cvs> info"
51 logger.debug "<cvs> info"
52 Info.new({:root_url => @root_url, :lastrev => nil})
52 Info.new({:root_url => @root_url, :lastrev => nil})
53 end
53 end
54
54
55 def get_previous_revision(revision)
55 def get_previous_revision(revision)
56 CvsRevisionHelper.new(revision).prevRev
56 CvsRevisionHelper.new(revision).prevRev
57 end
57 end
58
58
59 # Returns an Entries collection
59 # Returns an Entries collection
60 # or nil if the given path doesn't exist in the repository
60 # or nil if the given path doesn't exist in the repository
61 # this method is used by the repository-browser (aka LIST)
61 # this method is used by the repository-browser (aka LIST)
62 def entries(path=nil, identifier=nil)
62 def entries(path=nil, identifier=nil)
63 logger.debug "<cvs> entries '#{path}' with identifier '#{identifier}'"
63 logger.debug "<cvs> entries '#{path}' with identifier '#{identifier}'"
64 path_with_project="#{url}#{with_leading_slash(path)}"
64 path_with_project="#{url}#{with_leading_slash(path)}"
65 entries = Entries.new
65 entries = Entries.new
66 cmd = "#{CVS_BIN} -d #{shell_quote root_url} rls -e"
66 cmd = "#{CVS_BIN} -d #{shell_quote root_url} rls -e"
67 cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier
67 cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier
68 cmd << " #{shell_quote path_with_project}"
68 cmd << " #{shell_quote path_with_project}"
69 shellout(cmd) do |io|
69 shellout(cmd) do |io|
70 io.each_line(){|line|
70 io.each_line(){|line|
71 fields=line.chop.split('/',-1)
71 fields=line.chop.split('/',-1)
72 logger.debug(">>InspectLine #{fields.inspect}")
72 logger.debug(">>InspectLine #{fields.inspect}")
73
73
74 if fields[0]!="D"
74 if fields[0]!="D"
75 entries << Entry.new({:name => fields[-5],
75 entries << Entry.new({:name => fields[-5],
76 #:path => fields[-4].include?(path)?fields[-4]:(path + "/"+ fields[-4]),
76 #:path => fields[-4].include?(path)?fields[-4]:(path + "/"+ fields[-4]),
77 :path => "#{path}/#{fields[-5]}",
77 :path => "#{path}/#{fields[-5]}",
78 :kind => 'file',
78 :kind => 'file',
79 :size => nil,
79 :size => nil,
80 :lastrev => Revision.new({
80 :lastrev => Revision.new({
81 :revision => fields[-4],
81 :revision => fields[-4],
82 :name => fields[-4],
82 :name => fields[-4],
83 :time => Time.parse(fields[-3]),
83 :time => Time.parse(fields[-3]),
84 :author => ''
84 :author => ''
85 })
85 })
86 })
86 })
87 else
87 else
88 entries << Entry.new({:name => fields[1],
88 entries << Entry.new({:name => fields[1],
89 :path => "#{path}/#{fields[1]}",
89 :path => "#{path}/#{fields[1]}",
90 :kind => 'dir',
90 :kind => 'dir',
91 :size => nil,
91 :size => nil,
92 :lastrev => nil
92 :lastrev => nil
93 })
93 })
94 end
94 end
95 }
95 }
96 end
96 end
97 return nil if $? && $?.exitstatus != 0
97 return nil if $? && $?.exitstatus != 0
98 entries.sort_by_name
98 entries.sort_by_name
99 end
99 end
100
100
101 STARTLOG="----------------------------"
101 STARTLOG="----------------------------"
102 ENDLOG ="============================================================================="
102 ENDLOG ="============================================================================="
103
103
104 # Returns all revisions found between identifier_from and identifier_to
104 # Returns all revisions found between identifier_from and identifier_to
105 # in the repository. both identifier have to be dates or nil.
105 # in the repository. both identifier have to be dates or nil.
106 # these method returns nothing but yield every result in block
106 # these method returns nothing but yield every result in block
107 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}, &block)
107 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}, &block)
108 logger.debug "<cvs> revisions path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}"
108 logger.debug "<cvs> revisions path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}"
109
109
110 path_with_project="#{url}#{with_leading_slash(path)}"
110 path_with_project="#{url}#{with_leading_slash(path)}"
111 cmd = "#{CVS_BIN} -d #{shell_quote root_url} rlog"
111 cmd = "#{CVS_BIN} -d #{shell_quote root_url} rlog"
112 cmd << " -d\">#{time_to_cvstime(identifier_from)}\"" if identifier_from
112 cmd << " -d\">#{time_to_cvstime(identifier_from)}\"" if identifier_from
113 cmd << " #{shell_quote path_with_project}"
113 cmd << " #{shell_quote path_with_project}"
114 shellout(cmd) do |io|
114 shellout(cmd) do |io|
115 state="entry_start"
115 state="entry_start"
116
116
117 commit_log=String.new
117 commit_log=String.new
118 revision=nil
118 revision=nil
119 date=nil
119 date=nil
120 author=nil
120 author=nil
121 entry_path=nil
121 entry_path=nil
122 entry_name=nil
122 entry_name=nil
123 file_state=nil
123 file_state=nil
124 branch_map=nil
124 branch_map=nil
125
125
126 io.each_line() do |line|
126 io.each_line() do |line|
127
127
128 if state!="revision" && /^#{ENDLOG}/ =~ line
128 if state!="revision" && /^#{ENDLOG}/ =~ line
129 commit_log=String.new
129 commit_log=String.new
130 revision=nil
130 revision=nil
131 state="entry_start"
131 state="entry_start"
132 end
132 end
133
133
134 if state=="entry_start"
134 if state=="entry_start"
135 branch_map=Hash.new
135 branch_map=Hash.new
136 if /^RCS file: #{Regexp.escape(root_url_path)}\/#{Regexp.escape(path_with_project)}(.+),v$/ =~ line
136 if /^RCS file: #{Regexp.escape(root_url_path)}\/#{Regexp.escape(path_with_project)}(.+),v$/ =~ line
137 entry_path = normalize_cvs_path($1)
137 entry_path = normalize_cvs_path($1)
138 entry_name = normalize_path(File.basename($1))
138 entry_name = normalize_path(File.basename($1))
139 logger.debug("Path #{entry_path} <=> Name #{entry_name}")
139 logger.debug("Path #{entry_path} <=> Name #{entry_name}")
140 elsif /^head: (.+)$/ =~ line
140 elsif /^head: (.+)$/ =~ line
141 entry_headRev = $1 #unless entry.nil?
141 entry_headRev = $1 #unless entry.nil?
142 elsif /^symbolic names:/ =~ line
142 elsif /^symbolic names:/ =~ line
143 state="symbolic" #unless entry.nil?
143 state="symbolic" #unless entry.nil?
144 elsif /^#{STARTLOG}/ =~ line
144 elsif /^#{STARTLOG}/ =~ line
145 commit_log=String.new
145 commit_log=String.new
146 state="revision"
146 state="revision"
147 end
147 end
148 next
148 next
149 elsif state=="symbolic"
149 elsif state=="symbolic"
150 if /^(.*):\s(.*)/ =~ (line.strip)
150 if /^(.*):\s(.*)/ =~ (line.strip)
151 branch_map[$1]=$2
151 branch_map[$1]=$2
152 else
152 else
153 state="tags"
153 state="tags"
154 next
154 next
155 end
155 end
156 elsif state=="tags"
156 elsif state=="tags"
157 if /^#{STARTLOG}/ =~ line
157 if /^#{STARTLOG}/ =~ line
158 commit_log = ""
158 commit_log = ""
159 state="revision"
159 state="revision"
160 elsif /^#{ENDLOG}/ =~ line
160 elsif /^#{ENDLOG}/ =~ line
161 state="head"
161 state="head"
162 end
162 end
163 next
163 next
164 elsif state=="revision"
164 elsif state=="revision"
165 if /^#{ENDLOG}/ =~ line || /^#{STARTLOG}/ =~ line
165 if /^#{ENDLOG}/ =~ line || /^#{STARTLOG}/ =~ line
166 if revision
166 if revision
167
167
168 revHelper=CvsRevisionHelper.new(revision)
168 revHelper=CvsRevisionHelper.new(revision)
169 revBranch="HEAD"
169 revBranch="HEAD"
170
170
171 branch_map.each() do |branch_name,branch_point|
171 branch_map.each() do |branch_name,branch_point|
172 if revHelper.is_in_branch_with_symbol(branch_point)
172 if revHelper.is_in_branch_with_symbol(branch_point)
173 revBranch=branch_name
173 revBranch=branch_name
174 end
174 end
175 end
175 end
176
176
177 logger.debug("********** YIELD Revision #{revision}::#{revBranch}")
177 logger.debug("********** YIELD Revision #{revision}::#{revBranch}")
178
178
179 yield Revision.new({
179 yield Revision.new({
180 :time => date,
180 :time => date,
181 :author => author,
181 :author => author,
182 :message=>commit_log.chomp,
182 :message=>commit_log.chomp,
183 :paths => [{
183 :paths => [{
184 :revision => revision,
184 :revision => revision,
185 :branch=> revBranch,
185 :branch=> revBranch,
186 :path=>entry_path,
186 :path=>entry_path,
187 :name=>entry_name,
187 :name=>entry_name,
188 :kind=>'file',
188 :kind=>'file',
189 :action=>file_state
189 :action=>file_state
190 }]
190 }]
191 })
191 })
192 end
192 end
193
193
194 commit_log=String.new
194 commit_log=String.new
195 revision=nil
195 revision=nil
196
196
197 if /^#{ENDLOG}/ =~ line
197 if /^#{ENDLOG}/ =~ line
198 state="entry_start"
198 state="entry_start"
199 end
199 end
200 next
200 next
201 end
201 end
202
202
203 if /^branches: (.+)$/ =~ line
203 if /^branches: (.+)$/ =~ line
204 #TODO: version.branch = $1
204 #TODO: version.branch = $1
205 elsif /^revision (\d+(?:\.\d+)+).*$/ =~ line
205 elsif /^revision (\d+(?:\.\d+)+).*$/ =~ line
206 revision = $1
206 revision = $1
207 elsif /^date:\s+(\d+.\d+.\d+\s+\d+:\d+:\d+)/ =~ line
207 elsif /^date:\s+(\d+.\d+.\d+\s+\d+:\d+:\d+)/ =~ line
208 date = Time.parse($1)
208 date = Time.parse($1)
209 author = /author: ([^;]+)/.match(line)[1]
209 author = /author: ([^;]+)/.match(line)[1]
210 file_state = /state: ([^;]+)/.match(line)[1]
210 file_state = /state: ([^;]+)/.match(line)[1]
211 #TODO: linechanges only available in CVS.... maybe a feature our SVN implementation. i'm sure, they are
211 #TODO: linechanges only available in CVS.... maybe a feature our SVN implementation. i'm sure, they are
212 # useful for stats or something else
212 # useful for stats or something else
213 # linechanges =/lines: \+(\d+) -(\d+)/.match(line)
213 # linechanges =/lines: \+(\d+) -(\d+)/.match(line)
214 # unless linechanges.nil?
214 # unless linechanges.nil?
215 # version.line_plus = linechanges[1]
215 # version.line_plus = linechanges[1]
216 # version.line_minus = linechanges[2]
216 # version.line_minus = linechanges[2]
217 # else
217 # else
218 # version.line_plus = 0
218 # version.line_plus = 0
219 # version.line_minus = 0
219 # version.line_minus = 0
220 # end
220 # end
221 else
221 else
222 commit_log << line unless line =~ /^\*\*\* empty log message \*\*\*/
222 commit_log << line unless line =~ /^\*\*\* empty log message \*\*\*/
223 end
223 end
224 end
224 end
225 end
225 end
226 end
226 end
227 end
227 end
228
228
229 def diff(path, identifier_from, identifier_to=nil)
229 def diff(path, identifier_from, identifier_to=nil)
230 logger.debug "<cvs> diff path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}"
230 logger.debug "<cvs> diff path:'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}"
231 path_with_project="#{url}#{with_leading_slash(path)}"
231 path_with_project="#{url}#{with_leading_slash(path)}"
232 cmd = "#{CVS_BIN} -d #{shell_quote root_url} rdiff -u -r#{identifier_to.to_i} -r#{identifier_from.to_i} #{shell_quote path_with_project}"
232 cmd = "#{CVS_BIN} -d #{shell_quote root_url} rdiff -u -r#{identifier_to} -r#{identifier_from} #{shell_quote path_with_project}"
233 diff = []
233 diff = []
234 shellout(cmd) do |io|
234 shellout(cmd) do |io|
235 io.each_line do |line|
235 io.each_line do |line|
236 diff << line
236 diff << line
237 end
237 end
238 end
238 end
239 return nil if $? && $?.exitstatus != 0
239 return nil if $? && $?.exitstatus != 0
240 diff
240 diff
241 end
241 end
242
242
243 def cat(path, identifier=nil)
243 def cat(path, identifier=nil)
244 identifier = (identifier) ? identifier : "HEAD"
244 identifier = (identifier) ? identifier : "HEAD"
245 logger.debug "<cvs> cat path:'#{path}',identifier #{identifier}"
245 logger.debug "<cvs> cat path:'#{path}',identifier #{identifier}"
246 path_with_project="#{url}#{with_leading_slash(path)}"
246 path_with_project="#{url}#{with_leading_slash(path)}"
247 cmd = "#{CVS_BIN} -d #{shell_quote root_url} co"
247 cmd = "#{CVS_BIN} -d #{shell_quote root_url} co"
248 cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier
248 cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier
249 cmd << " -p #{shell_quote path_with_project}"
249 cmd << " -p #{shell_quote path_with_project}"
250 cat = nil
250 cat = nil
251 shellout(cmd) do |io|
251 shellout(cmd) do |io|
252 cat = io.read
252 cat = io.read
253 end
253 end
254 return nil if $? && $?.exitstatus != 0
254 return nil if $? && $?.exitstatus != 0
255 cat
255 cat
256 end
256 end
257
257
258 def annotate(path, identifier=nil)
258 def annotate(path, identifier=nil)
259 identifier = (identifier) ? identifier.to_i : "HEAD"
259 identifier = (identifier) ? identifier.to_i : "HEAD"
260 logger.debug "<cvs> annotate path:'#{path}',identifier #{identifier}"
260 logger.debug "<cvs> annotate path:'#{path}',identifier #{identifier}"
261 path_with_project="#{url}#{with_leading_slash(path)}"
261 path_with_project="#{url}#{with_leading_slash(path)}"
262 cmd = "#{CVS_BIN} -d #{shell_quote root_url} rannotate -r#{identifier} #{shell_quote path_with_project}"
262 cmd = "#{CVS_BIN} -d #{shell_quote root_url} rannotate -r#{identifier} #{shell_quote path_with_project}"
263 blame = Annotate.new
263 blame = Annotate.new
264 shellout(cmd) do |io|
264 shellout(cmd) do |io|
265 io.each_line do |line|
265 io.each_line do |line|
266 next unless line =~ %r{^([\d\.]+)\s+\(([^\)]+)\s+[^\)]+\):\s(.*)$}
266 next unless line =~ %r{^([\d\.]+)\s+\(([^\)]+)\s+[^\)]+\):\s(.*)$}
267 blame.add_line($3.rstrip, Revision.new(:revision => $1, :author => $2.strip))
267 blame.add_line($3.rstrip, Revision.new(:revision => $1, :author => $2.strip))
268 end
268 end
269 end
269 end
270 return nil if $? && $?.exitstatus != 0
270 return nil if $? && $?.exitstatus != 0
271 blame
271 blame
272 end
272 end
273
273
274 private
274 private
275
275
276 # Returns the root url without the connexion string
276 # Returns the root url without the connexion string
277 # :pserver:anonymous@foo.bar:/path => /path
277 # :pserver:anonymous@foo.bar:/path => /path
278 # :ext:cvsservername:/path => /path
278 # :ext:cvsservername:/path => /path
279 def root_url_path
279 def root_url_path
280 root_url.to_s.gsub(/^:.+:\d*/, '')
280 root_url.to_s.gsub(/^:.+:\d*/, '')
281 end
281 end
282
282
283 # convert a date/time into the CVS-format
283 # convert a date/time into the CVS-format
284 def time_to_cvstime(time)
284 def time_to_cvstime(time)
285 return nil if time.nil?
285 return nil if time.nil?
286 unless time.kind_of? Time
286 unless time.kind_of? Time
287 time = Time.parse(time)
287 time = Time.parse(time)
288 end
288 end
289 return time.strftime("%Y-%m-%d %H:%M:%S")
289 return time.strftime("%Y-%m-%d %H:%M:%S")
290 end
290 end
291
291
292 def normalize_cvs_path(path)
292 def normalize_cvs_path(path)
293 normalize_path(path.gsub(/Attic\//,''))
293 normalize_path(path.gsub(/Attic\//,''))
294 end
294 end
295
295
296 def normalize_path(path)
296 def normalize_path(path)
297 path.sub(/^(\/)*(.*)/,'\2').sub(/(.*)(,v)+/,'\1')
297 path.sub(/^(\/)*(.*)/,'\2').sub(/(.*)(,v)+/,'\1')
298 end
298 end
299 end
299 end
300
300
301 class CvsRevisionHelper
301 class CvsRevisionHelper
302 attr_accessor :complete_rev, :revision, :base, :branchid
302 attr_accessor :complete_rev, :revision, :base, :branchid
303
303
304 def initialize(complete_rev)
304 def initialize(complete_rev)
305 @complete_rev = complete_rev
305 @complete_rev = complete_rev
306 parseRevision()
306 parseRevision()
307 end
307 end
308
308
309 def branchPoint
309 def branchPoint
310 return @base
310 return @base
311 end
311 end
312
312
313 def branchVersion
313 def branchVersion
314 if isBranchRevision
314 if isBranchRevision
315 return @base+"."+@branchid
315 return @base+"."+@branchid
316 end
316 end
317 return @base
317 return @base
318 end
318 end
319
319
320 def isBranchRevision
320 def isBranchRevision
321 !@branchid.nil?
321 !@branchid.nil?
322 end
322 end
323
323
324 def prevRev
324 def prevRev
325 unless @revision==0
325 unless @revision==0
326 return buildRevision(@revision-1)
326 return buildRevision(@revision-1)
327 end
327 end
328 return buildRevision(@revision)
328 return buildRevision(@revision)
329 end
329 end
330
330
331 def is_in_branch_with_symbol(branch_symbol)
331 def is_in_branch_with_symbol(branch_symbol)
332 bpieces=branch_symbol.split(".")
332 bpieces=branch_symbol.split(".")
333 branch_start="#{bpieces[0..-3].join(".")}.#{bpieces[-1]}"
333 branch_start="#{bpieces[0..-3].join(".")}.#{bpieces[-1]}"
334 return (branchVersion==branch_start)
334 return (branchVersion==branch_start)
335 end
335 end
336
336
337 private
337 private
338 def buildRevision(rev)
338 def buildRevision(rev)
339 if rev== 0
339 if rev== 0
340 @base
340 @base
341 elsif @branchid.nil?
341 elsif @branchid.nil?
342 @base+"."+rev.to_s
342 @base+"."+rev.to_s
343 else
343 else
344 @base+"."+@branchid+"."+rev.to_s
344 @base+"."+@branchid+"."+rev.to_s
345 end
345 end
346 end
346 end
347
347
348 # Interpretiert die cvs revisionsnummern wie z.b. 1.14 oder 1.3.0.15
348 # Interpretiert die cvs revisionsnummern wie z.b. 1.14 oder 1.3.0.15
349 def parseRevision()
349 def parseRevision()
350 pieces=@complete_rev.split(".")
350 pieces=@complete_rev.split(".")
351 @revision=pieces.last.to_i
351 @revision=pieces.last.to_i
352 baseSize=1
352 baseSize=1
353 baseSize+=(pieces.size/2)
353 baseSize+=(pieces.size/2)
354 @base=pieces[0..-baseSize].join(".")
354 @base=pieces[0..-baseSize].join(".")
355 if baseSize > 2
355 if baseSize > 2
356 @branchid=pieces[-2]
356 @branchid=pieces[-2]
357 end
357 end
358 end
358 end
359 end
359 end
360 end
360 end
361 end
361 end
362 end
362 end
@@ -1,165 +1,166
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2008 Jean-Philippe Lang
2 # Copyright (C) 2006-2008 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
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
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.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19 require 'repositories_controller'
19 require 'repositories_controller'
20
20
21 # Re-raise errors caught by the controller.
21 # Re-raise errors caught by the controller.
22 class RepositoriesController; def rescue_action(e) raise e end; end
22 class RepositoriesController; def rescue_action(e) raise e end; end
23
23
24 class RepositoriesCvsControllerTest < ActionController::TestCase
24 class RepositoriesCvsControllerTest < ActionController::TestCase
25 fixtures :projects, :users, :roles, :members, :member_roles, :repositories, :enabled_modules
25
26
26 # No '..' in the repository path
27 # No '..' in the repository path
27 REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/cvs_repository'
28 REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/cvs_repository'
28 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
29 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
29 # CVS module
30 # CVS module
30 MODULE_NAME = 'test'
31 MODULE_NAME = 'test'
31
32
32 def setup
33 def setup
33 @controller = RepositoriesController.new
34 @controller = RepositoriesController.new
34 @request = ActionController::TestRequest.new
35 @request = ActionController::TestRequest.new
35 @response = ActionController::TestResponse.new
36 @response = ActionController::TestResponse.new
36 Setting.default_language = 'en'
37 Setting.default_language = 'en'
37 User.current = nil
38 User.current = nil
38
39
39 @project = Project.find(1)
40 @project = Project.find(1)
40 @project.repository = Repository::Cvs.create(:root_url => REPOSITORY_PATH,
41 @project.repository = Repository::Cvs.create(:root_url => REPOSITORY_PATH,
41 :url => MODULE_NAME)
42 :url => MODULE_NAME)
42 end
43 end
43
44
44 if File.directory?(REPOSITORY_PATH)
45 if File.directory?(REPOSITORY_PATH)
45 def test_show
46 def test_show
46 get :show, :id => 1
47 get :show, :id => 1
47 assert_response :success
48 assert_response :success
48 assert_template 'show'
49 assert_template 'show'
49 assert_not_nil assigns(:entries)
50 assert_not_nil assigns(:entries)
50 assert_not_nil assigns(:changesets)
51 assert_not_nil assigns(:changesets)
51 end
52 end
52
53
53 def test_browse_root
54 def test_browse_root
54 get :show, :id => 1
55 get :show, :id => 1
55 assert_response :success
56 assert_response :success
56 assert_template 'show'
57 assert_template 'show'
57 assert_not_nil assigns(:entries)
58 assert_not_nil assigns(:entries)
58 assert_equal 3, assigns(:entries).size
59 assert_equal 3, assigns(:entries).size
59
60
60 entry = assigns(:entries).detect {|e| e.name == 'images'}
61 entry = assigns(:entries).detect {|e| e.name == 'images'}
61 assert_equal 'dir', entry.kind
62 assert_equal 'dir', entry.kind
62
63
63 entry = assigns(:entries).detect {|e| e.name == 'README'}
64 entry = assigns(:entries).detect {|e| e.name == 'README'}
64 assert_equal 'file', entry.kind
65 assert_equal 'file', entry.kind
65 end
66 end
66
67
67 def test_browse_directory
68 def test_browse_directory
68 get :show, :id => 1, :path => ['images']
69 get :show, :id => 1, :path => ['images']
69 assert_response :success
70 assert_response :success
70 assert_template 'show'
71 assert_template 'show'
71 assert_not_nil assigns(:entries)
72 assert_not_nil assigns(:entries)
72 assert_equal ['add.png', 'delete.png', 'edit.png'], assigns(:entries).collect(&:name)
73 assert_equal ['add.png', 'delete.png', 'edit.png'], assigns(:entries).collect(&:name)
73 entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
74 entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
74 assert_not_nil entry
75 assert_not_nil entry
75 assert_equal 'file', entry.kind
76 assert_equal 'file', entry.kind
76 assert_equal 'images/edit.png', entry.path
77 assert_equal 'images/edit.png', entry.path
77 end
78 end
78
79
79 def test_browse_at_given_revision
80 def test_browse_at_given_revision
80 Project.find(1).repository.fetch_changesets
81 Project.find(1).repository.fetch_changesets
81 get :show, :id => 1, :path => ['images'], :rev => 1
82 get :show, :id => 1, :path => ['images'], :rev => 1
82 assert_response :success
83 assert_response :success
83 assert_template 'show'
84 assert_template 'show'
84 assert_not_nil assigns(:entries)
85 assert_not_nil assigns(:entries)
85 assert_equal ['delete.png', 'edit.png'], assigns(:entries).collect(&:name)
86 assert_equal ['delete.png', 'edit.png'], assigns(:entries).collect(&:name)
86 end
87 end
87
88
88 def test_entry
89 def test_entry
89 get :entry, :id => 1, :path => ['sources', 'watchers_controller.rb']
90 get :entry, :id => 1, :path => ['sources', 'watchers_controller.rb']
90 assert_response :success
91 assert_response :success
91 assert_template 'entry'
92 assert_template 'entry'
92 assert_no_tag :tag => 'td', :attributes => { :class => /line-code/},
93 assert_no_tag :tag => 'td', :attributes => { :class => /line-code/},
93 :content => /before_filter/
94 :content => /before_filter/
94 end
95 end
95
96
96 def test_entry_at_given_revision
97 def test_entry_at_given_revision
97 # changesets must be loaded
98 # changesets must be loaded
98 Project.find(1).repository.fetch_changesets
99 Project.find(1).repository.fetch_changesets
99 get :entry, :id => 1, :path => ['sources', 'watchers_controller.rb'], :rev => 2
100 get :entry, :id => 1, :path => ['sources', 'watchers_controller.rb'], :rev => 2
100 assert_response :success
101 assert_response :success
101 assert_template 'entry'
102 assert_template 'entry'
102 # this line was removed in r3
103 # this line was removed in r3
103 assert_tag :tag => 'td', :attributes => { :class => /line-code/},
104 assert_tag :tag => 'td', :attributes => { :class => /line-code/},
104 :content => /before_filter/
105 :content => /before_filter/
105 end
106 end
106
107
107 def test_entry_not_found
108 def test_entry_not_found
108 get :entry, :id => 1, :path => ['sources', 'zzz.c']
109 get :entry, :id => 1, :path => ['sources', 'zzz.c']
109 assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ },
110 assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ },
110 :content => /The entry or revision was not found in the repository/
111 :content => /The entry or revision was not found in the repository/
111 end
112 end
112
113
113 def test_entry_download
114 def test_entry_download
114 get :entry, :id => 1, :path => ['sources', 'watchers_controller.rb'], :format => 'raw'
115 get :entry, :id => 1, :path => ['sources', 'watchers_controller.rb'], :format => 'raw'
115 assert_response :success
116 assert_response :success
116 end
117 end
117
118
118 def test_directory_entry
119 def test_directory_entry
119 get :entry, :id => 1, :path => ['sources']
120 get :entry, :id => 1, :path => ['sources']
120 assert_response :success
121 assert_response :success
121 assert_template 'show'
122 assert_template 'show'
122 assert_not_nil assigns(:entry)
123 assert_not_nil assigns(:entry)
123 assert_equal 'sources', assigns(:entry).name
124 assert_equal 'sources', assigns(:entry).name
124 end
125 end
125
126
126 def test_diff
127 def test_diff
127 Project.find(1).repository.fetch_changesets
128 Project.find(1).repository.fetch_changesets
128 get :diff, :id => 1, :rev => 3, :type => 'inline'
129 get :diff, :id => 1, :rev => 3, :type => 'inline'
129 assert_response :success
130 assert_response :success
130 assert_template 'diff'
131 assert_template 'diff'
131 assert_tag :tag => 'td', :attributes => { :class => 'line-code diff_out' },
132 assert_tag :tag => 'td', :attributes => { :class => 'line-code diff_out' },
132 :content => /watched.remove_watcher/
133 :content => /watched.remove_watcher/
133 assert_tag :tag => 'td', :attributes => { :class => 'line-code diff_in' },
134 assert_tag :tag => 'td', :attributes => { :class => 'line-code diff_in' },
134 :content => /watched.remove_all_watcher/
135 :content => /watched.remove_all_watcher/
135 end
136 end
136
137
137 def test_annotate
138 def test_annotate
138 Project.find(1).repository.fetch_changesets
139 Project.find(1).repository.fetch_changesets
139 get :annotate, :id => 1, :path => ['sources', 'watchers_controller.rb']
140 get :annotate, :id => 1, :path => ['sources', 'watchers_controller.rb']
140 assert_response :success
141 assert_response :success
141 assert_template 'annotate'
142 assert_template 'annotate'
142 # 1.1 line
143 # 1.1 line
143 assert_tag :tag => 'th', :attributes => { :class => 'line-num' },
144 assert_tag :tag => 'th', :attributes => { :class => 'line-num' },
144 :content => '18',
145 :content => '18',
145 :sibling => { :tag => 'td', :attributes => { :class => 'revision' },
146 :sibling => { :tag => 'td', :attributes => { :class => 'revision' },
146 :content => /1.1/,
147 :content => /1.1/,
147 :sibling => { :tag => 'td', :attributes => { :class => 'author' },
148 :sibling => { :tag => 'td', :attributes => { :class => 'author' },
148 :content => /LANG/
149 :content => /LANG/
149 }
150 }
150 }
151 }
151 # 1.2 line
152 # 1.2 line
152 assert_tag :tag => 'th', :attributes => { :class => 'line-num' },
153 assert_tag :tag => 'th', :attributes => { :class => 'line-num' },
153 :content => '32',
154 :content => '32',
154 :sibling => { :tag => 'td', :attributes => { :class => 'revision' },
155 :sibling => { :tag => 'td', :attributes => { :class => 'revision' },
155 :content => /1.2/,
156 :content => /1.2/,
156 :sibling => { :tag => 'td', :attributes => { :class => 'author' },
157 :sibling => { :tag => 'td', :attributes => { :class => 'author' },
157 :content => /LANG/
158 :content => /LANG/
158 }
159 }
159 }
160 }
160 end
161 end
161 else
162 else
162 puts "CVS test repository NOT FOUND. Skipping functional tests !!!"
163 puts "CVS test repository NOT FOUND. Skipping functional tests !!!"
163 def test_fake; assert true end
164 def test_fake; assert true end
164 end
165 end
165 end
166 end
General Comments 0
You need to be logged in to leave comments. Login now