#!/usr/bin/ruby #-- #------------------------------------------------------------------------------- #++ # # == Introduction # # This script ensures that the default client view offered to users # for new client workspaces is based on a template client specified # in the trigger definition. # # == Synopsis # # defaultclient.rb # # == Sample Trigger Definition # # Using a trigger spec like this: # # defaultclient out client "defaultclient.rb baseclient %formname% %formfile%" # # would make the default client view offered to any user based on # the view defined in the client called 'baseclient'. Changing that # client spec would change the default view. # # == License # # Copyright (c) 1997-2008, Perforce Software, Inc. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # == Version # # $Id: //guest/tony_smith/perforce/P4Rubylib/triggers/defaultclient.rb#4 $ # #-- #------------------------------------------------------------------------------- #++ $:.unshift( File.dirname( __FILE__ ) ) require "P4" require "P4Triggers" #-- #------------------------------------------------------------------------------- # LOCAL CLASSES #------------------------------------------------------------------------------- #++ # # Our P4Trigger subclass. Using P4Trigger allows us to use the pre-existing # methods for error reporting and exit status handling. # class ClientTrigger < P4Trigger def initialize( client, template, filename ) super() @client = client @template = template @formfile = P4Trigger::FormFile.new( filename ) p4.exception_level = P4::RAISE_ERRORS 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.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 # Connect to server p4.connect # # 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() ) # 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" ] # 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 < Where: - the name of an existing client workspace on which all future client workspaces should be based (by default). - The name of the client spec the user's asking for - The name of the temporary file in which the current client spec is stored EOS exit( 1 ) end #-- #------------------------------------------------------------------------------- # START OF MAIN SCRIPT #------------------------------------------------------------------------------- #++ 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( client, template, formfile ); exit( trig.update_client() )