rscm-accurev 0.0.2 → 0.0.3

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.
data/TODO CHANGED
@@ -27,3 +27,4 @@ api - checkout(Time.infinite) just does update
27
27
  checkout(x) only works if ws not exist
28
28
  unless it implies nuke-and-re-checkout (slow)
29
29
 
30
+ api - need ac_update which returns an acresponse
data/lib/rscm/accurev.rb CHANGED
@@ -1,3 +1,4 @@
1
+ #!/usr/bin/env ruby
1
2
  require 'rubygems'
2
3
  require 'rscm/scm/accurev/api'
3
4
  require 'rscm/scm/accurev/command'
@@ -13,10 +13,15 @@ end
13
13
 
14
14
  module RSCM::Accurev
15
15
 
16
- class AccurevException < Exception ; end
16
+ class AccurevException < Exception
17
+ attr_reader :error_msg
18
+ def initialize( msg, error_msg=nil )
19
+ super( "#{msg}: #{error_msg}" )
20
+ @error_msg = error_msg
21
+ end
22
+ end
17
23
 
18
- # Indicates a failure of the update command due to unkept local modifications
19
- class StaleWorkspaceError < AccurevException; end
24
+ class StaleWorkspaceException < AccurevException; end
20
25
 
21
26
  # RSCM implementation for Accurev (http://www.accurev.com/).
22
27
  #
@@ -52,9 +57,9 @@ module RSCM::Accurev
52
57
 
53
58
  def initialize( checkout_dir=nil, depot=nil, workspace_stream=nil )
54
59
  @depot = depot
55
- @checkout_dir = checkout_dir
56
60
  @workspace_stream = workspace_stream
57
61
  @backing_stream = nil # will be pulled from files cmd output
62
+ @checkout_dir = checkout_dir
58
63
  end
59
64
 
60
65
  def name()
@@ -99,13 +104,13 @@ module RSCM::Accurev
99
104
 
100
105
  def ac_files( relative_path )
101
106
  cmd = Command.instance
102
- # there must be a better way to do this yield->yield loopage
103
- obj = []
104
- cmd.accurev_elements( StatData, "files", relative_path ) do |fd|
107
+ ret = []
108
+ acresponse = cmd.accurev( "files", relative_path )
109
+ acresponse['element'].each do |fd|
105
110
  yield fd if block_given?
106
- obj << fd
111
+ ret << fd
107
112
  end
108
- return obj
113
+ return ret
109
114
  end
110
115
 
111
116
  def ac_keep( files=[], message="" )
@@ -187,7 +192,7 @@ module RSCM::Accurev
187
192
  "-l", co )
188
193
  # sucks:
189
194
  if ( mkws_out =~ /already exists/ )
190
- raise AccurevException.new( mkws_out )
195
+ raise AccurevException.new( "Failed to checkout", mkws_out )
191
196
  end
192
197
  end
193
198
  puts "> Updating workspace.."
@@ -195,21 +200,33 @@ module RSCM::Accurev
195
200
  end
196
201
 
197
202
  def update( to_identifier=Time.infinite )
198
- co = PathConverter.nativepath_to_filepath( @checkout_dir )
203
+ co = RSCM::PathConverter.nativepath_to_filepath( @checkout_dir )
199
204
  unless File.exists?( co )
200
205
  raise AccurevException.new( "Workspace does not exist!" )
201
206
  end
202
207
  updated = []
203
- with_working_dir( co ) do
204
- accurev_elements( UpdateData, "update" ) do |up|
205
- yield up.location
206
- updated << up.location
208
+ Command.instance do |cmd|
209
+ cmd.working_dir = co
210
+ acresponse = cmd.accurev( "update" )
211
+ if acresponse.error
212
+ if acresponse.error =~ /workspace have been modified/
213
+ raise StaleWorkspaceException.new( "Workspace stale",
214
+ acresponse.error )
215
+ else
216
+ # some other update problem
217
+ raise AccurevException.new( "Error on update", acresponse.error )
218
+ end
219
+ end
220
+ if acresponse['element']
221
+ acresponse['element'].each do |up|
222
+ yield up.location if block_given?
223
+ updated << up.location
224
+ end
207
225
  end
208
226
  end
209
227
  return updated
210
228
  end
211
229
 
212
-
213
230
  # --- internals
214
231
 
215
232
  private
@@ -10,27 +10,36 @@ module RSCM
10
10
  #
11
11
  class Command
12
12
 
13
- attr_accessor :debug, :debug_to, :accurev, :working_dir
13
+ attr_accessor :debug, :debug_to, :accurev_bin, :working_dir
14
14
 
15
- # map of xml element types to classes
16
- # used by accurev_element to return a list of objects
17
- attr_accessor :classmap
15
+ # If you need to swap out the mapper class
16
+ attr_accessor :xmlmapper
18
17
 
19
18
  def initialize()
19
+ @xmlmapper = XMLMapper
20
20
  @debug = false
21
21
  @debug_to = STDOUT
22
- @accurev = "accurev"
22
+ @accurev_bin = "accurev"
23
23
  @working_dir = "."
24
24
  end
25
25
 
26
+ #
27
+ # Returns a command line string for executing the given
28
+ # accurev subcomment +cmd+ with arguments +opts+.
29
+ #
26
30
  def accurev_cmdline( cmd, *opts )
27
- return "#{@accurev} #{cmd} #{opts.join(' ')}";
31
+ return "#{@accurev_bin} #{cmd} #{opts.join(' ')}";
28
32
  end
29
-
30
- # Execute the given accurev subcommand, and return its
31
- # output as a plain uninterpreted string.
32
- # Not all accurev subcommands (eg, `accurev info`) support
33
- # `-fx` for xml output.
33
+
34
+ #
35
+ # Executes the given accurev subcommand +cmd+ with the
36
+ # given arguments +opts+. The command will be executed with
37
+ # standard (non-xml) output format. This method returns
38
+ # the stdout from the command execution.
39
+ #
40
+ # (Not all accurev subcommands (eg, `accurev info`) support
41
+ # `-fx` for xml output.)
42
+ #
34
43
  def accurev_nofx( cmd, *opts )
35
44
  # nativepath_to_filepath is actually generic to native
36
45
  dir = PathConverter.nativepath_to_filepath( @working_dir )
@@ -45,13 +54,19 @@ module RSCM
45
54
  end
46
55
  end
47
56
  end
48
-
49
- # Execute the given accurev subcommand, and return its
50
- # output as an REXML document. The options list to the command
51
- # will automatically have `-fx` prepended, to specify xml output.
57
+
58
+ #
59
+ # Executes the given accurev subcommand +cmd+ with the
60
+ # given arguments +opts+ in XML mode. The output of the command
61
+ # will be converted to an REXML document and returned.
62
+ # The command's options list will have `-fx` appended,
63
+ # to specify xml output format.
64
+ #
52
65
  # Certain quirks in <AcResponse>-type documents will be
53
- # corrected (see Accurev::AcXMLScrubIO).
54
- def accurev( cmd, *opts )
66
+ # corrected (see Accurev::AcXMLScrubIO). Note that not all
67
+ # accurev subcommands support the "-fx" option.
68
+ #
69
+ def accurev_xml( cmd, *opts )
55
70
  # nativepath_to_filepath is actually generic to native
56
71
  dir = PathConverter.nativepath_to_filepath( @working_dir )
57
72
  dir = File.expand_path( dir )
@@ -64,7 +79,8 @@ module RSCM
64
79
  Better.popen( cmdline ) do |stdout|
65
80
  output = stdout.read()
66
81
  if @debug
67
- @debug_to.puts( "raw>\n#{output}" )
82
+ @debug_to.puts( "raw>" )
83
+ @debug_to.puts( output )
68
84
  end
69
85
  begin
70
86
  return REXML::Document.new( AcXMLScrubIO.new( output ) )
@@ -75,27 +91,28 @@ module RSCM
75
91
  end
76
92
  end
77
93
 
78
- # Execute the given accurev subcommand using +accurev+,
79
- # and return the <element> REXML elements from the
80
- # resulting document.
81
- # For ac commands which emit the common <elements> format.
82
- def accurev_elements( mapclass, cmd, *opts )
83
- doc = self.accurev( cmd, opts )
94
+ #
95
+ # Execute the given accurev subcommand using +accurev_xml+,
96
+ # and return an object tree mirroring the structure of the
97
+ # XML output.
98
+ #
99
+ # This uses +XMLMapper+ to build the object tree.
100
+ #
101
+ def accurev( cmd, *opts )
102
+ doc = self.accurev_xml( cmd, opts )
84
103
  if @debug
104
+ @debug_to.puts( "doc>" )
85
105
  @debug_to.puts( doc )
86
106
  end
87
107
  if doc.elements.size==0
88
108
  raise "Unexpected output from #{cmd}: #{doc}"
89
109
  end
90
- objs = []
91
- doc.elements.each( "/AcResponse/element" ) do |e|
92
- o = mapclass.new( e )
93
- yield o if block_given?
94
- objs << o
95
- end
96
- return objs
110
+ mapper = @xmlmapper.new()
111
+ return mapper.map( doc.root )
97
112
  end
98
113
 
114
+ # static methods
115
+
99
116
  # Retrieve this thread's +Command+ instance.
100
117
  #
101
118
  # eg:
@@ -120,8 +137,9 @@ module RSCM
120
137
  Thread.current[ :RSCM_ACCUREV_COMMAND ] = nil
121
138
  end
122
139
 
140
+ private
141
+
123
142
  # new() is marked private, use Command.instance().
124
- private
125
143
  def new( *args )
126
144
  super(args)
127
145
  end
@@ -1,36 +1,152 @@
1
1
  module RSCM; module Accurev; end; end
2
2
 
3
+ require 'rexml/element'
4
+
3
5
  module RSCM::Accurev
4
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 +RSCM::Accurev::ElementBackedClass+ and checking
15
+ # each of those classes +element_name+ methods.
16
+ #
17
+ class XMLMapper
18
+
19
+ # Map of element (tag) names to (ruby) class.
20
+ attr_accessor :classmap
21
+
22
+ def initialize()
23
+ @classmap = {}
24
+ ObjectSpace.each_object( Class ) do |k|
25
+ if k.ancestors.delete( ElementBackedClass ) and k != ElementBackedClass
26
+ if k.respond_to?( :element_name )
27
+ @classmap[ k.element_name ] = k
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ #
34
+ # Build an object tree from the given REXML element and its children.
35
+ # The returned object will be a subclass of +ElementBackedClass+.
36
+ #
37
+ def map( e )
38
+ unless @classmap.has_key?( e.name )
39
+ return nil
40
+ end
41
+ o = @classmap[e.name].new( e )
42
+ e.children.each do |child|
43
+ if child.kind_of?( REXML::Element )
44
+ a = self.map( child )
45
+ unless a.nil?
46
+ if o.children[ a.class.element_name ].nil?
47
+ o.children[ a.class.element_name ] = []
48
+ end
49
+ o.children[ a.class.element_name ] << a
50
+ end
51
+ end
52
+ end
53
+ return o
54
+ end
55
+ end
56
+
57
+ #
58
+ # Generic base class for defining typed mirror classes for XML elements.
59
+ #
60
+ # A subclass of ElementBackedClass has:
61
+ #
62
+ # * A class static +element_name+ method, identifying what
63
+ # type of XML element it shadows
64
+ #
65
+ # * A set of attributes shadowing the XML attributes of its target element
66
+ #
67
+ # * A map (+children+) of child elements, keyed by element name
68
+ #
69
+ # * A (optional) +text_content+ attribute, populated when the
70
+ # target element has text subnodes.
71
+ #
5
72
  class ElementBackedClass
73
+
74
+ attr_accessor :children
75
+
6
76
  def self.element_name( name )
7
- @@name = name # this doesn't do what i think it does
77
+ class << self
78
+ self
79
+ end.send( :define_method, "element_name" ) {name}
8
80
  end
81
+
9
82
  def initialize( element=nil )
83
+ @children = {}
10
84
  unless element.nil?
11
85
  self.set_from_element(element)
12
86
  end
13
87
  end
88
+
89
+ # ebc['foo'] is a synonym for ebc.children['foo']
90
+ def []( key )
91
+ return self.children[key]
92
+ end
93
+
94
+ protected
95
+ # Does the work of calling object setters for each XML attribute.
14
96
  def set_from_element( e )
15
97
  e.attributes.each do |attr, value|
16
- if self.respond_to?( "#{attr}=" )
17
- self.send( "#{attr}=", value )
98
+ # downcase the attr name for method-happiness
99
+ # (also hacks around some inconsistent accurev attr names...)
100
+ mattr = attr.downcase
101
+ if self.respond_to?( "#{mattr}=" )
102
+ self.send( "#{mattr}=", value )
18
103
  end
19
104
  end
105
+ if self.respond_to?( :text_content= ) and ! e.text.nil?
106
+ self.text_content = e.text
107
+ end
108
+ end
109
+
110
+ end
111
+
112
+ #
113
+ # Data from the typical AcResponse root node.
114
+ #
115
+ class AcResponseData < ElementBackedClass
116
+ element_name 'AcResponse'
117
+ attr_accessor :command, :directory
118
+
119
+ # Returns this response's error message, or nil if no error detected.
120
+ def error
121
+ if self.children['message']
122
+ zmsg = self.children['message'][0]
123
+ if zmsg.error and zmsg.error == 'true'
124
+ return zmsg.text_content
125
+ end
126
+ else
127
+ return nil
128
+ end
20
129
  end
21
130
  end
22
131
 
23
- # Data from "accurev file" command:
24
- class StatData < ElementBackedClass
132
+ #
133
+ # Data from "accurev file", "accure update", "accurev stat" commands.
134
+ # Identifies workspace objects (files, directories, etc).
135
+ #
136
+ class ElementData < ElementBackedClass
25
137
  element_name 'element'
26
138
  attr_accessor :location, :status, :dir, :id
27
- attr_accessor :elemType, :namedVersion, :Virtual, :Real
139
+ attr_accessor :elemType, :namedVersion, :virtual, :real
28
140
  end
29
-
30
- # Data from "accurev update" command:
31
- class UpdateData < ElementBackedClass
32
- element_name 'element'
33
- attr_accessor :location
141
+
142
+ #
143
+ # Data from "accurev {file,update,stat}" commands.
144
+ # Streamed status/info messages, usually interleaved with ElementData
145
+ # nodes.
146
+ #
147
+ class MessageData < ElementBackedClass
148
+ element_name 'message'
149
+ attr_accessor :error, :text_content
34
150
  end
35
-
151
+
36
152
  end
@@ -0,0 +1,8 @@
1
+ <acResponse
2
+ command="update"Scanning entire workspace for files touched since last scan - ok
3
+ >
4
+ <progress
5
+ phase="Calculating changes"
6
+ increment="100"/>
7
+ <message>Transaction high-water mark would be updated</message>
8
+ </acResponse>
@@ -0,0 +1,125 @@
1
+ <acResponse
2
+ command="update"Scanning entire workspace for files touched since last scan - ok
3
+ >
4
+ <progress
5
+ phase="Calculating changes"
6
+ increment="100"/>
7
+ <progress
8
+ phase="results"
9
+ number="23"/>
10
+ <message>Would remove &quot;src/java/com/orbitz/dc/service/hc/HcItinerary.java&quot; .
11
+ </message>
12
+ <element
13
+ location="src/java/com/orbitz/dc/service/hc/HcItinerary.java"/>
14
+ <checkpoint/>
15
+ <message>Would replace content of &quot;src/java/com/orbitz/dc/core/Pricing.java&quot; .
16
+ </message>
17
+ <element
18
+ location="src/java/com/orbitz/dc/core/Pricing.java"/>
19
+ <checkpoint/>
20
+ <message>Would replace content of &quot;src/java/com/orbitz/dc/service/hc/HcSearchRequest.java&quot; .
21
+ </message>
22
+ <element
23
+ location="src/java/com/orbitz/dc/service/hc/HcSearchRequest.java"/>
24
+ <checkpoint/>
25
+ <message>Would replace content of &quot;src/java/com/orbitz/dc/service/hc/HcCreateReservationRequest.java&quot; .
26
+ </message>
27
+ <element
28
+ location="src/java/com/orbitz/dc/service/hc/HcCreateReservationRequest.java"/>
29
+ <checkpoint/>
30
+ <message>Would replace content of &quot;src/java/com/orbitz/dc/core/HcJourney.java&quot; .
31
+ </message>
32
+ <element
33
+ location="src/java/com/orbitz/dc/core/HcJourney.java"/>
34
+ <checkpoint/>
35
+ <message>Would replace content of &quot;src/java/com/orbitz/dc/service/hc/HcCreateReservationResponse.java&quot; .
36
+ </message>
37
+ <element
38
+ location="src/java/com/orbitz/dc/service/hc/HcCreateReservationResponse.java"/>
39
+ <checkpoint/>
40
+ <message>Would replace content of &quot;src/java/com/orbitz/dc/service/hc/HcCancelReservationRequest.java&quot; .
41
+ </message>
42
+ <element
43
+ location="src/java/com/orbitz/dc/service/hc/HcCancelReservationRequest.java"/>
44
+ <checkpoint/>
45
+ <message>Would replace content of &quot;src/java/com/orbitz/dc/service/hc/HcCancelReservationResponse.java&quot; .
46
+ </message>
47
+ <element
48
+ location="src/java/com/orbitz/dc/service/hc/HcCancelReservationResponse.java"/>
49
+ <checkpoint/>
50
+ <message>Would replace content of &quot;src/java/com/orbitz/dc/service/hc/HcModifyReservationResponse.java&quot; .
51
+ </message>
52
+ <element
53
+ location="src/java/com/orbitz/dc/service/hc/HcModifyReservationResponse.java"/>
54
+ <checkpoint/>
55
+ <message>Would replace content of &quot;src/java/com/orbitz/dc/service/hc/HcModifyReservationRequest.java&quot; .
56
+ </message>
57
+ <element
58
+ location="src/java/com/orbitz/dc/service/hc/HcModifyReservationRequest.java"/>
59
+ <checkpoint/>
60
+ <message>Would replace content of &quot;src/java/com/orbitz/dc/core/RateInfo.java&quot; .
61
+ </message>
62
+ <element
63
+ location="src/java/com/orbitz/dc/core/RateInfo.java"/>
64
+ <checkpoint/>
65
+ <message>Would replace content of &quot;src/java/com/orbitz/dc/core/VariableRateInfo.java&quot; .
66
+ </message>
67
+ <element
68
+ location="src/java/com/orbitz/dc/core/VariableRateInfo.java"/>
69
+ <checkpoint/>
70
+ <message>Would replace content of &quot;src/java/com/orbitz/dc/core/RATE_CATEGORY.java&quot; .
71
+ </message>
72
+ <element
73
+ location="src/java/com/orbitz/dc/core/RATE_CATEGORY.java"/>
74
+ <checkpoint/>
75
+ <message>Would replace content of &quot;src/java/com/orbitz/dc/core/RATE_COVERAGE.java&quot; .
76
+ </message>
77
+ <element
78
+ location="src/java/com/orbitz/dc/core/RATE_COVERAGE.java"/>
79
+ <checkpoint/>
80
+ <message>Would replace content of &quot;src/java/com/orbitz/dc/core/FlatRateInfo.java&quot; .
81
+ </message>
82
+ <element
83
+ location="src/java/com/orbitz/dc/core/FlatRateInfo.java"/>
84
+ <checkpoint/>
85
+ <message>Would replace content of &quot;src/java/com/orbitz/dc/core/HcItinerary.java&quot; .
86
+ </message>
87
+ <element
88
+ location="src/java/com/orbitz/dc/core/HcItinerary.java"/>
89
+ <checkpoint/>
90
+ <message>Would replace content of &quot;src/java/com/orbitz/dc/service/hc/HcSearch.java&quot; .
91
+ </message>
92
+ <element
93
+ location="src/java/com/orbitz/dc/service/hc/HcSearch.java"/>
94
+ <checkpoint/>
95
+ <message>Would replace content of &quot;src/java/com/orbitz/dc/service/hc/HcCreateReservation.java&quot; .
96
+ </message>
97
+ <element
98
+ location="src/java/com/orbitz/dc/service/hc/HcCreateReservation.java"/>
99
+ <checkpoint/>
100
+ <message>Would replace content of &quot;src/java/com/orbitz/dc/service/hc/HcModifyReservation.java&quot; .
101
+ </message>
102
+ <element
103
+ location="src/java/com/orbitz/dc/service/hc/HcModifyReservation.java"/>
104
+ <checkpoint/>
105
+ <message>Would replace content of &quot;src/java/com/orbitz/dc/service/hc/HcCancelReservation.java&quot; .
106
+ </message>
107
+ <element
108
+ location="src/java/com/orbitz/dc/service/hc/HcCancelReservation.java"/>
109
+ <checkpoint/>
110
+ <message>Would replace content of &quot;src/java/com/orbitz/dc/service/hc/HcRetrieveItinerary.java&quot; .
111
+ </message>
112
+ <element
113
+ location="src/java/com/orbitz/dc/service/hc/HcRetrieveItinerary.java"/>
114
+ <checkpoint/>
115
+ <message>Would replace content of &quot;src/java/com/orbitz/dc/service/hc/HcRetrieveItineraryRequest.java&quot; .
116
+ </message>
117
+ <element
118
+ location="src/java/com/orbitz/dc/service/hc/HcRetrieveItineraryRequest.java"/>
119
+ <checkpoint/>
120
+ <message>Would replace content of &quot;src/java/com/orbitz/dc/service/hc/HcRetrieveItineraryResponse.java&quot; .
121
+ </message>
122
+ <element
123
+ location="src/java/com/orbitz/dc/service/hc/HcRetrieveItineraryResponse.java"/>
124
+ <checkpoint/>
125
+ </acResponse>
@@ -0,0 +1,7 @@
1
+ <acResponse
2
+ command="update"Scanning entire workspace for files touched since last scan - ok
3
+ >
4
+ <progress
5
+ phase="Calculating changes"
6
+ increment="100"/>
7
+ </acResponse>
@@ -0,0 +1,147 @@
1
+ <acResponse
2
+ command="update"Scanning entire workspace for files touched since last scan - ok
3
+ >
4
+ <progress
5
+ phase="Calculating changes"
6
+ increment="100"/>
7
+ <progress
8
+ phase="results"
9
+ number="23"/>
10
+ <message>Removing &quot;src/java/com/orbitz/dc/service/hc/HcItinerary.java&quot; .
11
+ </message>
12
+ <element
13
+ location="src/java/com/orbitz/dc/service/hc/HcItinerary.java"/>
14
+ <checkpoint/>
15
+ <message>Content (1 K) of &quot;src/java/com/orbitz/dc/core/Pricing.java&quot; - ok
16
+ </message>
17
+ <element
18
+ location="src/java/com/orbitz/dc/core/Pricing.java"
19
+ size="1398"/>
20
+ <checkpoint/>
21
+ <message>Content (1 K) of &quot;src/java/com/orbitz/dc/service/hc/HcSearchRequest.java&quot; - ok
22
+ </message>
23
+ <element
24
+ location="src/java/com/orbitz/dc/service/hc/HcSearchRequest.java"
25
+ size="793"/>
26
+ <checkpoint/>
27
+ <message>Content (1 K) of &quot;src/java/com/orbitz/dc/service/hc/HcCreateReservationRequest.java&quot; - ok
28
+ </message>
29
+ <element
30
+ location="src/java/com/orbitz/dc/service/hc/HcCreateReservationRequest.java"
31
+ size="1712"/>
32
+ <checkpoint/>
33
+ <message>Content (3 K) of &quot;src/java/com/orbitz/dc/core/HcJourney.java&quot; - ok
34
+ </message>
35
+ <element
36
+ location="src/java/com/orbitz/dc/core/HcJourney.java"
37
+ size="3846"/>
38
+ <checkpoint/>
39
+ <message>Content (1 K) of &quot;src/java/com/orbitz/dc/service/hc/HcCreateReservationResponse.java&quot; - ok
40
+ </message>
41
+ <element
42
+ location="src/java/com/orbitz/dc/service/hc/HcCreateReservationResponse.java"
43
+ size="849"/>
44
+ <checkpoint/>
45
+ <message>Content (3 K) of &quot;src/java/com/orbitz/dc/service/hc/HcCancelReservationRequest.java&quot; - ok
46
+ </message>
47
+ <element
48
+ location="src/java/com/orbitz/dc/service/hc/HcCancelReservationRequest.java"
49
+ size="3046"/>
50
+ <checkpoint/>
51
+ <message>Content (1 K) of &quot;src/java/com/orbitz/dc/service/hc/HcCancelReservationResponse.java&quot; - ok
52
+ </message>
53
+ <element
54
+ location="src/java/com/orbitz/dc/service/hc/HcCancelReservationResponse.java"
55
+ size="756"/>
56
+ <checkpoint/>
57
+ <message>Content (1 K) of &quot;src/java/com/orbitz/dc/service/hc/HcModifyReservationResponse.java&quot; - ok
58
+ </message>
59
+ <element
60
+ location="src/java/com/orbitz/dc/service/hc/HcModifyReservationResponse.java"
61
+ size="849"/>
62
+ <checkpoint/>
63
+ <message>Content (1 K) of &quot;src/java/com/orbitz/dc/service/hc/HcModifyReservationRequest.java&quot; - ok
64
+ </message>
65
+ <element
66
+ location="src/java/com/orbitz/dc/service/hc/HcModifyReservationRequest.java"
67
+ size="1806"/>
68
+ <checkpoint/>
69
+ <message>Content (3 K) of &quot;src/java/com/orbitz/dc/core/RateInfo.java&quot; - ok
70
+ </message>
71
+ <element
72
+ location="src/java/com/orbitz/dc/core/RateInfo.java"
73
+ size="3495"/>
74
+ <checkpoint/>
75
+ <message>Content (2 K) of &quot;src/java/com/orbitz/dc/core/VariableRateInfo.java&quot; - ok
76
+ </message>
77
+ <element
78
+ location="src/java/com/orbitz/dc/core/VariableRateInfo.java"
79
+ size="2523"/>
80
+ <checkpoint/>
81
+ <message>Content (2 K) of &quot;src/java/com/orbitz/dc/core/RATE_CATEGORY.java&quot; - ok
82
+ </message>
83
+ <element
84
+ location="src/java/com/orbitz/dc/core/RATE_CATEGORY.java"
85
+ size="2513"/>
86
+ <checkpoint/>
87
+ <message>Content (2 K) of &quot;src/java/com/orbitz/dc/core/RATE_COVERAGE.java&quot; - ok
88
+ </message>
89
+ <element
90
+ location="src/java/com/orbitz/dc/core/RATE_COVERAGE.java"
91
+ size="2537"/>
92
+ <checkpoint/>
93
+ <message>Content (1 K) of &quot;src/java/com/orbitz/dc/core/FlatRateInfo.java&quot; - ok
94
+ </message>
95
+ <element
96
+ location="src/java/com/orbitz/dc/core/FlatRateInfo.java"
97
+ size="975"/>
98
+ <checkpoint/>
99
+ <message>Content (2 K) of &quot;src/java/com/orbitz/dc/core/HcItinerary.java&quot; - ok
100
+ </message>
101
+ <element
102
+ location="src/java/com/orbitz/dc/core/HcItinerary.java"
103
+ size="2707"/>
104
+ <checkpoint/>
105
+ <message>Content (1 K) of &quot;src/java/com/orbitz/dc/service/hc/HcSearch.java&quot; - ok
106
+ </message>
107
+ <element
108
+ location="src/java/com/orbitz/dc/service/hc/HcSearch.java"
109
+ size="1123"/>
110
+ <checkpoint/>
111
+ <message>Content (1 K) of &quot;src/java/com/orbitz/dc/service/hc/HcCreateReservation.java&quot; - ok
112
+ </message>
113
+ <element
114
+ location="src/java/com/orbitz/dc/service/hc/HcCreateReservation.java"
115
+ size="1146"/>
116
+ <checkpoint/>
117
+ <message>Content (1 K) of &quot;src/java/com/orbitz/dc/service/hc/HcModifyReservation.java&quot; - ok
118
+ </message>
119
+ <element
120
+ location="src/java/com/orbitz/dc/service/hc/HcModifyReservation.java"
121
+ size="1156"/>
122
+ <checkpoint/>
123
+ <message>Content (1 K) of &quot;src/java/com/orbitz/dc/service/hc/HcCancelReservation.java&quot; - ok
124
+ </message>
125
+ <element
126
+ location="src/java/com/orbitz/dc/service/hc/HcCancelReservation.java"
127
+ size="1150"/>
128
+ <checkpoint/>
129
+ <message>Content (1 K) of &quot;src/java/com/orbitz/dc/service/hc/HcRetrieveItinerary.java&quot; - ok
130
+ </message>
131
+ <element
132
+ location="src/java/com/orbitz/dc/service/hc/HcRetrieveItinerary.java"
133
+ size="1150"/>
134
+ <checkpoint/>
135
+ <message>Content (1 K) of &quot;src/java/com/orbitz/dc/service/hc/HcRetrieveItineraryRequest.java&quot; - ok
136
+ </message>
137
+ <element
138
+ location="src/java/com/orbitz/dc/service/hc/HcRetrieveItineraryRequest.java"
139
+ size="1477"/>
140
+ <checkpoint/>
141
+ <message>Content (1 K) of &quot;src/java/com/orbitz/dc/service/hc/HcRetrieveItineraryResponse.java&quot; - ok
142
+ </message>
143
+ <element
144
+ location="src/java/com/orbitz/dc/service/hc/HcRetrieveItineraryResponse.java"
145
+ size="756"/>
146
+ <checkpoint/>
147
+ </acResponse>
data/test/t_api.rb CHANGED
@@ -9,7 +9,7 @@ class AccurevAPITest < Test::Unit::TestCase
9
9
  def test_ac_files()
10
10
  Command.instance do |cmd|
11
11
  cmd.working_dir = "test"
12
- cmd.accurev = "./acreplay.rb eg/ac-files.xml"
12
+ cmd.accurev_bin = "./acreplay.rb eg/ac-files.xml"
13
13
  end
14
14
  api = API.new( ".", "test-bogus-depot", "test-bogus-depot-0-impl" )
15
15
  # test array returns
@@ -28,11 +28,49 @@ class AccurevAPITest < Test::Unit::TestCase
28
28
  assert_equal( count, 23 )
29
29
  end
30
30
 
31
- def test_update()
31
+ def test_update_stale()
32
32
  Command.instance do |cmd|
33
- cmd.working_dir = "test"
34
- cmd.accurev = "./acreplay.rb eg/update-stale.xml"
33
+ cmd.accurev_bin = "./acreplay.rb eg/update-stale.xml"
34
+ end
35
+ api = API.new( "test", "test-bogus-depot", "test-bogus-depot-0-impl" )
36
+ begin
37
+ u_elements = api.update()
38
+ flunk( "Simulated update with stale data should throw exception" )
39
+ rescue StaleWorkspaceException => e
40
+ assert( true, "Caught expected exception" )
41
+ assert( e.error_msg =~ /workspace have been modified/ )
42
+ end
43
+ end
44
+
45
+ def test_update_nochanges()
46
+ Command.instance do |cmd|
47
+ cmd.accurev_bin = "./acreplay.rb eg/update-nochanges.xml"
48
+ end
49
+ api = API.new( "test", "test-bogus-depot", "test-bogus-depot-0-impl" )
50
+ u_elements = api.update()
51
+ assert_not_nil( u_elements )
52
+ assert( u_elements.size == 0 )
53
+ end
54
+
55
+ def test_update_newwksp()
56
+ Command.instance do |cmd|
57
+ cmd.accurev_bin = "./acreplay.rb eg/update-newwksp.xml"
58
+ end
59
+ api = API.new( "test", "test-bogus-depot", "test-bogus-depot-0-impl" )
60
+ u_elements = api.update()
61
+ assert_not_nil( u_elements )
62
+ assert_equal( 44, u_elements.length )
63
+ u_elements.each do |location|
64
+ # api.update returns a list of relative filenames
65
+ assert( location =~ /^\// )
66
+ end
67
+ # test yield and array return XXX
68
+ updated = 0
69
+ api.update().each do |location|
70
+ updated += 1
71
+ assert( location =~ /^\// )
35
72
  end
73
+ assert_equal( 44, updated )
36
74
  end
37
75
 
38
76
  end
data/test/t_command.rb CHANGED
@@ -13,7 +13,7 @@ class CommandTest < Test::Unit::TestCase
13
13
  s = cmd.accurev_cmdline( "foo", "bar" )
14
14
  assert_equal( "accurev foo bar", s )
15
15
 
16
- cmd.accurev = "xyzzy"
16
+ cmd.accurev_bin = "xyzzy"
17
17
 
18
18
  s = cmd.accurev_cmdline( "foo", "bar" )
19
19
  assert_equal( "xyzzy foo bar", s )
@@ -24,22 +24,18 @@ class CommandTest < Test::Unit::TestCase
24
24
  def test_a_e
25
25
  cmd = Command.instance
26
26
  cmd.working_dir = "test"
27
- #cmd.debug = true
28
- #cmd.debug_to = File.open( "testing.log", "w" )
29
- cmd.accurev = "./acreplay.rb eg/update-newwksp.xml"
27
+ cmd.debug = true
28
+ cmd.debug_to = File.open( "/tmp/testing.log", "w" )
29
+ cmd.accurev_bin = "./acreplay.rb eg/update-newwksp.xml"
30
30
  # test listy output
31
- list = cmd.accurev_elements( RSCM::Accurev::StatData, "files" )
32
- assert( list.size > 0 )
33
- list.each do |fd|
34
- assert( fd.respond_to?( :location ) )
31
+ acresponse = cmd.accurev( "files" )
32
+ assert_not_nil( acresponse )
33
+ assert( acresponse.kind_of?( AcResponseData ) )
34
+ assert( acresponse['element'].size == 44 )
35
+ assert( acresponse['message'].size == 44 )
36
+ acresponse['element'].each do |e|
37
+ assert( e.kind_of?( ElementData ) )
35
38
  end
36
- # test yieldy output
37
- got_any = false
38
- cmd.accurev_elements( RSCM::Accurev::StatData, "files" ) do |fd|
39
- got_any = true
40
- assert( fd.respond_to?( :location ) )
41
- end
42
- assert( got_any )
43
39
  Command.discard
44
40
  end
45
41
 
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+ require 'stringio'
4
+ require 'rexml/document'
5
+ require 'rscm/scm/accurev/xml'
6
+ include REXML
7
+ include RSCM::Accurev
8
+
9
+ class ReadQueue < ElementBackedClass
10
+ element_name 'readqueue'
11
+ attr_accessor :owner
12
+ end
13
+
14
+ class Book < ElementBackedClass
15
+ element_name 'book'
16
+ attr_accessor :title, :author
17
+ end
18
+
19
+ class Paper < ElementBackedClass
20
+ element_name 'paper'
21
+ attr_accessor :uri
22
+ end
23
+
24
+ class Note < ElementBackedClass
25
+ element_name 'note'
26
+ attr_accessor :text, :text_content
27
+ end
28
+
29
+ INPUT = <<-EOI
30
+ <?xml version="1.0"?>
31
+ <readqueue owner="gdf">
32
+ <book title="Iron Council" author="China Mieville" />
33
+ <paper uri="http://svk.elixus.org?SVKTutorial">
34
+ <note text="re-read" />
35
+ </paper>
36
+ <book title="Someone Comes to Town, Someone Leaves Town"
37
+ author="Cory Doctorow" />
38
+ <book title="Concurrent Programming in Java" author="Doug Lea">
39
+ <note>Need Brains</note>
40
+ </book>
41
+ </readqueue>
42
+ EOI
43
+
44
+ class XMLMapperTest < Test::Unit::TestCase
45
+ def testmap
46
+ d = Document.new( StringIO.new( INPUT ) )
47
+ assert_equal( "readqueue", d.root.name )
48
+ mapper = XMLMapper.new
49
+ o = mapper.map( d.root )
50
+ assert( o.kind_of?( ElementBackedClass ) )
51
+ assert( o.kind_of?( ReadQueue ) )
52
+ assert_equal( 3, o.children['book'].length )
53
+ assert_equal( 1, o.children['paper'].length )
54
+ paper = o.children['paper'][0]
55
+ assert( paper.kind_of?( Paper ) )
56
+ assert_equal( "paper", paper.class.element_name )
57
+ assert_equal( "http://svk.elixus.org?SVKTutorial", paper.uri )
58
+ assert_equal( 1, paper.children['note'].length )
59
+ note = paper.children['note'][0]
60
+ assert_equal( "re-read", note.text )
61
+ b = nil
62
+ o.children['book'].each do |book|
63
+ b = book if book.author == "Doug Lea"
64
+ end
65
+ assert_equal( "Concurrent Programming in Java", b.title )
66
+ note = b.children['note'][0]
67
+ assert( note.text.nil? )
68
+ assert_equal( "Need Brains", note.text_content )
69
+
70
+ # test []
71
+ assert_equal( 3, o['book'].length )
72
+ end
73
+
74
+ end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: rscm-accurev
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.0.2
7
- date: 2005-08-10 00:00:00 -05:00
6
+ version: 0.0.3
7
+ date: 2005-08-15 00:00:00 -05:00
8
8
  summary: "RSCM::Accurev - RSCM API for Accurev"
9
9
  require_paths:
10
10
  - lib
@@ -33,6 +33,7 @@ files:
33
33
  - bumprelease.sh
34
34
  - lib
35
35
  - LICENSE
36
+ - pkg
36
37
  - Rakefile
37
38
  - README
38
39
  - test
@@ -42,7 +43,6 @@ files:
42
43
  - lib/rscm/accurev.rb
43
44
  - lib/rscm/scm
44
45
  - lib/rscm/scm/accurev
45
- - "lib/rscm/scm/accurev/#api.rb#"
46
46
  - lib/rscm/scm/accurev/api.rb
47
47
  - lib/rscm/scm/accurev/command.rb
48
48
  - lib/rscm/scm/accurev/filterio.rb
@@ -54,9 +54,14 @@ files:
54
54
  - test/t_filterio.rb
55
55
  - test/t_load.rb
56
56
  - test/t_scrubio.rb
57
+ - test/t_xmlmapper.rb
57
58
  - test/eg/ac-files.xml
59
+ - test/eg/update-i-nochanges.xml
60
+ - test/eg/update-i-updates.xml
58
61
  - test/eg/update-newwksp.xml
62
+ - test/eg/update-nochanges.xml
59
63
  - test/eg/update-stale.xml
64
+ - test/eg/update-updates.xml
60
65
  test_files: []
61
66
  rdoc_options:
62
67
  - "--line-numbers"
@@ -1,226 +0,0 @@
1
- # -*- ruby -*-
2
- require 'rubygems'
3
- require 'rscm/base'
4
- require 'rscm/path_converter'
5
- require 'rexml/document'
6
- require 'rscm/scm/accurev/xml'
7
- require 'rscm/scm/accurev/filterio'
8
- require 'rscm/scm/accurev/command'
9
-
10
- module RSCM
11
- module Accurev; end
12
- end
13
-
14
- module RSCM::Accurev
15
-
16
- class AccurevException < Exception ; end
17
-
18
- # Indicates a failure of the update command due to unkept local modifications
19
- class StaleWorkspaceError < AccurevException; end
20
-
21
- # RSCM implementation for Accurev (http://www.accurev.com/).
22
- #
23
- # Requires an accurev cli executable on the path, and the correct
24
- # environment for ac server/principal/password.
25
- #
26
- class API < RSCM::Base
27
- register self
28
-
29
- ann :description => "Accurev Depot"
30
- attr_accessor :depot
31
-
32
- ann :description => "Backing Stream (autodetected)"
33
- attr_accessor :backing_stream
34
-
35
- ann :description => "Workspace Stream"
36
- attr_accessor :workspace_stream
37
-
38
- # defined in Base
39
- # ann :description => "Filesystem Path to Workspace"
40
- # attr_accessor :checkout_dir
41
-
42
- STATUSES = {
43
- '(backed)' => :backed,
44
- '(external)' => :external,
45
- '(modified)' => :modified,
46
- '(kept)' => :kept,
47
- '(defunct)' => :defunct,
48
- '(missing)' => :missing,
49
- '(stranded)' => :stranded,
50
- '(overlap)' => :overlap
51
- }
52
-
53
- def initialize( checkout_dir=nil, depot=nil, workspace_stream=nil )
54
- @depot = depot
55
- @checkout_dir = checkout_dir
56
- @workspace_stream = workspace_stream
57
- @backing_stream = nil # will be pulled from files cmd output
58
- end
59
-
60
- def name()
61
- return "Accurev"
62
- end
63
-
64
- # Accurev operations are atomic:
65
- def transactional?
66
- return true
67
- end
68
-
69
- # "Adds +relative_filename+ to the working copy."
70
- def add( relative_filename )
71
- raise "XXX implement me"
72
- end
73
-
74
- def edit( relative_filename )
75
- # NOP - not required for ac
76
- end
77
-
78
- # "Returns a Revisions object for the period specified ... (inclusive)."
79
- def revisions( from_identifier, to_identifier=Time.infinity )
80
- raise "XXX implement me"
81
- end
82
-
83
- # default impl depends on a correct impl of revisions()
84
- # def uptodate?( identifier=nil )
85
- #
86
- # end
87
-
88
- # def checked_out? - base
89
-
90
- # accurev actually does have triggers, but I haven't implemented that yet
91
- def supports_trigger?
92
- false
93
- end
94
-
95
- # def diff() XXX
96
-
97
-
98
- # --- ac specific
99
-
100
- def ac_files( relative_path )
101
- cmd = Command.instance
102
- # there must be a better way to do this yield->yield loopage
103
- obj = []
104
- cmd.accurev_elements( StatData, "files", relative_path ) do |fd|
105
- yield fd if block_given?
106
- obj << fd
107
- end
108
- return obj
109
- end
110
-
111
- def ac_keep( files=[], message="" )
112
- raise "XXX implement me"
113
- end
114
-
115
- def ac_promote( files=[], message="" )
116
- raise "XXX implement me"
117
- end
118
-
119
- def ac_update( relative_path="." )
120
- d = accurev( "update", relative_path )
121
- if xxx_error_stale
122
- raise StaleWorkspaceError.new( "#{relative_path} is stale -- keep/anchor all changes and re-update" )
123
- end
124
- end
125
-
126
- def ac_purge( files=[] )
127
- raise "XXX implement me"
128
- end
129
-
130
- def ac_revert( files=[] )
131
- raise "XXX implement me"
132
- end
133
-
134
- def ac_move( current_file, new_file )
135
- raise "XXX implement me"
136
- end
137
-
138
- # ac info: shows eg, backing stream
139
- # but doesn't support -fx!
140
-
141
- # ac mkws
142
- # -b orbitz-host-gt3-0-impl
143
- # -w orbitz-host-gt3-0-impl-test2_gfast
144
- # -l `pwd`
145
- # - does not support fx (argh!@)
146
- # - does not pop
147
- #
148
-
149
- # diff: /usr/local/bin/acdiff (!) --fx
150
- # (after an ac cat on the backed file)
151
- # (eg, no in-process diffing ala cvs diff)
152
- # lists modified lines in xml
153
-
154
- # checkout():
155
- # "Checks out or updates[!] contents from a central SCM
156
- # to +checkout_dir+ - a local working copy."
157
- #
158
- # "The +to_identifier+ parameter may be optionally specified to
159
- # obtain files up to a particular time or label."
160
- #
161
- # For accurev, this:
162
- # * checks to see if @checkout_dir exists and appears checked out.
163
- # If it's already checked out, this calls update().
164
- # * otherwise, this creates a new workspace stream and populates it
165
- # at @checkout_dir.
166
- #
167
- # Unknown: support for +to_identifier+ (esp for update)?
168
- #
169
- # This method yields files in the workspace and doesn't need to be
170
- # overridden.
171
- # The checkout_silent() method does the actual work.
172
- #
173
- # Only yields files, not directories
174
- def checkout( to_identifier=Time.infinite )
175
- co = PathConverter.nativepath_to_filepath( @checkout_dir )
176
- unless File.exists?( co )
177
- puts "> creating new workspace..."
178
- if @backing_stream.nil?
179
- raise "Backing stream must be set"
180
- end
181
- if @workspace_stream.nil?
182
- raise "Workspace stream must be set"
183
- end
184
- mkws_out = self.accurev_nofx( "mkws",
185
- "-b", @backing_stream,
186
- "-w", @workspace_stream,
187
- "-l", co )
188
- # sucks:
189
- if ( mkws_out =~ /already exists/ )
190
- raise AccurevException.new( mkws_out )
191
- end
192
- end
193
- puts "> Updating workspace.."
194
- self.update( to_identifier )
195
- end
196
-
197
- def update( to_identifier=Time.infinite )
198
- co = PathConverter.nativepath_to_filepath( @checkout_dir )
199
- unless File.exists?( co )
200
- raise AccurevException.new( "Workspace does not exist!" )
201
- end
202
- updated = []
203
- with_working_dir( co ) do
204
- # XXX Command...
205
- accurev_elements( UpdateData, "update" ) do |up|
206
- yield up.location
207
- updated << up.location
208
- end
209
- end
210
- return updated
211
- end
212
-
213
-
214
- # --- internals
215
-
216
- private
217
-
218
- # Takes a status flags line (eg, "(modified)(kept)")
219
- # and returns a list of status flags.
220
- def map_status( status_line )
221
- l = status_line.split( " " ).map {|x| x.trim}
222
- end
223
-
224
- end
225
-
226
- end