# File:: buildp4.rb # Description:: Runs a script which builds some files, these files are then checked in p4 if it has changed. # the destination files MUST already exist in perforce, since adding new files has it complications over multiple p4 servers. # # Also due to a lack of time on my milestone - this script will have to be very much so limited in scope of what it does - I've decided not to support # multiple p4 servers - it's actually a lot more complex than I first though when dealing with wildcards / files that may or may not exists in either # p4 and may need added or edited. # # Author:: Derek Ward # Date:: 14th October 2010 # #----------------------------------------------------------------------------- # Uses #----------------------------------------------------------------------------- require 'pipeline/os/path' require 'pipeline/os/getopt' require 'pipeline/log/log' include Pipeline #----------------------------------------------------------------------------- # Constants #----------------------------------------------------------------------------- OPTIONS = [ [ '--checkout', '-ch', Getopt::REQUIRED, 'files to checkout that may or may not get built.' ], [ '--nosync', '-ns', Getopt::OPTIONAL, 'files not to sync.' ], [ '--command', '-co', Getopt::REQUIRED, 'script command to run including args' ], [ '--desc', '-d', Getopt::REQUIRED, 'description for checkin.' ], [ '--disablecheckin', '-dc', Getopt::BOOLEAN, 'prevent checkin ( for development )' ], [ '--rage', '-r', Getopt::BOOLEAN, 'p4 server to operate on is the rage server' ], [ '--submit_on_error', '-e', Getopt::BOOLEAN, 'submit changelist on error?' ] ] INFO = "[colourise=black]INFO_MSG: " INFO_BLUE = "[colourise=blue]INFO_MSG: " #----------------------------------------------------------------------------- # Implementation #----------------------------------------------------------------------------- class BuildP4 def initialize(checkout, desc, command, rage_p4, enable_checkin, submit_on_error, nosync) @checkout = checkout @desc = desc @command = command.gsub(">",">") @enable_checkin = enable_checkin puts "#{INFO_BLUE} Checkin is enabled" if @enable_checkin puts "#{INFO_BLUE} Checkin is disabled" unless @enable_checkin @rage_p4 = rage_p4 @submit_on_error = submit_on_error @nosync = nosync end #------------------------------------------------------------------------- # --- Control logic #------------------------------------------------------------------------- def run( config ) sync_check_out( config ) error_count = run_script() submit() if not ( @submit_on_error and error_count > 0 ) error_count end #------------------------------------------------------------------------- # --- Establish SCM connection, sync to files, and checkout #------------------------------------------------------------------------- def sync_check_out( config ) puts "#{INFO_BLUE} Creating p4" @p4 = @rage_p4 ? SCM::Perforce::create( config.sc_rage_server, config.sc_rage_username, config.sc_rage_workspace ) : SCM::Perforce::create( config.sc_server, config.sc_username, config.sc_workspace ) puts "#{INFO_BLUE} #{@checkout_files}" @checkout_files = @checkout.split @nosync_files = @nosync.split puts "#{INFO_BLUE} Connecting to p4 servers" raise Exception if not @p4 @p4.connect( ) raise Exception if not @p4.connected? puts "#{INFO_BLUE} Creating CL" @change_id = @p4.create_changelist( "buildp4 generated file @ #{Time.now} on #{ENV["COMPUTERNAME"]}\n#{@desc}" ) raise Exception if @change_id.nil? puts "#{INFO_BLUE}Changelist #{@change_id} is created" @checkout_files.each do |depot_filename| if (not @nosync_files.include? depot_filename) puts "#{INFO_BLUE} Syncing #{depot_filename}" @p4.run_sync( depot_filename ) end puts "Checking out #{depot_filename} in CL #{@change_id.to_s}" @p4.run_edit( '-c', @change_id.to_s, depot_filename ) puts "Reopening #{depot_filename} in CL #{@change_id.to_s}" @p4.run_reopen( '-c', @change_id.to_s, depot_filename ) end end #------------------------------------------------------------------------- # --- Run the script - yields to block if given. #------------------------------------------------------------------------- def run_script() error_count = 0 if (block_given?) yield( @checkout_files, error_count ) else # Run script cmd = @command puts "#{INFO_BLUE} Executing #{cmd}...\n" status, stdout, stderr = systemu(cmd) puts "#{INFO_BLUE} \n...Completed" $stderr.puts( cmd ) if ( stderr.length > 0 ) stderr.each do |err| error_count += 1 $stderr.puts "Error: #{err}" end stdout.each_with_index do |out, idx| puts out end end error_count end #------------------------------------------------------------------------- # --- Submit changes #------------------------------------------------------------------------- def submit() puts "#{INFO_BLUE}Reverting unchanged files #{@change_id}" @p4.run_revert( '-a', '-c', @change_id.to_s, '//...') files = @p4.run_opened( '-c', @change_id.to_s ) raise Exception if files.nil? puts "#{INFO_BLUE}There are #{files.size} files to submit." files.each do |file| puts "#{INFO_BLUE}#{file['depotFile']} has been updated and will be submitted." end if ( @enable_checkin ) if ( files.size > 0 ) puts "#{INFO_BLUE}Submitting file currently in #{@change_id}" submit_result = @p4.run_submit( '-c', @change_id.to_s ) puts "#{INFO_BLUE} Submit result : #{submit_result.to_s}" elsif ( 0 == files.size ) puts "#{INFO_BLUE}Deleting #{@change_id} no files changed." @p4.run_change('-d', @change_id.to_s) end else puts "#{INFO_BLUE}Checkin is disabled the CL is pending." end end end # class BuildP4 #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- if ( __FILE__ == $0 ) then error_count = 0 #----------------------------------------------------------------------------- # Code #----------------------------------------------------------------------------- begin #------------------------------------------------------------------------- # Entry-Point #------------------------------------------------------------------------- g_AppName = File::basename( __FILE__, '.rb' ) g_Config = Pipeline::Config.instance() g_Log = Log.new( g_AppName ) #------------------------------------------------------------------------- # Parse & validate Command Line #------------------------------------------------------------------------- opts, trailing = OS::Getopt.getopts( OPTIONS ) if ( opts['help'] ) then puts OS::Getopt.usage( OPTIONS ) response = message_box( "#{g_AppName} will exit.",g_AppName, BUTTONS_OK, ICON_QUESTION) Process.exit!( 1 ) end g_checkout = ( nil == opts['checkout'] ) ? nil : opts['checkout'] g_nosync = ( nil == opts['nosync'] ) ? nil : opts['nosync'] g_desc = ( nil == opts['desc'] ) ? nil : opts['desc'] g_command = ( nil == opts['command'] ) ? nil : opts['command'] g_enable_checkin = ( nil == opts['disablecheckin'] ) ? true : false g_rage_p4 = ( nil == opts['rage'] ) ? false : true g_submit_on_error = ( nil == opts['submit_on_error'] ) ? false : true build_p4 = BuildP4.new(g_checkout, g_desc, g_command, g_rage_p4, g_enable_checkin, g_submit_on_error, g_nosync) error_count = build_p4.run( g_Config ) rescue Exception => ex puts "#{g_AppName} unhandled exception: #{ex.message}" puts "Call stack:" puts ex.backtrace.join( "\n\t" ) end Process.exit! error_count end # buildp4.rb #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- #-----------------------------------------------------------------------------