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.
Files changed (52) hide show
  1. data/LICENSE +25 -0
  2. data/README +9 -0
  3. data/Rakefile +137 -0
  4. data/STATUS +63 -0
  5. data/TODO +43 -0
  6. data/apitest.rb +21 -0
  7. data/bumprelease.sh +13 -0
  8. data/lib/rscm/accurev.rb +18 -0
  9. data/lib/rscm/scm/accurev/api.rb +411 -0
  10. data/lib/rscm/scm/accurev/api.rb.mine +382 -0
  11. data/lib/rscm/scm/accurev/api.rb.r263 +364 -0
  12. data/lib/rscm/scm/accurev/api.rb.r265 +393 -0
  13. data/lib/rscm/scm/accurev/command.rb +151 -0
  14. data/lib/rscm/scm/accurev/exception.rb +38 -0
  15. data/lib/rscm/scm/accurev/filterio.rb +57 -0
  16. data/lib/rscm/scm/accurev/xml.rb +224 -0
  17. data/lib/test/unit/ui/xml/testrunner.rb +165 -0
  18. data/lib/test/unit/ui/xml/xmltestrunner.xslt +79 -0
  19. data/test/acreplay.rb +22 -0
  20. data/test/coverage/analyzer.rb +127 -0
  21. data/test/coverage/c_loader.rb +34 -0
  22. data/test/coverage/cover.rb +91 -0
  23. data/test/coverage/coverage_loader.rb +21 -0
  24. data/test/coverage/coveragetask.rb +38 -0
  25. data/test/coverage/index_tmpl.html +42 -0
  26. data/test/coverage/template.html +36 -0
  27. data/test/eg/ac-files.xml +172 -0
  28. data/test/eg/ac-pop.txt +195 -0
  29. data/test/eg/files-various-states.xml +188 -0
  30. data/test/eg/hist-oneweek-all.xml +1483 -0
  31. data/test/eg/hist-oneweek-external.xml +246 -0
  32. data/test/eg/hist-oneweek-promotes.xml +1092 -0
  33. data/test/eg/info.txt +14 -0
  34. data/test/eg/stat-a-various.xml +1789 -0
  35. data/test/eg/stat-m.xml +13 -0
  36. data/test/eg/stat-overlap.xml +13 -0
  37. data/test/eg/stat-x.xml +20 -0
  38. data/test/eg/update-i-mods-and-updates-and-overlap.xml +73 -0
  39. data/test/eg/update-i-nochanges.xml +8 -0
  40. data/test/eg/update-i-stale.xml +0 -0
  41. data/test/eg/update-i-updates.xml +125 -0
  42. data/test/eg/update-newwksp.xml +183 -0
  43. data/test/eg/update-nochanges.xml +7 -0
  44. data/test/eg/update-stale.xml +12 -0
  45. data/test/eg/update-updates.xml +147 -0
  46. data/test/t_api.rb +163 -0
  47. data/test/t_command.rb +85 -0
  48. data/test/t_filterio.rb +60 -0
  49. data/test/t_load.rb +11 -0
  50. data/test/t_scrubio.rb +117 -0
  51. data/test/t_xmlmapper.rb +75 -0
  52. metadata +106 -0
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ Copyright (c) 2005, Gregory D. Fast
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions
6
+ are met:
7
+
8
+ * Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+
11
+ * Redistributions in binary form must reproduce the above copyright
12
+ notice, this list of conditions and the following disclaimer in the
13
+ documentation and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README ADDED
@@ -0,0 +1,9 @@
1
+ RSCM::Accurev
2
+ =============
3
+
4
+ This is an api for interacting with the SCM tool accurev
5
+ (http://accurev.com).
6
+
7
+ NOTE: This is a early pre-alpha quality release, and is currently
8
+ unsuitable for use.
9
+
data/Rakefile ADDED
@@ -0,0 +1,137 @@
1
+ # -*- ruby -*-
2
+ require 'rubygems'
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+ require 'rake/rdoctask'
6
+ require 'rake/packagetask'
7
+ require 'rake/gempackagetask'
8
+ require 'tracer'
9
+
10
+ # this rakefile originally borrowed shamelessly from rscm
11
+
12
+ PKG_NAME = 'rscm-accurev'
13
+ PKG_BUILD = ENV['PKG_BUILD'] ? '.'+ENV['PKG_BUILD'] : ''
14
+ PKG_VERSION = '0.0' + PKG_BUILD
15
+ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
16
+ PKG_SUMMARY = 'RSCM::Accurev - RSCM API for Accurev'
17
+
18
+ desc "Default Task"
19
+ task :default => [ :test, :gem ]
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
32
+
33
+ # define a task(s) to run tests
34
+
35
+ test_files = FileList.new( "test/**/t_*.rb" )
36
+ TEST_OUTPUT = "html/test"
37
+
38
+ Rake::TestTask.new( :plaintest ) do |t|
39
+ t.libs << "test"
40
+ t.test_files = test_files
41
+ t.verbose = true
42
+ end
43
+
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
47
+ # (see doc/patches)
48
+ Rake::TestTask.new( :xmltest ) do |t|
49
+ t.libs << "test"
50
+ t.test_files = test_files
51
+ t.verbose = true
52
+ t.ruby_opts << '-rtest/unit/ui/xml/testrunner'
53
+ ENV['XMLTEST_OUTPUT'] = "#{TEST_OUTPUT}/testresults.xml"
54
+ t.options = "--runner=xml"
55
+ end
56
+ end # !HAVEXMLTEST
57
+
58
+
59
+ # backs up existing testresults.xml files in test target dir
60
+ task :backup_testresults do
61
+ unless File.exist?( TEST_OUTPUT )
62
+ mkdir_p( TEST_OUTPUT )
63
+ end
64
+ old = "#{TEST_OUTPUT}/testresults.xml"
65
+ if File.exist?( old )
66
+ stat = File.stat( old )
67
+ bak = stat.ctime.strftime('testresults-%Y%m%d-%H%M.xml')
68
+ new = "#{TEST_OUTPUT}/#{bak}"
69
+ #puts "...Backing up previous test results to #{new}"
70
+ mv( old, new )
71
+ end
72
+ end
73
+
74
+ # define a task to create rdocs
75
+ # keep a reference to it so we can reuse it in the gempkg task
76
+ rd_task = Rake::RDocTask.new( :rdoc ) do |rdoc|
77
+ rdoc.title = PKG_SUMMARY
78
+ rdoc.template = "doc/jamis.rb" # so nice
79
+ rdoc.options << '--line-numbers' << '--inline-source'
80
+ rdoc.rdoc_files.include( 'STATUS' )
81
+ rdoc.rdoc_files.include( 'lib/**/*.rb' )
82
+ rdoc.rdoc_files.include( 'doc/*.rd' )
83
+ end
84
+
85
+ PKG_FILES = FileList[
86
+ '*',
87
+ 'lib/**/*',
88
+ 'test/**/*'
89
+ ]
90
+
91
+ if ! defined?(Gem)
92
+ puts "Target 'package' requires RubyGems"
93
+ else
94
+ spec = Gem::Specification.new do |s|
95
+ s.name = PKG_NAME
96
+ s.version = PKG_VERSION
97
+ s.summary = PKG_SUMMARY
98
+ s.description = "RSCM::Accurev is an RSCM API for the SCM tool Accurev (http://www.accurev.com/)."
99
+ s.files = PKG_FILES.to_a
100
+ s.require_path = 'lib'
101
+ s.autorequire = 'rscm/scm/accurev'
102
+ s.has_rdoc = true
103
+ rd_task.options.each {|opt| s.rdoc_options << opt }
104
+ s.author = "Greg Fast"
105
+ s.email = "gdf@speakeasy.net"
106
+ s.homepage = "http://rscm-accurev.rubyforge.org"
107
+ end
108
+
109
+ # define a gem package task
110
+ Rake::GemPackageTask.new( spec ) do |pkg|
111
+ pkg.need_zip = true
112
+ pkg.need_tar = true
113
+ end
114
+ end
115
+
116
+ desc "Delete all generated files (includes built packages)"
117
+ task :realclean do
118
+ f = FileList[ 'pkg', 'html', 'doc/test*.xml' ]
119
+ rm_rf f
120
+ end
121
+
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
data/STATUS ADDED
@@ -0,0 +1,63 @@
1
+
2
+ = RSCM::Accurev Status
3
+
4
+ ------------------------
5
+
6
+ == Core RSCM API (RSCM::Accurev::API)
7
+
8
+ [checkout()] supported
9
+
10
+ - basic checkouts should work
11
+
12
+ - time-based checkouts do not work
13
+
14
+ [update()] basic updates work
15
+
16
+ - time-based updates ("update( yesterday )") not working
17
+
18
+ - elements list returned currently includes directories and removed files
19
+
20
+ [add()] unsupported, todo(?)
21
+
22
+ [edit()] supported (no-op)
23
+
24
+ [revisions()] supported
25
+
26
+ - time-based limits do not work
27
+
28
+ - should be history-based
29
+
30
+ -------------------------------------------
31
+
32
+ == Accurev-specific API (RSCM::Accurev::API)
33
+
34
+ [ac_update()] unsupported, todo
35
+
36
+ [ac_files()] supported
37
+
38
+ [ac_info()] supported
39
+
40
+ [ac_stat()] unsupported, use ac_files().
41
+
42
+ [ac_move()] unsupported, todo
43
+
44
+ [ac_pop()] unsupported, todo
45
+
46
+ [ac_purge()] unsupported, todo
47
+
48
+ [ac_hist()] unsupported, todo
49
+
50
+ [ac_keep()] unsupported, todo
51
+
52
+ [ac_promote()] unsupported, todo
53
+
54
+ -------------------------------------------
55
+
56
+ == Other Items
57
+
58
+ [code docs] woefully incomplete
59
+
60
+ [usage docs] virtually nonexistant
61
+
62
+ [test coverage] truly pitiful
63
+
data/TODO ADDED
@@ -0,0 +1,43 @@
1
+ # todo for rscm/scm/accurev.rb
2
+
3
+ api - checkout
4
+ - there is no rscm-api update() (only checkout-to-existing-ws)
5
+ - `pop`, `update`
6
+
7
+ **api - revisions
8
+ - `hist` (others?)
9
+
10
+ api - diff
11
+ - `diff` (yukx)
12
+
13
+ api - import_central, create_central
14
+ - munge depots - probably skip these, or use acxmlparser
15
+
16
+ api - api-specific commands to manage streams
17
+ - use acxmlparser
18
+
19
+ api - triggers?
20
+
21
+ **api - identifiers (Time or revision) to ac format
22
+ - is this even always applicable? does stat/update take limits?
23
+
24
+ # xml - s/FileStatus/FileData/
25
+
26
+ api - checkout(Time.infinite) just does update
27
+ checkout(x) only works if ws not exist
28
+ unless it implies nuke-and-re-checkout (slow)
29
+
30
+ api - need ac_update which returns an acresponse
31
+
32
+ api - update: elements list should not contain directories
33
+
34
+ api - update: elements list should probably not include removed files
35
+
36
+ # command - Command.working_dir is bad: should use with_working_dir()
37
+
38
+ *** api - checkout() should use `pop` instead of `mkws`, unless
39
+ user *really* wants it
40
+ - yeargh... how does update work with pop? just nuke and/or overwrite?
41
+
42
+ ac pop -R -v orbitz-host-gt3-0-rc -L . . > ~/cheese/rscm-accurev/test/eg/ac-pop.txt
43
+
data/apitest.rb ADDED
@@ -0,0 +1,21 @@
1
+ #!/opt/ruby/bin/ruby
2
+ require 'rubygems'
3
+
4
+ $:<<"lib"
5
+ require 'rscm/scm/accurev'
6
+
7
+ #files; ac = RSCM::Accurev.new( '/home/gfast/dev/orbitz-host-gt3-0-impl' )
8
+ #files; ac.ac_files(".").each do |f|
9
+ #files; puts "#{f.location}\t\t#{f.status}"
10
+ #files; end
11
+
12
+ # yes, i cannot spell, the dir is "hirdcar":
13
+ ac = RSCM::Accurev.new( '/home/gfast/dev/orbitz-api-hirdcar-0-rc' )
14
+ ac.backing_stream = "orbitz-api-hiredcar-0-rc"
15
+ ac.workspace_stream = "orbitz-api-hiredcar-0-rc-testing_gfast"
16
+ ac.checkout() do |l|
17
+ puts l
18
+ end
19
+
20
+
21
+
data/bumprelease.sh ADDED
@@ -0,0 +1,13 @@
1
+ #!/bin/sh
2
+
3
+ # gee, i bet you could stick this in the rakefile...
4
+
5
+ LAST=`cat .version.minor`
6
+ MINOR=$(( $LAST + 1 ))
7
+
8
+ perl -i~~ -pe "s/VERSION = '0.0.\d+'/VERSION = '0.0.$MINOR'/" \
9
+ lib/rscm/accurev.rb
10
+
11
+ PKG_BUILD=$MINOR rake package gem && \
12
+ echo $MINOR > .version.minor
13
+
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rscm/scm/accurev/api'
3
+ require 'rscm/scm/accurev/command'
4
+ require 'rscm/scm/accurev/xml'
5
+ require 'rscm/scm/accurev/filterio'
6
+
7
+ module RSCM
8
+ #
9
+ # == module RSCM::Accurev
10
+ #
11
+ # Namespace for accurev api classes and utils.
12
+ #
13
+ # See RSCM::Accurev::API.
14
+ #
15
+ module Accurev
16
+ VERSION = '0.0.5'
17
+ end
18
+ end
@@ -0,0 +1,411 @@
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
+ # remember: ac_files is non-recursive
115
+ def ac_files( relative_path )
116
+ cmd = Command.instance
117
+ ret = []
118
+ with_working_dir( co_filepath ) do
119
+ acresponse = cmd.accurev( "files", relative_path )
120
+ if acresponse['element'].nil?
121
+ return []
122
+ end
123
+ acresponse['element'].each do |fd|
124
+ yield fd if block_given?
125
+ ret << fd
126
+ end
127
+ end
128
+ return ret
129
+ end
130
+
131
+ def ac_stat( flag="-a" )
132
+ cmd = Command.instance
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
165
+ end
166
+ end
167
+
168
+ def ac_keep( files=[], message="" )
169
+ raise "XXX implement me"
170
+ end
171
+
172
+ def ac_promote( files=[], message="" )
173
+ raise "XXX implement me"
174
+ end
175
+
176
+ def ac_update( relative_path="." )
177
+ d = accurev( "update", relative_path )
178
+ if xxx_error_stale
179
+ raise StaleWorkspaceError.new( "#{relative_path} is stale -- keep/anchor all changes and re-update" )
180
+ end
181
+ end
182
+
183
+ def ac_purge( files=[] )
184
+ raise "XXX implement me"
185
+ end
186
+
187
+ def ac_revert( files=[] )
188
+ raise "XXX implement me"
189
+ end
190
+
191
+ def ac_move( current_file, new_file )
192
+ raise "XXX implement me"
193
+ end
194
+
195
+ #
196
+ # Performs an "accurev info" command in the workspace.
197
+ # Returns a map of
198
+ #
199
+ # 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
+
221
+ # ac mkws
222
+ # -b orbitz-host-gt3-0-impl
223
+ # -w orbitz-host-gt3-0-impl-test2_gfast
224
+ # -l `pwd`
225
+ # - does not support fx (argh!@)
226
+ # - does not pop
227
+ #
228
+
229
+ # diff: /usr/local/bin/acdiff (!) --fx
230
+ # (after an ac cat on the backed file)
231
+ # (eg, no in-process diffing ala cvs diff)
232
+ # lists modified lines in xml
233
+
234
+ #
235
+ # "Checks out or updates[!] contents from a central SCM
236
+ # to +checkout_dir+ - a local working copy."
237
+ #
238
+ # "The +to_identifier+ parameter may be optionally specified to
239
+ # obtain files up to a particular time or label."
240
+ #
241
+ # For accurev, this:
242
+ # * checks to see if +@checkout_dir+ exists and appears checked out.
243
+ # If it's already checked out, this calls +update()+. If
244
+ # +@checkout_dir+ exists and +to_identifier+ is given, an
245
+ # exception is raised.
246
+ # * otherwise, this creates a new workspace stream and populates it
247
+ # at +@checkout_dir+.
248
+ #
249
+ # This both returns and yields a list of updated files.
250
+ # Only updated files are returned, not directories.
251
+ #
252
+ # Current, ac_update returns both files and directories, including
253
+ # deleted files.
254
+ #
255
+ def checkout( to_identifier=Time.infinite )
256
+ co = RSCM::PathConverter.nativepath_to_filepath( @checkout_dir )
257
+ if @backing_stream.nil?
258
+ self.attempt_init_from_info()
259
+ end
260
+ if @workspace_stream.nil?
261
+ self.checkout_pop()
262
+ else
263
+ unless File.exists?( co )
264
+ # create new workspace
265
+ self.checkout_workspace()
266
+ end
267
+ # update workspace
268
+ self.update( to_identifier )
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)"
280
+ end
281
+ rm_rf( co )
282
+ end
283
+ mkdir(co)
284
+ with_working_dir( co ) do
285
+ cmd = Command.instance
286
+ pop_out = cmd.accurev_nofx("pop",
287
+ "-R",
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
298
+ 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
+ end
319
+ end
320
+
321
+ def update( to_identifier=Time.infinite )
322
+ co = RSCM::PathConverter.nativepath_to_filepath( @checkout_dir )
323
+ unless File.exists?( co )
324
+ raise AccurevException.new( "Workspace does not exist!" )
325
+ end
326
+ updated = []
327
+ with_working_dir( co ) do
328
+ cmd = Command.instance
329
+ acresponse = cmd.accurev( "update" )
330
+ if acresponse.error
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
348
+ end
349
+ end
350
+ return updated
351
+ end
352
+
353
+ # --- internals
354
+
355
+ # status flag mappings for "stat", "file" commands
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
376
+
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
392
+
393
+ # Takes a status flags line (eg, "(modified)(kept)")
394
+ # and returns a list of status flags.
395
+ def map_status( status_line )
396
+ l = status_line.split( " " ).map {|x| x.trim}
397
+ end
398
+
399
+ end
400
+
401
+ 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
+ #