rscm-accurev 0.0 → 0.0.1
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/Rakefile +7 -76
- data/TODO +3 -17
- data/lib/rscm/accurev.rb +1 -13
- data/lib/rscm/scm/accurev/#command.rb# +95 -0
- data/lib/rscm/scm/accurev/api.rb +77 -258
- data/lib/rscm/scm/accurev/command.rb +40 -97
- data/lib/rscm/scm/accurev/filterio.rb +4 -6
- data/lib/rscm/scm/accurev/xml.rb +11 -199
- data/test/t_command.rb +11 -59
- data/test/t_load.rb +0 -1
- data/test/t_scrubio.rb +6 -1
- data/{apitest.rb → test.rb} +0 -1
- data/{test/eg/update-newwksp.xml → testing.log} +138 -0
- metadata +15 -57
- data/STATUS +0 -63
- data/bumprelease.sh +0 -13
- data/lib/rscm/scm/accurev/api.rb.mine +0 -382
- data/lib/rscm/scm/accurev/api.rb.r263 +0 -364
- data/lib/rscm/scm/accurev/api.rb.r265 +0 -393
- data/lib/rscm/scm/accurev/exception.rb +0 -38
- data/lib/test/unit/ui/xml/testrunner.rb +0 -165
- data/lib/test/unit/ui/xml/xmltestrunner.xslt +0 -79
- data/test/coverage/analyzer.rb +0 -127
- data/test/coverage/c_loader.rb +0 -34
- data/test/coverage/cover.rb +0 -91
- data/test/coverage/coverage_loader.rb +0 -21
- data/test/coverage/coveragetask.rb +0 -38
- data/test/coverage/index_tmpl.html +0 -42
- data/test/coverage/template.html +0 -36
- data/test/eg/ac-files.xml +0 -172
- data/test/eg/ac-pop.txt +0 -195
- data/test/eg/files-various-states.xml +0 -188
- data/test/eg/hist-oneweek-all.xml +0 -1483
- data/test/eg/hist-oneweek-external.xml +0 -246
- data/test/eg/hist-oneweek-promotes.xml +0 -1092
- data/test/eg/info.txt +0 -14
- data/test/eg/stat-a-various.xml +0 -1789
- data/test/eg/stat-m.xml +0 -13
- data/test/eg/stat-overlap.xml +0 -13
- data/test/eg/stat-x.xml +0 -20
- data/test/eg/update-i-mods-and-updates-and-overlap.xml +0 -73
- data/test/eg/update-i-nochanges.xml +0 -8
- data/test/eg/update-i-stale.xml +0 -0
- data/test/eg/update-i-updates.xml +0 -125
- data/test/eg/update-nochanges.xml +0 -7
- data/test/eg/update-stale.xml +0 -12
- data/test/eg/update-updates.xml +0 -147
- data/test/t_api.rb +0 -163
- data/test/t_xmlmapper.rb +0 -75
data/lib/rscm/scm/accurev/api.rb
CHANGED
@@ -1,42 +1,27 @@
|
|
1
1
|
# -*- ruby -*-
|
2
|
-
|
3
|
-
# = api.rb
|
4
|
-
#
|
5
|
-
# API for interacting with accurev workspaces.
|
6
|
-
#
|
7
|
-
# Includes:
|
8
|
-
#
|
9
|
-
# * API
|
10
|
-
#
|
11
|
-
require 'stringio'
|
2
|
+
require 'rubygems'
|
12
3
|
require 'rscm/base'
|
13
4
|
require 'rscm/path_converter'
|
14
5
|
require 'rexml/document'
|
15
6
|
require 'rscm/scm/accurev/xml'
|
16
7
|
require 'rscm/scm/accurev/filterio'
|
17
8
|
require 'rscm/scm/accurev/command'
|
18
|
-
require 'rscm/scm/accurev/exception'
|
19
9
|
|
20
|
-
|
21
|
-
module
|
10
|
+
module RSCM
|
11
|
+
module Accurev; end
|
12
|
+
end
|
22
13
|
|
23
14
|
module RSCM::Accurev
|
24
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/).
|
25
22
|
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
# Requires an accurev cli executable on the path (see also
|
29
|
-
# RSCM::Accurev::Command), and the correct environment
|
30
|
-
# configuration for ac server/principal/password.
|
31
|
-
#
|
32
|
-
# ---
|
33
|
-
#
|
34
|
-
# === Example
|
35
|
-
#
|
36
|
-
# api = RSCM::Accurev::API.new( "./ws/proj-1", "proj", "proj-1" )
|
37
|
-
# api.checkout() each do |file|
|
38
|
-
# puts "Updated #{file}..."
|
39
|
-
# end
|
23
|
+
# Requires an accurev cli executable on the path, and the correct
|
24
|
+
# environment for ac server/principal/password.
|
40
25
|
#
|
41
26
|
class API < RSCM::Base
|
42
27
|
register self
|
@@ -47,32 +32,36 @@ module RSCM::Accurev
|
|
47
32
|
ann :description => "Backing Stream (autodetected)"
|
48
33
|
attr_accessor :backing_stream
|
49
34
|
|
50
|
-
# If workspace stream is nil (the default), checkout/update will be
|
51
|
-
# done using `accurev pop`. This is faster and more appropriate for
|
52
|
-
# read-only use; however a workspace is required for commits.
|
53
35
|
ann :description => "Workspace Stream"
|
54
36
|
attr_accessor :workspace_stream
|
55
37
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
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
|
67
55
|
@checkout_dir = checkout_dir
|
68
|
-
@
|
56
|
+
@workspace_stream = workspace_stream
|
57
|
+
@backing_stream = nil # will be pulled from files cmd output
|
69
58
|
end
|
70
59
|
|
71
60
|
def name()
|
72
61
|
return "Accurev"
|
73
62
|
end
|
74
63
|
|
75
|
-
# Accurev operations are atomic:
|
64
|
+
# Accurev operations are atomic:
|
76
65
|
def transactional?
|
77
66
|
return true
|
78
67
|
end
|
@@ -87,9 +76,6 @@ module RSCM::Accurev
|
|
87
76
|
end
|
88
77
|
|
89
78
|
# "Returns a Revisions object for the period specified ... (inclusive)."
|
90
|
-
#
|
91
|
-
# list txns (promotes to bs) from hist within the period
|
92
|
-
#
|
93
79
|
def revisions( from_identifier, to_identifier=Time.infinity )
|
94
80
|
raise "XXX implement me"
|
95
81
|
end
|
@@ -111,58 +97,20 @@ module RSCM::Accurev
|
|
111
97
|
|
112
98
|
# --- ac specific
|
113
99
|
|
114
|
-
# remember: ac_files is non-recursive
|
115
100
|
def ac_files( relative_path )
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
return []
|
122
|
-
end
|
123
|
-
acresponse['element'].each do |fd|
|
124
|
-
yield fd if block_given?
|
125
|
-
ret << fd
|
126
|
-
end
|
101
|
+
out = self.accurev( "files", relative_path )
|
102
|
+
# validate
|
103
|
+
raise AccurevException.new("Failed to get response") if out.nil?
|
104
|
+
if ( out.root.name!="AcResponse" )
|
105
|
+
raise AccurevException.new("Invalid response")
|
127
106
|
end
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
ret = []
|
134
|
-
with_working_dir( co_filepath ) do
|
135
|
-
acresponse = cmd.accurev( "stat", flag )
|
136
|
-
return [] if acresponse['element'].nil?
|
137
|
-
acresponse['element'].each do |fd|
|
138
|
-
yield fd if block_given?
|
139
|
-
ret << fd
|
140
|
-
end
|
141
|
-
end
|
142
|
-
return ret
|
143
|
-
end
|
144
|
-
|
145
|
-
# yeilds the TransactionData objects for the given time period
|
146
|
-
# (promotes only)
|
147
|
-
def ac_hist( from, to=Time.infinite )
|
148
|
-
cmd = Command.instance
|
149
|
-
lower = from.to_accurev
|
150
|
-
upper = "now"
|
151
|
-
unless to == Time.infinite
|
152
|
-
upper = to.to_accurev
|
153
|
-
end
|
154
|
-
with_working_dir( self.co_filepath ) do
|
155
|
-
acresponse = cmd.accurev( "hist",
|
156
|
-
"-t", "'#{upper}-#{lower}'",
|
157
|
-
"-k", "promote"
|
158
|
-
)
|
159
|
-
ret = []
|
160
|
-
acresponse['transaction'].each do |txn|
|
161
|
-
ret << txn
|
162
|
-
yield txn if block_given?
|
163
|
-
end
|
164
|
-
return ret
|
107
|
+
files = []
|
108
|
+
out.elements.each( "/AcResponse/element" ) do |e|
|
109
|
+
f = FileStatus.new( e )
|
110
|
+
yield f if block_given?
|
111
|
+
files << f
|
165
112
|
end
|
113
|
+
return files
|
166
114
|
end
|
167
115
|
|
168
116
|
def ac_keep( files=[], message="" )
|
@@ -192,32 +140,9 @@ module RSCM::Accurev
|
|
192
140
|
raise "XXX implement me"
|
193
141
|
end
|
194
142
|
|
195
|
-
#
|
196
|
-
# Performs an "accurev info" command in the workspace.
|
197
|
-
# Returns a map of
|
198
|
-
#
|
199
143
|
# ac info: shows eg, backing stream
|
200
|
-
# but doesn't support -fx!
|
201
|
-
|
202
|
-
def ac_info()
|
203
|
-
co = RSCM::PathConverter.nativepath_to_filepath( @checkout_dir )
|
204
|
-
unless File.exists?( co )
|
205
|
-
raise AccurevException.new( "Checkout dir #{co} does not exist" )
|
206
|
-
end
|
207
|
-
info = {}
|
208
|
-
with_working_dir( co ) do
|
209
|
-
cmd = Command.instance
|
210
|
-
io = StringIO.new( cmd.accurev_nofx( "info" ) )
|
211
|
-
io.each_line do |line|
|
212
|
-
next unless line =~ /\S/
|
213
|
-
if line =~ /^(.*?):\s+(.*)$/
|
214
|
-
info[$1] = $2
|
215
|
-
end
|
216
|
-
end
|
217
|
-
end
|
218
|
-
return info
|
219
|
-
end
|
220
|
-
|
144
|
+
# but doesn't support -fx!
|
145
|
+
|
221
146
|
# ac mkws
|
222
147
|
# -b orbitz-host-gt3-0-impl
|
223
148
|
# -w orbitz-host-gt3-0-impl-test2_gfast
|
@@ -231,7 +156,7 @@ module RSCM::Accurev
|
|
231
156
|
# (eg, no in-process diffing ala cvs diff)
|
232
157
|
# lists modified lines in xml
|
233
158
|
|
234
|
-
#
|
159
|
+
# checkout():
|
235
160
|
# "Checks out or updates[!] contents from a central SCM
|
236
161
|
# to +checkout_dir+ - a local working copy."
|
237
162
|
#
|
@@ -239,156 +164,60 @@ module RSCM::Accurev
|
|
239
164
|
# obtain files up to a particular time or label."
|
240
165
|
#
|
241
166
|
# For accurev, this:
|
242
|
-
# * checks to see if
|
243
|
-
# If it's already checked out, this calls
|
244
|
-
# +@checkout_dir+ exists and +to_identifier+ is given, an
|
245
|
-
# exception is raised.
|
167
|
+
# * checks to see if @checkout_dir exists and appears checked out.
|
168
|
+
# If it's already checked out, this calls update().
|
246
169
|
# * otherwise, this creates a new workspace stream and populates it
|
247
|
-
# at
|
248
|
-
#
|
249
|
-
# This both returns and yields a list of updated files.
|
250
|
-
# Only updated files are returned, not directories.
|
170
|
+
# at @checkout_dir.
|
251
171
|
#
|
252
|
-
#
|
253
|
-
# deleted files.
|
172
|
+
# Unknown: support for +to_identifier+ (esp for update)?
|
254
173
|
#
|
174
|
+
# This method yields files in the workspace and doesn't need to be
|
175
|
+
# overridden.
|
176
|
+
# The checkout_silent() method does the actual work.
|
177
|
+
#
|
178
|
+
# Only yields files, not directories
|
255
179
|
def checkout( to_identifier=Time.infinite )
|
256
|
-
co =
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
self.checkout_pop()
|
262
|
-
else
|
263
|
-
unless File.exists?( co )
|
264
|
-
# create new workspace
|
265
|
-
self.checkout_workspace()
|
180
|
+
co = PathConverter.nativepath_to_filepath( @checkout_dir )
|
181
|
+
unless File.exists?( co )
|
182
|
+
puts "> creating new workspace..."
|
183
|
+
if @backing_stream.nil?
|
184
|
+
raise "Backing stream must be set"
|
266
185
|
end
|
267
|
-
|
268
|
-
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
def checkout_pop()
|
273
|
-
co = RSCM::PathConverter.nativepath_to_filepath( @checkout_dir )
|
274
|
-
raise "A backing stream is required" if @backing_stream.nil?
|
275
|
-
raise "A working stream may not be given" unless @working_stream.nil?
|
276
|
-
# for `accurev pop`: remove and re-pop the checkout copy
|
277
|
-
if File.exists?( co )
|
278
|
-
unless @overwrite
|
279
|
-
raise "Checkout dir #{co} already exists (@overwrite=#@overwrite)"
|
186
|
+
if @workspace_stream.nil?
|
187
|
+
raise "Workspace stream must be set"
|
280
188
|
end
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
"-v", @backing_stream,
|
289
|
-
"-L", ".", ".")
|
290
|
-
elems = []
|
291
|
-
popio = StringIO.new( pop_out )
|
292
|
-
popio.each_line do |line|
|
293
|
-
if line =~ /^Populating element \/.\/(.*)$/
|
294
|
-
loc = $1
|
295
|
-
elems << loc
|
296
|
-
yield loc if block_given?
|
297
|
-
end
|
189
|
+
mkws_out = self.accurev_nofx( "mkws",
|
190
|
+
"-b", @backing_stream,
|
191
|
+
"-w", @workspace_stream,
|
192
|
+
"-l", co )
|
193
|
+
# sucks:
|
194
|
+
if ( mkws_out =~ /already exists/ )
|
195
|
+
raise AccurevException.new( mkws_out )
|
298
196
|
end
|
299
|
-
return elems
|
300
|
-
end
|
301
|
-
end
|
302
|
-
|
303
|
-
def checkout_workspace()
|
304
|
-
co = RSCM::PathConverter.nativepath_to_filepath( @checkout_dir )
|
305
|
-
raise "A backing stream is required" if @backing_stream.nil?
|
306
|
-
raise "A workspace is required" if @working_stream.nil?
|
307
|
-
if File.exist?( co ) and !@overwrite
|
308
|
-
raise "Checkout dir #{co} already exists (@overwrite=#@overwrite)"
|
309
|
-
end
|
310
|
-
cmd = Command.instance
|
311
|
-
mkws_out = cmd.accurev_nofx( "mkws",
|
312
|
-
"-b", @backing_stream,
|
313
|
-
"-w", @workspace_stream,
|
314
|
-
"-l", co )
|
315
|
-
# kinda sucks:
|
316
|
-
if ( mkws_out =~ /already exists/ )
|
317
|
-
raise AccurevException.new( "Failed to checkout", mkws_out )
|
318
197
|
end
|
198
|
+
puts "> Updating workspace.."
|
199
|
+
self.update( to_identifier )
|
319
200
|
end
|
320
201
|
|
321
202
|
def update( to_identifier=Time.infinite )
|
322
|
-
co =
|
203
|
+
co = PathConverter.nativepath_to_filepath( @checkout_dir )
|
323
204
|
unless File.exists?( co )
|
324
205
|
raise AccurevException.new( "Workspace does not exist!" )
|
325
206
|
end
|
326
207
|
updated = []
|
327
208
|
with_working_dir( co ) do
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
if acresponse.error =~ /workspace have been modified/
|
332
|
-
raise StaleWorkspaceException.new( "Workspace stale",
|
333
|
-
acresponse.error )
|
334
|
-
else
|
335
|
-
# some other update problem
|
336
|
-
raise AccurevException.new( "Error on update", acresponse.error )
|
337
|
-
end
|
338
|
-
end
|
339
|
-
if acresponse['element']
|
340
|
-
acresponse['element'].each do |up|
|
341
|
-
# "ac update" on a new workspace yields element locations
|
342
|
-
# with leading "/"s, which should be removed to get a proper
|
343
|
-
# relative path:
|
344
|
-
loc = up.location.sub( /^\//, "" )
|
345
|
-
yield loc if block_given?
|
346
|
-
updated << loc
|
347
|
-
end
|
209
|
+
accurev_elements( UpdateData, "update" ) do |up|
|
210
|
+
yield up.location
|
211
|
+
updated << up.location
|
348
212
|
end
|
349
213
|
end
|
350
214
|
return updated
|
351
215
|
end
|
352
216
|
|
353
|
-
# --- internals
|
354
217
|
|
355
|
-
#
|
356
|
-
STATUSES = {
|
357
|
-
'(backed)' => :backed,
|
358
|
-
'(external)' => :external,
|
359
|
-
'(modified)' => :modified,
|
360
|
-
'(kept)' => :kept,
|
361
|
-
'(defunct)' => :defunct,
|
362
|
-
'(missing)' => :missing,
|
363
|
-
'(stranded)' => :stranded,
|
364
|
-
'(overlap)' => :overlap
|
365
|
-
}
|
366
|
-
|
367
|
-
# private
|
368
|
-
|
369
|
-
# psuedo-accessor (cached)
|
370
|
-
def co_filepath
|
371
|
-
if @co_filepath.nil?
|
372
|
-
@co_filepath = RSCM::PathConverter.nativepath_to_filepath( @checkout_dir )
|
373
|
-
end
|
374
|
-
return @co_filepath
|
375
|
-
end
|
218
|
+
# --- internals
|
376
219
|
|
377
|
-
|
378
|
-
# Runs an `ac info` command in +@checkout_dir+, and tries to
|
379
|
-
# set +@backing_stream+ and +@workspace_stream+ from the output.
|
380
|
-
#
|
381
|
-
def attempt_init_from_info()
|
382
|
-
if File.exists?( self.co_filepath )
|
383
|
-
info = self.ac_info
|
384
|
-
if info.has_key?( "Basis" )
|
385
|
-
@backing_stream = info["Basis"]
|
386
|
-
end
|
387
|
-
if info.has_key?( "ws/ref" )
|
388
|
-
@workspace_stream = info["ws/ref"]
|
389
|
-
end
|
390
|
-
end
|
391
|
-
end
|
220
|
+
private
|
392
221
|
|
393
222
|
# Takes a status flags line (eg, "(modified)(kept)")
|
394
223
|
# and returns a list of status flags.
|
@@ -399,13 +228,3 @@ module RSCM::Accurev
|
|
399
228
|
end
|
400
229
|
|
401
230
|
end
|
402
|
-
|
403
|
-
class Time
|
404
|
-
def to_accurev
|
405
|
-
self.strftime( "%Y/%m/%d %H:%M:%S" )
|
406
|
-
end
|
407
|
-
end
|
408
|
-
|
409
|
-
#
|
410
|
-
# Copyright (c) 2005 Gregory D. Fast <gdf@speakeasy.net>
|
411
|
-
#
|
@@ -1,49 +1,35 @@
|
|
1
1
|
# -*- ruby -*-
|
2
2
|
|
3
|
+
require 'singleton'
|
4
|
+
|
3
5
|
module RSCM
|
4
6
|
module Accurev
|
5
7
|
|
6
|
-
#
|
7
|
-
# Executes accurev commands and deals with the output.
|
8
|
-
# This class is a thread local singleton: each thread
|
9
|
-
# calling +Command.instance+ gets a different instance.
|
10
|
-
#
|
11
8
|
class Command
|
9
|
+
include Singleton
|
12
10
|
|
13
|
-
attr_accessor :debug, :debug_to, :
|
14
|
-
|
15
|
-
# If you need to swap out the mapper class
|
16
|
-
attr_accessor :xmlmapper
|
11
|
+
attr_accessor :debug, :debug_to, :accurev, :working_dir
|
17
12
|
|
18
|
-
def initialize()
|
19
|
-
@xmlmapper = XMLMapper
|
13
|
+
def initialize( working_dir="." )
|
20
14
|
@debug = false
|
21
15
|
@debug_to = STDOUT
|
22
|
-
@
|
16
|
+
@accurev = "accurev"
|
17
|
+
@working_dir = working_dir
|
23
18
|
end
|
24
19
|
|
25
|
-
#
|
26
|
-
# Returns a command line string for executing the given
|
27
|
-
# accurev subcomment +cmd+ with arguments +opts+.
|
28
|
-
#
|
29
20
|
def accurev_cmdline( cmd, *opts )
|
30
|
-
return "#{@
|
21
|
+
return "#{@accurev} #{cmd} #{opts.join(' ')}";
|
31
22
|
end
|
32
|
-
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
# the stdout from the command execution.
|
38
|
-
#
|
39
|
-
# (Not all accurev subcommands (eg, `accurev info`) support
|
40
|
-
# `-fx` for xml output.)
|
41
|
-
#
|
23
|
+
|
24
|
+
# Execute the given accurev subcommand, and return its
|
25
|
+
# output as a plain uninterpreted string.
|
26
|
+
# Not all accurev subcommands (eg, `accurev info`) support
|
27
|
+
# `-fx` for xml output.
|
42
28
|
def accurev_nofx( cmd, *opts )
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
29
|
+
# nativepath_to_filepath is actually generic to native
|
30
|
+
dir = PathConverter.nativepath_to_filepath( @working_dir )
|
31
|
+
dir = File.expand_path( dir )
|
32
|
+
with_working_dir( dir ) do
|
47
33
|
cmdline = self.accurev_cmdline( cmd, opts )
|
48
34
|
if @debug
|
49
35
|
@debug_to.puts("ac> #{cmdline}")
|
@@ -51,26 +37,20 @@ module RSCM
|
|
51
37
|
Better.popen( cmdline ) do |stdout|
|
52
38
|
return stdout.read()
|
53
39
|
end
|
54
|
-
|
40
|
+
end
|
55
41
|
end
|
56
|
-
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
# will be converted to an REXML document and returned.
|
61
|
-
# The command's options list will have `-fx` appended,
|
62
|
-
# to specify xml output format.
|
63
|
-
#
|
42
|
+
|
43
|
+
# Execute the given accurev subcommand, and return its
|
44
|
+
# output as an REXML document. The options list to the command
|
45
|
+
# will automatically have `-fx` prepended, to specify xml output.
|
64
46
|
# Certain quirks in <AcResponse>-type documents will be
|
65
|
-
# corrected (see Accurev::AcXMLScrubIO).
|
66
|
-
|
67
|
-
|
68
|
-
|
47
|
+
# corrected (see Accurev::AcXMLScrubIO).
|
48
|
+
def accurev( cmd, *opts )
|
49
|
+
# nativepath_to_filepath is actually generic to native
|
50
|
+
dir = PathConverter.nativepath_to_filepath( @working_dir )
|
51
|
+
dir = File.expand_path( dir )
|
69
52
|
opts << "-fx"
|
70
|
-
|
71
|
-
## dir = PathConverter.nativepath_to_filepath( @working_dir )
|
72
|
-
## dir = File.expand_path( dir )
|
73
|
-
## with_working_dir( dir ) do
|
53
|
+
with_working_dir( dir ) do
|
74
54
|
cmdline = self.accurev_cmdline( cmd, opts )
|
75
55
|
if @debug
|
76
56
|
@debug_to.puts("ac> #{cmdline}")
|
@@ -78,8 +58,7 @@ module RSCM
|
|
78
58
|
Better.popen( cmdline ) do |stdout|
|
79
59
|
output = stdout.read()
|
80
60
|
if @debug
|
81
|
-
@debug_to.puts( "raw
|
82
|
-
@debug_to.puts( output )
|
61
|
+
@debug_to.puts( "raw>\n#{output}" )
|
83
62
|
end
|
84
63
|
begin
|
85
64
|
return REXML::Document.new( AcXMLScrubIO.new( output ) )
|
@@ -87,64 +66,28 @@ module RSCM
|
|
87
66
|
raise "Unexpected output from #{cmdline}: #{e}"
|
88
67
|
end
|
89
68
|
end
|
90
|
-
|
69
|
+
end
|
91
70
|
end
|
92
71
|
|
93
|
-
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
|
98
|
-
|
99
|
-
#
|
100
|
-
def accurev( cmd, *opts )
|
101
|
-
doc = self.accurev_xml( cmd, opts )
|
72
|
+
# Execute the given accurev subcommand using +accurev+,
|
73
|
+
# and return the <element> REXML elements from the
|
74
|
+
# resulting document.
|
75
|
+
# For ac commands which emit the common <elements> format.
|
76
|
+
def accurev_elements( mapclass, cmd, *opts )
|
77
|
+
doc = self.accurev( cmd, opts )
|
102
78
|
if @debug
|
103
|
-
@debug_to.puts( "doc>" )
|
104
79
|
@debug_to.puts( doc )
|
105
80
|
end
|
106
81
|
if doc.elements.size==0
|
107
82
|
raise "Unexpected output from #{cmd}: #{doc}"
|
108
83
|
end
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
# static methods
|
114
|
-
|
115
|
-
# Retrieve this thread's +Command+ instance.
|
116
|
-
#
|
117
|
-
# eg:
|
118
|
-
# cmd = Command.instance
|
119
|
-
# eg:
|
120
|
-
# Command.instance do |cmd|
|
121
|
-
# cmd.workspace_dir = "/var/tmp"
|
122
|
-
# end
|
123
|
-
#
|
124
|
-
def Command.instance()
|
125
|
-
if Thread.current[ :RSCM_ACCUREV_COMMAND ].nil?
|
126
|
-
Thread.current[ :RSCM_ACCUREV_COMMAND ] = Command.new
|
84
|
+
doc.elements.each( "/AcResponse/element" ) do |e|
|
85
|
+
o = mapclass.new( e )
|
86
|
+
yield o
|
127
87
|
end
|
128
|
-
yield Thread.current[ :RSCM_ACCUREV_COMMAND ] if block_given?
|
129
|
-
return Thread.current[ :RSCM_ACCUREV_COMMAND ]
|
130
|
-
end
|
131
|
-
|
132
|
-
# Discard the current thread's Command object.
|
133
|
-
# The next call to +Command.instance+ in this thread will
|
134
|
-
# return a new instance configured with the defaults.
|
135
|
-
def Command.discard()
|
136
|
-
Thread.current[ :RSCM_ACCUREV_COMMAND ] = nil
|
137
|
-
end
|
138
|
-
|
139
|
-
private
|
140
|
-
|
141
|
-
# new() is marked private, use Command.instance().
|
142
|
-
def new( *args )
|
143
|
-
super(args)
|
144
88
|
end
|
145
89
|
|
146
|
-
end
|
147
|
-
|
90
|
+
end
|
148
91
|
end
|
149
92
|
end
|
150
93
|
|
@@ -3,19 +3,17 @@ require 'stringio'
|
|
3
3
|
module RSCM
|
4
4
|
module Accurev
|
5
5
|
|
6
|
-
#
|
7
6
|
# IO stream which cleans irregularities out of accurev xml output.
|
8
7
|
#
|
9
8
|
# In particular:
|
10
9
|
#
|
11
|
-
#
|
12
|
-
#
|
10
|
+
# * the -fx output from `accurev update` has a root element of
|
11
|
+
# <acResponse>, not <AcResponse> like the other commands
|
13
12
|
#
|
14
|
-
#
|
15
|
-
#
|
13
|
+
# * `accurev update` emits broken XML when there are no files
|
14
|
+
# needing updates.
|
16
15
|
#
|
17
16
|
class AcXMLScrubIO < StringIO
|
18
|
-
|
19
17
|
# @param: sourceio - io or string source to wrap
|
20
18
|
def initialize( sourceio )
|
21
19
|
if sourceio.respond_to?( :read )
|