Class P4Record
In: P4table.rb
Parent: Object

Main record manipulation class. Handles the loading and saving of records as both jobs and files.

Methods
abandon    add_file    create    delete    each_file    exists=    exists?    exists?    file_list    get_file    load    metafile    method_missing    new    obliterate    query    rm_file    save   
Attributes
:files  [R] 
:id  [RW] 
:meta  [RW] 
:seq  [RW] 
:spec  [RW] 
:table  [RW] 
Public Class methods
load( id )

Load a record from its associated job. Use to load existing records rather than constructing new ones. Raises a RuntimeError if the record does not exist.

# File P4table.rb, line 427
    def P4Record.load( id )

	if ( ! P4Record.exists?( id ) )
	    raise( RuntimeError, "Record #{id.to_s} does not exist", caller )
	end

	rec = P4Record.new( id )
	rec.spec = P4Global.tagged.fetch_job( id.to_s )
	if rec.spec.has_key?( "files" )
	    rec.spec[ "files" ].each do
		|file|
		name = file.sub( ".*/", "" ).chomp
		f = P4RecFile.new( name, id ) 
		f.exists = true
		f.depot_path = file.chomp
		rec.files[ name ] =  f
	    end
	end
	rec.exists = true
	return rec
    end
query( table, expr )

Load all records matching a query expression. Uses a dynamically built "p4 jobs -e" expression to identify the matching records and then loads each record. Returns an array of P4Record objects.

# File P4table.rb, line 454
    def P4Record.query( table, expr )
	expr = "job=#{table} & ( " + expr + " )"
	P4Global.tagged.run_jobs( "-e", expr ).collect do
	    |job|
	    rec = P4Record.new( P4RecId.new_from_job( job[ "job" ] ) )
	    rec.spec = job
	    rec.spec[ "files" ].each do
		|file|
		name = file.sub( ".*/", "" ).chomp
		f = P4RecFile.new( name, id ) 
		f.exists = true
		f.depot_path = file
		rec.files[ name ] =  f
	    end
	    rec.exists = true
	    rec
	end
    end
create( table )

Create a new record in the given table. Returns the skeletal record populated with the default values from the jobspec for editing.

# File P4table.rb, line 477
    def P4Record.create( table )
	id = P4RecId.next( table )
	rec = P4Record.new( id )
	rec.spec = P4Global.tagged.fetch_job( id.to_s )
	return rec
    end
exists?( id )

Test for record existence

# File P4table.rb, line 487
    def P4Record.exists?( id )
	jobs = P4Global.tagged.run_jobs( "-e", "job=" + id.to_s )
	return jobs.length > 0 
    end
new( id )

Constructor: DON'T USE NEW DIRECTLY, CALL create/load.

# File P4table.rb, line 495
    def initialize( id )
	@id 	= id
	@table	= id.table
	@seq	= id.seq
	@spec	= nil
	@exists	= false
	@files	= Hash.new

	@files[ "meta" ] = P4RecFile.new( "meta", @id )
    end
Public Instance methods
exists?()

Test for record existence

# File P4table.rb, line 512
    def exists?
	return @exists
    end
exists=( bool )

Explicitly set record existence (or otherwise)

# File P4table.rb, line 519
    def exists=( bool )
	@exists = bool
    end
get_file( name )

Get a file handle by name (not the depot path). Returns a P4RecFile object.

# File P4table.rb, line 528
    def get_file( name )
	return @files[ name ] if @files.has_key?( name )
	raise( RuntimeError, "Record contains no file called #{name}", caller )
    end
metafile()

Get the meta file specifically. Just shorthand.

# File P4table.rb, line 536
    def metafile
	get_file( "meta" )
    end
each_file() {| f | ...}

Iterate over the files in the record

# File P4table.rb, line 543
    def each_file
	@files.each_value { |f| yield( f ) }
    end
add_file( name )

Add a new file attachment to this record

# File P4table.rb, line 550
    def add_file( name )
	if ( name == "meta" )
	    raise( RuntimeError, "The meta file already exists.", caller )
	end

	nfile = P4RecFile.new( name, @id )
	nfile.add
	@files[ "name" ] =  nfile
    end
rm_file( file )

Remove a file attachment

# File P4table.rb, line 563
    def rm_file( file )
	if ( file == "meta" )
	    raise( RuntimeError, "You can't delete the meta file", caller )
	end

	f = get_file( file )
	f.delete
	@files.delete( file )
    end
abandon()

Abandon all edits to this record. Use with care: it reverts the files that are open for add/edit/delete etc. but it doesn't reload the record from the job - it may be a new record. You should either discard the record or reload it yourself after calling abandon().

# File P4table.rb, line 580
    def abandon
	p4 = P4Global.tagged
	each_file do
	    |f|
	    fs = p4.run_fstat( f.ws_path )
	    if ( fs && fs[ "action" ] == "add" )
		File.unlink( f.ws_path )
	    end
	    p4.run_revert( f.depot_path )
	end
    end
file_list()

Get the list of files attached to this record in depot syntax

# File P4table.rb, line 595
    def file_list
	@files.values.collect do
	    |f|
	    f.depot_path
	end.compact.join( "\n" )
    end
save( desc )

Update the record. Updates the job and then archives the job into the meta file and saves any attached files. Provide the description you'd like to see attached to the change

# File P4table.rb, line 608
    def save( desc )
	# First rewrite the files list in case it's been modified
	@spec[ "files" ] = file_list

	# Next update the job with the values in the spec
	P4Global.tagged.save_job( @spec )

	# Now update the metafile with the job -o output
	if ( exists? )
	    metafile.edit
	else
	    metafile.add
	end

	metafile.mkdir
	metafile.write( P4Global.plain.fetch_job( @id.to_s ) )

	# Now submit
	change = P4Global.tagged.fetch_change
	change[ "Description" ] = desc
	P4Global.tagged.submit_spec( change )

	@exists = true
    end
delete( desc )

Delete a record. Deletes the files and the job.

# File P4table.rb, line 636
    def delete( desc )
	if ( ! exists? )
	    raise( RuntimeError, "Can't delete. Record doesn't exist.", caller )
	end

	@files.values.each { |f| f.delete }
	change = P4Global.tagged.fetch_change
	change[ "Description" ] = desc
	P4Global.tagged.submit_spec( change )
	P4Global.tagged.run_job( "-d", @spec[ "job" ] )
	@files = Hash.new
	@spec[ "files" ] = Array.new
	@exists = false
    end
obliterate()

Obliterate a record. Does exactly what it says on the tin.

# File P4table.rb, line 655
    def obliterate
	if ( ! exists? )
	    raise( RuntimeError, "Can't oblit. Record doesn't exist.", caller )
	end

	args = @files.values.collect { |f| f.depot_path } 
	P4Global.tagged.exception_level = 1
	P4Global.tagged.run_sync( args.collect { |a| a += "#none" } )
	P4Global.tagged.exception_level = 2
	P4Global.tagged.run_obliterate( "-y", args )
	P4Global.tagged.run_job( "-d", @spec[ "job" ] )
	@spec[ "files" ] = Array.new
	@files = Hash.new
	@exists = false
    end
method_missing( meth, *args )

Allow direct access to the fields in the jobspec by making them virtual method names of the form _<field>()

# File P4table.rb, line 675
    def method_missing( meth, *args )
	meth = meth.to_s
	raise if ( meth[0..0] != "_" )
	meth = meth[ 1..-1 ]
	if ( meth =~ /^(.*)=$/ )
	    meth = $1
	    @spec[ meth ] = args.shift
	elsif ( args.length == 0 && @spec.has_key?( meth ) )
	    @spec[ meth ]
	else
	    ""
	end
    end