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