default_client.rb #3

  • //
  • guest/
  • robert_cowham/
  • perforce/
  • utils/
  • triggers/
  • default_client.rb
  • View
  • Commits
  • Open Download .zip Download (7 KB)
#!/usr/bin/ruby
#--
#-------------------------------------------------------------------------------
#++
#
#= Introduction
#
#== Name:   default_client.rb
#
#== Author: Robert Cowham  <[email protected]>
#                   Tony Smith <[email protected]>
#
#== Description 
# 
#     Example trigger to set some default client options
#
#== Requires
#     Ruby
#     P4Ruby
#     P4Triggers module
#
#== Example 'triggers' section:
#
#     Triggers:
#	default_client form-out client "ruby c:/perforce/scripts/default_client.rb -p %serverport% -u perforce template_client %formname% %formfile% "
#
#        would make the default client view offered to any user based on 
#        the view defined in the client called 'template_client'. Changing that
#        client spec would change the default view for future clients.
#
#== Note
#
#     Either use a P4CONFIG file or specify -p etc using TriggerOptions
#
#--
#-------------------------------------------------------------------------------
#++
$:.unshift( File.dirname( __FILE__ ) )
require "P4"
require "P4Triggers"
require "ostruct"

class ClientTrigger < P4Trigger

    def initialize( options, client, template, filename )
        super( options )
        @client = client
        @template = template
        @formfile = P4Trigger::FormFile.new( filename )
        p4.exception_level = 1
        p4.connect
    end

    #
    # Check whether or not a client already exists. We do this using 'p4 info'
    # rather than 'p4 clients' since running 'p4 clients' on a large system
    # can be very expensive. 
    #
    def client_exists?( name )
        tp4 = P4.new
        tp4.client = name
        tp4.port = p4.port?
        tp4.user = p4.user?
        tp4.tagged
        tp4.connect

        info = tp4.run_info.shift
        tp4.disconnect

        return true if info.has_key?( 'clientRoot' )
        return false
    end

    #
    # Main method - loads the template spec, and makes the alterations to
    # the formfile in place.
    #
    def update_client()
        begin
            #
            # Sanity checks:
            #
            # (a) Don't do anything if the client already exists
            # (b) Don't do anything if the template doesn't exist
            # (c) Don't do anything if the client in question IS the template!
            #
            # Note that (c) is VITAL to prevent infinite recursion caused by
            # an 'out' trigger running a 'p4 client -o'!!!
            #
            return 0 if( client_exists?( @client ) )
            return 0 unless( client_exists?( @template ) )
            return 0 if( @client == @template )

            # First fetch the template spec. This will cause our Perforce
            # server to execute this script again in another thread/process. 
            # Fortunately, check (c) above stops the infinite loop
            #
            # Note that this also gets the specdef for clients from this server 
            # so that P4Ruby can cache it so parse_client() and format_client()
            # will not send any commands to the server.

            tspec = p4.fetch_client( @template )
            cspec = p4.parse_client( @formfile.load() )

            # Make sure that the clientspec is the default one which contains 1 or more mappings of depots only, e.g.
            #   //depot1/...  //cs/depot1/...
            # This handles the case where the user is copying a client from an existing template which we allow (by aborting)
            default = true
            cspec[ "View" ].each do
                |mapping|
                if mapping !~ %r(^//[^/]+/\.\.\.\s+) then
                    default = false
                end
            end
            return 0 if ( !default )
            
            # Now copy across the options and view from the template clientspec.
            # For the view, we have to replace the template name with the client
            # name as we copy.
            cspec[ "View" ] = tspec[ "View" ].collect do
                |mapping|
                mapping.sub( "//#{@template}/", "//#{@client}/" )
            end

            cspec[ "Options" ] = tspec[ "Options" ]
            cspec[ "SubmitOptions" ] = tspec[ "SubmitOptions" ]
            cspec[ "Description" ] = tspec[ "Description" ]
            
            # If root is on a windows drive (something:) then set new default
            cspec[ "Root" ].sub!(/\s*([^\n]*)/) {
    			match = $1.dup
    			case match
    			when /^\w:/
    				result = "d:\\work\\" + @client
                else
                    result = match
    			end
    			result
    		}

            # Now update the existing formfile with the new spec.
            @formfile.save( p4.format_client( cspec ) )
            return 0
        rescue
            return report_error()
        end
    end
end


#--
#-------------------------------------------------------------------------------
#                        LOCAL FUNCTIONS
#-------------------------------------------------------------------------------
#++


#
# Show a message explaining correct usage of this script and exit.
#
def croakusage()
    puts <<EOS

Usage: defaultclient.rb <templatename> <clientname> <formfile>

Where:
    <templatename>             - the name of an existing client workspace 
                                 on which all future client workspaces 
                                 should be based (by default).

    <clientname>               - The name of the client spec the user is 
                                 asking for

    <formfile>                 - The name of the temporary file in which the
                                 current client spec is stored

EOS
    exit( 1 )
end


#--
#-------------------------------------------------------------------------------
# START OF MAIN SCRIPT
#-------------------------------------------------------------------------------
#++

def main
    # parse options

    options = P4TriggerOptions.new(ARGV)
    options.parse_options!()

    # Check remaining parameters
    croakusage() unless ARGV.length() == 3
    template         = ARGV.shift;
    client           = ARGV.shift;
    formfile         = ARGV.shift;

    #
    # This next line is CRITICAL. It prevents an infinite recursion which will
    # only terminate when your server runs out of resources. This is because
    # this script is triggered whenever a user runs a 'p4 client -o' and this
    # script itself runs a 'p4 client -o' ...
    #
    exit( 0 ) if( client == template)
    trig = ClientTrigger.new( options, client, template, formfile );
    exit( trig.update_client() )
end

if __FILE__ == $0
    main
end
# Change User Description Committed
#3 6316 Robert Cowham Tidy up framework for reporting.
Merge in Tony's changes for trigger.
#2 5671 Robert Cowham Use similar mechanism to P4Triggers to allow port and other parameters to be specified.
#1 5664 Robert Cowham Add new example and also update docs to link to it.