rscm-accurev 0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+