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