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
# Checkout a new workspace:
api = RSCM::Accurev::API.new( "./ws/proj-1", "proj", "proj-1" )
api.checkout() each do |file|
puts "Updated #{file}..."
end
# Checkout a new (read-only) stream:
api = RSCM::Accurev::API.new( "./ws/proj-1", "proj" )
api.checkout() each {|f| ...}
# Update a checked-out workspace or copy:
api = RSCM::Accurev::API.new( "./ws/proj-1" )
api.checkout() each{|f| ... }
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
ann :description => “Backing Stream (autodetected)”.
-
#depot ⇒ Object
ann :description => “Accurev Depot”.
-
#overwrite ⇒ Object
ann :description => “Overwrite Mode: if true, co overwrites existing”.
-
#workspace_stream ⇒ Object
If workspace stream is nil (the default), checkout/update will be done using ‘accurev pop`.
Instance Method Summary collapse
-
#ac_files(relative_path) ⇒ Object
remember: ac_files is non-recursive.
-
#ac_hist(from, to = Time.infinity) ⇒ 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.infinity) ⇒ Object
“Checks out or updates contents from a central SCM to
checkout_dir
- a local working copy.”. - #checkout_pop ⇒ Object
-
#co_filepath ⇒ Object
psuedo-accessor (cached).
- #create_workspace ⇒ Object
- #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 (eg, [“modified”, “kept”]).
- #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.infinity) ⇒ Object
Updates an existing workspace stream checked out to @checkout_dir.
Constructor Details
#initialize(checkout_dir = nil, backing_stream = nil, workspace_stream = nil) ⇒ API
Returns a new instance of API.
71 72 73 74 75 76 77 |
# File 'lib/rscm/scm/accurev/api.rb', line 71 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
ann :description => “Backing Stream (autodetected)”
56 57 58 |
# File 'lib/rscm/scm/accurev/api.rb', line 56 def backing_stream @backing_stream end |
#depot ⇒ Object
ann :description => “Accurev Depot”
53 54 55 |
# File 'lib/rscm/scm/accurev/api.rb', line 53 def depot @depot end |
#overwrite ⇒ Object
ann :description => “Overwrite Mode: if true, co overwrites existing”
69 70 71 |
# File 'lib/rscm/scm/accurev/api.rb', line 69 def overwrite @overwrite end |
#workspace_stream ⇒ Object
If workspace stream is nil (the default), checkout/update will be done using ‘accurev pop`. This is faster and more appropriate for read-only use; however a workspace is required for commits. ann :description => “Workspace Stream”
62 63 64 |
# File 'lib/rscm/scm/accurev/api.rb', line 62 def workspace_stream @workspace_stream end |
Instance Method Details
#ac_files(relative_path) ⇒ Object
remember: ac_files is non-recursive
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/rscm/scm/accurev/api.rb', line 142 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.infinity) ⇒ Object
yeilds the TransactionData objects for the given time period (promotes only)
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/rscm/scm/accurev/api.rb', line 174 def ac_hist( from, to=Time.infinity ) cmd = Command.instance lower = from.to_accurev upper = "now" unless to == Time.infinity 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!
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/rscm/scm/accurev/api.rb', line 229 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
195 196 197 |
# File 'lib/rscm/scm/accurev/api.rb', line 195 def ac_keep( files=[], ="" ) raise "XXX implement me" end |
#ac_move(current_file, new_file) ⇒ Object
218 219 220 |
# File 'lib/rscm/scm/accurev/api.rb', line 218 def ac_move( current_file, new_file ) raise "XXX implement me" end |
#ac_promote(files = [], message = "") ⇒ Object
199 200 201 |
# File 'lib/rscm/scm/accurev/api.rb', line 199 def ac_promote( files=[], ="" ) raise "XXX implement me" end |
#ac_purge(files = []) ⇒ Object
210 211 212 |
# File 'lib/rscm/scm/accurev/api.rb', line 210 def ac_purge( files=[] ) raise "XXX implement me" end |
#ac_revert(files = []) ⇒ Object
214 215 216 |
# File 'lib/rscm/scm/accurev/api.rb', line 214 def ac_revert( files=[] ) raise "XXX implement me" end |
#ac_stat(flag = "-a") ⇒ Object
158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/rscm/scm/accurev/api.rb', line 158 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
203 204 205 206 207 208 |
# File 'lib/rscm/scm/accurev/api.rb', line 203 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.”
89 90 91 |
# File 'lib/rscm/scm/accurev/api.rb', line 89 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.
407 408 409 410 411 412 413 414 415 416 417 |
# File 'lib/rscm/scm/accurev/api.rb', line 407 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.infinity) ⇒ 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.
@yield: path
for each file/directory updated
See also #update().
XXX doesn’t yield
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
# File 'lib/rscm/scm/accurev/api.rb', line 274 def checkout( to_identifier=Time.infinity ) 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.create_workspace() end # update workspace ret = [] self.update( to_identifier ).each do |e| ret << e yield e if block_given? end end end |
#checkout_pop ⇒ Object
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 |
# File 'lib/rscm/scm/accurev/api.rb', line 295 def checkout_pop() co = RSCM::PathConverter.nativepath_to_filepath( @checkout_dir ) raise AccurevException.new("A backing stream is required") if @backing_stream.nil? raise AccurevException.new("A working stream may not be given") unless @workspace_stream.nil? # for `accurev pop`: remove and re-pop the checkout copy if File.exists?( co ) unless @overwrite raise AccurevException.new("Checkout dir #{co} already exists (@overwrite=#@overwrite)") end rm_rf( co ) end Dir.mkdir(co) unless File.exists?(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 |
#co_filepath ⇒ Object
psuedo-accessor (cached)
396 397 398 399 400 401 |
# File 'lib/rscm/scm/accurev/api.rb', line 396 def co_filepath if @co_filepath.nil? @co_filepath = RSCM::PathConverter.nativepath_to_filepath( @checkout_dir ) end return @co_filepath end |
#create_workspace ⇒ Object
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 |
# File 'lib/rscm/scm/accurev/api.rb', line 326 def create_workspace() co = RSCM::PathConverter.nativepath_to_filepath( @checkout_dir ) raise AccurevException.new("A backing stream is required") if @backing_stream.nil? raise AccurevException.new("A workspace is required") if @workspace_stream.nil? if File.exist?( co ) and !@overwrite raise AccurevException.new("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 |
#edit(relative_filename) ⇒ Object
93 94 95 |
# File 'lib/rscm/scm/accurev/api.rb', line 93 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 (eg, [“modified”, “kept”]).
421 422 423 424 425 |
# File 'lib/rscm/scm/accurev/api.rb', line 421 def map_status( status_line ) s = status_line.split( /\W/ ).delete_if do |x| x.nil? or x.length==0 end end |
#name ⇒ Object
79 80 81 |
# File 'lib/rscm/scm/accurev/api.rb', line 79 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
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/rscm/scm/accurev/api.rb', line 101 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
132 133 134 |
# File 'lib/rscm/scm/accurev/api.rb', line 132 def supports_trigger? false end |
#transactional? ⇒ Boolean
Accurev operations are atomic: returns true.
84 85 86 |
# File 'lib/rscm/scm/accurev/api.rb', line 84 def transactional? return true end |
#update(to_identifier = Time.infinity) ⇒ Object
Updates an existing workspace stream checked out to @checkout_dir
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 |
# File 'lib/rscm/scm/accurev/api.rb', line 347 def update( to_identifier=Time.infinity ) 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 |