rscm-accurev 0.0 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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 )
|