Class: RSCM::Accurev::API
- Inherits:
-
Base
- Object
- Base
- RSCM::Accurev::API
- Defined in:
- lib/rscm/scm/accurev/api.rb
Overview
RSCM implementation for Accurev (www.accurev.com).
Requires an accurev cli executable on the path (see also RSCM::Accurev::Command), and the correct environment configuration for ac server/principal/password.
Example
api = RSCM::Accurev::API.new( "./ws/proj-1", "proj", "proj-1" )
api.checkout() each do |file|
puts "Updated #{file}..."
end
Constant Summary collapse
- STATUSES =
status flag mappings for “stat”, “file” commands
{ '(backed)' => :backed, '(external)' => :external, '(modified)' => :modified, '(kept)' => :kept, '(defunct)' => :defunct, '(missing)' => :missing, '(stranded)' => :stranded, '(overlap)' => :overlap }
Instance Attribute Summary collapse
-
#backing_stream ⇒ Object
Returns the value of attribute backing_stream.
-
#depot ⇒ Object
Returns the value of attribute depot.
-
#overwrite ⇒ Object
Returns the value of attribute overwrite.
-
#workspace_stream ⇒ Object
Returns the value of attribute workspace_stream.
Instance Method Summary collapse
-
#ac_files(relative_path) ⇒ Object
remember: ac_files is non-recursive.
-
#ac_hist(from, to = Time.infinite) ⇒ Object
yeilds the TransactionData objects for the given time period (promotes only).
-
#ac_info ⇒ Object
Performs an “accurev info” command in the workspace.
- #ac_keep(files = [], message = "") ⇒ Object
- #ac_move(current_file, new_file) ⇒ Object
- #ac_promote(files = [], message = "") ⇒ Object
- #ac_purge(files = []) ⇒ Object
- #ac_revert(files = []) ⇒ Object
- #ac_stat(flag = "-a") ⇒ Object
- #ac_update(relative_path = ".") ⇒ Object
-
#add(relative_filename) ⇒ Object
“Adds
relative_filename
to the working copy.”. -
#attempt_init_from_info ⇒ Object
Runs an ‘ac info` command in @checkout_dir, and tries to set @backing_stream and @workspace_stream from the output.
-
#checkout(to_identifier = Time.infinite) ⇒ Object
“Checks out or updates contents from a central SCM to
checkout_dir
- a local working copy.”. - #checkout_pop ⇒ Object
- #checkout_workspace ⇒ Object
-
#co_filepath ⇒ Object
psuedo-accessor (cached).
- #edit(relative_filename) ⇒ Object
-
#initialize(checkout_dir = nil, backing_stream = nil, workspace_stream = nil) ⇒ API
constructor
A new instance of API.
-
#map_status(status_line) ⇒ Object
Takes a status flags line (eg, “(modified)(kept)”) and returns a list of status flags.
- #name ⇒ Object
-
#revisions(from_identifier, to_identifier = Time.infinity) ⇒ Object
“Returns a Revisions object for the period specified …
-
#supports_trigger? ⇒ Boolean
accurev actually does have triggers, but I haven’t implemented that yet.
-
#transactional? ⇒ Boolean
Accurev operations are atomic: returns true.
- #update(to_identifier = Time.infinite) ⇒ Object
Constructor Details
#initialize(checkout_dir = nil, backing_stream = nil, workspace_stream = nil) ⇒ API
Returns a new instance of API.
63 64 65 66 67 68 69 |
# File 'lib/rscm/scm/accurev/api.rb', line 63 def initialize(checkout_dir=nil, backing_stream=nil, workspace_stream=nil) @depot = nil # will be pulled from files cmd output @workspace_stream = workspace_stream @backing_stream = backing_stream @checkout_dir = checkout_dir @overwrite = false end |
Instance Attribute Details
#backing_stream ⇒ Object
Returns the value of attribute backing_stream.
48 49 50 |
# File 'lib/rscm/scm/accurev/api.rb', line 48 def backing_stream @backing_stream end |
#depot ⇒ Object
Returns the value of attribute depot.
45 46 47 |
# File 'lib/rscm/scm/accurev/api.rb', line 45 def depot @depot end |
#overwrite ⇒ Object
Returns the value of attribute overwrite.
61 62 63 |
# File 'lib/rscm/scm/accurev/api.rb', line 61 def overwrite @overwrite end |
#workspace_stream ⇒ Object
Returns the value of attribute workspace_stream.
54 55 56 |
# File 'lib/rscm/scm/accurev/api.rb', line 54 def workspace_stream @workspace_stream end |
Instance Method Details
#ac_files(relative_path) ⇒ Object
remember: ac_files is non-recursive
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/rscm/scm/accurev/api.rb', line 134 def ac_files( relative_path ) cmd = Command.instance ret = [] with_working_dir( co_filepath ) do acresponse = cmd.accurev( "files", relative_path ) if acresponse['element'].nil? return [] end acresponse['element'].each do |fd| yield fd if block_given? ret << fd end end return ret end |
#ac_hist(from, to = Time.infinite) ⇒ Object
yeilds the TransactionData objects for the given time period (promotes only)
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/rscm/scm/accurev/api.rb', line 166 def ac_hist( from, to=Time.infinite ) cmd = Command.instance lower = from.to_accurev upper = "now" unless to == Time.infinite upper = to.to_accurev end with_working_dir( self.co_filepath ) do acresponse = cmd.accurev( "hist", "-t", "'#{upper}-#{lower}'", "-k", "promote" ) ret = [] acresponse['transaction'].each do |txn| ret << txn yield txn if block_given? end return ret end end |
#ac_info ⇒ Object
Performs an “accurev info” command in the workspace. Returns a map of
ac info: shows eg, backing stream but doesn’t support -fx!
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
# File 'lib/rscm/scm/accurev/api.rb', line 221 def ac_info() co = RSCM::PathConverter.nativepath_to_filepath( @checkout_dir ) unless File.exists?( co ) raise AccurevException.new( "Checkout dir #{co} does not exist" ) end info = {} with_working_dir( co ) do cmd = Command.instance io = StringIO.new( cmd.accurev_nofx( "info" ) ) io.each_line do |line| next unless line =~ /\S/ if line =~ /^(.*?):\s+(.*)$/ info[$1] = $2 end end end return info end |
#ac_keep(files = [], message = "") ⇒ Object
187 188 189 |
# File 'lib/rscm/scm/accurev/api.rb', line 187 def ac_keep( files=[], ="" ) raise "XXX implement me" end |
#ac_move(current_file, new_file) ⇒ Object
210 211 212 |
# File 'lib/rscm/scm/accurev/api.rb', line 210 def ac_move( current_file, new_file ) raise "XXX implement me" end |
#ac_promote(files = [], message = "") ⇒ Object
191 192 193 |
# File 'lib/rscm/scm/accurev/api.rb', line 191 def ac_promote( files=[], ="" ) raise "XXX implement me" end |
#ac_purge(files = []) ⇒ Object
202 203 204 |
# File 'lib/rscm/scm/accurev/api.rb', line 202 def ac_purge( files=[] ) raise "XXX implement me" end |
#ac_revert(files = []) ⇒ Object
206 207 208 |
# File 'lib/rscm/scm/accurev/api.rb', line 206 def ac_revert( files=[] ) raise "XXX implement me" end |
#ac_stat(flag = "-a") ⇒ Object
150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/rscm/scm/accurev/api.rb', line 150 def ac_stat( flag="-a" ) cmd = Command.instance ret = [] with_working_dir( co_filepath ) do acresponse = cmd.accurev( "stat", flag ) return [] if acresponse['element'].nil? acresponse['element'].each do |fd| yield fd if block_given? ret << fd end end return ret end |
#ac_update(relative_path = ".") ⇒ Object
195 196 197 198 199 200 |
# File 'lib/rscm/scm/accurev/api.rb', line 195 def ac_update( relative_path="." ) d = accurev( "update", relative_path ) if xxx_error_stale raise StaleWorkspaceError.new( "#{relative_path} is stale -- keep/anchor all changes and re-update" ) end end |
#add(relative_filename) ⇒ Object
“Adds relative_filename
to the working copy.”
81 82 83 |
# File 'lib/rscm/scm/accurev/api.rb', line 81 def add( relative_filename ) raise "XXX implement me" end |
#attempt_init_from_info ⇒ Object
Runs an ‘ac info` command in @checkout_dir, and tries to set @backing_stream and @workspace_stream from the output.
387 388 389 390 391 392 393 394 395 396 397 |
# File 'lib/rscm/scm/accurev/api.rb', line 387 def attempt_init_from_info() if File.exists?( self.co_filepath ) info = self.ac_info if info.has_key?( "Basis" ) @backing_stream = info["Basis"] end if info.has_key?( "ws/ref" ) @workspace_stream = info["ws/ref"] end end end |
#checkout(to_identifier = Time.infinite) ⇒ Object
“Checks out or updates contents from a central SCM to checkout_dir
- a local working copy.”
“The to_identifier
parameter may be optionally specified to obtain files up to a particular time or label.”
For accurev, this:
-
checks to see if @checkout_dir exists and appears checked out. If it’s already checked out, this calls update(). If @checkout_dir exists and
to_identifier
is given, an exception is raised. -
otherwise, this creates a new workspace stream and populates it at @checkout_dir.
This both returns and yields a list of updated files. Only updated files are returned, not directories.
Current, ac_update returns both files and directories, including deleted files.
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
# File 'lib/rscm/scm/accurev/api.rb', line 261 def checkout( to_identifier=Time.infinite ) co = RSCM::PathConverter.nativepath_to_filepath( @checkout_dir ) if @backing_stream.nil? self.attempt_init_from_info() end if @workspace_stream.nil? self.checkout_pop() else unless File.exists?( co ) # create new workspace self.checkout_workspace() end # update workspace self.update( to_identifier ) end end |
#checkout_pop ⇒ Object
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
# File 'lib/rscm/scm/accurev/api.rb', line 278 def checkout_pop() co = RSCM::PathConverter.nativepath_to_filepath( @checkout_dir ) raise "A backing stream is required" if @backing_stream.nil? raise "A working stream may not be given" unless @working_stream.nil? # for `accurev pop`: remove and re-pop the checkout copy if File.exists?( co ) unless @overwrite raise "Checkout dir #{co} already exists (@overwrite=#@overwrite)" end rm_rf( co ) end mkdir(co) with_working_dir( co ) do cmd = Command.instance pop_out = cmd.accurev_nofx("pop", "-R", "-v", @backing_stream, "-L", ".", ".") elems = [] popio = StringIO.new( pop_out ) popio.each_line do |line| if line =~ /^Populating element \/.\/(.*)$/ loc = $1 elems << loc yield loc if block_given? end end return elems end end |
#checkout_workspace ⇒ Object
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 |
# File 'lib/rscm/scm/accurev/api.rb', line 309 def checkout_workspace() co = RSCM::PathConverter.nativepath_to_filepath( @checkout_dir ) raise "A backing stream is required" if @backing_stream.nil? raise "A workspace is required" if @working_stream.nil? if File.exist?( co ) and !@overwrite raise "Checkout dir #{co} already exists (@overwrite=#@overwrite)" end cmd = Command.instance mkws_out = cmd.accurev_nofx( "mkws", "-b", @backing_stream, "-w", @workspace_stream, "-l", co ) # kinda sucks: if ( mkws_out =~ /already exists/ ) raise AccurevException.new( "Failed to checkout", mkws_out ) end end |
#co_filepath ⇒ Object
psuedo-accessor (cached)
376 377 378 379 380 381 |
# File 'lib/rscm/scm/accurev/api.rb', line 376 def co_filepath if @co_filepath.nil? @co_filepath = RSCM::PathConverter.nativepath_to_filepath( @checkout_dir ) end return @co_filepath end |
#edit(relative_filename) ⇒ Object
85 86 87 |
# File 'lib/rscm/scm/accurev/api.rb', line 85 def edit( relative_filename ) # NOP - not required for ac end |
#map_status(status_line) ⇒ Object
Takes a status flags line (eg, “(modified)(kept)”) and returns a list of status flags.
401 402 403 |
# File 'lib/rscm/scm/accurev/api.rb', line 401 def map_status( status_line ) l = status_line.split( " " ).map {|x| x.trim} end |
#name ⇒ Object
71 72 73 |
# File 'lib/rscm/scm/accurev/api.rb', line 71 def name() return "Accurev" end |
#revisions(from_identifier, to_identifier = Time.infinity) ⇒ Object
“Returns a Revisions object for the period specified … (inclusive).”
list txns (promotes to bs) from hist within the period
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/rscm/scm/accurev/api.rb', line 93 def revisions( from_identifier, to_identifier=Time.infinity ) revisions = RSCM::Revisions.new() self.ac_hist( from_identifier, to_identifier ).each do |txn| txnrev = RSCM::Revision.new txnrev.identifier = txn.id txnrev.developer = txn.user txnrev. = txn['comment'].join("\n") unless txn['comment'].nil? txnrev.time = Time.at( txn.time.to_i ) txn['version'].each do |v| f = RSCM::RevisionFile.new() f.path = v.path # i think to get real status, you'd need to analyze keep txns f.status = RSCM::RevisionFile::MODIFIED # XXX? txn.type==promote here f.developer = txn.user f.native_revision_identifier = v.real # XXX or .virtual? f.time = Time.at( txn.time.to_i ) txnrev << f end revisions.add( txnrev ) end return revisions end |
#supports_trigger? ⇒ Boolean
accurev actually does have triggers, but I haven’t implemented that yet
124 125 126 |
# File 'lib/rscm/scm/accurev/api.rb', line 124 def supports_trigger? false end |
#transactional? ⇒ Boolean
Accurev operations are atomic: returns true.
76 77 78 |
# File 'lib/rscm/scm/accurev/api.rb', line 76 def transactional? return true end |
#update(to_identifier = Time.infinite) ⇒ Object
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 |
# File 'lib/rscm/scm/accurev/api.rb', line 327 def update( to_identifier=Time.infinite ) co = RSCM::PathConverter.nativepath_to_filepath( @checkout_dir ) unless File.exists?( co ) raise AccurevException.new( "Workspace does not exist!" ) end updated = [] with_working_dir( co ) do cmd = Command.instance acresponse = cmd.accurev( "update" ) if acresponse.error if acresponse.error =~ /workspace have been modified/ raise StaleWorkspaceException.new( "Workspace stale", acresponse.error ) else # some other update problem raise AccurevException.new( "Error on update", acresponse.error ) end end if acresponse['element'] acresponse['element'].each do |up| # "ac update" on a new workspace yields element locations # with leading "/"s, which should be removed to get a proper # relative path: loc = up.location.sub( /^\//, "" ) yield loc if block_given? updated << loc end end end return updated end |