rscm-accurev 0.0

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