368 lines
13 KiB
Ruby
Executable File
368 lines
13 KiB
Ruby
Executable File
#
|
|
# File:: bootstrap.rb
|
|
# Description:: Bootstrap
|
|
# - This script will analyse the return codes passed and perform bootstrap functionality.
|
|
# - See RSG.Pipeline.Core.Constants
|
|
# - Resume ( facilitated by return code 1 )
|
|
# - Sync tools head
|
|
# - Sync tools labelled
|
|
# - Sync tools config
|
|
# - Tools install ( coming soon?! )
|
|
# Author:: Derek Ward <derek@rockstarnorth.com>
|
|
# Date:: 18 March 2013
|
|
#
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Uses
|
|
#-----------------------------------------------------------------------------
|
|
|
|
require 'RSG.Base.dll'
|
|
require 'RSG.Pipeline.Core.dll'
|
|
require 'mscorlib'
|
|
require 'System.Core'
|
|
require 'RSG.Base.Configuration.dll'
|
|
require 'RSG.Base.Windows.dll'
|
|
require 'RSG.SourceControl.Perforce.dll'
|
|
require 'RSG.Pipeline.Automation.Common.dll'
|
|
require 'RSG.Pipeline.Services.dll'
|
|
include RSG::Base::Configuration
|
|
include RSG::Base::Logging
|
|
include RSG::Base::Logging::Universal
|
|
include RSG::Base::OS
|
|
include RSG::Base::Windows
|
|
include RSG::Pipeline::Core
|
|
include RSG::SourceControl::Perforce
|
|
include RSG::Pipeline::Automation::Common
|
|
include RSG::Pipeline::Services
|
|
|
|
require 'pipeline/os/options'
|
|
include Pipeline
|
|
|
|
require 'fileutils'
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Constants
|
|
#-----------------------------------------------------------------------------
|
|
AUTHOR = 'RSGEDI Tools'
|
|
EMAIL = 'RSGEDI Tools <*tools@rockstarnorth.com>'
|
|
OPTIONS = [
|
|
LongOption::new( 'host', LongOption::ArgType.Optional, 'h', 'host' ),
|
|
LongOption::new( 'role', LongOption::ArgType.Optional, 'r', 'role' ),
|
|
LongOption::new( 'automation', LongOption::ArgType.Optional, 'a', 'automation' ),
|
|
LongOption::new( 'filetransfer', LongOption::ArgType.Optional, 'f', 'filetransfer' ),
|
|
]
|
|
SYNC_SLEEP = 1 # Dont muck around unless you know what your doing
|
|
SYNC_SLEEP_LAST = 10 # Dont muck around unless you know what your doing
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Functions
|
|
#-----------------------------------------------------------------------------
|
|
|
|
#
|
|
# Kill the automation console
|
|
# wait for other RSG.Pipeline.automation processes to terminate
|
|
# otherwise a sync to an automation dll/exe will find itself in use.
|
|
def KillConsoleAndWaitForProcesses(log)
|
|
|
|
log.Message(" ")
|
|
log.Message("*********************************************************************")
|
|
log.Message("*** Bootstrap: Taskkill local RSG.Pipeline.Automation.Console.exe ***")
|
|
log.Message("*********************************************************************")
|
|
log.Message(" ")
|
|
|
|
kill_console_cmd = 'taskkill /F /IM rsg.pipeline.automation.console.exe 1>NUL 2>NUL'
|
|
|
|
system(kill_console_cmd)
|
|
|
|
log.Message(" ")
|
|
log.Message("*************************************************************************")
|
|
log.Message("*** Bootstrap: Wait for processes RSG.Pipeline.Automation.* to exit ***")
|
|
log.Message("*************************************************************************")
|
|
log.Message(" ")
|
|
|
|
|
|
# Now wait until processes with a particular naming convention have terminated
|
|
begin
|
|
found_process = false
|
|
processes = System::Diagnostics::Process.GetProcesses()
|
|
|
|
processes.each do |process|
|
|
if process.ProcessName =~ /(RSG\.Pipeline\.Automation.*)/i
|
|
process_name = $1
|
|
if (not process.ProcessName =~ /.*vshost.*/i)
|
|
log.Message("bootstrap.rb is waiting on process : " + process_name)
|
|
found_process = true
|
|
end
|
|
end
|
|
end
|
|
|
|
# ALWAYS sleep, even if there are no processes.
|
|
Kernel.sleep(SYNC_SLEEP)
|
|
end while found_process == true
|
|
|
|
log.Message(" ")
|
|
log.Message("**********************************************************************")
|
|
log.Message("*** Bootstrap: All processes RSG.Pipeline.Automation.* have exited ***")
|
|
log.Message("**********************************************************************")
|
|
log.Message(" ")
|
|
end
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Entry-Point
|
|
#-----------------------------------------------------------------------------
|
|
|
|
if ( __FILE__ == $0 ) then
|
|
|
|
g_Options = OS::Options::new( OPTIONS )
|
|
|
|
begin
|
|
if ( g_Options.is_enabled?( 'help' ) )
|
|
puts "#{__FILE__}"
|
|
puts "Usage:"
|
|
puts g_Options.usage()
|
|
exit( 1 )
|
|
end
|
|
|
|
exit( 0 ) if ( 0 == ARGV.size )
|
|
|
|
LogFactory.Initialize()
|
|
LogFactory.CreateApplicationConsoleLogTarget( )
|
|
g_Log = LogFactory.ApplicationLog
|
|
g_Config = RSG::Base::Configuration::ConfigFactory::CreateConfig( )
|
|
|
|
g_Log.Message(" ")
|
|
g_Log.Message("*****************")
|
|
g_Log.Message("*** Bootstrap ***")
|
|
g_Log.Message("*****************")
|
|
g_Log.Message(" ")
|
|
|
|
bootstrap_retcode = 0
|
|
|
|
# Examine return codes passed in to process - act on each
|
|
g_Options.trailing.each do |bootstrap_code|
|
|
|
|
g_Log.Message("Processing bootstrap code #{bootstrap_code}")
|
|
boot_code = Integer(bootstrap_code)
|
|
|
|
next if (boot_code==nil) # ignore all crap
|
|
|
|
toolsFileSpec = "#{g_Config.ToolsRoot}/..."
|
|
|
|
p4_sync_cmds = []
|
|
p4_sync_path = System::IO::Path::Combine(ENV['RS_TOOLSROOT'], 'tmp', ENV['RS_BOOTSTRAP_NAME'])
|
|
|
|
FileUtils.mkdir_p p4_sync_path
|
|
|
|
p4_sync_filename = System::IO::Path::Combine(p4_sync_path, 'p4_automation_tools_sync.bat')
|
|
|
|
#
|
|
# CLEAN CACHE
|
|
if (boot_code & Constants.Exit_CleanCache > 0)
|
|
|
|
KillConsoleAndWaitForProcesses(g_Log)
|
|
|
|
# Build cache folder path
|
|
cache_folder = System::IO::Path::Combine(ENV['RS_PROJROOT'], 'cache', 'automation');
|
|
|
|
g_Log.Message(" ")
|
|
g_Log.Message("*****************************************************")
|
|
g_Log.Message("*** Bootstrap: Cleaning cache {0} ***", cache_folder)
|
|
g_Log.Message("*****************************************************")
|
|
g_Log.Message(" ")
|
|
|
|
# Get folder and delete it
|
|
RSG::Pipeline::Services::Cache::ClearDirectory(g_Log, cache_folder)
|
|
|
|
g_Log.Message(" ")
|
|
g_Log.Message("*****************************************************")
|
|
g_Log.Message("*** Bootstrap: Cache cleaned ***")
|
|
g_Log.Message("*****************************************************")
|
|
g_Log.Message(" ")
|
|
end
|
|
|
|
#
|
|
# TOOLS SYNC HEAD
|
|
if (boot_code & Constants.Exit_SyncHead > 0)
|
|
|
|
KillConsoleAndWaitForProcesses(g_Log)
|
|
|
|
g_Log.Message(" ")
|
|
g_Log.Message("*****************************************************")
|
|
g_Log.Message("*** Bootstrap: Sync to tools head will occur soon ***")
|
|
g_Log.Message("*****************************************************")
|
|
g_Log.Message(" ")
|
|
|
|
#
|
|
# DW: No idea why - despite all attempts you can't run p4 sync using ironlib assemblies
|
|
# the solution is to run the sync once this script exits
|
|
#
|
|
|
|
p4_sync_cmds << "p4 sync #{toolsFileSpec}"
|
|
|
|
g_Log.Message(" ")
|
|
g_Log.Message("********************************")
|
|
g_Log.Message("*** Bootstrap: Sleep for {0}s ***", SYNC_SLEEP_LAST)
|
|
g_Log.Message("********************************")
|
|
g_Log.Message(" ")
|
|
|
|
# This sleep is important - it will reduce the likelihood that a process will restart when another process is still syncing.
|
|
# the biggest danger with this is p4 latency, but otherwise is quite unlikely to fail.
|
|
Kernel.sleep(SYNC_SLEEP_LAST)
|
|
end
|
|
|
|
#
|
|
# TOOLS SYNC LABEL
|
|
if (boot_code & Constants.Exit_SyncLabel > 0)
|
|
|
|
KillConsoleAndWaitForProcesses(g_Log)
|
|
|
|
g_Log.Message(" ")
|
|
g_Log.Message("*********************************************************")
|
|
g_Log.Message("*** Bootstrap: Sync to labelled tools will occur soon ***")
|
|
g_Log.Message("*********************************************************")
|
|
g_Log.Message(" ")
|
|
|
|
label = g_Config.Project.Labels[Label.ToolsCurrent]
|
|
|
|
toolsFileSpecLabel = "#{toolsFileSpec}@#{label},@#{label}"
|
|
p4_sync_cmds << "p4 sync #{toolsFileSpecLabel}"
|
|
|
|
g_Log.Message(" ")
|
|
g_Log.Message("************************************")
|
|
g_Log.Message("*** Bootstrap: Now sleep for {0}s ***", SYNC_SLEEP_LAST)
|
|
g_Log.Message("************************************")
|
|
g_Log.Message(" ")
|
|
|
|
|
|
# This sleep is important - it will reduce the likelihood that a process will restart when another process is still syncing.
|
|
# the biggest danger with this is p4 latency, but otherwise is quite unlikely to fail.
|
|
Kernel.sleep(SYNC_SLEEP_LAST)
|
|
end
|
|
|
|
#
|
|
# TOOLS SYNC CONFIG
|
|
|
|
sync_config = boot_code & Constants.Exit_SyncConfig > 0
|
|
sync_content = boot_code & Constants.Exit_SyncContent > 0
|
|
if (sync_config or sync_content)
|
|
|
|
KillConsoleAndWaitForProcesses(g_Log)
|
|
|
|
g_Log.Message(" ")
|
|
g_Log.Message("********************************************************")
|
|
g_Log.Message("*** Bootstrap: Sync to tools config will occur soon ***") if (sync_config)
|
|
g_Log.Message("*** Bootstrap: Sync to tools content will occur soon ***") if (sync_content)
|
|
g_Log.Message("********************************************************")
|
|
g_Log.Message(" ")
|
|
|
|
p4 = RSG::SourceControl::Perforce::P4.new()
|
|
all_files = []
|
|
if (sync_config)
|
|
g_Log.Message(" ")
|
|
g_Log.Message("\tCONFIG FILES")
|
|
g_Log.Message(" ")
|
|
files = ConfigSync.DepotFilesTriggeringRestartResync(p4, g_Options.command_options.Branch, g_Config, sync_config, false)
|
|
|
|
files.each do |file|
|
|
all_files << file
|
|
g_Log.Message("\t#{file}")
|
|
end
|
|
end
|
|
|
|
if (sync_content)
|
|
g_Log.Message(" ")
|
|
g_Log.Message("\tCONTENT FILES")
|
|
g_Log.Message(" ")
|
|
files = ConfigSync.DepotFilesTriggeringRestartResync(p4, g_Options.command_options.Branch, g_Config, false, sync_content)
|
|
|
|
files.each do |file|
|
|
all_files << file
|
|
g_Log.Message("\t#{file}")
|
|
end
|
|
end
|
|
|
|
|
|
# splice it up into managebale chunks due to B* 1839527
|
|
all_files_chunks = all_files.each_slice(100).to_a
|
|
|
|
all_files_chunks.each do |chunk_files|
|
|
|
|
files_joined = chunk_files.join(" ")
|
|
p4_sync_cmds << "p4 sync #{files_joined}"
|
|
|
|
end
|
|
|
|
g_Log.Message(" ")
|
|
g_Log.Message("************************************")
|
|
g_Log.Message("*** Bootstrap: Now sleep for {0}s ***", SYNC_SLEEP_LAST)
|
|
g_Log.Message("************************************")
|
|
g_Log.Message(" ")
|
|
|
|
|
|
# This sleep is important - it will reduce the likelihood that a process will restart when another process is still syncing.
|
|
# the biggest danger with this is p4 latency, but otherwise is quite unlikely to fail.
|
|
Kernel.sleep(SYNC_SLEEP_LAST)
|
|
end
|
|
|
|
|
|
#
|
|
# Write the p4 sync command to tools tmp - so we can run it later ( outside of ironruby - cos it keeps dlls open )
|
|
File.open(p4_sync_filename, 'w') do |f|
|
|
|
|
f.write("ECHO.\n")
|
|
f.write("ECHO *** BOOTSTRAP SYNCING NOW ***\n")
|
|
p4_sync_cmds.each do |p4_sync_cmd|
|
|
|
|
if (p4_sync_cmd != '')
|
|
f.write("ECHO *** #{p4_sync_cmd}\n")
|
|
f.write("ECHO.\n")
|
|
end
|
|
f.write("\n")
|
|
f.write(p4_sync_cmd)
|
|
f.write("\n")
|
|
end
|
|
|
|
if (p4_sync_cmds.length >= 0)
|
|
f.write("ECHO *** BOOTSTRAP SYNCING COMPLETED ***\n")
|
|
end
|
|
end
|
|
|
|
#
|
|
# RESUME
|
|
if (boot_code & Constants.Exit_Resume > 0)
|
|
bootstrap_retcode = 1 # This is the signal to the calling script to resume
|
|
g_Log.Message(" ")
|
|
g_Log.Message("*************************")
|
|
g_Log.Message("*** Bootstrap: Resume ***")
|
|
g_Log.Message("*************************")
|
|
g_Log.Message(" ")
|
|
end
|
|
end
|
|
|
|
g_Log.Message("Bootstrap exiting with #{bootstrap_retcode}")
|
|
exit bootstrap_retcode
|
|
|
|
rescue SystemExit => sex
|
|
|
|
LogFactory.ApplicationShutdown()
|
|
exit( sex.status )
|
|
|
|
rescue Exception => ex
|
|
|
|
g_Log.Exception( ex, "Exception during #{__FILE__}." )
|
|
|
|
puts "Exception during #{__FILE__}: #{ex.message}"
|
|
puts ex.backtrace.join("\n")
|
|
|
|
if ( g_Options.show_popups? ) then
|
|
dlg = RSG::Base::Windows::ExceptionStackTraceDlg::new( ex,
|
|
g_Config.EmailAddress, AUTHOR, EMAIL )
|
|
dlg.ShowDialog( )
|
|
end
|
|
|
|
exit( -1 )
|
|
end
|
|
end
|
|
|
|
# bootstrap.rb
|