rscm-accurev 0.0.4 → 0.0.6
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 +55 -8
- data/TODO +1 -1
- data/bumprelease.sh +3 -0
- data/lib/rscm/accurev.rb +3 -2
- data/lib/rscm/scm/accurev/api.rb +181 -71
- data/lib/rscm/scm/accurev/exception.rb +38 -0
- data/lib/rscm/scm/accurev/xml.rb +42 -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 +39 -39
- 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 +7 -7
- 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-updates.xml +46 -46
- data/test/eg/update-newwksp.xml +88 -88
- data/test/eg/update-updates.xml +46 -46
- data/test/fl +18 -0
- data/test/suite_all.rb +34 -0
- data/test/t_api.rb +47 -5
- data/test/t_command.rb +1 -0
- data/test/t_load.rb +1 -0
- data/test/t_rscm.rb +26 -0
- data/test/t_scrubio.rb +1 -0
- data/test/t_xmlmapper.rb +1 -0
- metadata +25 -3
- data/apitest.rb +0 -21
data/Rakefile
CHANGED
@@ -5,6 +5,7 @@ require 'rake/testtask'
|
|
5
5
|
require 'rake/rdoctask'
|
6
6
|
require 'rake/packagetask'
|
7
7
|
require 'rake/gempackagetask'
|
8
|
+
require 'tracer'
|
8
9
|
|
9
10
|
# this rakefile originally borrowed shamelessly from rscm
|
10
11
|
|
@@ -15,14 +16,24 @@ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
|
15
16
|
PKG_SUMMARY = 'RSCM::Accurev - RSCM API for Accurev'
|
16
17
|
|
17
18
|
desc "Default Task"
|
18
|
-
task :default => [ :test, :gem ]
|
19
|
+
task :default => [ :test, :verify, :gem ]
|
19
20
|
|
20
|
-
|
21
|
+
RAKEVERSION =~ /^(\d+)\.(\d+).(.*)/
|
22
|
+
rake_maj,rake_min,rake_patch = $1,$2,$3
|
23
|
+
if rake_maj.to_f < 1 and rake_min.to_f <= 5 and rake_patch.to_f <= 4
|
24
|
+
# use this for rake <= 0.5.4:
|
25
|
+
task :test => [ :plaintest ]
|
26
|
+
HAVEXMLTEST = false
|
27
|
+
else
|
28
|
+
# rake 0.5.4.6+ (0.5.5)
|
29
|
+
task :test => [ :backup_testresults, :xmltest ]
|
30
|
+
HAVEXMLTEST = true
|
31
|
+
end
|
21
32
|
|
22
33
|
# define a task(s) to run tests
|
23
34
|
|
24
35
|
test_files = FileList.new( "test/**/t_*.rb" )
|
25
|
-
TEST_OUTPUT = "
|
36
|
+
TEST_OUTPUT = "html/test"
|
26
37
|
|
27
38
|
Rake::TestTask.new( :plaintest ) do |t|
|
28
39
|
t.libs << "test"
|
@@ -30,8 +41,9 @@ Rake::TestTask.new( :plaintest ) do |t|
|
|
30
41
|
t.verbose = true
|
31
42
|
end
|
32
43
|
|
33
|
-
|
34
|
-
# requires a patch to
|
44
|
+
if HAVEXMLTEST
|
45
|
+
# rake<0.5.5 requires a patch to rake_test_loader.rb to exclude options
|
46
|
+
# rake<0.5.5 requires a patch to rake/testtask.rb to support ruby_opts
|
35
47
|
# (see doc/patches)
|
36
48
|
Rake::TestTask.new( :xmltest ) do |t|
|
37
49
|
t.libs << "test"
|
@@ -41,9 +53,14 @@ Rake::TestTask.new( :xmltest ) do |t|
|
|
41
53
|
ENV['XMLTEST_OUTPUT'] = "#{TEST_OUTPUT}/testresults.xml"
|
42
54
|
t.options = "--runner=xml"
|
43
55
|
end
|
56
|
+
end # !HAVEXMLTEST
|
57
|
+
|
44
58
|
|
45
59
|
# backs up existing testresults.xml files in test target dir
|
46
60
|
task :backup_testresults do
|
61
|
+
unless File.exist?( TEST_OUTPUT )
|
62
|
+
mkdir_p( TEST_OUTPUT )
|
63
|
+
end
|
47
64
|
old = "#{TEST_OUTPUT}/testresults.xml"
|
48
65
|
if File.exist?( old )
|
49
66
|
stat = File.stat( old )
|
@@ -97,9 +114,39 @@ else
|
|
97
114
|
end
|
98
115
|
|
99
116
|
desc "Delete all generated files (includes built packages)"
|
100
|
-
task :realclean
|
117
|
+
task :realclean do
|
101
118
|
f = FileList[ 'pkg', 'html', 'doc/test*.xml' ]
|
102
|
-
|
119
|
+
rm_rf f
|
103
120
|
end
|
104
121
|
|
105
|
-
|
122
|
+
desc "Coverage! (still a big hack)"
|
123
|
+
task :coverage => [ :test_coverage, :coverage_summary ]
|
124
|
+
|
125
|
+
Rake::TestTask.new( :test_coverage ) do |t|
|
126
|
+
t.libs << "test"
|
127
|
+
t.test_files = test_files
|
128
|
+
t.verbose = true
|
129
|
+
def t.rake_loader
|
130
|
+
'test/coverage/c_loader.rb'
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
task :coverage_summary do
|
135
|
+
# too many options!@
|
136
|
+
ruby "test/coverage/analyzer.rb xxx.trace html/coverage test/coverage/template.html test/coverage/index_tmpl.html"
|
137
|
+
end
|
138
|
+
|
139
|
+
desc "Perform various prerelease verifications"
|
140
|
+
task :verify do
|
141
|
+
require 'find'
|
142
|
+
Find.find(".") do |path|
|
143
|
+
if FileTest.directory?(path)
|
144
|
+
next
|
145
|
+
end
|
146
|
+
next if path =~ /^.\/tmp\/cleaner.pl$/
|
147
|
+
next if path =~ /^.\/Rakefile$/
|
148
|
+
if File.read(path) =~ /orbitz|duncllc|gfast|fduncan/i
|
149
|
+
fail "Cannot release #{path}, please clean up"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
data/TODO
CHANGED
data/bumprelease.sh
CHANGED
data/lib/rscm/accurev.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
require 'rubygems'
|
3
2
|
require 'rscm/scm/accurev/api'
|
4
3
|
require 'rscm/scm/accurev/command'
|
5
4
|
require 'rscm/scm/accurev/xml'
|
@@ -13,5 +12,7 @@ module RSCM
|
|
13
12
|
#
|
14
13
|
# See RSCM::Accurev::API.
|
15
14
|
#
|
16
|
-
module Accurev
|
15
|
+
module Accurev
|
16
|
+
VERSION = '0.0.6'
|
17
|
+
end
|
17
18
|
end
|
data/lib/rscm/scm/accurev/api.rb
CHANGED
@@ -4,41 +4,24 @@
|
|
4
4
|
#
|
5
5
|
# API for interacting with accurev workspaces.
|
6
6
|
#
|
7
|
+
# Includes:
|
8
|
+
#
|
9
|
+
# * API
|
10
|
+
#
|
7
11
|
require 'stringio'
|
8
|
-
require 'rubygems'
|
9
12
|
require 'rscm/base'
|
10
13
|
require 'rscm/path_converter'
|
11
14
|
require 'rexml/document'
|
12
15
|
require 'rscm/scm/accurev/xml'
|
13
16
|
require 'rscm/scm/accurev/filterio'
|
14
17
|
require 'rscm/scm/accurev/command'
|
18
|
+
require 'rscm/scm/accurev/exception'
|
15
19
|
|
16
20
|
# need to define module within module before you can use module X::Y
|
17
21
|
module RSCM; module Accurev; end; end
|
18
22
|
|
19
23
|
module RSCM::Accurev
|
20
24
|
|
21
|
-
#
|
22
|
-
# General exception class for errors processing commands.
|
23
|
-
#
|
24
|
-
# @attr error_msg Error message output by accurev.
|
25
|
-
#
|
26
|
-
class AccurevException < Exception
|
27
|
-
attr_reader :error_msg
|
28
|
-
def initialize( msg, error_msg=nil )
|
29
|
-
super( "#{msg}: #{error_msg}" )
|
30
|
-
@error_msg = error_msg
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
#
|
35
|
-
# Exception thrown when an update is performed
|
36
|
-
# on a workspace with unkept/unanchored modifications.
|
37
|
-
# Accurev requires that all modifications be handled before
|
38
|
-
# an update is performed.
|
39
|
-
#
|
40
|
-
class StaleWorkspaceException < AccurevException; end
|
41
|
-
|
42
25
|
#
|
43
26
|
# RSCM implementation for Accurev (http://www.accurev.com).
|
44
27
|
#
|
@@ -64,30 +47,25 @@ module RSCM::Accurev
|
|
64
47
|
ann :description => "Backing Stream (autodetected)"
|
65
48
|
attr_accessor :backing_stream
|
66
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.
|
67
53
|
ann :description => "Workspace Stream"
|
68
54
|
attr_accessor :workspace_stream
|
69
55
|
|
70
56
|
# [defined in Base]
|
71
57
|
# ann :description => "Filesystem Path to Workspace"
|
72
58
|
# attr_accessor :checkout_dir
|
59
|
+
|
60
|
+
ann :description => "Overwrite Mode: if true, co overwrites existing"
|
61
|
+
attr_accessor :overwrite
|
73
62
|
|
74
|
-
|
75
|
-
|
76
|
-
'(backed)' => :backed,
|
77
|
-
'(external)' => :external,
|
78
|
-
'(modified)' => :modified,
|
79
|
-
'(kept)' => :kept,
|
80
|
-
'(defunct)' => :defunct,
|
81
|
-
'(missing)' => :missing,
|
82
|
-
'(stranded)' => :stranded,
|
83
|
-
'(overlap)' => :overlap
|
84
|
-
}
|
85
|
-
|
86
|
-
def initialize( checkout_dir=nil, depot=nil, workspace_stream=nil )
|
87
|
-
@depot = depot
|
63
|
+
def initialize(checkout_dir=nil, backing_stream=nil, workspace_stream=nil)
|
64
|
+
@depot = nil # will be pulled from files cmd output
|
88
65
|
@workspace_stream = workspace_stream
|
89
|
-
@backing_stream =
|
66
|
+
@backing_stream = backing_stream
|
90
67
|
@checkout_dir = checkout_dir
|
68
|
+
@overwrite = false
|
91
69
|
end
|
92
70
|
|
93
71
|
def name()
|
@@ -109,8 +87,30 @@ module RSCM::Accurev
|
|
109
87
|
end
|
110
88
|
|
111
89
|
# "Returns a Revisions object for the period specified ... (inclusive)."
|
90
|
+
#
|
91
|
+
# list txns (promotes to bs) from hist within the period
|
92
|
+
#
|
112
93
|
def revisions( from_identifier, to_identifier=Time.infinity )
|
113
|
-
|
94
|
+
revisions = RSCM::Revisions.new()
|
95
|
+
self.ac_hist( from_identifier, to_identifier ).each do |txn|
|
96
|
+
txnrev = RSCM::Revision.new
|
97
|
+
txnrev.identifier = txn.id
|
98
|
+
txnrev.developer = txn.user
|
99
|
+
txnrev.message = txn['comment'].join("\n") unless txn['comment'].nil?
|
100
|
+
txnrev.time = Time.at( txn.time.to_i )
|
101
|
+
txn['version'].each do |v|
|
102
|
+
f = RSCM::RevisionFile.new()
|
103
|
+
f.path = v.path
|
104
|
+
# i think to get real status, you'd need to analyze keep txns
|
105
|
+
f.status = RSCM::RevisionFile::MODIFIED # XXX? txn.type==promote here
|
106
|
+
f.developer = txn.user
|
107
|
+
f.native_revision_identifier = v.real # XXX or .virtual?
|
108
|
+
f.time = Time.at( txn.time.to_i )
|
109
|
+
txnrev << f
|
110
|
+
end
|
111
|
+
revisions.add( txnrev )
|
112
|
+
end
|
113
|
+
return revisions
|
114
114
|
end
|
115
115
|
|
116
116
|
# default impl depends on a correct impl of revisions()
|
@@ -130,11 +130,29 @@ module RSCM::Accurev
|
|
130
130
|
|
131
131
|
# --- ac specific
|
132
132
|
|
133
|
+
# remember: ac_files is non-recursive
|
133
134
|
def ac_files( relative_path )
|
134
135
|
cmd = Command.instance
|
135
136
|
ret = []
|
136
|
-
with_working_dir(
|
137
|
+
with_working_dir( co_filepath ) do
|
137
138
|
acresponse = cmd.accurev( "files", relative_path )
|
139
|
+
if acresponse['element'].nil?
|
140
|
+
return []
|
141
|
+
end
|
142
|
+
acresponse['element'].each do |fd|
|
143
|
+
yield fd if block_given?
|
144
|
+
ret << fd
|
145
|
+
end
|
146
|
+
end
|
147
|
+
return ret
|
148
|
+
end
|
149
|
+
|
150
|
+
def ac_stat( flag="-a" )
|
151
|
+
cmd = Command.instance
|
152
|
+
ret = []
|
153
|
+
with_working_dir( co_filepath ) do
|
154
|
+
acresponse = cmd.accurev( "stat", flag )
|
155
|
+
return [] if acresponse['element'].nil?
|
138
156
|
acresponse['element'].each do |fd|
|
139
157
|
yield fd if block_given?
|
140
158
|
ret << fd
|
@@ -143,6 +161,29 @@ module RSCM::Accurev
|
|
143
161
|
return ret
|
144
162
|
end
|
145
163
|
|
164
|
+
# yeilds the TransactionData objects for the given time period
|
165
|
+
# (promotes only)
|
166
|
+
def ac_hist( from, to=Time.infinite )
|
167
|
+
cmd = Command.instance
|
168
|
+
lower = from.to_accurev
|
169
|
+
upper = "now"
|
170
|
+
unless to == Time.infinite
|
171
|
+
upper = to.to_accurev
|
172
|
+
end
|
173
|
+
with_working_dir( self.co_filepath ) do
|
174
|
+
acresponse = cmd.accurev( "hist",
|
175
|
+
"-t", "'#{upper}-#{lower}'",
|
176
|
+
"-k", "promote"
|
177
|
+
)
|
178
|
+
ret = []
|
179
|
+
acresponse['transaction'].each do |txn|
|
180
|
+
ret << txn
|
181
|
+
yield txn if block_given?
|
182
|
+
end
|
183
|
+
return ret
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
146
187
|
def ac_keep( files=[], message="" )
|
147
188
|
raise "XXX implement me"
|
148
189
|
end
|
@@ -180,7 +221,7 @@ module RSCM::Accurev
|
|
180
221
|
def ac_info()
|
181
222
|
co = RSCM::PathConverter.nativepath_to_filepath( @checkout_dir )
|
182
223
|
unless File.exists?( co )
|
183
|
-
raise AccurevException.new( "Checkout dir does not exist" )
|
224
|
+
raise AccurevException.new( "Checkout dir #{co} does not exist" )
|
184
225
|
end
|
185
226
|
info = {}
|
186
227
|
with_working_dir( co ) do
|
@@ -196,19 +237,6 @@ module RSCM::Accurev
|
|
196
237
|
return info
|
197
238
|
end
|
198
239
|
|
199
|
-
# ac mkws
|
200
|
-
# -b orbitz-host-gt3-0-impl
|
201
|
-
# -w orbitz-host-gt3-0-impl-test2_gfast
|
202
|
-
# -l `pwd`
|
203
|
-
# - does not support fx (argh!@)
|
204
|
-
# - does not pop
|
205
|
-
#
|
206
|
-
|
207
|
-
# diff: /usr/local/bin/acdiff (!) --fx
|
208
|
-
# (after an ac cat on the backed file)
|
209
|
-
# (eg, no in-process diffing ala cvs diff)
|
210
|
-
# lists modified lines in xml
|
211
|
-
|
212
240
|
#
|
213
241
|
# "Checks out or updates[!] contents from a central SCM
|
214
242
|
# to +checkout_dir+ - a local working copy."
|
@@ -232,28 +260,68 @@ module RSCM::Accurev
|
|
232
260
|
#
|
233
261
|
def checkout( to_identifier=Time.infinite )
|
234
262
|
co = RSCM::PathConverter.nativepath_to_filepath( @checkout_dir )
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
263
|
+
if @backing_stream.nil?
|
264
|
+
self.attempt_init_from_info()
|
265
|
+
end
|
266
|
+
if @workspace_stream.nil?
|
267
|
+
self.checkout_pop()
|
268
|
+
else
|
269
|
+
unless File.exists?( co )
|
270
|
+
# create new workspace
|
271
|
+
self.checkout_workspace()
|
239
272
|
end
|
240
|
-
|
241
|
-
|
273
|
+
# update workspace
|
274
|
+
self.update( to_identifier )
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
def checkout_pop()
|
279
|
+
co = RSCM::PathConverter.nativepath_to_filepath( @checkout_dir )
|
280
|
+
raise "A backing stream is required" if @backing_stream.nil?
|
281
|
+
raise "A working stream may not be given" unless @working_stream.nil?
|
282
|
+
# for `accurev pop`: remove and re-pop the checkout copy
|
283
|
+
if File.exists?( co )
|
284
|
+
unless @overwrite
|
285
|
+
raise "Checkout dir #{co} already exists (@overwrite=#@overwrite)"
|
242
286
|
end
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
287
|
+
rm_rf( co )
|
288
|
+
end
|
289
|
+
mkdir(co)
|
290
|
+
with_working_dir( co ) do
|
291
|
+
cmd = Command.instance
|
292
|
+
pop_out = cmd.accurev_nofx("pop",
|
293
|
+
"-R",
|
294
|
+
"-v", @backing_stream,
|
295
|
+
"-L", ".", ".")
|
296
|
+
elems = []
|
297
|
+
popio = StringIO.new( pop_out )
|
298
|
+
popio.each_line do |line|
|
299
|
+
if line =~ /^Populating element \/.\/(.*)$/
|
300
|
+
loc = $1
|
301
|
+
elems << loc
|
302
|
+
yield loc if block_given?
|
252
303
|
end
|
253
304
|
end
|
305
|
+
return elems
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def checkout_workspace()
|
310
|
+
co = RSCM::PathConverter.nativepath_to_filepath( @checkout_dir )
|
311
|
+
raise "A backing stream is required" if @backing_stream.nil?
|
312
|
+
raise "A workspace is required" if @working_stream.nil?
|
313
|
+
if File.exist?( co ) and !@overwrite
|
314
|
+
raise "Checkout dir #{co} already exists (@overwrite=#@overwrite)"
|
315
|
+
end
|
316
|
+
cmd = Command.instance
|
317
|
+
mkws_out = cmd.accurev_nofx( "mkws",
|
318
|
+
"-b", @backing_stream,
|
319
|
+
"-w", @workspace_stream,
|
320
|
+
"-l", co )
|
321
|
+
# kinda sucks:
|
322
|
+
if ( mkws_out =~ /already exists/ )
|
323
|
+
raise AccurevException.new( "Failed to checkout", mkws_out )
|
254
324
|
end
|
255
|
-
puts "> Updating workspace.."
|
256
|
-
self.update( to_identifier )
|
257
325
|
end
|
258
326
|
|
259
327
|
def update( to_identifier=Time.infinite )
|
@@ -290,7 +358,43 @@ module RSCM::Accurev
|
|
290
358
|
|
291
359
|
# --- internals
|
292
360
|
|
293
|
-
|
361
|
+
# status flag mappings for "stat", "file" commands
|
362
|
+
STATUSES = {
|
363
|
+
'(backed)' => :backed,
|
364
|
+
'(external)' => :external,
|
365
|
+
'(modified)' => :modified,
|
366
|
+
'(kept)' => :kept,
|
367
|
+
'(defunct)' => :defunct,
|
368
|
+
'(missing)' => :missing,
|
369
|
+
'(stranded)' => :stranded,
|
370
|
+
'(overlap)' => :overlap
|
371
|
+
}
|
372
|
+
|
373
|
+
# private
|
374
|
+
|
375
|
+
# psuedo-accessor (cached)
|
376
|
+
def co_filepath
|
377
|
+
if @co_filepath.nil?
|
378
|
+
@co_filepath = RSCM::PathConverter.nativepath_to_filepath( @checkout_dir )
|
379
|
+
end
|
380
|
+
return @co_filepath
|
381
|
+
end
|
382
|
+
|
383
|
+
#
|
384
|
+
# Runs an `ac info` command in +@checkout_dir+, and tries to
|
385
|
+
# set +@backing_stream+ and +@workspace_stream+ from the output.
|
386
|
+
#
|
387
|
+
def attempt_init_from_info()
|
388
|
+
if File.exists?( self.co_filepath )
|
389
|
+
info = self.ac_info
|
390
|
+
if info.has_key?( "Basis" )
|
391
|
+
@backing_stream = info["Basis"]
|
392
|
+
end
|
393
|
+
if info.has_key?( "ws/ref" )
|
394
|
+
@workspace_stream = info["ws/ref"]
|
395
|
+
end
|
396
|
+
end
|
397
|
+
end
|
294
398
|
|
295
399
|
# Takes a status flags line (eg, "(modified)(kept)")
|
296
400
|
# and returns a list of status flags.
|
@@ -302,6 +406,12 @@ module RSCM::Accurev
|
|
302
406
|
|
303
407
|
end
|
304
408
|
|
409
|
+
class Time
|
410
|
+
def to_accurev
|
411
|
+
self.strftime( "%Y/%m/%d %H:%M:%S" )
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
305
415
|
#
|
306
416
|
# Copyright (c) 2005 Gregory D. Fast <gdf@speakeasy.net>
|
307
417
|
#
|