rscm-accurev 0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/LICENSE +25 -0
  2. data/README +9 -0
  3. data/Rakefile +137 -0
  4. data/STATUS +63 -0
  5. data/TODO +43 -0
  6. data/apitest.rb +21 -0
  7. data/bumprelease.sh +13 -0
  8. data/lib/rscm/accurev.rb +18 -0
  9. data/lib/rscm/scm/accurev/api.rb +411 -0
  10. data/lib/rscm/scm/accurev/api.rb.mine +382 -0
  11. data/lib/rscm/scm/accurev/api.rb.r263 +364 -0
  12. data/lib/rscm/scm/accurev/api.rb.r265 +393 -0
  13. data/lib/rscm/scm/accurev/command.rb +151 -0
  14. data/lib/rscm/scm/accurev/exception.rb +38 -0
  15. data/lib/rscm/scm/accurev/filterio.rb +57 -0
  16. data/lib/rscm/scm/accurev/xml.rb +224 -0
  17. data/lib/test/unit/ui/xml/testrunner.rb +165 -0
  18. data/lib/test/unit/ui/xml/xmltestrunner.xslt +79 -0
  19. data/test/acreplay.rb +22 -0
  20. data/test/coverage/analyzer.rb +127 -0
  21. data/test/coverage/c_loader.rb +34 -0
  22. data/test/coverage/cover.rb +91 -0
  23. data/test/coverage/coverage_loader.rb +21 -0
  24. data/test/coverage/coveragetask.rb +38 -0
  25. data/test/coverage/index_tmpl.html +42 -0
  26. data/test/coverage/template.html +36 -0
  27. data/test/eg/ac-files.xml +172 -0
  28. data/test/eg/ac-pop.txt +195 -0
  29. data/test/eg/files-various-states.xml +188 -0
  30. data/test/eg/hist-oneweek-all.xml +1483 -0
  31. data/test/eg/hist-oneweek-external.xml +246 -0
  32. data/test/eg/hist-oneweek-promotes.xml +1092 -0
  33. data/test/eg/info.txt +14 -0
  34. data/test/eg/stat-a-various.xml +1789 -0
  35. data/test/eg/stat-m.xml +13 -0
  36. data/test/eg/stat-overlap.xml +13 -0
  37. data/test/eg/stat-x.xml +20 -0
  38. data/test/eg/update-i-mods-and-updates-and-overlap.xml +73 -0
  39. data/test/eg/update-i-nochanges.xml +8 -0
  40. data/test/eg/update-i-stale.xml +0 -0
  41. data/test/eg/update-i-updates.xml +125 -0
  42. data/test/eg/update-newwksp.xml +183 -0
  43. data/test/eg/update-nochanges.xml +7 -0
  44. data/test/eg/update-stale.xml +12 -0
  45. data/test/eg/update-updates.xml +147 -0
  46. data/test/t_api.rb +163 -0
  47. data/test/t_command.rb +85 -0
  48. data/test/t_filterio.rb +60 -0
  49. data/test/t_load.rb +11 -0
  50. data/test/t_scrubio.rb +117 -0
  51. data/test/t_xmlmapper.rb +75 -0
  52. metadata +106 -0
@@ -0,0 +1,38 @@
1
+ # -*- ruby -*-
2
+ #
3
+ # = exception.rb
4
+ #
5
+ # Exception classes for RSCM::Accurev
6
+ #
7
+ # Includes:
8
+ #
9
+ # * AccurevException
10
+ #
11
+ # * StaleWorkspaceException
12
+ #
13
+ module RSCM
14
+ module Accurev
15
+
16
+ #
17
+ # General exception class for errors processing commands.
18
+ #
19
+ # @attr error_msg Error message output by accurev.
20
+ #
21
+ class AccurevException < Exception
22
+ attr_reader :error_msg
23
+ def initialize( msg, error_msg=nil )
24
+ super( "#{msg}: #{error_msg}" )
25
+ @error_msg = error_msg
26
+ end
27
+ end
28
+
29
+ #
30
+ # Exception thrown when an update is performed
31
+ # on a workspace with unkept/unanchored modifications.
32
+ # Accurev requires that all modifications be handled before
33
+ # an update is performed.
34
+ #
35
+ class StaleWorkspaceException < AccurevException; end
36
+
37
+ end
38
+ end
@@ -0,0 +1,57 @@
1
+ require 'stringio'
2
+
3
+ module RSCM
4
+ module Accurev
5
+
6
+ #
7
+ # IO stream which cleans irregularities out of accurev xml output.
8
+ #
9
+ # In particular:
10
+ #
11
+ # * Unlike other commands, the +-fx+ output from _accurev update_
12
+ # has a root element of +<acResponse>+, not +<AcResponse>+.
13
+ #
14
+ # * _accurev update_ emits broken XML when there are no files
15
+ # to update.
16
+ #
17
+ class AcXMLScrubIO < StringIO
18
+
19
+ # @param: sourceio - io or string source to wrap
20
+ def initialize( sourceio )
21
+ if sourceio.respond_to?( :read )
22
+ super( clean( sourceio.read ) )
23
+ else
24
+ super( clean(sourceio) )
25
+ end
26
+ end
27
+
28
+ def clean( source )
29
+ File.open( "/tmp/scrubio.outA", "w" ).puts( source )
30
+ source.gsub!( /<acResponse/, "<AcResponse" )
31
+ source.gsub!( /<\/acResponse/, "<\/AcResponse" )
32
+ File.open( "/tmp/scrubio.outB", "w" ).puts( source )
33
+ source.gsub!( /command="update"[^>]*(>?)/, 'command="update"\1' )
34
+ File.open( "/tmp/scrubio.outC", "w" ).puts( source )
35
+ return source
36
+ end
37
+ end
38
+
39
+
40
+ #
41
+ # Simple filtering IO implementation.
42
+ #
43
+ # io = RSCM::Accurev::FilterIO.new( otherio ) do |string|
44
+ # string.gsub( "2", "fifty-one" )
45
+ # end
46
+ #
47
+ class FilterIO < StringIO
48
+ def initialize( sourceio, &filter )
49
+ str = filter.call( sourceio.read )
50
+ super( str )
51
+ end
52
+ end
53
+
54
+
55
+ end
56
+
57
+ end
@@ -0,0 +1,224 @@
1
+ module RSCM; module Accurev; end; end
2
+
3
+ require 'rexml/element'
4
+
5
+ module RSCM::Accurev
6
+
7
+ #
8
+ # XMLMapper creates an object tree from an XML element and its children.
9
+ #
10
+ # For each XML node, it locates a class associated with that node's name,
11
+ # and builds a new object of that type from the element.
12
+ #
13
+ # The nodename-class associations are determined by finding all
14
+ # classes derived from ElementBackedClass and checking
15
+ # each of those classes +element_name+ methods.
16
+ #
17
+ # See ElementBackedClass for examples.
18
+ #
19
+ class XMLMapper
20
+
21
+ # Map of element (tag) names to (ruby) class.
22
+ attr_accessor :classmap
23
+
24
+ def initialize()
25
+ @classmap = {}
26
+ ObjectSpace.each_object( Class ) do |k|
27
+ if k.ancestors.delete( ElementBackedClass ) and k != ElementBackedClass
28
+ if k.respond_to?( :element_name )
29
+ @classmap[ k.element_name ] = k
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ #
36
+ # Build an object tree from the given REXML element and its children.
37
+ # The returned object will be a subclass of +ElementBackedClass+.
38
+ #
39
+ def map( e )
40
+ unless @classmap.has_key?( e.name )
41
+ return nil
42
+ end
43
+ o = @classmap[e.name].new( e )
44
+ e.children.each do |child|
45
+ if child.kind_of?( REXML::Element )
46
+ a = self.map( child )
47
+ unless a.nil?
48
+ if o.children[ a.class.element_name ].nil?
49
+ o.children[ a.class.element_name ] = []
50
+ end
51
+ o.children[ a.class.element_name ] << a
52
+ end
53
+ end
54
+ end
55
+ return o
56
+ end
57
+ end
58
+
59
+ #
60
+ # Abstract base class for defining typed mirror classes for XML elements.
61
+ #
62
+ # A subclass of ElementBackedClass has:
63
+ #
64
+ # * A class static +element_name+ method, identifying what
65
+ # type of XML element it shadows
66
+ #
67
+ # * A set of attributes shadowing the XML attributes of its target element
68
+ #
69
+ # * A map (+children+) of child elements, keyed by element name
70
+ #
71
+ # * A (optional) +text_content+ attribute, populated when the
72
+ # target element has text subnodes.
73
+ #
74
+ # ---
75
+ #
76
+ # === Example
77
+ #
78
+ # For the XML element:
79
+ #
80
+ # <book title="The Monkey Wrench Gang" author="Edward Albee">
81
+ # <note>Lots of beer and dynamite</note>
82
+ # </book>
83
+ #
84
+ # You can define:
85
+ #
86
+ # class Book < ElementBackedClass
87
+ # element_name 'book'
88
+ # attr_accessor :title, :author
89
+ # end
90
+ #
91
+ # And then use XMLMapper to create instances:
92
+ #
93
+ # e = ...; # <book> node: REXML::Element
94
+ # book = XMLMapper.map(e)
95
+ # puts "Title: #{book.title}"
96
+ # puts "Author: #{book.author}"
97
+ # puts "Notes:"
98
+ # book['note'].each do |n|
99
+ # puts n.text_content
100
+ # end
101
+ #
102
+ class ElementBackedClass
103
+
104
+ attr_accessor :children
105
+
106
+ def self.element_name( name )
107
+ class << self
108
+ self
109
+ end.send( :define_method, "element_name" ) {name}
110
+ end
111
+
112
+ # currently advisory only
113
+ def self.children( *kidtypes )
114
+ # nothing XXX
115
+ end
116
+
117
+ def initialize( element=nil )
118
+ @children = {}
119
+ unless element.nil?
120
+ self.set_from_element(element)
121
+ end
122
+ end
123
+
124
+ # ebc['foo'] is a synonym for ebc.children['foo']
125
+ def []( key )
126
+ return self.children[key]
127
+ end
128
+
129
+ def to_s
130
+ s = "<#{self.class.element_name} "
131
+ self.instance_variables.each do |a|
132
+ unless a == "@children"
133
+ attr = a.sub( /^@/, "" )
134
+ s += "#{attr}='#{self.send(attr)}' "
135
+ end
136
+ end
137
+ s += "/>"
138
+ return s
139
+ end
140
+
141
+ protected
142
+ # Does the work of calling object setters for each XML attribute.
143
+ def set_from_element( e )
144
+ e.attributes.each do |attr, value|
145
+ # downcase the attr name for method-happiness
146
+ # (also hacks around some inconsistent accurev attr names...)
147
+ mattr = attr.downcase
148
+ if self.respond_to?( "#{mattr}=" )
149
+ self.send( "#{mattr}=", value )
150
+ end
151
+ end
152
+ if self.respond_to?( :text_content= ) and ! e.text.nil?
153
+ self.text_content = e.text
154
+ end
155
+ end
156
+
157
+ end
158
+
159
+ #
160
+ # Data from the typical AcResponse root node.
161
+ #
162
+ class AcResponseData < ElementBackedClass
163
+ element_name 'AcResponse'
164
+ attr_accessor :command, :directory
165
+
166
+ # Returns this response's error message, or nil if no error detected.
167
+ def error
168
+ if self.children['message']
169
+ zmsg = self.children['message'][0]
170
+ if zmsg.error and zmsg.error == 'true'
171
+ return zmsg.text_content
172
+ end
173
+ else
174
+ return nil
175
+ end
176
+ end
177
+ end
178
+
179
+ #
180
+ # Data from "accurev file", "accure update", "accurev stat" commands.
181
+ # Identifies workspace objects (files, directories, etc).
182
+ #
183
+ class ElementData < ElementBackedClass
184
+ element_name 'element'
185
+ attr_accessor :location, :status, :dir, :id
186
+ attr_accessor :elemType, :namedVersion, :virtual, :real
187
+ end
188
+
189
+ #
190
+ # Data from "accurev {file,update,stat}" commands.
191
+ # Streamed status/info messages, usually interleaved with ElementData
192
+ # nodes.
193
+ #
194
+ class MessageData < ElementBackedClass
195
+ element_name 'message'
196
+ attr_accessor :error, :text_content
197
+ end
198
+
199
+ #
200
+ # Version (element) records in a history transaction
201
+ #
202
+ class VersionData < ElementBackedClass
203
+ element_name 'version'
204
+ attr_accessor :path, :eid, :virtual, :real, :elem_type
205
+ end
206
+
207
+ #
208
+ # Commit messages on transactions
209
+ #
210
+ class CommentData < ElementBackedClass
211
+ element_name 'comment'
212
+ end
213
+
214
+ #
215
+ # Data from "accurev hist" - transaction groups
216
+ # Contains one or more VersionData.
217
+ #
218
+ class TransactionData < ElementBackedClass
219
+ element_name 'transaction'
220
+ children VersionData, CommentData
221
+ attr_accessor :id, :type, :time, :user
222
+ end
223
+
224
+ end
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit/ui/testrunnermediator'
4
+ require 'test/unit/ui/testrunnerutilities'
5
+ require 'test/unit/ui/console/testrunner'
6
+ require 'test/unit/autorunner'
7
+ require 'rexml/document'
8
+
9
+ module Test
10
+ module Unit
11
+ module UI
12
+ module XML
13
+
14
+ #
15
+ # XML::TestRunner - generate xml output for test results
16
+ #
17
+ # Example use:
18
+ #
19
+ # $ ruby -rtest/unit/ui/xml/testrunner test/test_1.rb --runner=xml
20
+ #
21
+ # By default, XML::TestRunner will output to stdout.
22
+ # You can set the environment variable $XMLTEST_OUTPUT to
23
+ # a filename to send the output to that file.
24
+ #
25
+ # The summary file created by this testrunner is XML, but
26
+ # this module also includes a stylesheet
27
+ # (test/unit/ui/xml/xmltestrunner.xslt) which converts it to
28
+ # HTML. Copy the XSLT file into the same directory as the
29
+ # test results file, and open the results file with a browser.
30
+ #
31
+ # ---
32
+ #
33
+ # (todo: use with rake)
34
+ #
35
+ class TestRunner < Test::Unit::UI::Console::TestRunner
36
+
37
+ def initialize( suite, output_level )
38
+ super( suite )
39
+ if ENV['XMLTEST_OUTPUT']
40
+ fn = ENV['XMLTEST_OUTPUT']
41
+ puts "Writing to #{fn}"
42
+ @io = File.open( fn, "w" )
43
+ @using_stdout = false
44
+ else
45
+ puts "Writing to stdout (along with everyone else...)"
46
+ @io = STDOUT
47
+ @using_stdout = true
48
+ end
49
+ create_document()
50
+ end
51
+
52
+ def create_document()
53
+ @doc = REXML::Document.new()
54
+ @doc << REXML::XMLDecl.new()
55
+
56
+ pi = REXML::Instruction.new(
57
+ "xml-stylesheet",
58
+ "type='text/xsl' href='xmltestrunner.xslt' "
59
+ )
60
+ @doc << pi
61
+
62
+ e = REXML::Element.new( "testsuite" )
63
+ e.attributes['rundate'] = Time.now
64
+ @doc << e
65
+ end
66
+
67
+ def to_s
68
+ @doc.to_s
69
+ end
70
+
71
+ def start
72
+ @current_test = nil
73
+ # setup_mediator
74
+ @mediator = TestRunnerMediator.new( @suite )
75
+ suite_name = @suite.to_s
76
+ if @suite.kind_of?(Module)
77
+ suite_name = @suite.name
78
+ end
79
+ @doc.root.attributes['name'] = suite_name
80
+ # attach_to_mediator - define callbacks
81
+ @mediator.add_listener( TestResult::FAULT,
82
+ &method(:add_fault) )
83
+ @mediator.add_listener( TestRunnerMediator::STARTED,
84
+ &method(:started) )
85
+ @mediator.add_listener( TestRunnerMediator::FINISHED,
86
+ &method(:finished) )
87
+ @mediator.add_listener( TestCase::STARTED,
88
+ &method(:test_started) )
89
+ @mediator.add_listener( TestCase::FINISHED,
90
+ &method(:test_finished) )
91
+ # return start_mediator
92
+ return @mediator.run_suite
93
+ end
94
+
95
+ # callbacks
96
+
97
+ def add_fault( fault )
98
+ ##STDERR.puts "Fault:"
99
+ @faults << fault
100
+ e = REXML::Element.new( "fault" )
101
+ e << REXML::CData.new( fault.long_display )
102
+ @current_test << e
103
+ end
104
+
105
+ def started( result )
106
+ #STDERR.puts "Started"
107
+ @result = result
108
+ end
109
+
110
+ def finished( elapsed_time )
111
+ #STDERR.puts "Finished"
112
+ res = REXML::Element.new( "result" )
113
+ summ = REXML::Element.new( "summary" )
114
+ summ.text = @result
115
+ res << summ
116
+ # @result is a Test::Unit::TestResults
117
+ res.attributes['passed'] = @result.passed?
118
+ res.attributes['testcount'] = @result.run_count
119
+ res.attributes['assertcount'] = @result.assertion_count
120
+ res.attributes['failures'] = @result.failure_count
121
+ res.attributes['errors'] = @result.error_count
122
+ @doc.root << res
123
+
124
+ e = REXML::Element.new( "elapsed-time" )
125
+ e.text = elapsed_time
126
+ @doc.root << e
127
+ @io.puts( @doc.to_s )
128
+
129
+ unless @using_stdout
130
+ puts @result
131
+ end
132
+ end
133
+
134
+ def test_started( name )
135
+ #STDERR.puts "Test: #{name} started"
136
+ e = REXML::Element.new( "test" )
137
+ e.attributes['name'] = name
138
+ #e.attributes['status'] = "failed"
139
+ @doc.root << e
140
+ @current_test = e
141
+ end
142
+
143
+ def test_finished( name )
144
+ #STDERR.puts "Test: #{name} finished"
145
+ # find //test[@name='name']
146
+ @current_test = nil
147
+ end
148
+
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
154
+
155
+ # "plug in" xmltestrunner into autorunner's list of known runners
156
+ # This enables the "--runner=xml" commandline option.
157
+ Test::Unit::AutoRunner::RUNNERS[:xml] = proc do |r|
158
+ require 'test/unit/ui/xml/testrunner'
159
+ Test::Unit::UI::XML::TestRunner
160
+ end
161
+
162
+ if __FILE__ == $0
163
+ Test::Unit::UI::XML::TestRunner.start_command_line_test
164
+ end
165
+