2014-03-14 14:13:41 -04:00
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
using System ;
using System.Collections.Generic ;
using System.Text ;
using System.IO ;
using AutomationTool ;
using UnrealBuildTool ;
using System.Reflection ;
2014-06-16 12:05:56 -04:00
using System.Xml ;
2014-08-18 13:29:39 -04:00
using System.Linq ;
2014-06-16 12:05:56 -04:00
public class ECJobPropsUtils
{
2014-08-22 13:39:55 -04:00
public static HashSet < string > ErrorsFromProps ( string Filename )
{
var Result = new HashSet < string > ( ) ;
XmlDocument Doc = new XmlDocument ( ) ;
Doc . Load ( Filename ) ;
foreach ( XmlElement ChildNode in Doc . FirstChild . ChildNodes )
{
if ( ChildNode . Name = = "propertySheet" )
{
foreach ( XmlElement PropertySheetChild in ChildNode . ChildNodes )
{
if ( PropertySheetChild . Name = = "property" )
{
bool IsDiag = false ;
foreach ( XmlElement PropertySheetChildDiag in PropertySheetChild . ChildNodes )
{
if ( PropertySheetChildDiag . Name = = "propertyName" & & PropertySheetChildDiag . InnerText = = "ec_diagnostics" )
{
IsDiag = true ;
}
if ( IsDiag & & PropertySheetChildDiag . Name = = "propertySheet" )
{
foreach ( XmlElement PropertySheetChildDiagSheet in PropertySheetChildDiag . ChildNodes )
{
if ( PropertySheetChildDiagSheet . Name = = "property" )
{
bool IsError = false ;
foreach ( XmlElement PropertySheetChildDiagSheetElem in PropertySheetChildDiagSheet . ChildNodes )
{
if ( PropertySheetChildDiagSheetElem . Name = = "propertyName" & & PropertySheetChildDiagSheetElem . InnerText . StartsWith ( "error-" ) )
{
IsError = true ;
}
if ( IsError & & PropertySheetChildDiagSheetElem . Name = = "propertySheet" )
{
foreach ( XmlElement PropertySheetChildDiagSheetElemInner in PropertySheetChildDiagSheetElem . ChildNodes )
{
if ( PropertySheetChildDiagSheetElemInner . Name = = "property" )
{
bool IsMessage = false ;
foreach ( XmlElement PropertySheetChildDiagSheetElemInner2 in PropertySheetChildDiagSheetElemInner . ChildNodes )
{
if ( PropertySheetChildDiagSheetElemInner2 . Name = = "propertyName" & & PropertySheetChildDiagSheetElemInner2 . InnerText = = "message" )
{
IsMessage = true ;
}
if ( IsMessage & & PropertySheetChildDiagSheetElemInner2 . Name = = "value" )
{
if ( ! PropertySheetChildDiagSheetElemInner2 . InnerText . Contains ( "LogTailsAndChanges" )
& & ! PropertySheetChildDiagSheetElemInner2 . InnerText . Contains ( "-MyJobStepId=" )
& & ! PropertySheetChildDiagSheetElemInner2 . InnerText . Contains ( "CommandUtils.Run: Run: Took " )
)
{
Result . Add ( PropertySheetChildDiagSheetElemInner2 . InnerText ) ;
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
return Result ;
}
2014-06-16 12:05:56 -04:00
}
public class TestECJobErrorParse : BuildCommand
{
2014-08-22 13:39:55 -04:00
public override void ExecuteBuild ( )
{
Log ( "*********************** TestECJobErrorParse" ) ;
2014-06-16 12:05:56 -04:00
2014-08-22 13:39:55 -04:00
string Filename = CombinePaths ( @"P:\Builds\UE4\GUBP\++depot+UE4-2104401-RootEditor_Failed\Engine\Saved\Logs" , "RootEditor_Failed.log" ) ;
var Errors = ECJobPropsUtils . ErrorsFromProps ( Filename ) ;
foreach ( var ThisError in Errors )
{
Log ( "Error: {0}" , ThisError ) ;
}
}
2014-06-16 12:05:56 -04:00
}
2014-03-14 14:13:41 -04:00
public class GUBP : BuildCommand
{
2014-08-22 13:39:55 -04:00
public string StoreName = null ;
public int CL = 0 ;
public int TimeIndex = 0 ;
public bool bSignBuildProducts = false ;
public bool bHasTests = false ;
public List < UnrealTargetPlatform > ActivePlatforms = null ;
public BranchInfo Branch = null ;
public bool bOrthogonalizeEditorPlatforms = false ;
public List < UnrealTargetPlatform > HostPlatforms ;
public bool bFake = false ;
public static bool bNoIOSOnPC = false ;
public static bool bBuildRocket = false ;
public static bool bForceIncrementalCompile = false ;
public static string ECProject = null ;
public string EmailHint ;
static public bool bPreflightBuild = false ;
public int PreflightShelveCL = 0 ;
static public string PreflightMangleSuffix = "" ;
public GUBPBranchHacker . BranchOptions BranchOptions = null ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
Dictionary < string , GUBPNode > GUBPNodes ;
Dictionary < string , bool > GUBPNodesCompleted ;
Dictionary < string , string > GUBPNodesControllingTrigger ;
Dictionary < string , string > GUBPNodesControllingTriggerDotName ;
2014-04-23 17:37:20 -04:00
2014-08-22 13:39:55 -04:00
class NodeHistory
{
public int LastSucceeded = 0 ;
public int LastFailed = 0 ;
public List < int > InProgress = new List < int > ( ) ;
public string InProgressString = "" ;
public List < int > Failed = new List < int > ( ) ;
public string FailedString = "" ;
public List < int > AllStarted = new List < int > ( ) ;
public List < int > AllSucceeded = new List < int > ( ) ;
public List < int > AllFailed = new List < int > ( ) ;
} ;
2014-04-23 17:37:20 -04:00
2014-08-22 13:39:55 -04:00
Dictionary < string , NodeHistory > GUBPNodesHistory ;
2014-04-23 17:37:20 -04:00
2014-08-22 13:39:55 -04:00
public string RocketUBTArgs ( bool bUseRocketInsteadOfBuildRocket = false )
{
if ( bBuildRocket )
{
return " -NoSimplygon " + ( bUseRocketInsteadOfBuildRocket ? "-Rocket" : "-BuildRocket" ) ;
}
return "" ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public abstract class GUBPNodeAdder
{
public virtual void AddNodes ( GUBP bp , UnrealTargetPlatform InHostPlatform )
{
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
private static List < GUBPNodeAdder > Adders ;
private void AddCustomNodes ( UnrealTargetPlatform InHostPlatform )
{
if ( Adders = = null )
{
Adders = new List < GUBPNodeAdder > ( ) ;
Assembly [ ] LoadedAssemblies = AppDomain . CurrentDomain . GetAssemblies ( ) ;
foreach ( var Dll in LoadedAssemblies )
{
Type [ ] AllTypes = Dll . GetTypes ( ) ;
foreach ( var PotentialConfigType in AllTypes )
{
if ( PotentialConfigType ! = typeof ( GUBPNodeAdder ) & & typeof ( GUBPNodeAdder ) . IsAssignableFrom ( PotentialConfigType ) )
{
GUBPNodeAdder Config = Activator . CreateInstance ( PotentialConfigType ) as GUBPNodeAdder ;
if ( Config ! = null )
{
Adders . Add ( Config ) ;
}
}
}
}
}
foreach ( var Adder in Adders )
{
Adder . AddNodes ( this , InHostPlatform ) ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public abstract class GUBPBranchHacker
{
public class BranchOptions
{
public List < UnrealTargetPlatform > PlatformsToRemove = new List < UnrealTargetPlatform > ( ) ;
2014-09-10 12:30:17 -04:00
public List < string > ExcludeNodes = new List < string > ( ) ;
public bool bNoAutomatedTesting = false ;
2014-09-29 21:43:13 -04:00
public bool bNoDocumentation = false ;
2014-08-22 13:39:55 -04:00
}
public virtual void ModifyOptions ( GUBP bp , ref BranchOptions Options , string Branch )
{
}
}
2014-05-13 11:30:38 -04:00
2014-08-22 13:39:55 -04:00
private static List < GUBPBranchHacker > BranchHackers ;
private GUBPBranchHacker . BranchOptions GetBranchOptions ( string Branch )
{
if ( BranchHackers = = null )
{
BranchHackers = new List < GUBPBranchHacker > ( ) ;
Assembly [ ] LoadedAssemblies = AppDomain . CurrentDomain . GetAssemblies ( ) ;
foreach ( var Dll in LoadedAssemblies )
{
Type [ ] AllTypes = Dll . GetTypes ( ) ;
foreach ( var PotentialConfigType in AllTypes )
{
if ( PotentialConfigType ! = typeof ( GUBPBranchHacker ) & & typeof ( GUBPBranchHacker ) . IsAssignableFrom ( PotentialConfigType ) )
{
GUBPBranchHacker Config = Activator . CreateInstance ( PotentialConfigType ) as GUBPBranchHacker ;
if ( Config ! = null )
{
BranchHackers . Add ( Config ) ;
}
}
}
}
}
var Result = new GUBPBranchHacker . BranchOptions ( ) ;
foreach ( var Hacker in BranchHackers )
{
Hacker . ModifyOptions ( this , ref Result , Branch ) ;
}
return Result ;
}
2014-05-13 11:30:38 -04:00
2014-08-22 13:39:55 -04:00
public abstract class GUBPEmailHacker
2014-08-28 17:00:26 -04:00
{
2014-08-22 13:39:55 -04:00
public virtual List < string > AddEmails ( GUBP bp , string Branch , string NodeName )
{
return new List < string > ( ) ;
}
public virtual List < string > ModifyEmail ( string Email , GUBP bp , string Branch , string NodeName )
{
return new List < string > { Email } ;
}
public virtual List < string > FinalizeEmails ( List < string > Emails , GUBP bp , string Branch , string NodeName )
{
return Emails ;
}
2014-08-28 16:40:17 -04:00
public virtual bool VetoEmailingCausers ( GUBP bp , string Branch , string NodeName )
{
return false ; // People who have submitted since last-green will be included unless vetoed by overriding this method.
}
2014-08-28 17:00:26 -04:00
}
2014-04-23 18:27:56 -04:00
2014-08-22 13:39:55 -04:00
private static List < GUBPEmailHacker > EmailHackers ;
2014-08-28 16:40:17 -04:00
private string HackEmails ( string Emails , string Causers , string Branch , string NodeName )
2014-08-22 13:39:55 -04:00
{
string OnlyEmail = ParseParamValue ( "OnlyEmail" ) ;
if ( ! String . IsNullOrEmpty ( OnlyEmail ) )
{
return OnlyEmail ;
}
EmailHint = ParseParamValue ( "EmailHint" ) ;
if ( EmailHint = = null )
{
EmailHint = "" ;
}
if ( EmailHackers = = null )
{
EmailHackers = new List < GUBPEmailHacker > ( ) ;
Assembly [ ] LoadedAssemblies = AppDomain . CurrentDomain . GetAssemblies ( ) ;
foreach ( var Dll in LoadedAssemblies )
{
Type [ ] AllTypes = Dll . GetTypes ( ) ;
foreach ( var PotentialConfigType in AllTypes )
{
if ( PotentialConfigType ! = typeof ( GUBPEmailHacker ) & & typeof ( GUBPEmailHacker ) . IsAssignableFrom ( PotentialConfigType ) )
{
GUBPEmailHacker Config = Activator . CreateInstance ( PotentialConfigType ) as GUBPEmailHacker ;
if ( Config ! = null )
{
EmailHackers . Add ( Config ) ;
}
}
}
}
}
List < string > Result = new List < string > ( Emails . Split ( ' ' ) ) ;
2014-08-28 16:40:17 -04:00
if ( ! EmailHackers . Any ( x = > x . VetoEmailingCausers ( this , Branch , NodeName ) ) )
{
Result . AddRange ( Causers . Split ( ' ' ) ) ;
}
2014-08-22 13:39:55 -04:00
foreach ( var EmailHacker in EmailHackers )
{
Result . AddRange ( EmailHacker . AddEmails ( this , Branch , NodeName ) ) ;
}
foreach ( var EmailHacker in EmailHackers )
{
var NewResult = new List < string > ( ) ;
foreach ( var Email in Result )
{
NewResult . AddRange ( EmailHacker . ModifyEmail ( Email , this , Branch , NodeName ) ) ;
}
Result = NewResult ;
}
foreach ( var EmailHacker in EmailHackers )
{
Result = EmailHacker . FinalizeEmails ( Result , this , Branch , NodeName ) ;
}
string FinalEmails = "" ;
int Count = 0 ;
foreach ( var Email in Result )
{
FinalEmails = GUBPNode . MergeSpaceStrings ( FinalEmails , Email ) ;
Count + + ;
}
return FinalEmails ;
}
public abstract class GUBPFrequencyHacker
{
public virtual int GetNodeFrequency ( GUBP bp , string Branch , string NodeName , int BaseFrequency )
{
return new int ( ) ;
}
}
private static List < GUBPFrequencyHacker > FrequencyHackers ;
private int HackFrequency ( GUBP bp , string Branch , string NodeName , int BaseFrequency )
{
int Frequency = BaseFrequency ;
if ( FrequencyHackers = = null )
{
FrequencyHackers = new List < GUBPFrequencyHacker > ( ) ;
Assembly [ ] LoadedAssemblies = AppDomain . CurrentDomain . GetAssemblies ( ) ;
foreach ( var Dll in LoadedAssemblies )
{
Type [ ] AllTypes = Dll . GetTypes ( ) ;
foreach ( var PotentialConfigType in AllTypes )
{
if ( PotentialConfigType ! = typeof ( GUBPFrequencyHacker ) & & typeof ( GUBPFrequencyHacker ) . IsAssignableFrom ( PotentialConfigType ) )
{
GUBPFrequencyHacker Config = Activator . CreateInstance ( PotentialConfigType ) as GUBPFrequencyHacker ;
if ( Config ! = null )
{
FrequencyHackers . Add ( Config ) ;
}
}
}
}
}
foreach ( var FrequencyHacker in FrequencyHackers )
{
Frequency = FrequencyHacker . GetNodeFrequency ( bp , Branch , NodeName , BaseFrequency ) ;
}
return Frequency ;
}
public abstract class GUBPNode
{
public List < string > FullNamesOfDependencies = new List < string > ( ) ;
public List < string > FullNamesOfPseudosependencies = new List < string > ( ) ; //these are really only used for sorting. We want the editor to fail before the monolithics. Think of it as "can't possibly be useful without".
public List < string > BuildProducts = null ;
public List < string > AllDependencyBuildProducts = null ;
public List < string > AllDependencies = null ;
public string AgentSharingGroup = "" ;
public int ComputedDependentCISFrequencyQuantumShift = - 1 ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public virtual string GetFullName ( )
{
throw new AutomationException ( "Unimplemented GetFullName." ) ;
}
public virtual string GameNameIfAnyForTempStorage ( )
{
return "" ;
}
public virtual string RootIfAnyForTempStorage ( )
{
return "" ;
}
public virtual void DoBuild ( GUBP bp )
{
BuildProducts = new List < string > ( ) ;
SaveRecordOfSuccessAndAddToBuildProducts ( ) ;
}
public virtual void PostLoadFromSharedTempStorage ( GUBP bp )
{
}
public virtual void DoFakeBuild ( GUBP bp ) // this is used to more rapidly test a build system, it does nothing but save a record of success as a build product
{
BuildProducts = new List < string > ( ) ;
SaveRecordOfSuccessAndAddToBuildProducts ( ) ;
}
public virtual bool IsSticky ( )
{
return false ;
}
public virtual bool SendSuccessEmail ( )
{
return false ;
}
public virtual bool RunInEC ( )
{
return true ;
}
public virtual bool IsAggregate ( )
{
return false ;
}
public virtual int AgentMemoryRequirement ( GUBP bp )
{
return 0 ;
}
public virtual int TimeoutInMinutes ( )
{
return 90 ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
/// <summary>
/// When triggered by CIS (instead of a person) this dictates how often this node runs.
/// The builder has a increasing index, specified with -TimeIndex=N
/// If N mod (1 lshift CISFrequencyQuantumShift()) is not 0, the node is skipped
/// </summary>
public virtual int CISFrequencyQuantumShift ( GUBP bp )
{
return 0 ;
}
/// <summary>
/// As above the maximum of all ancestors and pseudoancestors
/// </summary>
public int DependentCISFrequencyQuantumShift ( )
{
if ( ComputedDependentCISFrequencyQuantumShift < 0 )
{
throw new AutomationException ( "Asked for frequency shift before it was computed." ) ;
}
return ComputedDependentCISFrequencyQuantumShift ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public virtual float Priority ( )
{
return 100.0f ;
}
public virtual bool TriggerNode ( )
{
return false ;
}
public virtual void SetAsExplicitTrigger ( )
{
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
}
public virtual string ECAgentString ( )
{
return "" ;
}
public virtual string ECProcedureInfix ( )
{
return "" ;
}
public virtual string ECProcedure ( )
{
if ( IsSticky ( ) & & AgentSharingGroup ! = "" )
{
throw new AutomationException ( "Node {0} is both agent sharing and sitcky." , GetFullName ( ) ) ;
}
return String . Format ( "GUBP{0}_UAT_Node{1}{2}" , ECProcedureInfix ( ) , IsSticky ( ) ? "" : "_Parallel" , AgentSharingGroup ! = "" ? "_AgentShare" : "" ) ;
}
public virtual string ECProcedureParams ( )
{
2014-09-03 10:12:50 -04:00
var Result = String . Format ( ", {{actualParameterName => 'Sticky', value => '{0}'}}" , IsSticky ( ) ? 1 : 0 ) ;
2014-08-22 13:39:55 -04:00
if ( AgentSharingGroup ! = "" )
{
2014-09-03 10:12:50 -04:00
Result + = String . Format ( ", {{actualParameterName => 'AgentSharingGroup', value => '{0}'}}" , AgentSharingGroup ) ;
2014-08-22 13:39:55 -04:00
}
return Result ;
}
public static string MergeSpaceStrings ( params string [ ] EmailLists )
{
var Emails = new List < string > ( ) ;
foreach ( var EmailList in EmailLists )
{
if ( ! String . IsNullOrEmpty ( EmailList ) )
{
List < string > Parts = new List < string > ( EmailList . Split ( ' ' ) ) ;
foreach ( var Email in Parts )
{
if ( ! string . IsNullOrEmpty ( Email ) & & ! Emails . Contains ( Email ) )
{
Emails . Add ( Email ) ;
}
}
}
}
string Result = "" ;
foreach ( var Email in Emails )
{
if ( Result ! = "" )
{
Result + = " " ;
}
Result + = Email ;
}
return Result ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public void SaveRecordOfSuccessAndAddToBuildProducts ( string Contents = "Just a record of success." )
{
string RecordOfSuccess = CombinePaths ( CommandUtils . CmdEnv . LocalRoot , "Engine" , "Saved" , "Logs" , GetFullName ( ) + "_Success.log" ) ;
CommandUtils . CreateDirectory ( Path . GetDirectoryName ( RecordOfSuccess ) ) ;
CommandUtils . WriteAllText ( RecordOfSuccess , Contents ) ;
AddBuildProduct ( RecordOfSuccess ) ;
}
public void AddDependency ( string Node )
{
if ( ! FullNamesOfDependencies . Contains ( Node ) )
{
FullNamesOfDependencies . Add ( Node ) ;
}
}
public void AddPseudodependency ( string Node )
{
if ( ! FullNamesOfPseudosependencies . Contains ( Node ) )
{
FullNamesOfPseudosependencies . Add ( Node ) ;
}
}
public void RemovePseudodependency ( string Node )
{
if ( FullNamesOfPseudosependencies . Contains ( Node ) )
{
FullNamesOfPseudosependencies . Remove ( Node ) ;
}
}
public void AddBuildProduct ( string Filename )
{
if ( ! CommandUtils . FileExists_NoExceptions ( true , Filename ) )
{
throw new AutomationException ( "Cannot add build product {0} because it does not exist." , Filename ) ;
}
FileInfo Info = new FileInfo ( Filename ) ;
if ( ! BuildProducts . Contains ( Info . FullName ) )
{
BuildProducts . Add ( Info . FullName ) ;
}
}
public void AddDependentBuildProduct ( string Filename )
{
if ( ! CommandUtils . FileExists_NoExceptions ( true , Filename ) )
{
throw new AutomationException ( "Cannot add build product {0} because it does not exist." , Filename ) ;
}
FileInfo Info = new FileInfo ( Filename ) ;
if ( ! AllDependencyBuildProducts . Contains ( Info . FullName ) )
{
AllDependencyBuildProducts . Add ( Info . FullName ) ;
}
}
public void AddAllDependent ( string Node )
{
if ( ! AllDependencies . Contains ( Node ) )
{
AllDependencies . Add ( Node ) ;
}
}
public void RemoveOveralppingBuildProducts ( )
{
foreach ( var ToRemove in AllDependencyBuildProducts )
{
BuildProducts . Remove ( ToRemove ) ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
}
public class VersionFilesNode : GUBPNode
{
public static string StaticGetFullName ( )
{
return "VersionFiles" ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( ) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public override void DoBuild ( GUBP bp )
{
var UE4Build = new UE4Build ( bp ) ;
BuildProducts = UE4Build . UpdateVersionFiles ( ActuallyUpdateVersionFiles : CommandUtils . P4Enabled & & CommandUtils . AllowSubmit ) ;
}
public override bool IsSticky ( )
{
return true ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public class HostPlatformNode : GUBPNode
{
protected UnrealTargetPlatform HostPlatform ;
public HostPlatformNode ( UnrealTargetPlatform InHostPlatform )
{
HostPlatform = InHostPlatform ;
}
public static string StaticGetHostPlatformSuffix ( UnrealTargetPlatform InHostPlatform , UnrealTargetPlatform InAgentPlatform = UnrealTargetPlatform . Unknown )
{
if ( InHostPlatform = = UnrealTargetPlatform . Mac )
{
if ( InAgentPlatform = = UnrealTargetPlatform . Win64 )
{
return "_ForMac" ;
}
return "_OnMac" ;
}
2014-09-05 21:50:16 -04:00
else if ( InHostPlatform = = UnrealTargetPlatform . Linux )
{
return "_OnLinux" ;
}
2014-08-22 13:39:55 -04:00
return "" ;
}
public virtual UnrealTargetPlatform GetAgentPlatform ( )
{
return HostPlatform ;
}
public override string ECProcedureInfix ( )
{
if ( GetAgentPlatform ( ) = = UnrealTargetPlatform . Mac )
{
if ( IsSticky ( ) )
{
throw new AutomationException ( "Node {0} is sticky, but Mac hosted. Sticky nodes must be PC hosted." , GetFullName ( ) ) ;
}
return "_Mac" ;
}
2014-09-08 09:45:35 -04:00
if ( GetAgentPlatform ( ) = = UnrealTargetPlatform . Linux )
{
if ( IsSticky ( ) )
{
throw new AutomationException ( "Node {0} is sticky, but Linux hosted. Sticky nodes must be PC hosted." , GetFullName ( ) ) ;
}
return "_Linux" ;
}
2014-08-22 13:39:55 -04:00
return "" ;
}
public virtual string GetHostPlatformSuffix ( )
{
return StaticGetHostPlatformSuffix ( HostPlatform , GetAgentPlatform ( ) ) ;
}
public UnrealTargetPlatform GetAltHostPlatform ( )
{
return GUBP . GetAltHostPlatform ( HostPlatform ) ;
}
public override int TimeoutInMinutes ( )
{
return base . TimeoutInMinutes ( ) + ( ( HostPlatform = = UnrealTargetPlatform . Mac ) ? 30 : 0 ) ; // Mac is slower and more resource constrained
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public class CompileNode : HostPlatformNode
{
public CompileNode ( UnrealTargetPlatform InHostPlatform , bool DependentOnCompileTools = true )
: base ( InHostPlatform )
{
if ( DependentOnCompileTools )
{
AddDependency ( ToolsForCompileNode . StaticGetFullName ( HostPlatform ) ) ;
}
else
{
AddDependency ( VersionFilesNode . StaticGetFullName ( ) ) ;
}
}
public virtual UE4Build . BuildAgenda GetAgenda ( GUBP bp )
{
return null ;
}
public virtual void PostBuild ( GUBP bp , UE4Build UE4Build )
{
}
public virtual void PostBuildProducts ( GUBP bp )
{
}
public virtual bool DeleteBuildProducts ( )
{
return false ;
}
public override void DoBuild ( GUBP bp )
{
BuildProducts = new List < string > ( ) ;
var UE4Build = new UE4Build ( bp ) ;
UE4Build . BuildAgenda Agenda = GetAgenda ( bp ) ;
if ( Agenda ! = null )
{
bool ReallyDeleteBuildProducts = DeleteBuildProducts ( ) & & ! GUBP . bForceIncrementalCompile ;
Agenda . DoRetries = false ; // these would delete build products
UE4Build . Build ( Agenda , InDeleteBuildProducts : ReallyDeleteBuildProducts , InUpdateVersionFiles : false , InForceUnity : true ) ;
PostBuild ( bp , UE4Build ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
UE4Build . CheckBuildProducts ( UE4Build . BuildProductFiles ) ;
foreach ( var Product in UE4Build . BuildProductFiles )
{
AddBuildProduct ( Product ) ;
}
RemoveOveralppingBuildProducts ( ) ;
if ( bp . bSignBuildProducts )
{
// Sign everything we built
CodeSign . SignMultipleIfEXEOrDLL ( bp , BuildProducts ) ;
}
PostBuildProducts ( bp ) ;
}
if ( Agenda = = null | | ( BuildProducts . Count = = 0 & & GUBP . bForceIncrementalCompile ) )
{
SaveRecordOfSuccessAndAddToBuildProducts ( "Nothing to actually compile" ) ;
}
}
public override int TimeoutInMinutes ( )
{
return base . TimeoutInMinutes ( ) + ( ( HostPlatform = = UnrealTargetPlatform . Mac ) ? 30 : 0 ) ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public class ToolsForCompileNode : CompileNode
{
public ToolsForCompileNode ( UnrealTargetPlatform InHostPlatform )
: base ( InHostPlatform , false )
{
AgentSharingGroup = "Editor" + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public static string StaticGetFullName ( UnrealTargetPlatform InHostPlatform )
{
return "ToolsForCompile" + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( HostPlatform ) ;
}
public override bool DeleteBuildProducts ( )
{
return true ;
}
public override int AgentMemoryRequirement ( GUBP bp )
{
if ( bp . ParseParam ( "Launcher" ) | | bp . TimeIndex ! = 0 )
{
return base . AgentMemoryRequirement ( bp ) ;
}
return 32 ;
}
public override UE4Build . BuildAgenda GetAgenda ( GUBP bp )
{
var Agenda = new UE4Build . BuildAgenda ( ) ;
2014-09-05 21:50:16 -04:00
if ( HostPlatform = = UnrealTargetPlatform . Win64 & & ! GUBP . bForceIncrementalCompile )
2014-08-22 13:39:55 -04:00
{
Agenda . DotNetProjects . AddRange (
new string [ ]
2014-03-14 14:13:41 -04:00
{
@"Engine\Source\Programs\DotNETCommon\DotNETUtilities\DotNETUtilities.csproj" ,
@"Engine\Source\Programs\RPCUtility\RPCUtility.csproj" ,
}
2014-08-22 13:39:55 -04:00
) ;
}
string AddArgs = "-CopyAppBundleBackToDevice" + bp . RocketUBTArgs ( ) ;
2014-04-28 14:35:09 -04:00
2014-08-22 13:39:55 -04:00
Agenda . AddTargets ( new string [ ] { "UnrealHeaderTool" } , HostPlatform , UnrealTargetConfiguration . Development , InAddArgs : AddArgs ) ;
return Agenda ;
}
public override void PostBuild ( GUBP bp , UE4Build UE4Build )
{
2014-09-05 21:50:16 -04:00
if ( HostPlatform = = UnrealTargetPlatform . Win64 )
2014-08-22 13:39:55 -04:00
{
UE4Build . AddUATFilesToBuildProducts ( ) ;
UE4Build . AddUBTFilesToBuildProducts ( ) ;
}
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public class RootEditorNode : CompileNode
{
public RootEditorNode ( UnrealTargetPlatform InHostPlatform )
: base ( InHostPlatform )
{
AgentSharingGroup = "Editor" + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public static string StaticGetFullName ( UnrealTargetPlatform InHostPlatform )
{
return "RootEditor" + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( HostPlatform ) ;
}
public override bool DeleteBuildProducts ( )
{
return true ;
}
public override UE4Build . BuildAgenda GetAgenda ( GUBP bp )
{
var Agenda = new UE4Build . BuildAgenda ( ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
string AddArgs = "-nobuilduht" + bp . RocketUBTArgs ( ) ;
if ( bp . bOrthogonalizeEditorPlatforms )
{
AddArgs + = " -skipnonhostplatforms" ;
}
Agenda . AddTargets (
new string [ ] { bp . Branch . BaseEngineProject . Properties . Targets [ TargetRules . TargetType . Editor ] . TargetName } ,
HostPlatform , UnrealTargetConfiguration . Development , InAddArgs : AddArgs ) ;
foreach ( var ProgramTarget in bp . Branch . BaseEngineProject . Properties . Programs )
{
if ( ProgramTarget . Rules . GUBP_AlwaysBuildWithBaseEditor ( ) & & ProgramTarget . Rules . SupportsPlatform ( HostPlatform ) )
{
Agenda . AddTargets ( new string [ ] { ProgramTarget . TargetName } , HostPlatform , UnrealTargetConfiguration . Development , InAddArgs : AddArgs ) ;
}
}
return Agenda ;
}
void DeleteStaleDLLs ( GUBP bp )
{
if ( GUBP . bForceIncrementalCompile )
{
return ;
}
var Targets = new List < string > { bp . Branch . BaseEngineProject . Properties . Targets [ TargetRules . TargetType . Editor ] . TargetName } ;
foreach ( var ProgramTarget in bp . Branch . BaseEngineProject . Properties . Programs )
{
if ( ProgramTarget . Rules . GUBP_AlwaysBuildWithBaseEditor ( ) & & ProgramTarget . Rules . SupportsPlatform ( HostPlatform ) )
{
Targets . Add ( ProgramTarget . TargetName ) ;
}
}
2014-04-23 17:28:32 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var Target in Targets )
{
var EnginePlatformBinaries = CommandUtils . CombinePaths ( CommandUtils . CmdEnv . LocalRoot , "Engine" , "Binaries" , HostPlatform . ToString ( ) ) ;
var Wildcard = Target + "-*" ;
Log ( "************Deleting stale editor DLLs, path {0} wildcard {1}" , EnginePlatformBinaries , Wildcard ) ;
foreach ( var DiskFile in FindFiles ( Wildcard , true , EnginePlatformBinaries ) )
{
bool IsBuildProduct = false ;
foreach ( var Product in BuildProducts )
{
if ( Product . Equals ( DiskFile , StringComparison . InvariantCultureIgnoreCase ) )
{
IsBuildProduct = true ;
break ;
}
}
if ( ! IsBuildProduct )
{
DeleteFile ( DiskFile ) ;
}
}
var EnginePluginBinaries = CommandUtils . CombinePaths ( CommandUtils . CmdEnv . LocalRoot , "Engine" , "Plugins" ) ;
var HostSubstring = CommandUtils . CombinePaths ( "/" , HostPlatform . ToString ( ) , "/" ) ;
Log ( "************Deleting stale editor DLLs, path {0} wildcard {1} host {2}" , EnginePluginBinaries , Wildcard , HostSubstring ) ;
foreach ( var DiskFile in FindFiles ( Wildcard , true , EnginePluginBinaries ) )
{
if ( DiskFile . IndexOf ( HostSubstring , StringComparison . InvariantCultureIgnoreCase ) < 0 )
{
continue ;
}
bool IsBuildProduct = false ;
foreach ( var Product in BuildProducts )
{
if ( Product . Equals ( DiskFile , StringComparison . InvariantCultureIgnoreCase ) )
{
IsBuildProduct = true ;
break ;
}
}
if ( ! IsBuildProduct )
{
DeleteFile ( DiskFile ) ;
}
}
}
}
public override void PostLoadFromSharedTempStorage ( GUBP bp )
{
DeleteStaleDLLs ( bp ) ;
}
public override void PostBuildProducts ( GUBP bp )
{
DeleteStaleDLLs ( bp ) ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public class ToolsNode : CompileNode
{
public ToolsNode ( UnrealTargetPlatform InHostPlatform )
: base ( InHostPlatform )
{
if ( ! GUBP . bBuildRocket ) // more errors and more performance by just starting before the root editor is done
{
AddPseudodependency ( RootEditorNode . StaticGetFullName ( HostPlatform ) ) ;
}
AgentSharingGroup = "ToolsGroup" + StaticGetHostPlatformSuffix ( HostPlatform ) ;
}
public static string StaticGetFullName ( UnrealTargetPlatform InHostPlatform )
{
return "Tools" + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( HostPlatform ) ;
}
public override float Priority ( )
{
return base . Priority ( ) - 1 ;
}
public override bool DeleteBuildProducts ( )
{
return true ;
}
public override UE4Build . BuildAgenda GetAgenda ( GUBP bp )
{
var Agenda = new UE4Build . BuildAgenda ( ) ;
2014-03-14 14:13:41 -04:00
2014-09-05 21:50:16 -04:00
if ( HostPlatform = = UnrealTargetPlatform . Win64 )
2014-08-22 13:39:55 -04:00
{
2014-04-25 10:39:39 -04:00
if ( ! GUBP . bForceIncrementalCompile )
{
Agenda . DotNetProjects . AddRange (
new string [ ]
{
CombinePaths ( @"Engine\Source\Programs\UnrealControls\UnrealControls.csproj" ) ,
}
) ;
}
2014-08-22 13:39:55 -04:00
Agenda . DotNetSolutions . AddRange (
2014-04-25 10:39:39 -04:00
new string [ ]
{
CombinePaths ( @"Engine\Source\Programs\NetworkProfiler\NetworkProfiler.sln" ) ,
}
2014-08-22 13:39:55 -04:00
) ;
if ( ! GUBP . bForceIncrementalCompile )
{
2014-04-25 10:39:39 -04:00
Agenda . SwarmProject = CombinePaths ( @"Engine\Source\Programs\UnrealSwarm\UnrealSwarm.sln" ) ;
}
2014-08-22 13:39:55 -04:00
Agenda . IOSDotNetProjects . AddRange (
new string [ ]
2014-04-25 10:39:39 -04:00
{
CombinePaths ( @"Engine\Source\Programs\IOS\iPhonePackager\iPhonePackager.csproj" ) ,
CombinePaths ( @"Engine\Source\Programs\IOS\DeploymentServer\DeploymentServer.csproj" ) ,
CombinePaths ( @"Engine\Source\Programs\IOS\MobileDeviceInterface\MobileDeviceInterface.csproj" ) ,
CombinePaths ( @"Engine\Source\Programs\IOS\DeploymentInterface\DeploymentInterface.csproj" ) ,
}
2014-08-22 13:39:55 -04:00
) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
string AddArgs = "-nobuilduht -skipactionhistory -CopyAppBundleBackToDevice" + bp . RocketUBTArgs ( ) ; ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var ProgramTarget in bp . Branch . BaseEngineProject . Properties . Programs )
{
bool bInternalOnly ;
bool SeparateNode ;
2014-04-23 17:51:55 -04:00
2014-08-22 13:39:55 -04:00
if ( ProgramTarget . Rules . GUBP_AlwaysBuildWithTools ( HostPlatform , GUBP . bBuildRocket , out bInternalOnly , out SeparateNode ) & & ProgramTarget . Rules . SupportsPlatform ( HostPlatform ) & & ! bInternalOnly & & ! SeparateNode )
{
foreach ( var Plat in ProgramTarget . Rules . GUBP_ToolPlatforms ( HostPlatform ) )
{
foreach ( var Config in ProgramTarget . Rules . GUBP_ToolConfigs ( HostPlatform ) )
{
Agenda . AddTargets ( new string [ ] { ProgramTarget . TargetName } , Plat , Config , InAddArgs : AddArgs ) ;
}
}
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
return Agenda ;
}
}
public class SingleToolsNode : CompileNode
{
SingleTargetProperties ProgramTarget ;
public SingleToolsNode ( UnrealTargetPlatform InHostPlatform , SingleTargetProperties InProgramTarget )
: base ( InHostPlatform )
{
ProgramTarget = InProgramTarget ;
if ( ! GUBP . bBuildRocket ) // more errors and more performance by just starting before the root editor is done
{
AddPseudodependency ( RootEditorNode . StaticGetFullName ( HostPlatform ) ) ;
}
AgentSharingGroup = "ToolsGroup" + StaticGetHostPlatformSuffix ( HostPlatform ) ;
}
public static string StaticGetFullName ( UnrealTargetPlatform InHostPlatform , SingleTargetProperties InProgramTarget )
{
return "Tools_" + InProgramTarget . TargetName + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( HostPlatform , ProgramTarget ) ;
}
public override float Priority ( )
{
return base . Priority ( ) + 2 ;
}
public override bool DeleteBuildProducts ( )
{
return true ;
}
public override UE4Build . BuildAgenda GetAgenda ( GUBP bp )
{
var Agenda = new UE4Build . BuildAgenda ( ) ;
2014-04-23 17:51:55 -04:00
2014-08-22 13:39:55 -04:00
string AddArgs = "-nobuilduht -skipactionhistory -CopyAppBundleBackToDevice" + bp . RocketUBTArgs ( ) ; ;
2014-04-23 17:51:55 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var Plat in ProgramTarget . Rules . GUBP_ToolPlatforms ( HostPlatform ) )
{
foreach ( var Config in ProgramTarget . Rules . GUBP_ToolConfigs ( HostPlatform ) )
{
Agenda . AddTargets ( new string [ ] { ProgramTarget . TargetName } , Plat , Config , InAddArgs : AddArgs ) ;
}
}
return Agenda ;
}
}
2014-04-23 17:51:55 -04:00
2014-08-22 13:39:55 -04:00
public class InternalToolsNode : CompileNode
{
public InternalToolsNode ( UnrealTargetPlatform InHostPlatform )
: base ( InHostPlatform )
{
if ( ! GUBP . bBuildRocket ) // more errors and more performance by just starting before the root editor is done
{
AddPseudodependency ( RootEditorNode . StaticGetFullName ( HostPlatform ) ) ;
}
AgentSharingGroup = "ToolsGroup" + StaticGetHostPlatformSuffix ( HostPlatform ) ;
}
public static string StaticGetFullName ( UnrealTargetPlatform InHostPlatform )
{
return "InternalTools" + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( HostPlatform ) ;
}
public override float Priority ( )
{
return base . Priority ( ) - 2 ;
}
public override int CISFrequencyQuantumShift ( GUBP bp )
{
2014-09-03 10:12:50 -04:00
int Result = base . CISFrequencyQuantumShift ( bp ) + 1 ;
2014-08-22 13:39:55 -04:00
return Result ;
}
public override bool DeleteBuildProducts ( )
{
return true ;
}
public override UE4Build . BuildAgenda GetAgenda ( GUBP bp )
{
bool bAnyAdded = false ;
var Agenda = new UE4Build . BuildAgenda ( ) ;
2014-03-14 14:13:41 -04:00
2014-09-05 21:50:16 -04:00
if ( HostPlatform = = UnrealTargetPlatform . Win64 )
2014-08-22 13:39:55 -04:00
{
bAnyAdded = true ;
Agenda . DotNetProjects . AddRange (
new string [ ]
2014-03-14 14:13:41 -04:00
{
CombinePaths ( @"Engine\Source\Programs\Distill\Distill.csproj" ) ,
2014-04-29 21:51:03 -04:00
CombinePaths ( @"Engine\Source\Programs\NotForLicensees\CrashReportServer\CrashReportCommon\CrashReportCommon.csproj" ) ,
CombinePaths ( @"Engine\Source\Programs\NotForLicensees\CrashReportServer\CrashReportReceiver\CrashReportReceiver.csproj" ) ,
CombinePaths ( @"Engine\Source\Programs\NotForLicensees\CrashReportServer\CrashReportProcess\CrashReportProcess.csproj" ) ,
2014-03-14 14:13:41 -04:00
CombinePaths ( @"Engine\Source\Programs\CrashReporter\RegisterPII\RegisterPII.csproj" ) ,
} ) ;
2014-08-22 13:39:55 -04:00
Agenda . DotNetSolutions . AddRange (
new string [ ]
2014-03-14 14:13:41 -04:00
{
CombinePaths ( @"Engine\Source\Programs\UnrealDocTool\UnrealDocTool\UnrealDocTool.sln" ) ,
}
2014-08-22 13:39:55 -04:00
) ;
Agenda . ExtraDotNetFiles . AddRange (
new string [ ]
2014-03-14 14:13:41 -04:00
{
"Interop.IWshRuntimeLibrary" ,
"UnrealMarkdown" ,
"CommonUnrealMarkdown" ,
}
2014-08-22 13:39:55 -04:00
) ;
}
string AddArgs = "-nobuilduht -skipactionhistory -CopyAppBundleBackToDevice" + bp . RocketUBTArgs ( ) ; ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var ProgramTarget in bp . Branch . BaseEngineProject . Properties . Programs )
{
bool bInternalOnly ;
bool SeparateNode ;
2014-04-23 17:51:55 -04:00
2014-08-22 13:39:55 -04:00
if ( ProgramTarget . Rules . GUBP_AlwaysBuildWithTools ( HostPlatform , GUBP . bBuildRocket , out bInternalOnly , out SeparateNode ) & & ProgramTarget . Rules . SupportsPlatform ( HostPlatform ) & & bInternalOnly & & ! SeparateNode )
{
foreach ( var Plat in ProgramTarget . Rules . GUBP_ToolPlatforms ( HostPlatform ) )
{
foreach ( var Config in ProgramTarget . Rules . GUBP_ToolConfigs ( HostPlatform ) )
{
Agenda . AddTargets ( new string [ ] { ProgramTarget . TargetName } , Plat , Config , InAddArgs : AddArgs ) ;
bAnyAdded = true ;
}
}
}
}
if ( bAnyAdded )
{
return Agenda ;
}
return null ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public class SingleInternalToolsNode : CompileNode
{
SingleTargetProperties ProgramTarget ;
public SingleInternalToolsNode ( UnrealTargetPlatform InHostPlatform , SingleTargetProperties InProgramTarget )
: base ( InHostPlatform )
{
ProgramTarget = InProgramTarget ;
if ( ! GUBP . bBuildRocket ) // more errors and more performance by just starting before the root editor is done
{
AddPseudodependency ( RootEditorNode . StaticGetFullName ( HostPlatform ) ) ;
}
AgentSharingGroup = "ToolsGroup" + StaticGetHostPlatformSuffix ( HostPlatform ) ;
}
public static string StaticGetFullName ( UnrealTargetPlatform InHostPlatform , SingleTargetProperties InProgramTarget )
{
return "InternalTools_" + InProgramTarget . TargetName + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( HostPlatform , ProgramTarget ) ;
}
public override int CISFrequencyQuantumShift ( GUBP bp )
{
int Result = base . CISFrequencyQuantumShift ( bp ) + 1 ;
return Result ;
}
public override float Priority ( )
{
return base . Priority ( ) + 3 ;
}
public override bool DeleteBuildProducts ( )
{
return true ;
}
public override UE4Build . BuildAgenda GetAgenda ( GUBP bp )
{
var Agenda = new UE4Build . BuildAgenda ( ) ;
2014-04-23 17:51:55 -04:00
2014-08-22 13:39:55 -04:00
string AddArgs = "-nobuilduht -skipactionhistory -CopyAppBundleBackToDevice" + bp . RocketUBTArgs ( ) ; ;
2014-04-23 17:51:55 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var Plat in ProgramTarget . Rules . GUBP_ToolPlatforms ( HostPlatform ) )
{
foreach ( var Config in ProgramTarget . Rules . GUBP_ToolConfigs ( HostPlatform ) )
{
Agenda . AddTargets ( new string [ ] { ProgramTarget . TargetName } , Plat , Config , InAddArgs : AddArgs ) ;
}
}
return Agenda ;
}
}
2014-04-23 17:51:55 -04:00
2014-08-22 13:39:55 -04:00
public class EditorPlatformNode : CompileNode
{
UnrealTargetPlatform EditorPlatform ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public EditorPlatformNode ( UnrealTargetPlatform InHostPlatform , UnrealTargetPlatform Plat )
: base ( InHostPlatform )
{
AgentSharingGroup = "Editor" + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
EditorPlatform = Plat ;
AddDependency ( RootEditorNode . StaticGetFullName ( InHostPlatform ) ) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public static string StaticGetFullName ( UnrealTargetPlatform InHostPlatform , UnrealTargetPlatform Plat )
{
return Plat . ToString ( ) + "_EditorPlatform" + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( HostPlatform , EditorPlatform ) ;
}
public override float Priority ( )
{
return base . Priority ( ) + 1 ;
}
public override int CISFrequencyQuantumShift ( GUBP bp )
{
int Result = base . CISFrequencyQuantumShift ( bp ) ;
return Result ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public override UE4Build . BuildAgenda GetAgenda ( GUBP bp )
{
if ( ! bp . bOrthogonalizeEditorPlatforms )
{
throw new AutomationException ( "EditorPlatformNode node should not be used unless we are orthogonalizing editor platforms." ) ;
}
var Agenda = new UE4Build . BuildAgenda ( ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
Agenda . AddTargets (
new string [ ] { bp . Branch . BaseEngineProject . Properties . Targets [ TargetRules . TargetType . Editor ] . TargetName } ,
HostPlatform , UnrealTargetConfiguration . Development , InAddArgs : "-nobuilduht -skipactionhistory -CopyAppBundleBackToDevice -onlyplatformspecificfor=" + EditorPlatform . ToString ( ) ) ;
foreach ( var ProgramTarget in bp . Branch . BaseEngineProject . Properties . Programs )
{
if ( ProgramTarget . Rules . GUBP_AlwaysBuildWithBaseEditor ( ) & & ProgramTarget . Rules . SupportsPlatform ( HostPlatform ) & & ProgramTarget . Rules . GUBP_NeedsPlatformSpecificDLLs ( ) )
{
Agenda . AddTargets ( new string [ ] { ProgramTarget . TargetName } , HostPlatform , UnrealTargetConfiguration . Development , InAddArgs : "-nobuilduht -skipactionhistory -CopyAppBundleBackToDevice -onlyplatformspecificfor=" + EditorPlatform . ToString ( ) ) ;
}
}
return Agenda ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public class EditorGameNode : CompileNode
{
BranchInfo . BranchUProject GameProj ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public EditorGameNode ( GUBP bp , UnrealTargetPlatform InHostPlatform , BranchInfo . BranchUProject InGameProj )
: base ( InHostPlatform )
{
AgentSharingGroup = "Editor" + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
GameProj = InGameProj ;
AddDependency ( RootEditorNode . StaticGetFullName ( InHostPlatform ) ) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public static string StaticGetFullName ( UnrealTargetPlatform InHostPlatform , BranchInfo . BranchUProject InGameProj )
{
return InGameProj . GameName + "_EditorGame" + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( HostPlatform , GameProj ) ;
}
public override string GameNameIfAnyForTempStorage ( )
{
return GameProj . GameName ;
}
public override float Priority ( )
{
float Result = base . Priority ( ) ;
if ( GameProj . Options ( HostPlatform ) . bTestWithShared )
{
Result - = 1 ;
}
return Result ;
}
public override int CISFrequencyQuantumShift ( GUBP bp )
{
int Result = base . CISFrequencyQuantumShift ( bp ) ;
if ( GameProj . Options ( HostPlatform ) . bTestWithShared )
{
Result + = 3 ;
}
return Result ;
}
public override UE4Build . BuildAgenda GetAgenda ( GUBP bp )
{
var Agenda = new UE4Build . BuildAgenda ( ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
string Args = "-nobuilduht -skipactionhistory -skipnonhostplatforms -CopyAppBundleBackToDevice -forceheadergeneration" + bp . RocketUBTArgs ( true ) ;
2014-04-02 18:09:23 -04:00
2014-08-22 13:39:55 -04:00
Agenda . AddTargets (
new string [ ] { GameProj . Properties . Targets [ TargetRules . TargetType . Editor ] . TargetName } ,
HostPlatform , UnrealTargetConfiguration . Development , GameProj . FilePath , InAddArgs : Args ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
return Agenda ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public class GamePlatformMonolithicsNode : CompileNode
{
BranchInfo . BranchUProject GameProj ;
UnrealTargetPlatform TargetPlatform ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public GamePlatformMonolithicsNode ( GUBP bp , UnrealTargetPlatform InHostPlatform , BranchInfo . BranchUProject InGameProj , UnrealTargetPlatform InTargetPlatform )
: base ( InHostPlatform )
{
GameProj = InGameProj ;
TargetPlatform = InTargetPlatform ;
if ( TargetPlatform = = UnrealTargetPlatform . PS4 )
{
var PS4MapFileUtil = bp . Branch . FindProgram ( "PS4MapFileUtil" ) ;
if ( PS4MapFileUtil . Rules = = null )
{
throw new AutomationException ( "PS4MapFileUtil is not is this branch, but is required to build PS4 monolithics" ) ;
}
AddDependency ( SingleToolsNode . StaticGetFullName ( HostPlatform , PS4MapFileUtil ) ) ;
}
if ( InGameProj . GameName ! = bp . Branch . BaseEngineProject . GameName & & GameProj . Properties . Targets . ContainsKey ( TargetRules . TargetType . Editor ) )
{
AddPseudodependency ( EditorGameNode . StaticGetFullName ( InHostPlatform , GameProj ) ) ;
if ( bp . HasNode ( GamePlatformMonolithicsNode . StaticGetFullName ( HostPlatform , bp . Branch . BaseEngineProject , TargetPlatform ) ) )
{
AddPseudodependency ( GamePlatformMonolithicsNode . StaticGetFullName ( HostPlatform , bp . Branch . BaseEngineProject , TargetPlatform ) ) ;
}
}
else
{
if ( TargetPlatform ! = InHostPlatform & & bp . HasNode ( GamePlatformMonolithicsNode . StaticGetFullName ( InHostPlatform , bp . Branch . BaseEngineProject , InHostPlatform ) )
& & ! GUBP . bBuildRocket ) // more errors and more performance by just starting, for example, IOS without waiting for mac
{
AddPseudodependency ( GamePlatformMonolithicsNode . StaticGetFullName ( InHostPlatform , bp . Branch . BaseEngineProject , InHostPlatform ) ) ;
}
if ( GUBP . bBuildRocket & & InGameProj . GameName = = bp . Branch . BaseEngineProject . GameName )
{
AgentSharingGroup = "UE4_" + InTargetPlatform + "_Mono" + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
// lets just start this right away AddPseudodependency(RootEditorHeadersNode.StaticGetFullName(HostPlatform)); // maybe we should start these sooner, but that rather tangles the agent groups
}
}
if ( InGameProj . Options ( InHostPlatform ) . bTestWithShared ) /// compiling templates is only for testing purposes, and we will group them to avoid saturating the farm
{
AddPseudodependency ( WaitForTestShared . StaticGetFullName ( ) ) ;
AgentSharingGroup = "TemplateMonolithics" + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
2014-05-29 17:45:17 -04:00
2014-08-22 13:39:55 -04:00
if ( GUBP . bBuildRocket )
{
var Target = bp . Branch . BaseEngineProject . Properties . Targets [ TargetRules . TargetType . Game ] ;
var Configs = Target . Rules . GUBP_GetConfigs_MonolithicOnly ( HostPlatform , TargetPlatform ) ;
foreach ( var Config in Configs )
{
if ( HostPlatform = = UnrealTargetPlatform . Win64 )
{
if ( TargetPlatform = = UnrealTargetPlatform . Win32 & & Config ! = UnrealTargetConfiguration . Shipping )
{
continue ;
}
if ( TargetPlatform = = UnrealTargetPlatform . Win64 & & Config ! = UnrealTargetConfiguration . Development )
{
continue ;
}
if ( TargetPlatform = = UnrealTargetPlatform . Android & & Config ! = UnrealTargetConfiguration . Shipping & & Config ! = UnrealTargetConfiguration . Development )
{
continue ;
}
2014-09-22 12:34:00 -04:00
if ( TargetPlatform = = UnrealTargetPlatform . Linux & & Config ! = UnrealTargetConfiguration . Shipping & & Config ! = UnrealTargetConfiguration . Development )
{
continue ;
}
2014-08-22 13:39:55 -04:00
}
else if ( Config ! = UnrealTargetConfiguration . Shipping & & Config ! = UnrealTargetConfiguration . Development )
{
continue ;
}
Log ( "Building {0} for Host={1} Target={2} Config={3} for rocket. Node={4}" , Target . TargetName , HostPlatform , TargetPlatform , Config , GetFullName ( ) ) ;
}
}
2014-05-29 17:45:17 -04:00
2014-08-22 13:39:55 -04:00
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public static string StaticGetFullName ( UnrealTargetPlatform InHostPlatform , BranchInfo . BranchUProject InGameProj , UnrealTargetPlatform InTargetPlatform )
{
2014-09-09 12:18:17 -04:00
return InGameProj . GameName + "_" + InTargetPlatform + "_Mono" + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
2014-08-22 13:39:55 -04:00
}
public override string GetFullName ( )
{
return StaticGetFullName ( HostPlatform , GameProj , TargetPlatform ) ;
}
public override string GameNameIfAnyForTempStorage ( )
{
return GameProj . GameName ;
}
public override bool DeleteBuildProducts ( )
{
return true ;
}
2014-06-23 14:06:45 -04:00
2014-08-22 13:39:55 -04:00
public override int CISFrequencyQuantumShift ( GUBP bp )
{
int Result = base . CISFrequencyQuantumShift ( bp ) ;
if ( GameProj . GameName ! = bp . Branch . BaseEngineProject . GameName )
{
Result + = 3 ; //only every 80m
}
else if ( TargetPlatform ! = HostPlatform )
{
Result + = 2 ; //only every 40m
}
return Result ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public override UE4Build . BuildAgenda GetAgenda ( GUBP bp )
{
if ( ! bp . ActivePlatforms . Contains ( TargetPlatform ) )
{
throw new AutomationException ( "{0} is not a supported platform for {1}" , TargetPlatform . ToString ( ) , GetFullName ( ) ) ;
}
var Agenda = new UE4Build . BuildAgenda ( ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
string Args = "-nobuilduht -skipactionhistory -CopyAppBundleBackToDevice" + bp . RocketUBTArgs ( ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var Kind in BranchInfo . MonolithicKinds )
{
if ( GUBP . bBuildRocket & & Kind ! = TargetRules . TargetType . Game )
{
continue ;
}
if ( GameProj . Properties . Targets . ContainsKey ( Kind ) )
{
var Target = GameProj . Properties . Targets [ Kind ] ;
var Platforms = Target . Rules . GUBP_GetPlatforms_MonolithicOnly ( HostPlatform ) ;
2014-08-18 13:29:39 -04:00
var AdditionalPlatforms = Target . Rules . GUBP_GetBuildOnlyPlatforms_MonolithicOnly ( HostPlatform ) ;
var AllPlatforms = Platforms . Union ( AdditionalPlatforms ) ;
if ( AllPlatforms . Contains ( TargetPlatform ) & & Target . Rules . SupportsPlatform ( TargetPlatform ) )
2014-08-22 13:39:55 -04:00
{
var Configs = Target . Rules . GUBP_GetConfigs_MonolithicOnly ( HostPlatform , TargetPlatform ) ;
foreach ( var Config in Configs )
{
if ( GUBP . bBuildRocket )
{
if ( HostPlatform = = UnrealTargetPlatform . Win64 )
{
if ( TargetPlatform = = UnrealTargetPlatform . Win32 & & Config ! = UnrealTargetConfiguration . Shipping )
{
continue ;
}
if ( TargetPlatform = = UnrealTargetPlatform . Win64 & & Config ! = UnrealTargetConfiguration . Development )
{
continue ;
}
if ( TargetPlatform = = UnrealTargetPlatform . Android & & Config ! = UnrealTargetConfiguration . Shipping & & Config ! = UnrealTargetConfiguration . Development )
{
continue ;
}
2014-09-22 12:34:00 -04:00
if ( TargetPlatform = = UnrealTargetPlatform . Linux & & Config ! = UnrealTargetConfiguration . Shipping & & Config ! = UnrealTargetConfiguration . Development )
{
continue ;
}
2014-08-22 13:39:55 -04:00
}
else if ( Config ! = UnrealTargetConfiguration . Shipping & & Config ! = UnrealTargetConfiguration . Development )
{
continue ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
if ( GameProj . GameName = = bp . Branch . BaseEngineProject . GameName )
{
Agenda . AddTargets ( new string [ ] { Target . TargetName } , TargetPlatform , Config , InAddArgs : Args ) ;
}
else
{
Agenda . AddTargets ( new string [ ] { Target . TargetName } , TargetPlatform , Config , GameProj . FilePath , InAddArgs : Args ) ;
}
}
}
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
return Agenda ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public class RootEditorHeadersNode : HostPlatformNode
{
public RootEditorHeadersNode ( UnrealTargetPlatform InHostPlatform )
: base ( InHostPlatform )
{
AgentSharingGroup = "Editor" + StaticGetHostPlatformSuffix ( HostPlatform ) ;
AddDependency ( RootEditorNode . StaticGetFullName ( HostPlatform ) ) ;
}
public static string StaticGetFullName ( UnrealTargetPlatform InHostPlatform )
{
return "RootEditorHeaders" + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( HostPlatform ) ;
}
public override float Priority ( )
{
return 1000000.0f ; // right after the root editor
}
public override void DoBuild ( GUBP bp )
{
BuildProducts = new List < string > ( ) ;
2014-03-16 04:24:33 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var FileToCopy in CommandUtils . FindFiles ( "*.h" , true , CommandUtils . CombinePaths ( CmdEnv . LocalRoot , @"Engine\Intermediate\Build\" , HostPlatform . ToString ( ) , "Inc" ) ) )
{
AddBuildProduct ( FileToCopy ) ;
}
var Targets = new List < string > { bp . Branch . BaseEngineProject . Properties . Targets [ TargetRules . TargetType . Editor ] . TargetName } ;
foreach ( var ProgramTarget in bp . Branch . BaseEngineProject . Properties . Programs )
{
if ( ProgramTarget . Rules . GUBP_AlwaysBuildWithBaseEditor ( ) & & ProgramTarget . Rules . SupportsPlatform ( HostPlatform ) )
{
Targets . Add ( ProgramTarget . TargetName ) ;
}
}
foreach ( var Target in Targets )
{
foreach ( var FileToCopy in CommandUtils . FindFiles ( "*.h" , true , CommandUtils . CombinePaths ( CmdEnv . LocalRoot , @"Engine\Intermediate\Build\" , HostPlatform . ToString ( ) , Target , "Inc" ) ) )
{
AddBuildProduct ( FileToCopy ) ;
}
}
2014-04-23 17:46:17 -04:00
2014-08-22 13:39:55 -04:00
var EnginePluginsDirectory = Path . Combine ( CommandUtils . CmdEnv . LocalRoot , "Engine/Plugins" ) ;
var EnginePlugins = new List < PluginInfo > ( ) ;
Plugins . FindPluginsIn ( EnginePluginsDirectory , PluginInfo . LoadedFromType . Engine , ref EnginePlugins ) ;
2014-03-16 04:24:33 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var EnginePlugin in EnginePlugins )
{
foreach ( var FileToCopy in CommandUtils . FindFiles ( "*" , true , CommandUtils . CombinePaths ( EnginePlugin . Directory , @"Intermediate\Build" , HostPlatform . ToString ( ) , "Inc" ) ) )
{
AddBuildProduct ( FileToCopy ) ;
}
}
RemoveOveralppingBuildProducts ( ) ;
}
}
2014-03-16 04:24:33 -04:00
2014-08-22 13:39:55 -04:00
public class GameMonolithicHeadersNode : HostPlatformNode
{
UnrealTargetPlatform TargetPlatform ;
2014-03-16 04:24:33 -04:00
2014-08-22 13:39:55 -04:00
public GameMonolithicHeadersNode ( GUBP bp , UnrealTargetPlatform InHostPlatform , UnrealTargetPlatform InTargetPlatform )
: base ( InHostPlatform )
{
TargetPlatform = InTargetPlatform ;
AgentSharingGroup = "UE4_" + InTargetPlatform + "_Mono" + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
AddDependency ( GamePlatformMonolithicsNode . StaticGetFullName ( HostPlatform , bp . Branch . BaseEngineProject , TargetPlatform ) ) ;
}
public static string StaticGetFullName ( UnrealTargetPlatform InHostPlatform , UnrealTargetPlatform InTargetPlatform )
{
return "UE4_" + InTargetPlatform + "_MonolithicHeaders" + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( HostPlatform , TargetPlatform ) ;
}
public override float Priority ( )
{
return 1000000.0f ; // right after the game monolithics
}
public override void DoBuild ( GUBP bp )
{
if ( ! UnrealBuildTool . Utils . IsRunningOnMono & & TargetPlatform = = UnrealTargetPlatform . IOS )
{
throw new AutomationException ( "these rocket header node require real mac path." ) ;
}
BuildProducts = new List < string > ( ) ;
2014-04-25 10:39:39 -04:00
if ( TargetPlatform ! = HostPlatform )
{
// host platform overlaps with the editor, so we don't want them here
var PlatformDir = TargetPlatform . ToString ( ) ;
foreach ( var FileToCopy in CommandUtils . FindFiles ( "*.h" , true , CommandUtils . CombinePaths ( CmdEnv . LocalRoot , @"Engine\Intermediate\Build\" , PlatformDir , "Inc" ) ) )
{
AddBuildProduct ( FileToCopy ) ;
}
2014-03-16 04:24:33 -04:00
2014-04-25 10:39:39 -04:00
// these may not be any new build products here, but we will check anyway
var EnginePluginsDirectory = Path . Combine ( CommandUtils . CmdEnv . LocalRoot , "Engine/Plugins" ) ;
var EnginePlugins = new List < PluginInfo > ( ) ;
Plugins . FindPluginsIn ( EnginePluginsDirectory , PluginInfo . LoadedFromType . Engine , ref EnginePlugins ) ;
2014-04-02 18:09:23 -04:00
2014-04-25 10:39:39 -04:00
foreach ( var EnginePlugin in EnginePlugins )
{
foreach ( var FileToCopy in CommandUtils . FindFiles ( "*" , true , CommandUtils . CombinePaths ( EnginePlugin . Directory , @"Intermediate\Build" , PlatformDir , "Inc" ) ) )
{
AddBuildProduct ( FileToCopy ) ;
}
}
}
2014-08-22 13:39:55 -04:00
RemoveOveralppingBuildProducts ( ) ;
if ( BuildProducts . Count = = 0 )
{
SaveRecordOfSuccessAndAddToBuildProducts ( ) ; // could be empty
}
}
}
public class SuccessNode : GUBPNode
{
public SuccessNode ( )
{
}
public override void DoBuild ( GUBP bp )
{
BuildProducts = new List < string > ( ) ;
SaveRecordOfSuccessAndAddToBuildProducts ( ) ;
}
public override bool SendSuccessEmail ( )
{
return true ;
}
}
public class GeneralSuccessNode : GUBP . SuccessNode
{
string MyName ;
public GeneralSuccessNode ( string InMyName )
{
MyName = InMyName ;
}
public static string StaticGetFullName ( string InMyName )
{
return InMyName + "_Success" ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( MyName ) ;
}
}
public class AggregateNode : GUBPNode
{
public AggregateNode ( )
{
}
public override bool RunInEC ( )
{
return false ;
}
public override bool IsAggregate ( )
{
return true ;
}
public override void DoBuild ( GUBP bp )
{
BuildProducts = new List < string > ( ) ;
}
public override void DoFakeBuild ( GUBP bp ) // this is used to more rapidly test a build system, it does nothing but save a record of success as a build product
{
BuildProducts = new List < string > ( ) ;
}
}
public class HostPlatformAggregateNode : AggregateNode
{
protected UnrealTargetPlatform HostPlatform ;
public HostPlatformAggregateNode ( UnrealTargetPlatform InHostPlatform )
{
HostPlatform = InHostPlatform ;
}
public static string StaticGetHostPlatformSuffix ( UnrealTargetPlatform InHostPlatform )
{
return HostPlatformNode . StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public virtual string GetHostPlatformSuffix ( )
{
return StaticGetHostPlatformSuffix ( HostPlatform ) ;
}
public UnrealTargetPlatform GetAltHostPlatform ( )
{
return GUBP . GetAltHostPlatform ( HostPlatform ) ;
}
}
public class EditorAndToolsNode : HostPlatformAggregateNode
{
public EditorAndToolsNode ( GUBP bp , UnrealTargetPlatform InHostPlatform )
: base ( InHostPlatform )
{
AddDependency ( RootEditorNode . StaticGetFullName ( HostPlatform ) ) ;
AddDependency ( ToolsNode . StaticGetFullName ( HostPlatform ) ) ;
AddDependency ( InternalToolsNode . StaticGetFullName ( HostPlatform ) ) ;
if ( InHostPlatform = = UnrealTargetPlatform . Win64 )
2014-06-03 14:38:05 -04:00
{
2014-08-22 13:39:55 -04:00
var VersionSelector = bp . Branch . FindProgram ( "UnrealVersionSelector" ) ;
if ( VersionSelector . Rules ! = null )
{
2014-06-03 14:38:05 -04:00
AddDependency ( SingleInternalToolsNode . StaticGetFullName ( HostPlatform , VersionSelector ) ) ;
}
}
2014-08-22 13:39:55 -04:00
}
public static string StaticGetFullName ( UnrealTargetPlatform InHostPlatform )
{
return "BaseEditorAndTools" + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( HostPlatform ) ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public class AggregatePromotableNode : AggregateNode
{
protected List < UnrealTargetPlatform > HostPlatforms ;
string PromotionLabelPrefix ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public AggregatePromotableNode ( List < UnrealTargetPlatform > InHostPlatforms , string InPromotionLabelPrefix )
{
HostPlatforms = InHostPlatforms ;
foreach ( var HostPlatform in HostPlatforms )
{
AddDependency ( EditorAndToolsNode . StaticGetFullName ( HostPlatform ) ) ;
}
PromotionLabelPrefix = InPromotionLabelPrefix ;
}
public static string StaticGetFullName ( string InPromotionLabelPrefix )
{
return InPromotionLabelPrefix + "_Promotable_Aggregate" ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( PromotionLabelPrefix ) ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public class GameAggregatePromotableNode : AggregatePromotableNode
{
BranchInfo . BranchUProject GameProj ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public GameAggregatePromotableNode ( GUBP bp , List < UnrealTargetPlatform > InHostPlatforms , BranchInfo . BranchUProject InGameProj )
: base ( InHostPlatforms , InGameProj . GameName )
{
GameProj = InGameProj ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var HostPlatform in HostPlatforms )
{
AddDependency ( RootEditorNode . StaticGetFullName ( HostPlatform ) ) ;
if ( InGameProj . GameName ! = bp . Branch . BaseEngineProject . GameName & & GameProj . Properties . Targets . ContainsKey ( TargetRules . TargetType . Editor ) )
{
AddDependency ( EditorGameNode . StaticGetFullName ( HostPlatform , GameProj ) ) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
// add all of the platforms I use
{
var Platforms = bp . GetMonolithicPlatformsForUProject ( HostPlatform , InGameProj , false ) ;
if ( bp . bOrthogonalizeEditorPlatforms )
{
foreach ( var Plat in Platforms )
{
AddDependency ( EditorPlatformNode . StaticGetFullName ( HostPlatform , Plat ) ) ;
}
}
}
{
var Platforms = bp . GetMonolithicPlatformsForUProject ( HostPlatform , InGameProj , true ) ;
foreach ( var Plat in Platforms )
{
AddDependency ( GamePlatformMonolithicsNode . StaticGetFullName ( HostPlatform , GameProj , Plat ) ) ;
}
}
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public static string StaticGetFullName ( BranchInfo . BranchUProject InGameProj )
{
return AggregatePromotableNode . StaticGetFullName ( InGameProj . GameName ) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public override string GameNameIfAnyForTempStorage ( )
{
return GameProj . GameName ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public class SharedAggregatePromotableNode : AggregatePromotableNode
{
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public SharedAggregatePromotableNode ( GUBP bp , List < UnrealTargetPlatform > InHostPlatforms )
: base ( InHostPlatforms , "Shared" )
{
foreach ( var HostPlatform in HostPlatforms )
{
{
var Options = bp . Branch . BaseEngineProject . Options ( HostPlatform ) ;
if ( Options . bIsPromotable & & ! Options . bSeparateGamePromotion )
{
AddDependency ( GameAggregatePromotableNode . StaticGetFullName ( bp . Branch . BaseEngineProject ) ) ;
}
}
foreach ( var CodeProj in bp . Branch . CodeProjects )
{
var Options = CodeProj . Options ( HostPlatform ) ;
if ( ! Options . bSeparateGamePromotion )
{
if ( Options . bIsPromotable )
{
AddDependency ( GameAggregatePromotableNode . StaticGetFullName ( CodeProj ) ) ;
}
else if ( Options . bTestWithShared )
{
AddDependency ( EditorGameNode . StaticGetFullName ( HostPlatform , CodeProj ) ) ; // if we are just testing, we will still include the editor stuff
}
}
}
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public static string StaticGetFullName ( )
{
return AggregatePromotableNode . StaticGetFullName ( "Shared" ) ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public class WaitForUserInput : GUBPNode
{
protected bool bTriggerWasTriggered ;
public WaitForUserInput ( )
{
bTriggerWasTriggered = false ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public override void DoBuild ( GUBP bp )
{
BuildProducts = new List < string > ( ) ;
SaveRecordOfSuccessAndAddToBuildProducts ( ) ;
}
public override bool TriggerNode ( )
{
return true ;
}
public override void SetAsExplicitTrigger ( )
{
bTriggerWasTriggered = true ;
}
public override bool IsSticky ( )
{
return bTriggerWasTriggered ;
}
public virtual string GetTriggerStateName ( )
{
return "GenericTrigger" ;
}
public virtual string GetTriggerDescText ( )
{
return "GenericTrigger no description text available" ;
}
public virtual string GetTriggerActionText ( )
{
return "GenericTrigger no action text available" ;
}
public virtual bool TriggerRequiresRecursiveWorkflow ( )
{
return true ;
}
public override string ECProcedure ( )
{
if ( bTriggerWasTriggered )
{
return base . ECProcedure ( ) ; // after this user hits the trigger, we want to run this as an ordinary node
}
if ( TriggerRequiresRecursiveWorkflow ( ) )
{
return String . Format ( "GUBP_UAT_Trigger" ) ; //here we run a recursive workflow to wait for the trigger
}
return String . Format ( "GUBP_Hardcoded_Trigger" ) ; //here we advance the state in the hardcoded workflow so folks can approve
}
public override string ECProcedureParams ( )
{
var Result = base . ECProcedureParams ( ) ;
if ( ! bTriggerWasTriggered )
{
2014-09-03 10:12:50 -04:00
Result + = String . Format ( ", {{actualParameterName => 'TriggerState', value => '{0}'}}, {{actualParameterName => 'ActionText', value =>\"{1}\"}}, {{actualParameterName => 'DescText', value =>\"{2}\"}}" , GetTriggerStateName ( ) , GetTriggerActionText ( ) , GetTriggerDescText ( ) ) ;
//Result += String.Format(" --actualParameter TriggerState={0} --actualParameter ActionText=\"{1}\" --actualParameter DescText=\"{2}\"", GetTriggerStateName(), GetTriggerActionText(), GetTriggerDescText());
2014-08-22 13:39:55 -04:00
}
return Result ;
}
public override int TimeoutInMinutes ( )
{
return 0 ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public class WaitForPromotionUserInput : WaitForUserInput
{
string PromotionLabelPrefix ;
string PromotionLabelSuffix ;
protected bool bLabelPromoted ; // true if this is the promoted version
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public WaitForPromotionUserInput ( string InPromotionLabelPrefix , string InPromotionLabelSuffix , bool bInLabelPromoted )
{
PromotionLabelPrefix = InPromotionLabelPrefix ;
PromotionLabelSuffix = InPromotionLabelSuffix ;
bLabelPromoted = bInLabelPromoted ;
if ( bLabelPromoted )
{
AddDependency ( LabelPromotableNode . StaticGetFullName ( PromotionLabelPrefix , false ) ) ;
}
else
{
AddDependency ( AggregatePromotableNode . StaticGetFullName ( PromotionLabelPrefix ) ) ;
}
}
public static string StaticGetFullName ( string InPromotionLabelPrefix , string InPromotionLabelSuffix , bool bInLabelPromoted )
{
return InPromotionLabelPrefix + ( bInLabelPromoted ? "_WaitForPromotion" : "_WaitForPromotable" ) + InPromotionLabelSuffix ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( PromotionLabelPrefix , PromotionLabelSuffix , bLabelPromoted ) ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public class WaitForGamePromotionUserInput : WaitForPromotionUserInput
{
BranchInfo . BranchUProject GameProj ;
bool bCustomWorkflow ;
public WaitForGamePromotionUserInput ( GUBP bp , BranchInfo . BranchUProject InGameProj , bool bInLabelPromoted )
: base ( InGameProj . GameName , "" , bInLabelPromoted )
{
GameProj = InGameProj ;
var Options = InGameProj . Options ( UnrealTargetPlatform . Win64 ) ;
bCustomWorkflow = Options . bCustomWorkflowForPromotion ;
}
public static string StaticGetFullName ( BranchInfo . BranchUProject InGameProj , bool bInLabelPromoted )
{
return WaitForPromotionUserInput . StaticGetFullName ( InGameProj . GameName , "" , bInLabelPromoted ) ;
}
public override string GameNameIfAnyForTempStorage ( )
{
return GameProj . GameName ;
}
public override string GetTriggerDescText ( )
{
if ( bLabelPromoted )
{
return GameProj . GameName + " is ready for promotion." ;
}
return GameProj . GameName + " is ready to make a promotable label and begin testing." ;
}
public override string GetTriggerActionText ( )
{
if ( bLabelPromoted )
{
return "Promote " + GameProj . GameName + "." ;
}
return "Make a promotable label for " + GameProj . GameName + " and begin testing." ;
}
public override string GetTriggerStateName ( )
{
if ( bCustomWorkflow )
{
return GetFullName ( ) ;
}
return base . GetTriggerStateName ( ) ;
}
public override bool TriggerRequiresRecursiveWorkflow ( )
{
if ( bCustomWorkflow )
{
return ! bLabelPromoted ; // the promotable starts the hardcoded chain
}
return base . TriggerRequiresRecursiveWorkflow ( ) ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public class WaitForSharedPromotionUserInput : WaitForPromotionUserInput
{
public WaitForSharedPromotionUserInput ( GUBP bp , bool bInLabelPromoted )
: base ( "Shared" , IsMainBranch ( ) , bInLabelPromoted )
{
}
public override string GetTriggerDescText ( )
{
if ( bLabelPromoted )
{
return "The shared promotable is ready for promotion." ;
}
return "The shared promotable is ready to make a promotable label." ;
}
public override string GetTriggerActionText ( )
{
if ( bLabelPromoted )
{
return "Promote the shared promotable." ;
}
return "Make the shared promotable label." ;
}
public static string StaticGetFullName ( bool bInLabelPromoted )
{
return WaitForPromotionUserInput . StaticGetFullName ( "Shared" , IsMainBranch ( ) , bInLabelPromoted ) ;
}
public static string IsMainBranch ( )
{
string isMain = "" ;
if ( P4Enabled )
{
string CurrentBranch = P4Env . BuildRootP4 ;
if ( CurrentBranch = = "//depot/UE4" )
{
isMain = "_WithNightlys" ;
}
}
return isMain ;
}
public override string GetTriggerStateName ( )
{
return GetFullName ( ) ;
}
public override bool TriggerRequiresRecursiveWorkflow ( )
{
return ! bLabelPromoted ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public class LabelPromotableNode : GUBPNode
{
string PromotionLabelPrefix ;
protected bool bLabelPromoted ; // true if this is the promoted version
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public LabelPromotableNode ( string InPromotionLabelPrefix , string InPromotionLabelSuffix , bool bInLabelPromoted )
{
PromotionLabelPrefix = InPromotionLabelPrefix ;
bLabelPromoted = bInLabelPromoted ;
AddDependency ( WaitForPromotionUserInput . StaticGetFullName ( PromotionLabelPrefix , InPromotionLabelSuffix , bLabelPromoted ) ) ;
}
string LabelName ( bool bLocalLabelPromoted )
{
string LabelPrefix = PromotionLabelPrefix ;
string CompleteLabelPrefix = ( bLocalLabelPromoted ? "Promoted-" : "Promotable-" ) + LabelPrefix ;
if ( LabelPrefix = = "Shared" & & bLocalLabelPromoted )
{
// shared promotion has a shorter name
CompleteLabelPrefix = "Promoted" ;
}
if ( LabelPrefix = = "Shared" & & ! bLocalLabelPromoted )
{
//shared promotable has a shorter name
CompleteLabelPrefix = "Promotable" ;
}
if ( GUBP . bBuildRocket )
{
CompleteLabelPrefix = "Rocket-" + CompleteLabelPrefix ;
}
if ( GUBP . bPreflightBuild )
{
CompleteLabelPrefix = CompleteLabelPrefix + PreflightMangleSuffix ;
}
return CompleteLabelPrefix ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public override bool IsSticky ( )
{
return true ;
}
public override bool SendSuccessEmail ( )
{
return true ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public override void DoBuild ( GUBP bp )
{
BuildProducts = new List < string > ( ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
if ( P4Enabled )
{
if ( AllDependencyBuildProducts . Count = = 0 )
{
throw new AutomationException ( "{0} has no build products" , GetFullName ( ) ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
if ( bLabelPromoted )
{
2014-04-02 18:09:23 -04:00
P4 . MakeDownstreamLabelFromLabel ( P4Env , LabelName ( true ) , LabelName ( false ) ) ;
2014-08-22 13:39:55 -04:00
}
else
{
2014-04-02 18:09:23 -04:00
int WorkingCL = P4 . CreateChange ( P4Env . Client , String . Format ( "GUBP Node {0} built from changelist {1}" , GetFullName ( ) , bp . CL ) ) ;
2014-08-22 13:39:55 -04:00
Log ( "Build from {0} Working in {1}" , bp . CL , WorkingCL ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
var ProductsToSubmit = new List < String > ( ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var Product in AllDependencyBuildProducts )
{
// hacks to keep certain things out of P4
if (
! Product . EndsWith ( "version.h" , StringComparison . InvariantCultureIgnoreCase ) & &
! Product . EndsWith ( "version.cpp" , StringComparison . InvariantCultureIgnoreCase ) & &
2014-03-14 14:13:41 -04:00
! Product . Replace ( '\\' , '/' ) . EndsWith ( "DotNetCommon/MetaData.cs" , StringComparison . InvariantCultureIgnoreCase ) & &
2014-08-22 13:39:55 -04:00
! Product . EndsWith ( "_Success.log" , StringComparison . InvariantCultureIgnoreCase )
)
{
ProductsToSubmit . Add ( Product ) ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
// Open files for add or edit
UE4Build . AddBuildProductsToChangelist ( WorkingCL , ProductsToSubmit ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
// Check everything in!
int SubmittedCL ;
2014-04-02 18:09:23 -04:00
P4 . Submit ( WorkingCL , out SubmittedCL , true , true ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
// Label it
2014-04-02 18:09:23 -04:00
P4 . MakeDownstreamLabel ( P4Env , LabelName ( false ) , null ) ;
2014-08-22 13:39:55 -04:00
}
}
SaveRecordOfSuccessAndAddToBuildProducts ( ) ;
}
public static string StaticGetFullName ( string InPromotionLabelPrefix , bool bInLabelPromoted )
{
return InPromotionLabelPrefix + ( bInLabelPromoted ? "_LabelPromoted" : "_LabelPromotable" ) ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( PromotionLabelPrefix , bLabelPromoted ) ;
}
}
2014-05-01 07:33:06 -04:00
2014-08-22 13:39:55 -04:00
public class GameLabelPromotableNode : LabelPromotableNode
{
BranchInfo . BranchUProject GameProj ;
public GameLabelPromotableNode ( GUBP bp , BranchInfo . BranchUProject InGameProj , bool bInLabelPromoted )
: base ( InGameProj . GameName , "" , bInLabelPromoted )
{
GameProj = InGameProj ;
}
2014-05-01 07:33:06 -04:00
2014-08-22 13:39:55 -04:00
public static string StaticGetFullName ( BranchInfo . BranchUProject InGameProj , bool bInLabelPromoted )
{
return LabelPromotableNode . StaticGetFullName ( InGameProj . GameName , bInLabelPromoted ) ;
}
public override string GameNameIfAnyForTempStorage ( )
{
return GameProj . GameName ;
}
}
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
public class SharedLabelPromotableNode : LabelPromotableNode
{
public SharedLabelPromotableNode ( GUBP bp , bool bInLabelPromoted )
: base ( "Shared" , IsMainBranch ( ) , bInLabelPromoted )
{
}
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
public static string StaticGetFullName ( bool bInLabelPromoted )
{
return LabelPromotableNode . StaticGetFullName ( "Shared" , bInLabelPromoted ) ;
}
public static string IsMainBranch ( )
{
string isMain = "" ;
if ( P4Enabled )
{
string CurrentBranch = P4Env . BuildRootP4 ;
if ( CurrentBranch = = "//depot/UE4" )
{
isMain = "_WithNightlys" ;
}
}
return isMain ;
}
}
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
public class WaitForTestShared : AggregateNode
{
public WaitForTestShared ( GUBP bp )
{
}
public static string StaticGetFullName ( )
{
return "Shared_TestingAggregate" ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( ) ;
}
public override int CISFrequencyQuantumShift ( GUBP bp )
{
return base . CISFrequencyQuantumShift ( bp ) + 5 ;
}
}
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
public class CookNode : HostPlatformNode
{
BranchInfo . BranchUProject GameProj ;
UnrealTargetPlatform TargetPlatform ;
string CookPlatform ;
bool bIsMassive ;
2014-10-08 10:49:02 -04:00
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
public CookNode ( GUBP bp , UnrealTargetPlatform InHostPlatform , BranchInfo . BranchUProject InGameProj , UnrealTargetPlatform InTargetPlatform , string InCookPlatform )
: base ( InHostPlatform )
{
GameProj = InGameProj ;
TargetPlatform = InTargetPlatform ;
CookPlatform = InCookPlatform ;
bIsMassive = false ;
AddDependency ( EditorAndToolsNode . StaticGetFullName ( HostPlatform ) ) ;
if ( bp . bOrthogonalizeEditorPlatforms )
{
if ( TargetPlatform ! = HostPlatform & & TargetPlatform ! = GUBP . GetAltHostPlatform ( HostPlatform ) )
{
AddDependency ( EditorPlatformNode . StaticGetFullName ( HostPlatform , TargetPlatform ) ) ;
}
2014-10-08 10:49:02 -04:00
}
2014-08-22 13:39:55 -04:00
bool bIsShared = false ;
// is this the "base game" or a non code project?
if ( InGameProj . GameName ! = bp . Branch . BaseEngineProject . GameName & & GameProj . Properties . Targets . ContainsKey ( TargetRules . TargetType . Editor ) )
{
var Options = InGameProj . Options ( HostPlatform ) ;
2014-10-08 10:49:02 -04:00
bIsMassive = Options . bIsMassive ;
2014-08-22 13:39:55 -04:00
AddDependency ( EditorGameNode . StaticGetFullName ( HostPlatform , GameProj ) ) ;
// add an arc to prevent cooks from running until promotable is labeled
if ( Options . bIsPromotable )
{
if ( ! Options . bSeparateGamePromotion )
{
bIsShared = true ;
}
}
else if ( Options . bTestWithShared )
{
bIsShared = true ;
}
AddPseudodependency ( GamePlatformMonolithicsNode . StaticGetFullName ( HostPlatform , GameProj , TargetPlatform ) ) ;
}
else
{
2014-10-08 10:49:02 -04:00
bIsShared = true ;
2014-08-22 13:39:55 -04:00
AddPseudodependency ( GamePlatformMonolithicsNode . StaticGetFullName ( HostPlatform , bp . Branch . BaseEngineProject , TargetPlatform ) ) ;
}
if ( bIsShared )
{
// add an arc to prevent cooks from running until promotable is labeled
AddPseudodependency ( WaitForTestShared . StaticGetFullName ( ) ) ;
AgentSharingGroup = "SharedCooks" + StaticGetHostPlatformSuffix ( HostPlatform ) ;
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
// If the cook fails for the base engine, don't bother trying
if ( InGameProj . GameName ! = bp . Branch . BaseEngineProject . GameName & & bp . HasNode ( CookNode . StaticGetFullName ( HostPlatform , bp . Branch . BaseEngineProject , CookPlatform ) ) )
{
AddPseudodependency ( CookNode . StaticGetFullName ( HostPlatform , bp . Branch . BaseEngineProject , CookPlatform ) ) ;
}
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
// If the base cook platform fails, don't bother trying other ones
string BaseCookedPlatform = Platform . Platforms [ HostPlatform ] . GetCookPlatform ( false , false , "" ) ;
if ( InGameProj . GameName = = bp . Branch . BaseEngineProject . GameName & & CookPlatform ! = BaseCookedPlatform & &
bp . HasNode ( CookNode . StaticGetFullName ( HostPlatform , bp . Branch . BaseEngineProject , BaseCookedPlatform ) ) )
{
AddPseudodependency ( CookNode . StaticGetFullName ( HostPlatform , bp . Branch . BaseEngineProject , BaseCookedPlatform ) ) ;
}
2014-10-08 10:49:02 -04:00
}
2014-08-22 13:39:55 -04:00
}
public static string StaticGetFullName ( UnrealTargetPlatform InHostPlatform , BranchInfo . BranchUProject InGameProj , string InCookPlatform )
{
return InGameProj . GameName + "_" + InCookPlatform + "_Cook" + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( HostPlatform , GameProj , CookPlatform ) ;
}
public override string GameNameIfAnyForTempStorage ( )
{
return GameProj . GameName ;
}
public override int CISFrequencyQuantumShift ( GUBP bp )
{
return base . CISFrequencyQuantumShift ( bp ) + 3 + ( bIsMassive ? 1 : 0 ) ;
}
public override float Priority ( )
{
return 10.0f ;
}
public override int AgentMemoryRequirement ( GUBP bp )
{
return bIsMassive ? 32 : 0 ;
}
public override int TimeoutInMinutes ( )
{
return bIsMassive ? 240 : base . TimeoutInMinutes ( ) ;
}
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
public override string RootIfAnyForTempStorage ( )
{
return CombinePaths ( Path . GetDirectoryName ( GameProj . FilePath ) , "Saved" , "Cooked" , CookPlatform ) ;
}
public override void DoBuild ( GUBP bp )
{
if ( HostPlatform = = UnrealTargetPlatform . Mac )
{
// not sure if we need something here or if the cook commandlet will automatically convert the exe name
}
2014-09-25 13:32:08 -04:00
2014-10-08 10:49:02 -04:00
CommandUtils . CookCommandlet ( GameProj . FilePath , "UE4Editor-Cmd.exe" , null , null , null , CookPlatform ) ;
2014-09-25 13:32:08 -04:00
2014-08-22 13:39:55 -04:00
var CookedPath = RootIfAnyForTempStorage ( ) ;
var CookedFiles = CommandUtils . FindFiles ( "*" , true , CookedPath ) ;
if ( CookedFiles . GetLength ( 0 ) < 1 )
{
throw new AutomationException ( "CookedPath {1} did not produce any files." , CookedPath ) ;
}
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
BuildProducts = new List < string > ( ) ;
foreach ( var CookedFile in CookedFiles )
{
AddBuildProduct ( CookedFile ) ;
}
}
}
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
public class DDCNode : HostPlatformNode
{
BranchInfo . BranchUProject GameProj ;
UnrealTargetPlatform TargetPlatform ;
string CookPlatform ;
bool bIsMassive ;
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
public DDCNode ( GUBP bp , UnrealTargetPlatform InHostPlatform , BranchInfo . BranchUProject InGameProj , UnrealTargetPlatform InTargetPlatform , string InCookPlatform )
: base ( InHostPlatform )
{
GameProj = InGameProj ;
TargetPlatform = InTargetPlatform ;
CookPlatform = InCookPlatform ;
bIsMassive = false ;
AddDependency ( RootEditorNode . StaticGetFullName ( HostPlatform ) ) ;
if ( bp . bOrthogonalizeEditorPlatforms )
{
if ( TargetPlatform ! = HostPlatform & & TargetPlatform ! = GUBP . GetAltHostPlatform ( HostPlatform ) )
{
AddDependency ( EditorPlatformNode . StaticGetFullName ( HostPlatform , TargetPlatform ) ) ;
}
}
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
bool bIsShared = false ;
// is this the "base game" or a non code project?
if ( InGameProj . GameName ! = bp . Branch . BaseEngineProject . GameName & & GameProj . Properties . Targets . ContainsKey ( TargetRules . TargetType . Editor ) )
{
var Options = InGameProj . Options ( HostPlatform ) ;
bIsMassive = Options . bIsMassive ;
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
AddDependency ( EditorGameNode . StaticGetFullName ( HostPlatform , GameProj ) ) ;
// add an arc to prevent DDCNode from running until promotable is labeled
if ( Options . bIsPromotable )
{
if ( Options . bSeparateGamePromotion )
{
// AddPseudodependency(GameLabelPromotableNode.StaticGetFullName(GameProj, false));
}
else
{
bIsShared = true ;
}
}
else if ( Options . bTestWithShared )
{
bIsShared = true ;
}
//AddPseudodependency(GamePlatformMonolithicsNode.StaticGetFullName(HostPlatform, GameProj, TargetPlatform));
}
else
{
bIsShared = true ;
//AddPseudodependency(GamePlatformMonolithicsNode.StaticGetFullName(HostPlatform, bp.Branch.BaseEngineProject, TargetPlatform));
}
if ( bIsShared )
{
// add an arc to prevent cooks from running until promotable is labeled
//AddPseudodependency(WaitForTestShared.StaticGetFullName());
//AgentSharingGroup = "SharedCooks" + StaticGetHostPlatformSuffix(HostPlatform);
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
// If the cook fails for the base engine, don't bother trying
if ( InGameProj . GameName ! = bp . Branch . BaseEngineProject . GameName & & bp . HasNode ( DDCNode . StaticGetFullName ( HostPlatform , bp . Branch . BaseEngineProject , CookPlatform ) ) )
{
//AddPseudodependency(DDCNode.StaticGetFullName(HostPlatform, bp.Branch.BaseEngineProject, CookPlatform));
}
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
// If the base cook platform fails, don't bother trying other ones
string BaseCookedPlatform = Platform . Platforms [ HostPlatform ] . GetCookPlatform ( false , false , "" ) ;
if ( InGameProj . GameName = = bp . Branch . BaseEngineProject . GameName & & CookPlatform ! = BaseCookedPlatform & &
bp . HasNode ( DDCNode . StaticGetFullName ( HostPlatform , bp . Branch . BaseEngineProject , BaseCookedPlatform ) ) )
{
//AddPseudodependency(DDCNode.StaticGetFullName(HostPlatform, bp.Branch.BaseEngineProject, BaseCookedPlatform));
}
}
}
public static string StaticGetFullName ( UnrealTargetPlatform InHostPlatform , BranchInfo . BranchUProject InGameProj , string InCookPlatform )
{
return InGameProj . GameName + "_" + InCookPlatform . Replace ( "+" , "_" ) + "_DDC" + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( HostPlatform , GameProj , CookPlatform ) ;
}
public override string GameNameIfAnyForTempStorage ( )
{
return GameProj . GameName ;
}
public override float Priority ( )
{
return base . Priority ( ) + 10.0f ;
}
public override int AgentMemoryRequirement ( GUBP bp )
{
return bIsMassive ? 32 : 0 ;
}
public override int TimeoutInMinutes ( )
{
return bIsMassive ? 240 : base . TimeoutInMinutes ( ) ;
}
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
public override void DoBuild ( GUBP bp )
{
if ( HostPlatform = = UnrealTargetPlatform . Mac )
{
// not sure if we need something here or if the cook commandlet will automatically convert the exe name
}
CommandUtils . DDCCommandlet ( GameProj . FilePath , "UE4Editor-Cmd.exe" , null , CookPlatform , "-fill" ) ;
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
BuildProducts = new List < string > ( ) ;
SaveRecordOfSuccessAndAddToBuildProducts ( ) ;
}
}
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
public class GamePlatformCookedAndCompiledNode : HostPlatformAggregateNode
{
BranchInfo . BranchUProject GameProj ;
UnrealTargetPlatform TargetPlatform ;
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
public GamePlatformCookedAndCompiledNode ( GUBP bp , UnrealTargetPlatform InHostPlatform , BranchInfo . BranchUProject InGameProj , UnrealTargetPlatform InTargetPlatform , bool bCodeProject )
: base ( InHostPlatform )
{
GameProj = InGameProj ;
TargetPlatform = InTargetPlatform ;
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var Kind in BranchInfo . MonolithicKinds )
{
if ( bCodeProject )
{
if ( GameProj . Properties . Targets . ContainsKey ( Kind ) )
{
var Target = GameProj . Properties . Targets [ Kind ] ;
var Platforms = Target . Rules . GUBP_GetPlatforms_MonolithicOnly ( HostPlatform ) ;
if ( Platforms . Contains ( TargetPlatform ) & & Target . Rules . SupportsPlatform ( TargetPlatform ) )
{
//@todo how do we get the client target platform?
string CookedPlatform = Platform . Platforms [ TargetPlatform ] . GetCookPlatform ( Kind = = TargetRules . TargetType . Server , Kind = = TargetRules . TargetType . Client , "" ) ;
2014-10-08 10:49:02 -04:00
if ( Target . Rules . GUBP_AlternateCookPlatform ( HostPlatform , CookedPlatform ) ! = "" )
{
CookedPlatform = Target . Rules . GUBP_AlternateCookPlatform ( HostPlatform , CookedPlatform ) ;
}
2014-08-22 13:39:55 -04:00
AddDependency ( CookNode . StaticGetFullName ( HostPlatform , GameProj , CookedPlatform ) ) ;
AddDependency ( GamePlatformMonolithicsNode . StaticGetFullName ( HostPlatform , GameProj , TargetPlatform ) ) ;
}
}
}
else
{
if ( Kind = = TargetRules . TargetType . Game ) //for now, non-code projects don't do client or server.
{
if ( bp . Branch . BaseEngineProject . Properties . Targets . ContainsKey ( Kind ) )
{
var Target = bp . Branch . BaseEngineProject . Properties . Targets [ Kind ] ;
var Platforms = Target . Rules . GUBP_GetPlatforms_MonolithicOnly ( HostPlatform ) ;
if ( Platforms . Contains ( TargetPlatform ) & & Target . Rules . SupportsPlatform ( TargetPlatform ) )
{
//@todo how do we get the client target platform?
string CookedPlatform = Platform . Platforms [ TargetPlatform ] . GetCookPlatform ( Kind = = TargetRules . TargetType . Server , Kind = = TargetRules . TargetType . Client , "" ) ;
AddDependency ( CookNode . StaticGetFullName ( HostPlatform , GameProj , CookedPlatform ) ) ;
AddDependency ( GamePlatformMonolithicsNode . StaticGetFullName ( HostPlatform , bp . Branch . BaseEngineProject , TargetPlatform ) ) ;
}
}
}
}
}
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
// put these in the right agent group, even though they aren't exposed to EC to sort right.
if ( InGameProj . GameName ! = bp . Branch . BaseEngineProject . GameName & & GameProj . Properties . Targets . ContainsKey ( TargetRules . TargetType . Editor ) )
{
var Options = InGameProj . Options ( HostPlatform ) ;
if ( ( Options . bIsPromotable | | Options . bTestWithShared ) & & ! Options . bSeparateGamePromotion )
{
AgentSharingGroup = "SharedCooks" + StaticGetHostPlatformSuffix ( HostPlatform ) ;
}
}
else
{
AgentSharingGroup = "SharedCooks" + StaticGetHostPlatformSuffix ( HostPlatform ) ;
}
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
}
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
public static string StaticGetFullName ( UnrealTargetPlatform InHostPlatform , BranchInfo . BranchUProject InGameProj , UnrealTargetPlatform InTargetPlatform )
{
return InGameProj . GameName + "_" + InTargetPlatform + "_CookedAndCompiled" + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( HostPlatform , GameProj , TargetPlatform ) ;
}
public override string GameNameIfAnyForTempStorage ( )
{
return GameProj . GameName ;
}
} ;
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
public class FormalBuildNode : HostPlatformNode
{
BranchInfo . BranchUProject GameProj ;
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
//CAUTION, these are lists, but it isn't clear that lists really work on all platforms, so we stick to one node per build
List < UnrealTargetPlatform > ClientTargetPlatforms ;
List < UnrealTargetPlatform > ServerTargetPlatforms ;
List < UnrealTargetConfiguration > ClientConfigs ;
List < UnrealTargetConfiguration > ServerConfigs ;
bool ClientNotGame ;
2014-09-25 20:38:35 -04:00
bool bIsCode ;
2014-09-03 10:12:50 -04:00
UnrealBuildTool . TargetRules . TargetType GameOrClient ;
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
public FormalBuildNode ( GUBP bp ,
BranchInfo . BranchUProject InGameProj ,
UnrealTargetPlatform InHostPlatform ,
List < UnrealTargetPlatform > InClientTargetPlatforms = null ,
List < UnrealTargetConfiguration > InClientConfigs = null ,
List < UnrealTargetPlatform > InServerTargetPlatforms = null ,
List < UnrealTargetConfiguration > InServerConfigs = null ,
2014-09-03 10:12:50 -04:00
bool InClientNotGame = false
2014-08-22 13:39:55 -04:00
)
: base ( InHostPlatform )
{
GameProj = InGameProj ;
ClientTargetPlatforms = InClientTargetPlatforms ;
ServerTargetPlatforms = InServerTargetPlatforms ;
ClientConfigs = InClientConfigs ;
ServerConfigs = InServerConfigs ;
2014-09-03 10:12:50 -04:00
ClientNotGame = InClientNotGame ;
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
GameOrClient = TargetRules . TargetType . Game ;
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
if ( ClientNotGame )
{
GameOrClient = TargetRules . TargetType . Client ;
}
2014-09-25 20:38:35 -04:00
if ( InGameProj . GameName ! = bp . Branch . BaseEngineProject . GameName & & GameProj . Properties . Targets . ContainsKey ( TargetRules . TargetType . Editor ) )
{
bIsCode = true ;
}
else
{
bIsCode = false ;
}
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
// verify we actually built these
var WorkingGameProject = InGameProj ;
if ( ! WorkingGameProject . Properties . Targets . ContainsKey ( TargetRules . TargetType . Editor ) )
{
// this is a codeless project, use the base project
WorkingGameProject = bp . Branch . BaseEngineProject ;
}
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
var AllTargetPlatforms = new List < UnrealTargetPlatform > ( ) ;
2014-08-18 13:29:39 -04:00
var Options = InGameProj . Options ( HostPlatform ) ;
2014-08-22 13:39:55 -04:00
if ( ! Options . bSeparateGamePromotion )
2014-08-18 13:29:39 -04:00
{
2014-08-22 13:39:55 -04:00
AddPseudodependency ( SharedLabelPromotableNode . StaticGetFullName ( false ) ) ;
2014-08-18 13:29:39 -04:00
}
2014-08-22 13:39:55 -04:00
if ( ClientTargetPlatforms ! = null )
{
if ( ! WorkingGameProject . Properties . Targets . ContainsKey ( GameOrClient ) )
{
throw new AutomationException ( "Can't make a game build for {0} because it doesn't have a {1} target." , WorkingGameProject . GameName , GameOrClient . ToString ( ) ) ;
}
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var Plat in ClientTargetPlatforms )
{
if ( ! AllTargetPlatforms . Contains ( Plat ) )
{
AllTargetPlatforms . Add ( Plat ) ;
}
}
if ( ClientConfigs = = null )
{
ClientConfigs = new List < UnrealTargetConfiguration > ( ) { UnrealTargetConfiguration . Development } ;
}
foreach ( var Plat in ClientTargetPlatforms )
{
if ( ! WorkingGameProject . Properties . Targets [ GameOrClient ] . Rules . GUBP_GetPlatforms_MonolithicOnly ( HostPlatform ) . Contains ( Plat ) )
{
throw new AutomationException ( "Can't make a game/client build for {0} because we didn't build platform {1}." , WorkingGameProject . GameName , Plat . ToString ( ) ) ;
}
foreach ( var Config in ClientConfigs )
{
if ( ! WorkingGameProject . Properties . Targets [ GameOrClient ] . Rules . GUBP_GetConfigs_MonolithicOnly ( HostPlatform , Plat ) . Contains ( Config ) )
{
throw new AutomationException ( "Can't make a game/client build for {0} because we didn't build platform {1} config {2}." , WorkingGameProject . GameName , Plat . ToString ( ) , Config . ToString ( ) ) ;
}
}
}
}
if ( ServerTargetPlatforms ! = null )
{
if ( ! WorkingGameProject . Properties . Targets . ContainsKey ( TargetRules . TargetType . Server ) & & ServerTargetPlatforms ! = null )
{
throw new AutomationException ( "Can't make a server build for {0} because it doesn't have a server target." , WorkingGameProject . GameName ) ;
}
foreach ( var Plat in ServerTargetPlatforms )
{
if ( ! AllTargetPlatforms . Contains ( Plat ) )
{
AllTargetPlatforms . Add ( Plat ) ;
}
}
if ( ServerConfigs = = null )
{
ServerConfigs = new List < UnrealTargetConfiguration > ( ) { UnrealTargetConfiguration . Development } ;
}
foreach ( var Plat in ServerTargetPlatforms )
{
if ( ! WorkingGameProject . Properties . Targets [ TargetRules . TargetType . Server ] . Rules . GUBP_GetPlatforms_MonolithicOnly ( HostPlatform ) . Contains ( Plat ) )
{
throw new AutomationException ( "Can't make a server build for {0} because we didn't build platform {1}." , WorkingGameProject . GameName , Plat . ToString ( ) ) ;
}
foreach ( var Config in ServerConfigs )
{
if ( ! WorkingGameProject . Properties . Targets [ TargetRules . TargetType . Server ] . Rules . GUBP_GetConfigs_MonolithicOnly ( HostPlatform , Plat ) . Contains ( Config ) )
{
throw new AutomationException ( "Can't make a server build for {0} because we didn't build platform {1} config {2}." , WorkingGameProject . GameName , Plat . ToString ( ) , Config . ToString ( ) ) ;
}
}
}
}
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
// add dependencies for cooked and compiled
foreach ( var Plat in AllTargetPlatforms )
{
2014-09-03 10:12:50 -04:00
AddDependency ( GamePlatformCookedAndCompiledNode . StaticGetFullName ( HostPlatform , GameProj , Plat ) ) ;
}
2014-08-22 13:39:55 -04:00
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public static string StaticGetFullName ( BranchInfo . BranchUProject InGameProj , UnrealTargetPlatform InHostPlatform , List < UnrealTargetPlatform > InClientTargetPlatforms = null , List < UnrealTargetConfiguration > InClientConfigs = null , List < UnrealTargetPlatform > InServerTargetPlatforms = null , List < UnrealTargetConfiguration > InServerConfigs = null , bool InClientNotGame = false )
{
string Infix = "" ;
if ( InClientNotGame )
{
if ( InClientTargetPlatforms ! = null & & InClientTargetPlatforms . Count = = 1 )
{
Infix = "_Client_" + InClientTargetPlatforms [ 0 ] . ToString ( ) ;
}
if ( InClientConfigs ! = null & & InClientConfigs . Count = = 1 )
{
Infix + = "_Client_" + InClientConfigs [ 0 ] . ToString ( ) ;
}
}
else
{
if ( InClientTargetPlatforms ! = null & & InClientTargetPlatforms . Count = = 1 )
{
Infix = "_" + InClientTargetPlatforms [ 0 ] . ToString ( ) ;
}
if ( InClientConfigs ! = null & & InClientConfigs . Count = = 1 )
{
Infix + = "_" + InClientConfigs [ 0 ] . ToString ( ) ;
}
}
if ( InServerTargetPlatforms ! = null & & InServerTargetPlatforms . Count = = 1 )
{
Infix = "_Serv_" + InServerTargetPlatforms [ 0 ] . ToString ( ) ;
}
if ( InServerConfigs ! = null & & InServerConfigs . Count = = 1 )
{
Infix + = "_Serv_" + InServerConfigs [ 0 ] . ToString ( ) ;
}
return InGameProj . GameName + Infix + "_MakeBuild" + HostPlatformNode . StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( GameProj , HostPlatform , ClientTargetPlatforms , ClientConfigs , ServerTargetPlatforms , ServerConfigs , ClientNotGame ) ;
}
public override string GameNameIfAnyForTempStorage ( )
{
return GameProj . GameName ;
}
public override bool SendSuccessEmail ( )
{
return true ;
}
public override string ECAgentString ( )
{
string Result = base . ECAgentString ( ) ;
foreach ( UnrealTargetPlatform Plat in ClientTargetPlatforms )
{
if ( Plat = = UnrealTargetPlatform . XboxOne )
{
Result = MergeSpaceStrings ( Result , Plat . ToString ( ) ) ;
}
}
return Result ;
}
public override float Priority ( )
{
2014-09-03 10:12:50 -04:00
return base . Priority ( ) + 20.0f ;
2014-08-22 13:39:55 -04:00
}
2014-09-09 13:57:48 -04:00
public override int CISFrequencyQuantumShift ( GUBP bp )
{
return base . CISFrequencyQuantumShift ( bp ) + 3 ;
}
2014-08-22 13:39:55 -04:00
public static string GetArchiveDirectory ( BranchInfo . BranchUProject InGameProj , UnrealTargetPlatform InHostPlatform , List < UnrealTargetPlatform > InClientTargetPlatforms = null , List < UnrealTargetConfiguration > InClientConfigs = null , List < UnrealTargetPlatform > InServerTargetPlatforms = null , List < UnrealTargetConfiguration > InServerConfigs = null , bool InClientNotGame = false )
{
string BaseDir = ResolveSharedBuildDirectory ( InGameProj . GameName ) ;
string NodeName = StaticGetFullName ( InGameProj , InHostPlatform , InClientTargetPlatforms , InClientConfigs , InServerTargetPlatforms , InServerConfigs , InClientNotGame ) ;
string Inner = P4Env . BuildRootEscaped + "-CL-" + P4Env . ChangelistString ;
if ( GUBP . bPreflightBuild )
{
Inner = Inner + PreflightMangleSuffix ;
}
string ArchiveDirectory = CombinePaths ( BaseDir , NodeName , Inner ) ;
return ArchiveDirectory ;
}
public override void DoBuild ( GUBP bp )
{
BuildProducts = new List < string > ( ) ;
string ProjectArg = "" ;
if ( ! String . IsNullOrEmpty ( GameProj . FilePath ) )
{
ProjectArg = " -project=\"" + GameProj . FilePath + "\"" ;
}
string Args = String . Format ( "BuildCookRun{0} -SkipBuild -SkipCook -Stage -Pak -Package -NoSubmit" , ProjectArg ) ;
2014-03-14 14:13:41 -04:00
2014-08-08 11:08:16 -04:00
bool bXboxOneTarget = false ;
2014-08-22 13:39:55 -04:00
if ( ClientTargetPlatforms ! = null )
{
bool bFirstClient = true ;
foreach ( var Plat in ClientTargetPlatforms )
{
2014-08-08 11:08:16 -04:00
if ( Plat = = UnrealTargetPlatform . XboxOne )
{
bXboxOneTarget = true ;
}
2014-08-22 13:39:55 -04:00
if ( bFirstClient )
{
bFirstClient = false ;
Args + = String . Format ( " -platform={0}" , Plat . ToString ( ) ) ;
}
else
{
Args + = String . Format ( "+{0}" , Plat . ToString ( ) ) ;
}
2014-09-25 20:38:35 -04:00
if ( bIsCode )
2014-09-25 10:11:15 -04:00
{
2014-09-25 13:32:08 -04:00
var Target = GameProj . Properties . Targets [ TargetRules . TargetType . Game ] ;
if ( ClientNotGame )
{
Target = GameProj . Properties . Targets [ TargetRules . TargetType . Client ] ;
}
if ( Target . Rules . GUBP_AdditionalPackageParameters ( HostPlatform , Plat ) ! = "" )
{
Args + = " " + Target . Rules . GUBP_AdditionalPackageParameters ( HostPlatform , Plat ) ;
}
2014-09-25 10:11:15 -04:00
}
2014-08-22 13:39:55 -04:00
}
bool bFirstClientConfig = true ;
foreach ( var Config in ClientConfigs )
{
if ( bFirstClientConfig )
{
bFirstClientConfig = false ;
Args + = String . Format ( " -clientconfig={0}" , Config . ToString ( ) ) ;
}
else
{
Args + = String . Format ( "+{0}" , Config . ToString ( ) ) ;
}
}
if ( ClientNotGame )
{
2014-09-25 10:11:15 -04:00
Args + = " -client" ;
2014-08-22 13:39:55 -04:00
}
}
else
{
Args + = " -noclient" ;
}
if ( ServerTargetPlatforms ! = null )
{
Args + = " -server" ;
bool bFirstServer = true ;
foreach ( var Plat in ServerTargetPlatforms )
{
2014-08-08 11:08:16 -04:00
if ( Plat = = UnrealTargetPlatform . XboxOne )
{
bXboxOneTarget = true ;
}
if ( bFirstServer )
2014-08-22 13:39:55 -04:00
{
bFirstServer = false ;
Args + = String . Format ( " -serverplatform={0}" , Plat . ToString ( ) ) ;
}
else
{
Args + = String . Format ( "+{0}" , Plat . ToString ( ) ) ;
}
2014-09-25 20:38:35 -04:00
if ( bIsCode )
2014-09-25 10:11:15 -04:00
{
2014-09-25 13:32:08 -04:00
var Target = GameProj . Properties . Targets [ TargetRules . TargetType . Server ] ;
if ( Target . Rules . GUBP_AdditionalPackageParameters ( HostPlatform , Plat ) ! = "" )
{
Args + = " " + Target . Rules . GUBP_AdditionalPackageParameters ( HostPlatform , Plat ) ;
}
2014-09-25 10:11:15 -04:00
}
2014-08-22 13:39:55 -04:00
}
bool bFirstServerConfig = true ;
foreach ( var Config in ServerConfigs )
{
if ( bFirstServerConfig )
{
bFirstServerConfig = false ;
Args + = String . Format ( " -serverconfig={0}" , Config . ToString ( ) ) ;
}
else
{
Args + = String . Format ( "+{0}" , Config . ToString ( ) ) ;
}
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
string FinalArchiveDirectory = "" ;
2014-08-08 11:08:16 -04:00
string IntermediateArchiveDirectory = FinalArchiveDirectory ;
2014-08-22 13:39:55 -04:00
if ( P4Enabled )
{
FinalArchiveDirectory = GetArchiveDirectory ( GameProj , HostPlatform , ClientTargetPlatforms , ClientConfigs , ServerTargetPlatforms , ServerConfigs , ClientNotGame ) ;
2014-08-08 11:08:16 -04:00
IntermediateArchiveDirectory = FinalArchiveDirectory ;
// Xbox One packaging does not function with remote file systems. Use a temp local directory to package and then move files into final location.
if ( bXboxOneTarget )
{
IntermediateArchiveDirectory = Path . Combine ( Path . GetTempPath ( ) , "GUBP.XboxOne" ) ;
if ( DirectoryExists_NoExceptions ( IntermediateArchiveDirectory ) )
{
DeleteDirectory_NoExceptions ( IntermediateArchiveDirectory ) ;
}
CreateDirectory_NoExceptions ( IntermediateArchiveDirectory ) ;
}
CleanFormalBuilds ( FinalArchiveDirectory ) ;
if ( DirectoryExists_NoExceptions ( FinalArchiveDirectory ) )
2014-08-22 13:39:55 -04:00
{
if ( IsBuildMachine )
{
2014-08-08 11:08:16 -04:00
throw new AutomationException ( "Archive directory already exists {0}" , FinalArchiveDirectory ) ;
2014-08-22 13:39:55 -04:00
}
2014-08-08 11:08:16 -04:00
DeleteDirectory_NoExceptions ( FinalArchiveDirectory ) ;
2014-08-22 13:39:55 -04:00
}
2014-08-08 11:08:16 -04:00
Args + = String . Format ( " -Archive -archivedirectory={0}" , CommandUtils . MakePathSafeToUseWithCommandLine ( IntermediateArchiveDirectory ) ) ;
2014-08-22 13:39:55 -04:00
}
2014-09-25 10:11:15 -04:00
2014-08-22 13:39:55 -04:00
string LogFile = CommandUtils . RunUAT ( CommandUtils . CmdEnv , Args ) ;
2014-08-08 11:08:16 -04:00
2014-08-22 13:39:55 -04:00
if ( P4Enabled )
{
2014-08-08 11:08:16 -04:00
if ( ! FinalArchiveDirectory . Equals ( IntermediateArchiveDirectory , StringComparison . InvariantCultureIgnoreCase ) )
{
CopyDirectory_NoExceptions ( IntermediateArchiveDirectory , FinalArchiveDirectory ) ;
DeleteDirectory_NoExceptions ( IntermediateArchiveDirectory ) ;
}
}
2014-08-22 13:39:55 -04:00
SaveRecordOfSuccessAndAddToBuildProducts ( CommandUtils . ReadAllText ( LogFile ) ) ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public class TestNode : HostPlatformNode
{
public TestNode ( UnrealTargetPlatform InHostPlatform )
: base ( InHostPlatform )
{
}
public override float Priority ( )
{
return 0.0f ;
}
public virtual void DoTest ( GUBP bp )
{
}
public override void DoBuild ( GUBP bp )
{
BuildProducts = new List < string > ( ) ;
DoTest ( bp ) ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public class FormalBuildTestNode : TestNode
{
BranchInfo . BranchUProject GameProj ;
UnrealTargetPlatform ClientTargetPlatform ;
UnrealTargetConfiguration ClientConfig ;
UnrealBuildTool . TargetRules . TargetType GameOrClient ;
2014-06-03 10:37:01 -04:00
2014-08-22 13:39:55 -04:00
public FormalBuildTestNode ( GUBP bp ,
BranchInfo . BranchUProject InGameProj ,
UnrealTargetPlatform InHostPlatform ,
UnrealTargetPlatform InClientTargetPlatform ,
UnrealTargetConfiguration InClientConfig
)
: base ( InHostPlatform )
{
GameProj = InGameProj ;
ClientTargetPlatform = InClientTargetPlatform ;
ClientConfig = InClientConfig ;
GameOrClient = TargetRules . TargetType . Game ;
2014-06-03 10:37:01 -04:00
2014-08-22 13:39:55 -04:00
// verify we actually built these
var WorkingGameProject = InGameProj ;
2014-08-18 12:09:20 -04:00
var Options = InGameProj . Options ( HostPlatform ) ;
2014-08-22 13:39:55 -04:00
if ( ! Options . bSeparateGamePromotion )
2014-08-18 12:09:20 -04:00
{
AddPseudodependency ( SharedLabelPromotableNode . StaticGetFullName ( false ) ) ;
}
2014-08-22 13:39:55 -04:00
if ( ! WorkingGameProject . Properties . Targets . ContainsKey ( TargetRules . TargetType . Editor ) )
{
// this is a codeless project, use the base project
WorkingGameProject = bp . Branch . BaseEngineProject ;
}
if ( ! WorkingGameProject . Properties . Targets . ContainsKey ( GameOrClient ) )
{
throw new AutomationException ( "Can't make a game build for {0} because it doesn't have a {1} target." , WorkingGameProject . GameName , GameOrClient . ToString ( ) ) ;
}
2014-06-03 10:37:01 -04:00
2014-08-22 13:39:55 -04:00
if ( ! WorkingGameProject . Properties . Targets [ GameOrClient ] . Rules . GUBP_GetPlatforms_MonolithicOnly ( HostPlatform ) . Contains ( ClientTargetPlatform ) )
{
throw new AutomationException ( "Can't make a game/client build for {0} because we didn't build platform {1}." , WorkingGameProject . GameName , ClientTargetPlatform . ToString ( ) ) ;
}
if ( ! WorkingGameProject . Properties . Targets [ GameOrClient ] . Rules . GUBP_GetConfigs_MonolithicOnly ( HostPlatform , ClientTargetPlatform ) . Contains ( ClientConfig ) )
{
throw new AutomationException ( "Can't make a game/client build for {0} because we didn't build platform {1} config {2}." , WorkingGameProject . GameName , ClientTargetPlatform . ToString ( ) , ClientConfig . ToString ( ) ) ;
}
AddDependency ( FormalBuildNode . StaticGetFullName ( GameProj , HostPlatform , new List < UnrealTargetPlatform > ( ) { ClientTargetPlatform } , InClientConfigs : new List < UnrealTargetConfiguration > ( ) { ClientConfig } , InClientNotGame : GameOrClient = = TargetRules . TargetType . Client ) ) ;
}
2014-06-03 10:37:01 -04:00
2014-08-22 13:39:55 -04:00
public static string StaticGetFullName ( BranchInfo . BranchUProject InGameProj , UnrealTargetPlatform InHostPlatform , UnrealTargetPlatform InClientTargetPlatform , UnrealTargetConfiguration InClientConfig )
{
string Infix = "_" + InClientTargetPlatform . ToString ( ) ;
Infix + = "_" + InClientConfig . ToString ( ) ;
return InGameProj . GameName + Infix + "_TestBuild" + HostPlatformNode . StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( GameProj , HostPlatform , ClientTargetPlatform , ClientConfig ) ;
}
public override string GameNameIfAnyForTempStorage ( )
{
return GameProj . GameName ;
}
public override float Priority ( )
{
return base . Priority ( ) - 20.0f ;
}
public override int CISFrequencyQuantumShift ( GUBP bp )
{
return base . CISFrequencyQuantumShift ( bp ) + 3 ;
}
public override void DoTest ( GUBP bp )
{
string ProjectArg = "" ;
if ( ! String . IsNullOrEmpty ( GameProj . FilePath ) )
{
ProjectArg = " -project=\"" + GameProj . FilePath + "\"" ;
}
2014-06-03 10:37:01 -04:00
2014-08-22 13:39:55 -04:00
string ArchiveDirectory = FormalBuildNode . GetArchiveDirectory ( GameProj , HostPlatform , new List < UnrealTargetPlatform > ( ) { ClientTargetPlatform } , InClientConfigs : new List < UnrealTargetConfiguration > ( ) { ClientConfig } , InClientNotGame : GameOrClient = = TargetRules . TargetType . Client ) ;
if ( ! DirectoryExists_NoExceptions ( ArchiveDirectory ) )
{
throw new AutomationException ( "Archive directory does not exist {0}, so we can't test the build." , ArchiveDirectory ) ;
}
2014-06-03 10:37:01 -04:00
2014-08-22 13:39:55 -04:00
string WorkingCommandline = String . Format ( "TestFormalBuild {0} -Archive -alldevices -archivedirectory={1} -platform={2} -clientconfig={3} -runtimeoutseconds=300" ,
ProjectArg , CommandUtils . MakePathSafeToUseWithCommandLine ( ArchiveDirectory ) , ClientTargetPlatform . ToString ( ) , ClientConfig . ToString ( ) ) ;
2014-06-03 10:37:01 -04:00
2014-08-22 13:39:55 -04:00
if ( WorkingCommandline . Contains ( "-project=\"\"" ) )
{
throw new AutomationException ( "Command line {0} contains -project=\"\" which is doomed to fail" , WorkingCommandline ) ;
}
string LogFile = RunUAT ( CommandUtils . CmdEnv , WorkingCommandline ) ;
SaveRecordOfSuccessAndAddToBuildProducts ( CommandUtils . ReadAllText ( LogFile ) ) ;
}
public override string ECAgentString ( )
{
string Result = base . ECAgentString ( ) ;
if ( ClientTargetPlatform ! = HostPlatform )
{
Result = MergeSpaceStrings ( Result , ClientTargetPlatform . ToString ( ) ) ;
}
return Result ;
}
}
2014-06-03 10:37:01 -04:00
2014-09-22 12:13:56 -04:00
public class NonUnityToolNode : TestNode
{
SingleTargetProperties ProgramTarget ;
public NonUnityToolNode ( UnrealTargetPlatform InHostPlatform , SingleTargetProperties InProgramTarget )
: base ( InHostPlatform )
{
ProgramTarget = InProgramTarget ;
AddPseudodependency ( SingleInternalToolsNode . StaticGetFullName ( HostPlatform , ProgramTarget ) ) ;
AddPseudodependency ( RootEditorNode . StaticGetFullName ( HostPlatform ) ) ;
}
public static string StaticGetFullName ( UnrealTargetPlatform InHostPlatform , SingleTargetProperties InGameProj )
{
return InGameProj . TargetName + "_NonUnityTestCompile" + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( HostPlatform , ProgramTarget ) ;
}
public override int CISFrequencyQuantumShift ( GUBP bp )
{
int Result = base . CISFrequencyQuantumShift ( bp ) + 2 ;
if ( HostPlatform = = UnrealTargetPlatform . Mac )
{
Result + = 1 ;
}
return Result ;
}
public override int AgentMemoryRequirement ( GUBP bp )
{
int Result = base . AgentMemoryRequirement ( bp ) ;
if ( HostPlatform = = UnrealTargetPlatform . Mac )
{
Result = 32 ;
}
return Result ;
}
public override void DoTest ( GUBP bp )
{
var Build = new UE4Build ( bp ) ;
var Agenda = new UE4Build . BuildAgenda ( ) ;
Agenda . AddTargets ( new string [ ] { "UnrealHeaderTool" } , HostPlatform , UnrealTargetConfiguration . Development ) ;
Agenda . AddTargets ( new string [ ] { ProgramTarget . TargetName } , HostPlatform , UnrealTargetConfiguration . Development , InAddArgs : "-skipnonhostplatforms" ) ;
Build . Build ( Agenda , InDeleteBuildProducts : true , InUpdateVersionFiles : false , InForceNonUnity : true ) ;
UE4Build . CheckBuildProducts ( Build . BuildProductFiles ) ;
SaveRecordOfSuccessAndAddToBuildProducts ( ) ;
}
}
2014-08-22 13:39:55 -04:00
public class NonUnityTestNode : TestNode
{
public NonUnityTestNode ( UnrealTargetPlatform InHostPlatform )
: base ( InHostPlatform )
{
AddPseudodependency ( RootEditorNode . StaticGetFullName ( HostPlatform ) ) ;
}
public static string StaticGetFullName ( UnrealTargetPlatform InHostPlatform )
{
return "NonUnityTestCompile" + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( HostPlatform ) ;
}
public override int CISFrequencyQuantumShift ( GUBP bp )
{
int Result = base . CISFrequencyQuantumShift ( bp ) + 2 ;
if ( HostPlatform = = UnrealTargetPlatform . Mac )
{
Result + = 1 ;
}
return Result ;
}
public override int AgentMemoryRequirement ( GUBP bp )
{
int Result = base . AgentMemoryRequirement ( bp ) ;
if ( HostPlatform = = UnrealTargetPlatform . Mac )
{
Result = 32 ;
}
return Result ;
}
public override void DoTest ( GUBP bp )
{
var Build = new UE4Build ( bp ) ;
var Agenda = new UE4Build . BuildAgenda ( ) ;
Agenda . AddTargets ( new string [ ] { "UnrealHeaderTool" } , HostPlatform , UnrealTargetConfiguration . Development ) ;
Agenda . AddTargets (
new string [ ] { bp . Branch . BaseEngineProject . Properties . Targets [ TargetRules . TargetType . Editor ] . TargetName } ,
HostPlatform , UnrealTargetConfiguration . Development , InAddArgs : "-skipnonhostplatforms" ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var Kind in BranchInfo . MonolithicKinds )
{
if ( bp . Branch . BaseEngineProject . Properties . Targets . ContainsKey ( Kind ) )
{
var Target = bp . Branch . BaseEngineProject . Properties . Targets [ Kind ] ;
Agenda . AddTargets ( new string [ ] { Target . TargetName } , HostPlatform , UnrealTargetConfiguration . Development ) ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
Build . Build ( Agenda , InDeleteBuildProducts : true , InUpdateVersionFiles : false , InForceNonUnity : true ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
UE4Build . CheckBuildProducts ( Build . BuildProductFiles ) ;
SaveRecordOfSuccessAndAddToBuildProducts ( ) ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public class IOSOnPCTestNode : TestNode
{
public IOSOnPCTestNode ( GUBP bp )
: base ( UnrealTargetPlatform . Win64 )
{
AddDependency ( ToolsForCompileNode . StaticGetFullName ( UnrealTargetPlatform . Win64 ) ) ;
AddDependency ( ToolsNode . StaticGetFullName ( UnrealTargetPlatform . Win64 ) ) ;
AddPseudodependency ( GamePlatformMonolithicsNode . StaticGetFullName ( UnrealTargetPlatform . Mac , bp . Branch . BaseEngineProject , UnrealTargetPlatform . IOS ) ) ;
}
public static string StaticGetFullName ( )
{
return "IOSOnPCTestCompile" ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( ) ;
}
public override int CISFrequencyQuantumShift ( GUBP bp )
{
return base . CISFrequencyQuantumShift ( bp ) + 3 ;
}
public override void DoTest ( GUBP bp )
{
var Build = new UE4Build ( bp ) ;
var Agenda = new UE4Build . BuildAgenda ( ) ;
2014-05-05 16:21:56 -04:00
2014-08-22 13:39:55 -04:00
Agenda . AddTargets ( new string [ ] { bp . Branch . BaseEngineProject . Properties . Targets [ TargetRules . TargetType . Game ] . TargetName } , UnrealTargetPlatform . IOS , UnrealTargetConfiguration . Development ) ;
2014-05-05 16:21:56 -04:00
2014-08-22 13:39:55 -04:00
Build . Build ( Agenda , InDeleteBuildProducts : true , InUpdateVersionFiles : false ) ;
2014-05-05 16:21:56 -04:00
2014-08-22 13:39:55 -04:00
UE4Build . CheckBuildProducts ( Build . BuildProductFiles ) ;
SaveRecordOfSuccessAndAddToBuildProducts ( ) ;
}
}
2014-05-05 16:21:56 -04:00
2014-08-22 13:39:55 -04:00
public class UATTestNode : TestNode
{
string TestName ;
BranchInfo . BranchUProject GameProj ;
string UATCommandLine ;
bool DependsOnEditor ;
List < UnrealTargetPlatform > DependsOnCooked ;
float ECPriority ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public UATTestNode ( GUBP bp , UnrealTargetPlatform InHostPlatform , BranchInfo . BranchUProject InGameProj , string InTestName , string InUATCommandLine , string InAgentSharingGroup , bool InDependsOnEditor = true , List < UnrealTargetPlatform > InDependsOnCooked = null , float InECPriority = 0.0f )
: base ( InHostPlatform )
{
AgentSharingGroup = InAgentSharingGroup ;
ECPriority = InECPriority ;
GameProj = InGameProj ;
TestName = InTestName ;
UATCommandLine = InUATCommandLine ;
bool bWillCook = InUATCommandLine . IndexOf ( "-cook" ) > = 0 ;
DependsOnEditor = InDependsOnEditor | | bWillCook ;
if ( InDependsOnCooked ! = null )
{
DependsOnCooked = InDependsOnCooked ;
}
else
{
DependsOnCooked = new List < UnrealTargetPlatform > ( ) ;
}
if ( DependsOnEditor )
{
AddDependency ( EditorAndToolsNode . StaticGetFullName ( HostPlatform ) ) ;
if ( GameProj . GameName ! = bp . Branch . BaseEngineProject . GameName )
{
if ( GameProj . Properties . Targets . ContainsKey ( TargetRules . TargetType . Editor ) )
{
AddDependency ( EditorGameNode . StaticGetFullName ( HostPlatform , GameProj ) ) ;
}
}
}
foreach ( var Plat in DependsOnCooked )
{
AddDependency ( GamePlatformCookedAndCompiledNode . StaticGetFullName ( HostPlatform , GameProj , Plat ) ) ;
}
AddPseudodependency ( WaitForTestShared . StaticGetFullName ( ) ) ;
// If the same test fails for the base engine, don't bother trying
if ( InGameProj . GameName ! = bp . Branch . BaseEngineProject . GameName )
{
if ( bp . HasNode ( UATTestNode . StaticGetFullName ( HostPlatform , bp . Branch . BaseEngineProject , TestName ) ) )
{
AddPseudodependency ( UATTestNode . StaticGetFullName ( HostPlatform , bp . Branch . BaseEngineProject , InTestName ) ) ;
}
else
{
bool bFoundACook = false ;
foreach ( var Plat in DependsOnCooked )
{
var PlatTestName = "CookedGameTest_" + Plat . ToString ( ) ;
if ( bp . HasNode ( UATTestNode . StaticGetFullName ( HostPlatform , bp . Branch . BaseEngineProject , PlatTestName ) ) )
{
AddPseudodependency ( UATTestNode . StaticGetFullName ( HostPlatform , bp . Branch . BaseEngineProject , PlatTestName ) ) ;
bFoundACook = true ;
}
}
2014-07-22 11:45:18 -04:00
2014-08-22 13:39:55 -04:00
if ( ! bFoundACook & & bp . HasNode ( UATTestNode . StaticGetFullName ( HostPlatform , bp . Branch . BaseEngineProject , "EditorTest" ) ) )
{
AddPseudodependency ( UATTestNode . StaticGetFullName ( HostPlatform , bp . Branch . BaseEngineProject , "EditorTest" ) ) ;
}
2014-07-22 11:45:18 -04:00
2014-08-22 13:39:55 -04:00
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
if ( InGameProj . GameName = = bp . Branch . BaseEngineProject . GameName )
{
ECPriority = ECPriority + 1.0f ;
}
if ( UATCommandLine . IndexOf ( "-RunAutomationTests" , StringComparison . InvariantCultureIgnoreCase ) > = 0 )
{
ECPriority = ECPriority - 4.0f ;
if ( UATCommandLine . IndexOf ( "-EditorTest" , StringComparison . InvariantCultureIgnoreCase ) > = 0 )
{
ECPriority = ECPriority - 4.0f ;
}
}
else if ( UATCommandLine . IndexOf ( "-EditorTest" , StringComparison . InvariantCultureIgnoreCase ) > = 0 )
{
ECPriority = ECPriority + 2.0f ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
}
public override float Priority ( )
{
return ECPriority ;
}
public override int CISFrequencyQuantumShift ( GUBP bp )
{
return base . CISFrequencyQuantumShift ( bp ) + 5 ;
}
public override string ECAgentString ( )
{
string Result = base . ECAgentString ( ) ;
foreach ( UnrealTargetPlatform platform in Enum . GetValues ( typeof ( UnrealTargetPlatform ) ) )
{
if ( platform ! = HostPlatform & & platform ! = GetAltHostPlatform ( ) )
{
if ( UATCommandLine . IndexOf ( "-platform=" + platform . ToString ( ) , StringComparison . InvariantCultureIgnoreCase ) > = 0 )
{
Result = MergeSpaceStrings ( Result , platform . ToString ( ) ) ;
}
}
}
return Result ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public static string StaticGetFullName ( UnrealTargetPlatform InHostPlatform , BranchInfo . BranchUProject InGameProj , string InTestName )
{
return InGameProj . GameName + "_" + InTestName + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( HostPlatform , GameProj , TestName ) ;
}
public override string GameNameIfAnyForTempStorage ( )
{
return GameProj . GameName ;
}
public override void DoTest ( GUBP bp )
{
string ProjectArg = "" ;
if ( ! String . IsNullOrEmpty ( GameProj . FilePath ) & & UATCommandLine . IndexOf ( "-project=" , StringComparison . InvariantCultureIgnoreCase ) < 0 )
{
ProjectArg = " -project=\"" + GameProj . FilePath + "\"" ;
}
string WorkingCommandline = UATCommandLine + ProjectArg + " -NoSubmit -addcmdline=\"-DisablePS4TMAPI\"" ;
if ( WorkingCommandline . Contains ( "-project=\"\"" ) )
{
throw new AutomationException ( "Command line {0} contains -project=\"\" which is doomed to fail" , WorkingCommandline ) ;
}
string LogFile = RunUAT ( CommandUtils . CmdEnv , WorkingCommandline ) ;
SaveRecordOfSuccessAndAddToBuildProducts ( CommandUtils . ReadAllText ( LogFile ) ) ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public class GameAggregateNode : HostPlatformAggregateNode
{
BranchInfo . BranchUProject GameProj ;
string AggregateName ;
float ECPriority ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public GameAggregateNode ( GUBP bp , UnrealTargetPlatform InHostPlatform , BranchInfo . BranchUProject InGameProj , string InAggregateName , List < string > Dependencies , float InECPriority = 100.0f )
: base ( InHostPlatform )
{
GameProj = InGameProj ;
AggregateName = InAggregateName ;
ECPriority = InECPriority ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var Dep in Dependencies )
{
AddDependency ( Dep ) ;
}
}
public override float Priority ( )
{
return ECPriority ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public static string StaticGetFullName ( UnrealTargetPlatform InHostPlatform , BranchInfo . BranchUProject InGameProj , string InAggregateName )
{
return InGameProj . GameName + "_" + InAggregateName + StaticGetHostPlatformSuffix ( InHostPlatform ) ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( HostPlatform , GameProj , AggregateName ) ;
}
public override string GameNameIfAnyForTempStorage ( )
{
return GameProj . GameName ;
}
} ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public class CleanSharedTempStorageNode : GUBPNode
{
public CleanSharedTempStorageNode ( GUBP bp )
{
var ToolsNode = bp . FindNode ( ToolsForCompileNode . StaticGetFullName ( UnrealTargetPlatform . Win64 ) ) ;
AgentSharingGroup = ToolsNode . AgentSharingGroup ;
}
public override float Priority ( )
{
return - 1E15f ;
}
2014-04-29 21:53:42 -04:00
2014-08-22 13:39:55 -04:00
public static string StaticGetFullName ( )
{
return "CleanSharedTempStorage" ;
}
public override string GetFullName ( )
{
return StaticGetFullName ( ) ;
}
public override void DoBuild ( GUBP bp )
{
{
var StartTime = DateTime . UtcNow ;
foreach ( var NodeToDo in bp . GUBPNodes )
{
CleanSharedTempStorageDirectory ( NodeToDo . Value . GameNameIfAnyForTempStorage ( ) ) ;
}
var BuildDuration = ( DateTime . UtcNow - StartTime ) . TotalMilliseconds ;
Log ( "Took {0}s to clear temp storage of old files." , BuildDuration / 1000 ) ;
}
2014-04-29 21:53:42 -04:00
2014-08-22 13:39:55 -04:00
BuildProducts = new List < string > ( ) ;
SaveRecordOfSuccessAndAddToBuildProducts ( ) ;
}
public override int CISFrequencyQuantumShift ( GUBP bp )
{
return base . CISFrequencyQuantumShift ( bp ) + 3 ;
}
} ;
2014-04-29 21:53:42 -04:00
2014-08-22 13:39:55 -04:00
public string AddNode ( GUBPNode Node )
{
string Name = Node . GetFullName ( ) ;
if ( GUBPNodes . ContainsKey ( Name ) )
{
throw new AutomationException ( "Attempt to add a duplicate node {0}" , Node . GetFullName ( ) ) ;
}
GUBPNodes . Add ( Name , Node ) ;
return Name ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public bool HasNode ( string Node )
{
return GUBPNodes . ContainsKey ( Node ) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public GUBPNode FindNode ( string Node )
{
return GUBPNodes [ Node ] ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public void RemovePseudodependencyFromNode ( string Node , string Dep )
{
if ( ! GUBPNodes . ContainsKey ( Node ) )
{
throw new AutomationException ( "Node {0} not found" , Node ) ;
}
GUBPNodes [ Node ] . RemovePseudodependency ( Dep ) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
List < string > GetDependencies ( string NodeToDo , bool bFlat = false , bool ECOnly = false )
{
var Result = new List < string > ( ) ;
foreach ( var Node in GUBPNodes [ NodeToDo ] . FullNamesOfDependencies )
{
bool Usable = GUBPNodes [ Node ] . RunInEC ( ) | | ! ECOnly ;
if ( Usable )
{
if ( ! Result . Contains ( Node ) )
{
Result . Add ( Node ) ;
}
}
if ( bFlat | | ! Usable )
{
foreach ( var RNode in GetDependencies ( Node , bFlat , ECOnly ) )
{
if ( ! Result . Contains ( RNode ) )
{
Result . Add ( RNode ) ;
}
}
}
}
foreach ( var Node in GUBPNodes [ NodeToDo ] . FullNamesOfPseudosependencies )
{
bool Usable = GUBPNodes [ Node ] . RunInEC ( ) | | ! ECOnly ;
if ( Usable )
{
if ( ! Result . Contains ( Node ) )
{
Result . Add ( Node ) ;
}
}
if ( bFlat | | ! Usable )
{
foreach ( var RNode in GetDependencies ( Node , bFlat , ECOnly ) )
{
if ( ! Result . Contains ( RNode ) )
{
Result . Add ( RNode ) ;
}
}
}
}
return Result ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
List < string > GetECDependencies ( string NodeToDo , bool bFlat = false )
{
return GetDependencies ( NodeToDo , bFlat , true ) ;
}
bool NodeDependsOn ( string Rootward , string Leafward )
{
var Deps = GetDependencies ( Leafward , true ) ;
return Deps . Contains ( Rootward ) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
string GetControllingTrigger ( string NodeToDo )
{
if ( GUBPNodesControllingTrigger . ContainsKey ( NodeToDo ) )
{
return GUBPNodesControllingTrigger [ NodeToDo ] ;
}
var Result = "" ;
foreach ( var Node in GUBPNodes [ NodeToDo ] . FullNamesOfDependencies )
{
if ( ! GUBPNodes . ContainsKey ( Node ) )
{
throw new AutomationException ( "Dependency {0} in {1} not found." , Node , NodeToDo ) ;
}
bool IsTrigger = GUBPNodes [ Node ] . TriggerNode ( ) ;
if ( IsTrigger )
{
if ( Node ! = Result & & ! string . IsNullOrEmpty ( Result ) )
{
throw new AutomationException ( "Node {0} has two controlling triggers {1} and {2}." , NodeToDo , Node , Result ) ;
}
Result = Node ;
}
else
{
string NewResult = GetControllingTrigger ( Node ) ;
if ( ! String . IsNullOrEmpty ( NewResult ) )
{
if ( NewResult ! = Result & & ! string . IsNullOrEmpty ( Result ) )
{
throw new AutomationException ( "Node {0} has two controlling triggers {1} and {2}." , NodeToDo , NewResult , Result ) ;
}
Result = NewResult ;
}
}
}
foreach ( var Node in GUBPNodes [ NodeToDo ] . FullNamesOfPseudosependencies )
{
if ( ! GUBPNodes . ContainsKey ( Node ) )
{
throw new AutomationException ( "Pseudodependency {0} in {1} not found." , Node , NodeToDo ) ;
}
bool IsTrigger = GUBPNodes [ Node ] . TriggerNode ( ) ;
if ( IsTrigger )
{
if ( Node ! = Result & & ! string . IsNullOrEmpty ( Result ) )
{
throw new AutomationException ( "Node {0} has two controlling triggers {1} and {2}." , NodeToDo , Node , Result ) ;
}
Result = Node ;
}
else
{
string NewResult = GetControllingTrigger ( Node ) ;
if ( ! String . IsNullOrEmpty ( NewResult ) )
{
if ( NewResult ! = Result & & ! string . IsNullOrEmpty ( Result ) )
{
throw new AutomationException ( "Node {0} has two controlling triggers {1} and {2}." , NodeToDo , NewResult , Result ) ;
}
Result = NewResult ;
}
}
}
GUBPNodesControllingTrigger . Add ( NodeToDo , Result ) ;
return Result ;
}
string GetControllingTriggerDotName ( string NodeToDo )
{
if ( GUBPNodesControllingTriggerDotName . ContainsKey ( NodeToDo ) )
{
return GUBPNodesControllingTriggerDotName [ NodeToDo ] ;
}
string Result = "" ;
string WorkingNode = NodeToDo ;
while ( true )
{
string ThisResult = GetControllingTrigger ( WorkingNode ) ;
if ( ThisResult = = "" )
{
break ;
}
if ( Result ! = "" )
{
Result = "." + Result ;
}
Result = ThisResult + Result ;
WorkingNode = ThisResult ;
}
GUBPNodesControllingTriggerDotName . Add ( NodeToDo , Result ) ;
return Result ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public string CISFrequencyQuantumShiftString ( string NodeToDo )
{
string FrequencyString = "" ;
int Quantum = GUBPNodes [ NodeToDo ] . DependentCISFrequencyQuantumShift ( ) ;
if ( Quantum > 0 )
{
int Minutes = 20 * ( 1 < < Quantum ) ;
if ( Minutes < 60 )
{
FrequencyString = string . Format ( " ({0}m)" , Minutes ) ;
}
else
{
FrequencyString = string . Format ( " ({0}h{1}m)" , Minutes / 60 , Minutes % 60 ) ;
}
}
return FrequencyString ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public int ComputeDependentCISFrequencyQuantumShift ( string NodeToDo )
{
int Result = GUBPNodes [ NodeToDo ] . ComputedDependentCISFrequencyQuantumShift ;
if ( Result < 0 )
{
Result = GUBPNodes [ NodeToDo ] . CISFrequencyQuantumShift ( this ) ;
Result = GetFrequencyForNode ( this , GUBPNodes [ NodeToDo ] . GetFullName ( ) , Result ) ;
foreach ( var Dep in GUBPNodes [ NodeToDo ] . FullNamesOfDependencies )
{
Result = Math . Max ( ComputeDependentCISFrequencyQuantumShift ( Dep ) , Result ) ;
}
foreach ( var Dep in GUBPNodes [ NodeToDo ] . FullNamesOfPseudosependencies )
{
Result = Math . Max ( ComputeDependentCISFrequencyQuantumShift ( Dep ) , Result ) ;
}
if ( Result < 0 )
{
throw new AutomationException ( "Failed to compute shift." ) ;
}
GUBPNodes [ NodeToDo ] . ComputedDependentCISFrequencyQuantumShift = Result ;
}
return Result ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
bool NodeIsAlreadyComplete ( string NodeToDo , bool LocalOnly )
{
if ( GUBPNodesCompleted . ContainsKey ( NodeToDo ) )
{
return GUBPNodesCompleted [ NodeToDo ] ;
}
string NodeStoreName = StoreName + "-" + GUBPNodes [ NodeToDo ] . GetFullName ( ) ;
string GameNameIfAny = GUBPNodes [ NodeToDo ] . GameNameIfAnyForTempStorage ( ) ;
bool Result ;
if ( LocalOnly )
{
Result = LocalTempStorageExists ( CmdEnv , NodeStoreName , bQuiet : true ) ;
}
else
{
Result = TempStorageExists ( CmdEnv , NodeStoreName , GameNameIfAny , bQuiet : true ) ;
}
if ( Result )
{
Log ( "***** GUBP Trigger Node was already triggered {0} -> {1} : {2}" , GUBPNodes [ NodeToDo ] . GetFullName ( ) , GameNameIfAny , NodeStoreName ) ;
}
else
{
Log ( "***** GUBP Trigger Node was NOT yet triggered {0} -> {1} : {2}" , GUBPNodes [ NodeToDo ] . GetFullName ( ) , GameNameIfAny , NodeStoreName ) ;
}
GUBPNodesCompleted . Add ( NodeToDo , Result ) ;
return Result ;
}
string RunECTool ( string Args , bool bQuiet = false )
{
if ( ParseParam ( "FakeEC" ) )
{
Log ( "***** Would have ran ectool {0}" , Args ) ;
return "We didn't actually run ectool" ;
}
else
{
ERunOptions Opts = ERunOptions . Default ;
if ( bQuiet )
{
Opts = ( Opts & ~ ERunOptions . AllowSpew ) | ERunOptions . NoLoggingOfRunCommand ;
}
return RunAndLog ( "ectool" , Args , Options : Opts ) ;
}
}
2014-09-03 10:12:50 -04:00
void WriteECPerl ( List < string > Args )
{
Args . Add ( "$batch->submit();" ) ;
string ECPerlFile = CommandUtils . CombinePaths ( CommandUtils . CmdEnv . LogFolder , "jobsteps.pl" ) ;
WriteAllLines_NoExceptions ( ECPerlFile , Args . ToArray ( ) ) ;
}
2014-08-28 17:05:26 -04:00
string GetEMailListForNode ( GUBP bp , string NodeToDo , string Emails , string Causers )
2014-08-22 13:39:55 -04:00
{
var BranchForEmail = "" ;
if ( P4Enabled )
{
BranchForEmail = P4Env . BuildRootP4 ;
}
2014-08-28 16:40:17 -04:00
return HackEmails ( Emails , Causers , BranchForEmail , NodeToDo ) ;
2014-08-22 13:39:55 -04:00
}
int GetFrequencyForNode ( GUBP bp , string NodeToDo , int BaseFrequency )
{
var BranchForFrequency = "" ;
if ( P4Enabled )
{
BranchForFrequency = P4Env . BuildRootP4 ;
}
return HackFrequency ( bp , BranchForFrequency , NodeToDo , BaseFrequency ) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
List < P4Connection . ChangeRecord > GetChanges ( int LastOutputForChanges , int TopCL , int LastGreen )
{
var Result = new List < P4Connection . ChangeRecord > ( ) ;
if ( TopCL > LastGreen )
{
if ( LastOutputForChanges > 1990000 )
{
string Cmd = String . Format ( "{0}@{1},{2} {3}@{4},{5}" ,
CombinePaths ( PathSeparator . Slash , P4Env . BuildRootP4 , "*" , "Source" , "..." ) , LastOutputForChanges + 1 , TopCL ,
CombinePaths ( PathSeparator . Slash , P4Env . BuildRootP4 , "*" , "Build" , "..." ) , LastOutputForChanges + 1 , TopCL
) ;
List < P4Connection . ChangeRecord > ChangeRecords ;
2014-04-23 18:27:14 -04:00
if ( P4 . Changes ( out ChangeRecords , Cmd , false , true , LongComment : true ) )
2014-08-22 13:39:55 -04:00
{
foreach ( var Record in ChangeRecords )
{
if ( ! Record . User . Equals ( "buildmachine" , StringComparison . InvariantCultureIgnoreCase ) )
{
Result . Add ( Record ) ;
}
}
}
else
{
throw new AutomationException ( "Could not get changes; cmdline: p4 changes {0}" , Cmd ) ;
}
}
else
{
throw new AutomationException ( "That CL looks pretty far off {0}" , LastOutputForChanges ) ;
}
}
return Result ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
int PrintChanges ( int LastOutputForChanges , int TopCL , int LastGreen )
{
var ChangeRecords = GetChanges ( LastOutputForChanges , TopCL , LastGreen ) ;
foreach ( var Record in ChangeRecords )
{
var Summary = Record . Summary . Replace ( "\r" , "\n" ) ;
if ( Summary . IndexOf ( "\n" ) > 0 )
{
Summary = Summary . Substring ( 0 , Summary . IndexOf ( "\n" ) ) ;
}
Log ( " {0} {1} {2}" , Record . CL , Record . UserEmail , Summary ) ;
}
return TopCL ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
void PrintDetailedChanges ( NodeHistory History , bool bShowAllChanges = false )
{
var StartTime = DateTime . UtcNow ;
2014-04-29 09:35:49 -04:00
2014-08-22 13:39:55 -04:00
string Me = String . Format ( "{0} <<<< local sync" , P4Env . Changelist ) ;
int LastOutputForChanges = 0 ;
int LastGreen = History . LastSucceeded ;
if ( bShowAllChanges )
{
if ( History . AllStarted . Count > 0 )
{
LastGreen = History . AllStarted [ 0 ] ;
}
}
foreach ( var cl in History . AllStarted )
{
if ( cl < LastGreen )
{
continue ;
}
if ( P4Env . Changelist < cl & & Me ! = "" )
{
LastOutputForChanges = PrintChanges ( LastOutputForChanges , P4Env . Changelist , LastGreen ) ;
Log ( " {0}" , Me ) ;
Me = "" ;
}
string Status = "In Process" ;
if ( History . AllSucceeded . Contains ( cl ) )
{
Status = "ok" ;
}
if ( History . AllFailed . Contains ( cl ) )
{
Status = "FAIL" ;
}
LastOutputForChanges = PrintChanges ( LastOutputForChanges , cl , LastGreen ) ;
Log ( " {0} {1}" , cl , Status ) ;
}
if ( Me ! = "" )
{
LastOutputForChanges = PrintChanges ( LastOutputForChanges , P4Env . Changelist , LastGreen ) ;
Log ( " {0}" , Me ) ;
}
var BuildDuration = ( DateTime . UtcNow - StartTime ) . TotalMilliseconds ;
Log ( "Took {0}s to get P4 history" , BuildDuration / 1000 ) ;
2014-04-29 09:35:49 -04:00
2014-08-22 13:39:55 -04:00
}
void PrintNodes ( GUBP bp , List < string > Nodes , bool LocalOnly , List < string > UnfinishedTriggers = null )
{
bool bShowAllChanges = bp . ParseParam ( "AllChanges" ) & & GUBPNodesHistory ! = null ;
bool bShowChanges = ( bp . ParseParam ( "Changes" ) & & GUBPNodesHistory ! = null ) | | bShowAllChanges ;
bool bShowDetailedHistory = ( bp . ParseParam ( "History" ) & & GUBPNodesHistory ! = null ) | | bShowChanges ;
bool bShowDependencies = bp . ParseParam ( "ShowDependencies" ) ;
bool bShowECDependencies = bp . ParseParam ( "ShowECDependencies" ) ;
bool bShowHistory = ! bp . ParseParam ( "NoHistory" ) & & GUBPNodesHistory ! = null ;
bool AddEmailProps = bp . ParseParam ( "ShowEmails" ) ;
bool ECProc = bp . ParseParam ( "ShowECProc" ) ;
bool ECOnly = bp . ParseParam ( "ShowECOnly" ) ;
bool bShowTriggers = true ;
string LastControllingTrigger = "" ;
string LastAgentGroup = "" ;
foreach ( var NodeToDo in Nodes )
{
if ( ECOnly & & ! GUBPNodes [ NodeToDo ] . RunInEC ( ) )
{
continue ;
}
string EMails = "" ;
if ( AddEmailProps )
{
2014-08-28 16:40:17 -04:00
EMails = GetEMailListForNode ( bp , NodeToDo , "" , "" ) ;
2014-08-22 13:39:55 -04:00
}
if ( bShowTriggers )
{
string MyControllingTrigger = GetControllingTriggerDotName ( NodeToDo ) ;
if ( MyControllingTrigger ! = LastControllingTrigger )
{
LastControllingTrigger = MyControllingTrigger ;
if ( MyControllingTrigger ! = "" )
{
string Finished = "" ;
if ( UnfinishedTriggers ! = null )
{
string MyShortControllingTrigger = GetControllingTrigger ( NodeToDo ) ;
if ( UnfinishedTriggers . Contains ( MyShortControllingTrigger ) )
{
Finished = "(not yet triggered)" ;
}
else
{
Finished = "(already triggered)" ;
}
}
Log ( " Controlling Trigger: {0} {1}" , MyControllingTrigger , Finished ) ;
}
}
}
if ( GUBPNodes [ NodeToDo ] . AgentSharingGroup ! = LastAgentGroup & & GUBPNodes [ NodeToDo ] . AgentSharingGroup ! = "" )
{
Log ( " Agent Group: {0}" , GUBPNodes [ NodeToDo ] . AgentSharingGroup ) ;
}
LastAgentGroup = GUBPNodes [ NodeToDo ] . AgentSharingGroup ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
string Agent = GUBPNodes [ NodeToDo ] . ECAgentString ( ) ;
if ( Agent ! = "" )
{
Agent = "[" + Agent + "]" ;
}
string MemoryReq = "[" + GUBPNodes [ NodeToDo ] . AgentMemoryRequirement ( bp ) . ToString ( ) + "]" ;
if ( MemoryReq = = "[0]" )
{
MemoryReq = "" ;
}
string FrequencyString = CISFrequencyQuantumShiftString ( NodeToDo ) ;
2014-05-02 10:44:27 -04:00
2014-08-22 13:39:55 -04:00
Log ( " {0}{1}{2}{3}{4}{5}{6} {7} {8}" ,
( LastAgentGroup ! = "" ? " " : "" ) ,
NodeToDo ,
FrequencyString ,
NodeIsAlreadyComplete ( NodeToDo , LocalOnly ) ? " - (Completed)" : "" ,
GUBPNodes [ NodeToDo ] . TriggerNode ( ) ? " - (TriggerNode)" : "" ,
GUBPNodes [ NodeToDo ] . IsSticky ( ) ? " - (Sticky)" : "" ,
Agent ,
MemoryReq ,
EMails ,
ECProc ? GUBPNodes [ NodeToDo ] . ECProcedure ( ) : ""
) ;
if ( bShowHistory & & GUBPNodesHistory . ContainsKey ( NodeToDo ) )
{
var History = GUBPNodesHistory [ NodeToDo ] ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
if ( bShowDetailedHistory )
{
PrintDetailedChanges ( History , bShowAllChanges ) ;
}
else
{
Log ( " Last Success: {0}" , History . LastSucceeded ) ;
Log ( " Last Fail : {0}" , History . LastFailed ) ;
Log ( " Fails Since: {0}" , History . FailedString ) ;
Log ( " InProgress Since: {0}" , History . InProgressString ) ;
}
}
if ( bShowDependencies )
{
foreach ( var Dep in GUBPNodes [ NodeToDo ] . FullNamesOfDependencies )
{
Log ( " dep> {0}" , Dep ) ;
}
foreach ( var Dep in GUBPNodes [ NodeToDo ] . FullNamesOfPseudosependencies )
{
Log ( " pdep> {0}" , Dep ) ;
}
}
if ( bShowECDependencies )
{
foreach ( var Dep in GetECDependencies ( NodeToDo ) )
{
Log ( " {0}" , Dep ) ;
}
}
}
}
public void SaveGraphVisualization ( List < string > Nodes )
{
var GraphNodes = new List < GraphNode > ( ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
var NodeToGraphNodeMap = new Dictionary < string , GraphNode > ( ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
for ( var NodeIndex = 0 ; NodeIndex < Nodes . Count ; + + NodeIndex )
{
var Node = Nodes [ NodeIndex ] ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
var GraphNode = new GraphNode ( )
{
Id = GraphNodes . Count ,
Label = Node
} ;
GraphNodes . Add ( GraphNode ) ;
NodeToGraphNodeMap . Add ( Node , GraphNode ) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
// Connect everything together
var GraphEdges = new List < GraphEdge > ( ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
for ( var NodeIndex = 0 ; NodeIndex < Nodes . Count ; + + NodeIndex )
{
var Node = Nodes [ NodeIndex ] ;
GraphNode NodeGraphNode = NodeToGraphNodeMap [ Node ] ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var Dep in GUBPNodes [ Node ] . FullNamesOfDependencies )
{
GraphNode PrerequisiteFileGraphNode ;
if ( NodeToGraphNodeMap . TryGetValue ( Dep , out PrerequisiteFileGraphNode ) )
{
// Connect a file our action is dependent on, to our action itself
var NewGraphEdge = new GraphEdge ( )
{
Id = GraphEdges . Count ,
Source = PrerequisiteFileGraphNode ,
Target = NodeGraphNode ,
Color = new GraphColor ( ) { R = 0.0f , G = 0.0f , B = 0.0f , A = 0.75f }
} ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
GraphEdges . Add ( NewGraphEdge ) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
}
foreach ( var Dep in GUBPNodes [ Node ] . FullNamesOfPseudosependencies )
{
GraphNode PrerequisiteFileGraphNode ;
if ( NodeToGraphNodeMap . TryGetValue ( Dep , out PrerequisiteFileGraphNode ) )
{
// Connect a file our action is dependent on, to our action itself
var NewGraphEdge = new GraphEdge ( )
{
Id = GraphEdges . Count ,
Source = PrerequisiteFileGraphNode ,
Target = NodeGraphNode ,
Color = new GraphColor ( ) { R = 0.0f , G = 0.0f , B = 0.0f , A = 0.25f }
} ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
GraphEdges . Add ( NewGraphEdge ) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
string Filename = CommandUtils . CombinePaths ( CommandUtils . CmdEnv . LogFolder , "GubpGraph.gexf" ) ;
Log ( "Writing graph to {0}" , Filename ) ;
GraphVisualization . WriteGraphFile ( Filename , "GUBP Nodes" , GraphNodes , GraphEdges ) ;
Log ( "Wrote graph to {0}" , Filename ) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
// when the host is win64, this is win32 because those are also "host platforms"
static public UnrealTargetPlatform GetAltHostPlatform ( UnrealTargetPlatform HostPlatform )
{
UnrealTargetPlatform AltHostPlatform = UnrealTargetPlatform . Unknown ; // when the host is win64, this is win32 because those are also "host platforms"
if ( HostPlatform = = UnrealTargetPlatform . Win64 )
{
AltHostPlatform = UnrealTargetPlatform . Win32 ;
}
return AltHostPlatform ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public List < UnrealTargetPlatform > GetMonolithicPlatformsForUProject ( UnrealTargetPlatform HostPlatform , BranchInfo . BranchUProject GameProj , bool bIncludeHostPlatform )
{
UnrealTargetPlatform AltHostPlatform = GetAltHostPlatform ( HostPlatform ) ;
var Result = new List < UnrealTargetPlatform > ( ) ;
foreach ( var Kind in BranchInfo . MonolithicKinds )
{
if ( GameProj . Properties . Targets . ContainsKey ( Kind ) )
{
var Target = GameProj . Properties . Targets [ Kind ] ;
var Platforms = Target . Rules . GUBP_GetPlatforms_MonolithicOnly ( HostPlatform ) ;
2014-08-18 13:29:39 -04:00
var AdditionalPlatforms = Target . Rules . GUBP_GetBuildOnlyPlatforms_MonolithicOnly ( HostPlatform ) ;
var AllPlatforms = Platforms . Union ( AdditionalPlatforms ) ;
foreach ( var Plat in AllPlatforms )
2014-08-22 13:39:55 -04:00
{
if ( GUBP . bNoIOSOnPC & & Plat = = UnrealTargetPlatform . IOS & & HostPlatform = = UnrealTargetPlatform . Win64 )
{
continue ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
if ( ActivePlatforms . Contains ( Plat ) & & Target . Rules . SupportsPlatform ( Plat ) & &
( ( Plat ! = HostPlatform & & Plat ! = AltHostPlatform ) | | bIncludeHostPlatform ) )
{
Result . Add ( Plat ) ;
}
}
}
}
return Result ;
}
List < int > ConvertCLToIntList ( List < string > Strings )
{
var Result = new List < int > ( ) ;
foreach ( var ThisString in Strings )
{
int ThisInt = int . Parse ( ThisString ) ;
if ( ThisInt < 1960000 | | ThisInt > 3000000 )
{
Log ( "CL {0} appears to be out of range" , ThisInt ) ;
}
Result . Add ( ThisInt ) ;
}
Result . Sort ( ) ;
return Result ;
}
void SaveStatus ( string NodeToDo , string Suffix , string NodeStoreName , bool bSaveSharedTempStorage , string GameNameIfAny , string JobStepIDForFailure = null )
{
string Contents = "Just a status record: " + Suffix ;
if ( ! String . IsNullOrEmpty ( JobStepIDForFailure ) & & IsBuildMachine )
{
try
{
Contents = RunECTool ( String . Format ( "getProperties --jobStepId {0} --recurse 1" , JobStepIDForFailure ) , true ) ;
}
catch ( Exception Ex )
{
Log ( System . Diagnostics . TraceEventType . Warning , "Failed to get properties for jobstep to save them." ) ;
Log ( System . Diagnostics . TraceEventType . Warning , LogUtils . FormatException ( Ex ) ) ;
}
}
string RecordOfSuccess = CombinePaths ( CommandUtils . CmdEnv . LocalRoot , "Engine" , "Saved" , "Logs" , NodeToDo + Suffix + ".log" ) ;
CreateDirectory ( Path . GetDirectoryName ( RecordOfSuccess ) ) ;
WriteAllText ( RecordOfSuccess , Contents ) ;
StoreToTempStorage ( CmdEnv , NodeStoreName + Suffix , new List < string > { RecordOfSuccess } , ! bSaveSharedTempStorage , GameNameIfAny ) ;
}
string GetPropertyFromStep ( string PropertyPath )
{
string Property = "" ;
Property = RunECTool ( "getProperty \"" + PropertyPath + "\"" ) ;
Property = Property . TrimEnd ( '\r' , '\n' ) ;
return Property ;
2014-08-18 13:29:39 -04:00
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
int CountZeros ( int Num )
{
if ( Num < 0 )
{
throw new AutomationException ( "Bad CountZeros" ) ;
}
if ( Num = = 0 )
{
return 31 ;
}
int Result = 0 ;
while ( ( Num & 1 ) = = 0 )
{
Result + + ;
Num > > = 1 ;
}
return Result ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
List < string > TopologicalSort ( HashSet < string > NodesToDo , string ExplicitTrigger = "" , bool LocalOnly = false , bool SubSort = false , bool DoNotConsiderCompletion = false )
{
var StartTime = DateTime . UtcNow ;
2014-04-02 18:09:23 -04:00
2014-08-22 13:39:55 -04:00
var OrdereredToDo = new List < string > ( ) ;
2014-04-28 16:25:35 -04:00
2014-08-22 13:39:55 -04:00
var SortedAgentGroupChains = new Dictionary < string , List < string > > ( ) ;
if ( ! SubSort )
{
var AgentGroupChains = new Dictionary < string , List < string > > ( ) ;
foreach ( var NodeToDo in NodesToDo )
{
string MyAgentGroup = GUBPNodes [ NodeToDo ] . AgentSharingGroup ;
if ( MyAgentGroup ! = "" )
{
if ( ! AgentGroupChains . ContainsKey ( MyAgentGroup ) )
{
AgentGroupChains . Add ( MyAgentGroup , new List < string > { NodeToDo } ) ;
}
else
{
AgentGroupChains [ MyAgentGroup ] . Add ( NodeToDo ) ;
}
}
}
foreach ( var Chain in AgentGroupChains )
{
SortedAgentGroupChains . Add ( Chain . Key , TopologicalSort ( new HashSet < string > ( Chain . Value ) , ExplicitTrigger , LocalOnly , true , DoNotConsiderCompletion ) ) ;
}
Log ( "***************Done with recursion" ) ;
}
2014-04-02 18:09:23 -04:00
2014-08-22 13:39:55 -04:00
// here we do a topological sort of the nodes, subject to a lexographical and priority sort
while ( NodesToDo . Count > 0 )
{
bool bProgressMade = false ;
float BestPriority = - 1E20f ;
string BestNode = "" ;
bool BestPseudoReady = false ;
var NonReadyAgentGroups = new HashSet < string > ( ) ;
var NonPeudoReadyAgentGroups = new HashSet < string > ( ) ;
var ExaminedAgentGroups = new HashSet < string > ( ) ;
foreach ( var NodeToDo in NodesToDo )
{
bool bReady = true ;
bool bPseudoReady = true ;
if ( ! SubSort & & GUBPNodes [ NodeToDo ] . AgentSharingGroup ! = "" )
{
if ( ExaminedAgentGroups . Contains ( GUBPNodes [ NodeToDo ] . AgentSharingGroup ) )
{
bReady = ! NonReadyAgentGroups . Contains ( GUBPNodes [ NodeToDo ] . AgentSharingGroup ) ;
bPseudoReady = ! NonPeudoReadyAgentGroups . Contains ( GUBPNodes [ NodeToDo ] . AgentSharingGroup ) ; //this might not be accurate if bReady==false
}
else
{
ExaminedAgentGroups . Add ( GUBPNodes [ NodeToDo ] . AgentSharingGroup ) ;
foreach ( var ChainNode in SortedAgentGroupChains [ GUBPNodes [ NodeToDo ] . AgentSharingGroup ] )
{
foreach ( var Dep in GUBPNodes [ ChainNode ] . FullNamesOfDependencies )
{
if ( ! GUBPNodes . ContainsKey ( Dep ) )
{
throw new AutomationException ( "Dependency {0} node found." , Dep ) ;
}
if ( ! SortedAgentGroupChains [ GUBPNodes [ NodeToDo ] . AgentSharingGroup ] . Contains ( Dep ) & & NodesToDo . Contains ( Dep ) )
{
bReady = false ;
break ;
}
}
if ( ! bReady )
{
NonReadyAgentGroups . Add ( GUBPNodes [ NodeToDo ] . AgentSharingGroup ) ;
break ;
}
foreach ( var Dep in GUBPNodes [ ChainNode ] . FullNamesOfPseudosependencies )
{
if ( ! GUBPNodes . ContainsKey ( Dep ) )
{
throw new AutomationException ( "Pseudodependency {0} node found." , Dep ) ;
}
if ( ! SortedAgentGroupChains [ GUBPNodes [ NodeToDo ] . AgentSharingGroup ] . Contains ( Dep ) & & NodesToDo . Contains ( Dep ) )
{
bPseudoReady = false ;
NonPeudoReadyAgentGroups . Add ( GUBPNodes [ NodeToDo ] . AgentSharingGroup ) ;
break ;
}
}
}
}
}
else
{
foreach ( var Dep in GUBPNodes [ NodeToDo ] . FullNamesOfDependencies )
{
if ( ! GUBPNodes . ContainsKey ( Dep ) )
{
throw new AutomationException ( "Dependency {0} node found." , Dep ) ;
}
if ( NodesToDo . Contains ( Dep ) )
{
bReady = false ;
break ;
}
}
foreach ( var Dep in GUBPNodes [ NodeToDo ] . FullNamesOfPseudosependencies )
{
if ( ! GUBPNodes . ContainsKey ( Dep ) )
{
throw new AutomationException ( "Pseudodependency {0} node found." , Dep ) ;
}
if ( NodesToDo . Contains ( Dep ) )
{
bPseudoReady = false ;
break ;
}
}
}
var Priority = GUBPNodes [ NodeToDo ] . Priority ( ) ;
2014-04-02 18:09:23 -04:00
2014-08-22 13:39:55 -04:00
if ( bReady & & BestNode ! = "" )
{
if ( String . Compare ( GetControllingTriggerDotName ( BestNode ) , GetControllingTriggerDotName ( NodeToDo ) ) < 0 ) //sorted by controlling trigger
{
bReady = false ;
}
else if ( String . Compare ( GetControllingTriggerDotName ( BestNode ) , GetControllingTriggerDotName ( NodeToDo ) ) = = 0 ) //sorted by controlling trigger
{
if ( GUBPNodes [ BestNode ] . IsSticky ( ) & & ! GUBPNodes [ NodeToDo ] . IsSticky ( ) ) //sticky nodes first
{
bReady = false ;
}
else if ( GUBPNodes [ BestNode ] . IsSticky ( ) = = GUBPNodes [ NodeToDo ] . IsSticky ( ) )
{
if ( BestPseudoReady & & ! bPseudoReady )
{
bReady = false ;
}
else if ( BestPseudoReady = = bPseudoReady )
{
bool IamLateTrigger = ! DoNotConsiderCompletion & & GUBPNodes [ NodeToDo ] . TriggerNode ( ) & & NodeToDo ! = ExplicitTrigger & & ! NodeIsAlreadyComplete ( NodeToDo , LocalOnly ) ;
bool BestIsLateTrigger = ! DoNotConsiderCompletion & & GUBPNodes [ BestNode ] . TriggerNode ( ) & & BestNode ! = ExplicitTrigger & & ! NodeIsAlreadyComplete ( BestNode , LocalOnly ) ;
if ( BestIsLateTrigger & & ! IamLateTrigger )
{
bReady = false ;
}
else if ( BestIsLateTrigger = = IamLateTrigger )
{
2014-04-02 18:09:23 -04:00
2014-08-22 13:39:55 -04:00
if ( Priority < BestPriority )
{
bReady = false ;
}
else if ( Priority = = BestPriority )
{
if ( BestNode . CompareTo ( NodeToDo ) < 0 )
{
bReady = false ;
}
}
}
}
}
}
}
if ( bReady )
{
BestPriority = Priority ;
BestNode = NodeToDo ;
BestPseudoReady = bPseudoReady ;
bProgressMade = true ;
}
}
if ( bProgressMade )
{
if ( ! SubSort & & GUBPNodes [ BestNode ] . AgentSharingGroup ! = "" )
{
foreach ( var ChainNode in SortedAgentGroupChains [ GUBPNodes [ BestNode ] . AgentSharingGroup ] )
{
OrdereredToDo . Add ( ChainNode ) ;
NodesToDo . Remove ( ChainNode ) ;
}
}
else
{
OrdereredToDo . Add ( BestNode ) ;
NodesToDo . Remove ( BestNode ) ;
}
}
2014-04-02 18:09:23 -04:00
2014-08-22 13:39:55 -04:00
if ( ! bProgressMade & & NodesToDo . Count > 0 )
{
Log ( "Cycle in GUBP, could not resolve:" ) ;
foreach ( var NodeToDo in NodesToDo )
{
string Deps = "" ;
if ( ! SubSort & & GUBPNodes [ NodeToDo ] . AgentSharingGroup ! = "" )
{
foreach ( var ChainNode in SortedAgentGroupChains [ GUBPNodes [ NodeToDo ] . AgentSharingGroup ] )
{
foreach ( var Dep in GUBPNodes [ ChainNode ] . FullNamesOfDependencies )
{
if ( ! SortedAgentGroupChains [ GUBPNodes [ NodeToDo ] . AgentSharingGroup ] . Contains ( Dep ) & & NodesToDo . Contains ( Dep ) )
{
Deps = Deps + Dep + "[" + ChainNode + "->" + GUBPNodes [ NodeToDo ] . AgentSharingGroup + "]" + " " ;
}
}
}
}
foreach ( var Dep in GUBPNodes [ NodeToDo ] . FullNamesOfDependencies )
{
if ( NodesToDo . Contains ( Dep ) )
{
Deps = Deps + Dep + " " ;
}
}
foreach ( var Dep in GUBPNodes [ NodeToDo ] . FullNamesOfPseudosependencies )
{
if ( NodesToDo . Contains ( Dep ) )
{
Deps = Deps + Dep + " " ;
}
}
Log ( " {0} deps: {1}" , NodeToDo , Deps ) ;
}
throw new AutomationException ( "Cycle in GUBP" ) ;
}
}
if ( ! SubSort )
{
var BuildDuration = ( DateTime . UtcNow - StartTime ) . TotalMilliseconds ;
Log ( "Took {0}s to sort {1} nodes" , BuildDuration / 1000 , OrdereredToDo . Count ) ;
}
2014-04-02 18:09:23 -04:00
2014-08-22 13:39:55 -04:00
return OrdereredToDo ;
}
2014-04-28 16:25:35 -04:00
2014-08-22 13:39:55 -04:00
string GetJobStepPath ( string Dep )
{
if ( Dep ! = "Noop" & & GUBPNodes [ Dep ] . AgentSharingGroup ! = "" )
{
return "jobSteps[" + GUBPNodes [ Dep ] . AgentSharingGroup + "]/jobSteps[" + Dep + "]" ;
}
return "jobSteps[" + Dep + "]" ;
}
string GetJobStep ( string ParentPath , string Dep )
{
return ParentPath + "/" + GetJobStepPath ( Dep ) ;
}
2014-04-02 18:09:23 -04:00
2014-08-22 13:39:55 -04:00
void UpdateNodeHistory ( string Node , string CLString )
{
if ( GUBPNodes [ Node ] . RunInEC ( ) & & ! GUBPNodes [ Node ] . TriggerNode ( ) & & CLString ! = "" )
{
string GameNameIfAny = GUBPNodes [ Node ] . GameNameIfAnyForTempStorage ( ) ;
string NodeStoreWildCard = StoreName . Replace ( CLString , "*" ) + "-" + GUBPNodes [ Node ] . GetFullName ( ) ;
var History = new NodeHistory ( ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
History . AllStarted = ConvertCLToIntList ( FindTempStorageManifests ( CmdEnv , NodeStoreWildCard + StartedTempStorageSuffix , false , true , GameNameIfAny ) ) ;
History . AllSucceeded = ConvertCLToIntList ( FindTempStorageManifests ( CmdEnv , NodeStoreWildCard + SucceededTempStorageSuffix , false , true , GameNameIfAny ) ) ;
History . AllFailed = ConvertCLToIntList ( FindTempStorageManifests ( CmdEnv , NodeStoreWildCard + FailedTempStorageSuffix , false , true , GameNameIfAny ) ) ;
2014-04-23 18:43:04 -04:00
2014-08-22 13:39:55 -04:00
if ( History . AllFailed . Count > 0 )
{
History . LastFailed = History . AllFailed [ History . AllFailed . Count - 1 ] ;
}
if ( History . AllSucceeded . Count > 0 )
{
History . LastSucceeded = History . AllSucceeded [ History . AllSucceeded . Count - 1 ] ;
2014-04-23 18:43:04 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var Failed in History . AllFailed )
{
if ( Failed > History . LastSucceeded )
{
History . Failed . Add ( Failed ) ;
History . FailedString = GUBPNode . MergeSpaceStrings ( History . FailedString , String . Format ( "{0}" , Failed ) ) ;
}
}
foreach ( var Started in History . AllStarted )
{
if ( Started > History . LastSucceeded & & ! History . Failed . Contains ( Started ) )
{
History . InProgress . Add ( Started ) ;
History . InProgressString = GUBPNode . MergeSpaceStrings ( History . InProgressString , String . Format ( "{0}" , Started ) ) ;
}
}
if ( GUBPNodesHistory . ContainsKey ( Node ) )
{
GUBPNodesHistory . Remove ( Node ) ;
}
GUBPNodesHistory . Add ( Node , History ) ;
}
}
}
2014-04-23 18:43:04 -04:00
2014-08-22 13:39:55 -04:00
bool HashSetEqual ( HashSet < string > A , HashSet < string > B )
{
if ( A . Count ! = B . Count )
{
return false ;
}
foreach ( var Elem in A )
{
if ( ! B . Contains ( Elem ) )
{
return false ;
}
}
foreach ( var Elem in B )
{
if ( ! A . Contains ( Elem ) )
{
return false ;
}
}
return true ;
}
2014-04-23 18:43:04 -04:00
2014-08-22 13:39:55 -04:00
int FindLastNonDuplicateFail ( string NodeToDo , string CLString )
{
var History = GUBPNodesHistory [ NodeToDo ] ;
int Result = P4Env . Changelist ;
2014-06-16 12:05:56 -04:00
2014-08-22 13:39:55 -04:00
string GameNameIfAny = GUBPNodes [ NodeToDo ] . GameNameIfAnyForTempStorage ( ) ;
string NodeStore = StoreName + "-" + GUBPNodes [ NodeToDo ] . GetFullName ( ) + FailedTempStorageSuffix ;
2014-06-16 12:05:56 -04:00
2014-08-22 13:39:55 -04:00
var BackwardsFails = new List < int > ( History . AllFailed ) ;
BackwardsFails . Add ( P4Env . Changelist ) ;
BackwardsFails . Sort ( ) ;
BackwardsFails . Reverse ( ) ;
HashSet < string > CurrentErrors = null ;
foreach ( var CL in BackwardsFails )
{
if ( CL > P4Env . Changelist )
{
continue ;
}
if ( CL < = History . LastSucceeded )
{
break ;
}
var ThisNodeStore = NodeStore . Replace ( CLString , String . Format ( "{0}" , CL ) ) ;
DeleteLocalTempStorage ( CmdEnv , ThisNodeStore , true ) ; // these all clash locally, which is fine we just retrieve them from shared
2014-06-16 12:05:56 -04:00
2014-08-22 13:39:55 -04:00
List < string > Files = null ;
try
{
bool WasLocal ;
Files = RetrieveFromTempStorage ( CmdEnv , ThisNodeStore , out WasLocal , GameNameIfAny ) ; // this will fail on our CL if we didn't fail or we are just setting up the branch
}
catch ( Exception )
{
}
if ( Files = = null )
{
continue ;
}
if ( Files . Count ! = 1 )
{
throw new AutomationException ( "Unexpected number of files for fail record {0}" , Files . Count ) ;
}
string ErrorFile = Files [ 0 ] ;
var ThisErrors = ECJobPropsUtils . ErrorsFromProps ( ErrorFile ) ;
if ( CurrentErrors = = null )
{
CurrentErrors = ThisErrors ;
}
else
{
if ( CurrentErrors . Count = = 0 | | ! HashSetEqual ( CurrentErrors , ThisErrors ) )
{
break ;
}
Result = CL ;
}
}
return Result ;
}
List < string > GetECPropsForNode ( string NodeToDo , string CLString , out string EMails , bool OnlyLateUpdates = false )
{
var StartTime = DateTime . UtcNow ;
2014-06-16 12:46:07 -04:00
2014-08-22 13:39:55 -04:00
var ECProps = new List < string > ( ) ;
EMails = "" ;
string FailCauserEMails = "" ;
string EMailNote = "" ;
bool SendSuccessForGreenAfterRed = false ;
int NumPeople = 0 ;
if ( GUBPNodesHistory . ContainsKey ( NodeToDo ) )
{
var History = GUBPNodesHistory [ NodeToDo ] ;
2014-04-29 09:35:49 -04:00
2014-08-22 13:39:55 -04:00
ECProps . Add ( string . Format ( "LastGreen/{0}={1}" , NodeToDo , History . LastSucceeded ) ) ;
ECProps . Add ( string . Format ( "RedsSince/{0}={1}" , NodeToDo , History . FailedString ) ) ;
ECProps . Add ( string . Format ( "InProgress/{0}={1}" , NodeToDo , History . InProgressString ) ) ;
2014-04-23 18:43:04 -04:00
2014-08-22 13:39:55 -04:00
if ( History . LastSucceeded > 0 & & History . LastSucceeded < P4Env . Changelist )
{
int LastNonDuplicateFail = P4Env . Changelist ;
try
{
if ( OnlyLateUpdates )
{
LastNonDuplicateFail = FindLastNonDuplicateFail ( NodeToDo , CLString ) ;
if ( LastNonDuplicateFail < P4Env . Changelist )
{
Log ( "*** Red-after-red spam reduction, changed CL {0} to CL {1} because the errors didn't change." , P4Env . Changelist , LastNonDuplicateFail ) ;
}
}
}
catch ( Exception Ex )
{
LastNonDuplicateFail = P4Env . Changelist ;
Log ( System . Diagnostics . TraceEventType . Warning , "Failed to FindLastNonDuplicateFail." ) ;
Log ( System . Diagnostics . TraceEventType . Warning , LogUtils . FormatException ( Ex ) ) ;
}
2014-06-16 12:05:56 -04:00
2014-08-22 13:39:55 -04:00
var ChangeRecords = GetChanges ( History . LastSucceeded , LastNonDuplicateFail , History . LastSucceeded ) ;
foreach ( var Record in ChangeRecords )
{
FailCauserEMails = GUBPNode . MergeSpaceStrings ( FailCauserEMails , Record . UserEmail ) ;
}
if ( ! String . IsNullOrEmpty ( FailCauserEMails ) )
{
NumPeople + + ;
foreach ( var AChar in FailCauserEMails . ToCharArray ( ) )
{
if ( AChar = = ' ' )
{
NumPeople + + ;
}
}
if ( NumPeople > 50 )
{
EMailNote = String . Format ( "This step has been broken for more than 50 changes. It last succeeded at CL {0}. " , History . LastSucceeded ) ;
}
}
}
else if ( History . LastSucceeded < = 0 )
{
EMailNote = String . Format ( "This step has been broken for more than a few days, so there is no record of it ever succeeding. " ) ;
}
if ( EMailNote ! = "" & & ! String . IsNullOrEmpty ( History . FailedString ) )
{
EMailNote + = String . Format ( "It has failed at CLs {0}. " , History . FailedString ) ;
}
if ( EMailNote ! = "" & & ! String . IsNullOrEmpty ( History . InProgressString ) )
{
EMailNote + = String . Format ( "These CLs are being built right now {0}. " , History . InProgressString ) ;
}
if ( History . LastSucceeded > 0 & & History . LastSucceeded < P4Env . Changelist & & History . LastFailed > History . LastSucceeded & & History . LastFailed < P4Env . Changelist )
{
SendSuccessForGreenAfterRed = ParseParam ( "CIS" ) ;
}
}
else
{
ECProps . Add ( string . Format ( "LastGreen/{0}=0" , NodeToDo ) ) ;
ECProps . Add ( string . Format ( "RedsSince/{0}=" , NodeToDo ) ) ;
ECProps . Add ( string . Format ( "InProgress/{0}=" , NodeToDo ) ) ;
}
2014-04-30 09:58:02 -04:00
2014-08-22 13:39:55 -04:00
ECProps . Add ( string . Format ( "FailCausers/{0}={1}" , NodeToDo , FailCauserEMails ) ) ;
ECProps . Add ( string . Format ( "EmailNotes/{0}={1}" , NodeToDo , EMailNote ) ) ;
2014-04-30 09:58:02 -04:00
2014-08-22 13:39:55 -04:00
{
var AdditonalEmails = "" ;
2014-08-28 16:40:17 -04:00
string Causers = "" ;
2014-08-22 13:39:55 -04:00
if ( ParseParam ( "CIS" ) & & ! GUBPNodes [ NodeToDo ] . SendSuccessEmail ( ) & & ! GUBPNodes [ NodeToDo ] . TriggerNode ( ) )
{
2014-08-28 16:40:17 -04:00
Causers = FailCauserEMails ;
2014-08-28 17:00:26 -04:00
}
2014-08-22 13:39:55 -04:00
string AddEmails = ParseParamValue ( "AddEmails" ) ;
if ( ! String . IsNullOrEmpty ( AddEmails ) )
{
AdditonalEmails = GUBPNode . MergeSpaceStrings ( AddEmails , AdditonalEmails ) ;
}
2014-04-23 18:43:04 -04:00
2014-08-28 16:40:17 -04:00
EMails = GetEMailListForNode ( this , NodeToDo , AdditonalEmails , Causers ) ;
2014-04-23 18:43:04 -04:00
2014-08-22 13:39:55 -04:00
ECProps . Add ( "FailEmails/" + NodeToDo + "=" + EMails ) ;
}
if ( GUBPNodes [ NodeToDo ] . SendSuccessEmail ( ) | | SendSuccessForGreenAfterRed )
{
ECProps . Add ( "SendSuccessEmail/" + NodeToDo + "=1" ) ;
}
else
{
ECProps . Add ( "SendSuccessEmail/" + NodeToDo + "=0" ) ;
}
if ( ! OnlyLateUpdates )
{
ECProps . Add ( string . Format ( "AgentRequirementString/{0}={1}" , NodeToDo , GUBPNodes [ NodeToDo ] . ECAgentString ( ) ) ) ;
ECProps . Add ( string . Format ( "RequiredMemory/{0}={1}" , NodeToDo , GUBPNodes [ NodeToDo ] . AgentMemoryRequirement ( this ) ) ) ;
ECProps . Add ( string . Format ( "Timeouts/{0}={1}" , NodeToDo , GUBPNodes [ NodeToDo ] . TimeoutInMinutes ( ) ) ) ;
ECProps . Add ( string . Format ( "JobStepPath/{0}={1}" , NodeToDo , GetJobStepPath ( NodeToDo ) ) ) ;
}
var BuildDuration = ( DateTime . UtcNow - StartTime ) . TotalMilliseconds ;
Log ( "Took {0}s to get P4 history for node {1}" , BuildDuration / 1000 , NodeToDo ) ;
2014-04-23 18:43:04 -04:00
2014-08-22 13:39:55 -04:00
return ECProps ;
}
2014-04-23 18:43:04 -04:00
2014-08-22 13:39:55 -04:00
void UpdateECProps ( string NodeToDo , string CLString )
{
try
{
Log ( "Updating node props for node {0}" , NodeToDo ) ;
string EMails ;
var Props = GetECPropsForNode ( NodeToDo , CLString , out EMails , true ) ;
foreach ( var Prop in Props )
{
var Parts = Prop . Split ( "=" . ToCharArray ( ) ) ;
RunECTool ( String . Format ( "setProperty \"/myWorkflow/{0}\" \"{1}\"" , Parts [ 0 ] , Parts [ 1 ] ) , true ) ;
}
}
catch ( Exception Ex )
{
Log ( System . Diagnostics . TraceEventType . Warning , "Failed to UpdateECProps." ) ;
Log ( System . Diagnostics . TraceEventType . Warning , LogUtils . FormatException ( Ex ) ) ;
}
}
2014-04-23 18:43:04 -04:00
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
[Help("Runs one, several or all of the GUBP nodes")]
[Help(typeof(UE4Build))]
2014-09-06 13:20:05 -04:00
[Help("NoMac", "Toggle to exclude the Mac host platform, default is Win64+Mac+Linux")]
[Help("NoLinux", "Toggle to exclude the Linux (PC, 64-bit) host platform, default is Win64+Mac+Linux")]
[Help("NoPC", "Toggle to exclude the PC host platform, default is Win64+Mac+Linux")]
2014-08-22 13:39:55 -04:00
[Help("CleanLocal", "delete the local temp storage before we start")]
[Help("Store=", "Sets the name of the temp storage block, normally, this is built for you.")]
[Help("StoreSuffix=", "Tacked onto a store name constructed from CL, branch, etc")]
[Help("TimeIndex=", "An integer used to determine subsets to run based on DependentCISFrequencyQuantumShift")]
[Help("UserTimeIndex=", "An integer used to determine subsets to run based on DependentCISFrequencyQuantumShift, this one overrides TimeIndex")]
[Help("PreflightUID=", "A unique integer tag from EC used as part of the tempstorage, builds and label names to distinguish multiple attempts.")]
[Help("Node=", "Nodes to process, -node=Node1+Node2+Node3, if no nodes or games are specified, defaults to all nodes.")]
[Help("SetupNode=", "Like -Node, but only applies with CommanderJobSetupOnly")]
[Help("RelatedToNode=", "Nodes to process, -RelatedToNode=Node1+Node2+Node3, use all nodes that either depend on these nodes or these nodes depend on them.")]
[Help("SetupRelatedToNode=", "Like -RelatedToNode, but only applies with CommanderJobSetupOnly")]
[Help("OnlyNode=", "Nodes to process NO dependencies, -OnlyNode=Node1+Node2+Node3, if no nodes or games are specified, defaults to all nodes.")]
[Help("TriggerNode=", "Trigger Nodes to process, -triggernode=Node.")]
[Help("Game=", "Games to process, -game=Game1+Game2+Game3, if no games or nodes are specified, defaults to all nodes.")]
[Help("ListOnly", "List Nodes in this branch")]
[Help("SaveGraph", "Save graph as an xml file")]
[Help("CommanderJobSetupOnly", "Set up the EC branch info via ectool and quit")]
[Help("FakeEC", "don't run ectool, rather just do it locally, emulating what EC would have done.")]
[Help("Fake", "Don't actually build anything, just store a record of success as the build product for each node.")]
[Help("AllPlatforms", "Regardless of what is installed on this machine, set up the graph for all platforms; true by default on build machines.")]
[Help("SkipTriggers", "ignore all triggers")]
[Help("CL", "force the CL to something, disregarding the P4 value.")]
[Help("History", "Like ListOnly, except gives you a full history. Must have -P4 for this to work.")]
[Help("Changes", "Like history, but also shows the P4 changes. Must have -P4 for this to work.")]
[Help("AllChanges", "Like changes except includes changes before the last green. Must have -P4 for this to work.")]
[Help("EmailOnly", "Only emails the folks given in the argument.")]
[Help("AddEmails", "Add these space delimited emails too all email lists.")]
[Help("ShowDependencies", "Show node dependencies.")]
[Help("ShowECDependencies", "Show EC node dependencies instead.")]
[Help("ShowECProc", "Show EC proc names.")]
[Help("BuildRocket", "Build in rocket mode.")]
[Help("ShowECOnly", "Only show EC nodes.")]
[Help("ECProject", "From EC, the name of the project, used to get a version number.")]
[Help("CIS", "This is a CIS run, assign TimeIndex based on the history.")]
[Help("ForceIncrementalCompile", "make sure all compiles are incremental")]
[Help("AutomatedTesting", "Allow automated testing, currently disabled.")]
[Help("StompCheck", "Look for stomped build products.")]
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
public override void ExecuteBuild ( )
{
Log ( "************************* GUBP" ) ;
string PreflightShelveCLString = GetEnvVar ( "uebp_PreflightShelveCL" ) ;
if ( ( ! String . IsNullOrEmpty ( PreflightShelveCLString ) & & IsBuildMachine ) | | ParseParam ( "PreflightTest" ) )
{
Log ( "**** Preflight shelve {0}" , PreflightShelveCLString ) ;
if ( ! String . IsNullOrEmpty ( PreflightShelveCLString ) )
{
PreflightShelveCL = int . Parse ( PreflightShelveCLString ) ;
if ( PreflightShelveCL < 2000000 )
{
throw new AutomationException ( "{0} does not look like a CL" ) ;
}
}
bPreflightBuild = true ;
}
ECProject = ParseParamValue ( "ECProject" ) ;
if ( ECProject = = null )
{
ECProject = "" ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
HostPlatforms = new List < UnrealTargetPlatform > ( ) ;
if ( ! ParseParam ( "NoPC" ) )
{
HostPlatforms . Add ( UnrealTargetPlatform . Win64 ) ;
}
var BranchForOptions = "" ;
if ( P4Enabled )
{
BranchForOptions = P4Env . BuildRootP4 ;
}
BranchOptions = GetBranchOptions ( BranchForOptions ) ;
2014-09-05 21:50:16 -04:00
bool WithMac = ! BranchOptions . PlatformsToRemove . Contains ( UnrealTargetPlatform . Mac ) ;
2014-08-22 13:39:55 -04:00
if ( ParseParam ( "NoMac" ) )
{
WithMac = false ;
}
if ( WithMac )
{
HostPlatforms . Add ( UnrealTargetPlatform . Mac ) ;
}
2014-04-23 17:37:20 -04:00
2014-09-05 21:50:16 -04:00
bool WithLinux = ! BranchOptions . PlatformsToRemove . Contains ( UnrealTargetPlatform . Linux ) ;
2014-09-06 13:20:05 -04:00
// @TODO: exclude temporarily unless running on a Linux machine to prevent spurious GUBP failures
if ( UnrealBuildTool . BuildHostPlatform . Current . Platform ! = UnrealTargetPlatform . Linux | | ParseParam ( "NoLinux" ) )
2014-09-05 21:50:16 -04:00
{
WithLinux = false ;
}
if ( WithLinux )
{
HostPlatforms . Add ( UnrealTargetPlatform . Linux ) ;
}
bBuildRocket = ParseParam ( "BuildRocket" ) ;
2014-08-22 13:39:55 -04:00
bForceIncrementalCompile = ParseParam ( "ForceIncrementalCompile" ) ;
2014-09-10 12:30:17 -04:00
bool bNoAutomatedTesting = ParseParam ( "NoAutomatedTesting" ) | | BranchOptions . bNoAutomatedTesting ;
2014-08-22 13:39:55 -04:00
StoreName = ParseParamValue ( "Store" ) ;
string StoreSuffix = ParseParamValue ( "StoreSuffix" , "" ) ;
if ( bBuildRocket )
{
StoreSuffix = StoreSuffix + "-Rkt" ;
}
if ( bPreflightBuild )
{
int PreflightUID = ParseParamInt ( "PreflightUID" , 0 ) ;
PreflightMangleSuffix = String . Format ( "-PF-{0}-{1}" , PreflightShelveCL , PreflightUID ) ;
StoreSuffix = StoreSuffix + PreflightMangleSuffix ;
}
CL = ParseParamInt ( "CL" , 0 ) ;
bool bCleanLocalTempStorage = ParseParam ( "CleanLocal" ) ;
bool bChanges = ParseParam ( "Changes" ) | | ParseParam ( "AllChanges" ) ;
bool bHistory = ParseParam ( "History" ) | | bChanges ;
bool bListOnly = ParseParam ( "ListOnly" ) | | bHistory ;
bool bSkipTriggers = ParseParam ( "SkipTriggers" ) ;
bFake = ParseParam ( "fake" ) ;
bool bFakeEC = ParseParam ( "FakeEC" ) ;
TimeIndex = ParseParamInt ( "TimeIndex" , 0 ) ;
if ( TimeIndex = = 0 )
{
TimeIndex = ParseParamInt ( "UserTimeIndex" , 0 ) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
bNoIOSOnPC = HostPlatforms . Contains ( UnrealTargetPlatform . Mac ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
bool bSaveSharedTempStorage = false ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
if ( bHistory & & ! P4Enabled )
{
throw new AutomationException ( "-Changes and -History require -P4." ) ;
}
bool LocalOnly = true ;
string CLString = "" ;
if ( String . IsNullOrEmpty ( StoreName ) )
{
if ( P4Enabled )
{
if ( CL = = 0 )
{
CL = P4Env . Changelist ;
}
CLString = String . Format ( "{0}" , CL ) ;
StoreName = P4Env . BuildRootEscaped + "-" + CLString ;
bSaveSharedTempStorage = CommandUtils . IsBuildMachine ;
LocalOnly = false ;
}
else
{
StoreName = "TempLocal" ;
bSaveSharedTempStorage = false ;
}
}
StoreName = StoreName + StoreSuffix ;
if ( bFakeEC )
{
LocalOnly = true ;
}
if ( bSaveSharedTempStorage )
{
if ( ! HaveSharedTempStorage ( true ) )
{
throw new AutomationException ( "Request to save to temp storage, but {0} is unavailable." , UE4TempStorageDirectory ( ) ) ;
}
bSignBuildProducts = true ;
}
else if ( ! LocalOnly & & ! HaveSharedTempStorage ( false ) )
{
Log ( "Looks like we want to use shared temp storage, but since we don't have it, we won't use it." ) ;
LocalOnly = true ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
bool CommanderSetup = ParseParam ( "CommanderJobSetupOnly" ) ;
string ExplicitTrigger = "" ;
if ( CommanderSetup )
{
ExplicitTrigger = ParseParamValue ( "TriggerNode" ) ;
if ( ExplicitTrigger = = null )
{
ExplicitTrigger = "" ;
}
}
2014-04-02 18:09:23 -04:00
2014-08-22 13:39:55 -04:00
if ( ParseParam ( "CIS" ) & & ExplicitTrigger = = "" & & CommanderSetup ) // explicit triggers will already have a time index assigned
{
if ( ! P4Enabled )
{
throw new AutomationException ( "Can't have -CIS without P4 support" ) ;
}
var P4IndexFileP4 = CombinePaths ( PathSeparator . Slash , CommandUtils . P4Env . BuildRootP4 , "Engine" , "Build" , "CISCounter.txt" ) ;
var P4IndexFileLocal = CombinePaths ( CmdEnv . LocalRoot , "Engine" , "Build" , "CISCounter.txt" ) ;
int Retry = 0 ;
bool bDone = false ;
while ( + + Retry < 20 & & ! bDone )
{
int NowMinutes = ( int ) ( ( DateTime . UtcNow - new DateTime ( 2014 , 1 , 1 ) ) . TotalMinutes ) ;
if ( NowMinutes < 3 * 30 * 24 )
{
throw new AutomationException ( "bad date calc" ) ;
}
if ( ! FileExists_NoExceptions ( P4IndexFileLocal ) )
{
Log ( "{0} doesn't exist, checking in a new one" , P4IndexFileP4 ) ;
WriteAllText ( P4IndexFileLocal , "-1 0" ) ;
int WorkingCL = - 1 ;
try
{
2014-04-02 18:09:23 -04:00
WorkingCL = P4 . CreateChange ( P4Env . Client , "Adding new CIS Counter" ) ;
P4 . Add ( WorkingCL , P4IndexFileP4 ) ;
2014-08-22 13:39:55 -04:00
int SubmittedCL ;
2014-04-02 18:09:23 -04:00
P4 . Submit ( WorkingCL , out SubmittedCL ) ;
2014-08-22 13:39:55 -04:00
}
catch ( Exception )
{
Log ( "Add of CIS counter failed, assuming it now exists." ) ;
if ( WorkingCL > 0 )
{
2014-04-02 18:09:23 -04:00
P4 . DeleteChange ( WorkingCL ) ;
2014-08-22 13:39:55 -04:00
}
}
}
2014-04-02 18:09:23 -04:00
P4 . Sync ( "-f " + P4IndexFileP4 + "#head" ) ;
2014-08-22 13:39:55 -04:00
if ( ! FileExists_NoExceptions ( P4IndexFileLocal ) )
{
Log ( "{0} doesn't exist, checking in a new one" , P4IndexFileP4 ) ;
WriteAllText ( P4IndexFileLocal , "-1 0" ) ;
int WorkingCL = - 1 ;
try
{
WorkingCL = P4 . CreateChange ( P4Env . Client , "Adding new CIS Counter" ) ;
P4 . Add ( WorkingCL , P4IndexFileP4 ) ;
int SubmittedCL ;
P4 . Submit ( WorkingCL , out SubmittedCL ) ;
}
catch ( Exception )
{
Log ( "Add of CIS counter failed, assuming it now exists." ) ;
if ( WorkingCL > 0 )
{
P4 . DeleteChange ( WorkingCL ) ;
}
}
}
var Data = ReadAllText ( P4IndexFileLocal ) ;
var Parts = Data . Split ( " " . ToCharArray ( ) ) ;
int Index = int . Parse ( Parts [ 0 ] ) ;
int Minutes = int . Parse ( Parts [ 1 ] ) ;
2014-04-02 18:09:23 -04:00
2014-08-22 13:39:55 -04:00
int DeltaMinutes = NowMinutes - Minutes ;
2014-04-02 18:09:23 -04:00
2014-08-22 13:39:55 -04:00
const int TimeQuantum = 20 ;
2014-04-02 18:09:23 -04:00
2014-08-22 13:39:55 -04:00
int NewIndex = Index + 1 ;
2014-04-02 18:09:23 -04:00
2014-08-22 13:39:55 -04:00
if ( DeltaMinutes > TimeQuantum * 2 )
{
if ( DeltaMinutes > TimeQuantum * ( 1 < < 8 ) )
{
// it has been forever, lets just start over
NewIndex = 0 ;
}
else
{
int WorkingIndex = NewIndex + 1 ;
for ( int WorkingDelta = DeltaMinutes - TimeQuantum ; WorkingDelta > 0 ; WorkingDelta - = TimeQuantum , WorkingIndex + + )
{
if ( CountZeros ( NewIndex ) < CountZeros ( WorkingIndex ) )
{
NewIndex = WorkingIndex ;
}
}
}
}
{
var Line = String . Format ( "{0} {1}" , NewIndex , NowMinutes ) ;
Log ( "Attempting to write {0} with {1}" , P4IndexFileP4 , Line ) ;
int WorkingCL = - 1 ;
try
{
2014-04-02 18:09:23 -04:00
WorkingCL = P4 . CreateChange ( P4Env . Client , "Updating CIS Counter" ) ;
P4 . Edit ( WorkingCL , P4IndexFileP4 ) ;
2014-08-22 13:39:55 -04:00
WriteAllText ( P4IndexFileLocal , Line ) ;
int SubmittedCL ;
2014-04-02 18:09:23 -04:00
P4 . Submit ( WorkingCL , out SubmittedCL ) ;
2014-08-22 13:39:55 -04:00
bDone = true ;
TimeIndex = NewIndex ;
}
catch ( Exception )
{
Log ( "Edit of CIS counter failed, assuming someone else checked in, retrying." ) ;
if ( WorkingCL > 0 )
{
2014-04-02 18:09:23 -04:00
P4 . DeleteChange ( WorkingCL ) ;
2014-08-22 13:39:55 -04:00
}
System . Threading . Thread . Sleep ( 30000 ) ;
}
}
}
if ( ! bDone )
{
throw new AutomationException ( "Failed to update the CIS counter after 20 tries." ) ;
}
Log ( "Setting TimeIndex to {0}" , TimeIndex ) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
Log ( "************************* CL: {0}" , CL ) ;
Log ( "************************* P4Enabled: {0}" , P4Enabled ) ;
foreach ( var HostPlatform in HostPlatforms )
{
Log ( "************************* HostPlatform: {0}" , HostPlatform . ToString ( ) ) ;
}
Log ( "************************* StoreName: {0}" , StoreName . ToString ( ) ) ;
Log ( "************************* bCleanLocalTempStorage: {0}" , bCleanLocalTempStorage ) ;
Log ( "************************* bSkipTriggers: {0}" , bSkipTriggers ) ;
Log ( "************************* bSaveSharedTempStorage: {0}" , bSaveSharedTempStorage ) ;
Log ( "************************* bSignBuildProducts: {0}" , bSignBuildProducts ) ;
Log ( "************************* bFake: {0}" , bFake ) ;
Log ( "************************* bFakeEC: {0}" , bFakeEC ) ;
Log ( "************************* bHistory: {0}" , bHistory ) ;
Log ( "************************* TimeIndex: {0}" , TimeIndex ) ;
Log ( "************************* bBuildRocket: {0}" , bBuildRocket ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
GUBPNodes = new Dictionary < string , GUBPNode > ( ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
Branch = new BranchInfo ( HostPlatforms ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
if ( IsBuildMachine | | ParseParam ( "AllPlatforms" ) )
{
ActivePlatforms = new List < UnrealTargetPlatform > ( ) ;
foreach ( var GameProj in Branch . CodeProjects )
{
foreach ( var Kind in BranchInfo . MonolithicKinds )
{
if ( GameProj . Properties . Targets . ContainsKey ( Kind ) )
{
var Target = GameProj . Properties . Targets [ Kind ] ;
foreach ( var HostPlatform in HostPlatforms )
{
var Platforms = Target . Rules . GUBP_GetPlatforms_MonolithicOnly ( HostPlatform ) ;
2014-08-18 13:29:39 -04:00
var AdditionalPlatforms = Target . Rules . GUBP_GetBuildOnlyPlatforms_MonolithicOnly ( HostPlatform ) ;
var AllPlatforms = Platforms . Union ( AdditionalPlatforms ) ;
foreach ( var Plat in AllPlatforms )
2014-08-22 13:39:55 -04:00
{
if ( Target . Rules . SupportsPlatform ( Plat ) & & ! ActivePlatforms . Contains ( Plat ) )
{
ActivePlatforms . Add ( Plat ) ;
}
}
}
}
}
}
}
else
{
2014-09-12 15:56:47 -04:00
ActivePlatforms = new List < UnrealTargetPlatform > ( CommandUtils . KnownTargetPlatforms ) ;
2014-08-22 13:39:55 -04:00
}
if ( bBuildRocket )
{
var FilteredActivePlatforms = new List < UnrealTargetPlatform > ( ) ;
foreach ( var Plat in ActivePlatforms )
{
2014-09-23 15:40:21 -04:00
if ( Plat ! = UnrealTargetPlatform . HTML5 & &
2014-08-22 13:39:55 -04:00
( Plat ! = UnrealTargetPlatform . PS4 | | ParseParam ( "WithPS4" ) ) & &
Plat ! = UnrealTargetPlatform . WinRT & &
Plat ! = UnrealTargetPlatform . WinRT_ARM & &
Plat ! = UnrealTargetPlatform . XboxOne
)
{
FilteredActivePlatforms . Add ( Plat ) ;
}
}
ActivePlatforms = FilteredActivePlatforms ;
}
var SupportedPlatforms = new List < UnrealTargetPlatform > ( ) ;
foreach ( var Plat in ActivePlatforms )
{
if ( ! BranchOptions . PlatformsToRemove . Contains ( Plat ) )
{
SupportedPlatforms . Add ( Plat ) ;
}
}
ActivePlatforms = SupportedPlatforms ;
foreach ( var Plat in ActivePlatforms )
{
Log ( "Active Platform: {0}" , Plat . ToString ( ) ) ;
}
2014-03-14 14:13:41 -04:00
2014-09-05 21:50:16 -04:00
if ( HostPlatforms . Count > = 2 )
2014-08-22 13:39:55 -04:00
{
// make sure each project is set up with the right assumptions on monolithics that prefer a platform.
foreach ( var CodeProj in Branch . CodeProjects )
{
var OptionsMac = CodeProj . Options ( UnrealTargetPlatform . Mac ) ;
var OptionsPC = CodeProj . Options ( UnrealTargetPlatform . Win64 ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
var MacMonos = GetMonolithicPlatformsForUProject ( UnrealTargetPlatform . Mac , CodeProj , false ) ;
var PCMonos = GetMonolithicPlatformsForUProject ( UnrealTargetPlatform . Win64 , CodeProj , false ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
if ( ! OptionsMac . bIsPromotable & & OptionsPC . bIsPromotable & &
( MacMonos . Contains ( UnrealTargetPlatform . IOS ) | | PCMonos . Contains ( UnrealTargetPlatform . IOS ) ) )
{
throw new AutomationException ( "Project {0} is promotable for PC, not promotable for Mac and uses IOS monothics. Since Mac is the preferred platform for IOS, please add Mac as a promotable platform." , CodeProj . GameName ) ;
}
if ( OptionsMac . bIsPromotable & & ! OptionsPC . bIsPromotable & &
( MacMonos . Contains ( UnrealTargetPlatform . Android ) | | PCMonos . Contains ( UnrealTargetPlatform . Android ) ) )
{
throw new AutomationException ( "Project {0} is not promotable for PC, promotable for Mac and uses Android monothics. Since PC is the preferred platform for Android, please add PC as a promotable platform." , CodeProj . GameName ) ;
}
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
AddNode ( new VersionFilesNode ( ) ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var HostPlatform in HostPlatforms )
{
AddNode ( new ToolsForCompileNode ( HostPlatform ) ) ;
2014-09-18 14:24:42 -04:00
AddNode ( new RootEditorNode ( HostPlatform ) ) ;
2014-08-22 13:39:55 -04:00
if ( bBuildRocket )
{
AddNode ( new RootEditorHeadersNode ( HostPlatform ) ) ;
}
AddNode ( new ToolsNode ( HostPlatform ) ) ;
2014-04-23 17:57:49 -04:00
AddNode ( new InternalToolsNode ( HostPlatform ) ) ;
2014-08-22 13:39:55 -04:00
foreach ( var ProgramTarget in Branch . BaseEngineProject . Properties . Programs )
{
bool bInternalOnly ;
bool SeparateNode ;
2014-04-23 17:51:55 -04:00
2014-08-22 13:39:55 -04:00
if ( ProgramTarget . Rules . GUBP_AlwaysBuildWithTools ( HostPlatform , GUBP . bBuildRocket , out bInternalOnly , out SeparateNode ) & & ProgramTarget . Rules . SupportsPlatform ( HostPlatform ) & & SeparateNode )
{
if ( bInternalOnly )
{
AddNode ( new SingleInternalToolsNode ( HostPlatform , ProgramTarget ) ) ;
}
else
{
AddNode ( new SingleToolsNode ( HostPlatform , ProgramTarget ) ) ;
}
}
2014-09-22 12:13:56 -04:00
if ( ProgramTarget . Rules . GUBP_IncludeNonUnityToolTest ( ) )
{
AddNode ( new NonUnityToolNode ( HostPlatform , ProgramTarget ) ) ;
}
2014-08-22 13:39:55 -04:00
}
2014-09-18 14:24:42 -04:00
foreach ( var CodeProj in Branch . CodeProjects )
{
2014-09-22 12:13:56 -04:00
foreach ( var ProgramTarget in CodeProj . Properties . Programs )
2014-09-18 14:24:42 -04:00
{
bool bInternalNodeOnly ;
bool SeparateNode ;
2014-09-22 12:13:56 -04:00
if ( ProgramTarget . Rules . GUBP_AlwaysBuildWithTools ( HostPlatform , GUBP . bBuildRocket , out bInternalNodeOnly , out SeparateNode ) & & ProgramTarget . Rules . SupportsPlatform ( HostPlatform ) & & SeparateNode )
2014-09-18 14:24:42 -04:00
{
if ( bInternalNodeOnly )
{
2014-09-22 12:13:56 -04:00
AddNode ( new SingleInternalToolsNode ( HostPlatform , ProgramTarget ) ) ;
2014-09-18 14:24:42 -04:00
}
else
{
2014-09-22 12:13:56 -04:00
AddNode ( new SingleToolsNode ( HostPlatform , ProgramTarget ) ) ;
2014-09-18 14:24:42 -04:00
}
}
2014-09-22 12:13:56 -04:00
if ( ProgramTarget . Rules . GUBP_IncludeNonUnityToolTest ( ) )
{
AddNode ( new NonUnityToolNode ( HostPlatform , ProgramTarget ) ) ;
}
2014-09-18 14:24:42 -04:00
}
}
2014-04-23 17:51:55 -04:00
2014-08-22 13:39:55 -04:00
AddNode ( new EditorAndToolsNode ( this , HostPlatform ) ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
if ( bOrthogonalizeEditorPlatforms )
{
foreach ( var Plat in ActivePlatforms )
{
if ( Plat ! = HostPlatform & & Plat ! = GetAltHostPlatform ( HostPlatform ) )
{
if ( Platform . Platforms [ HostPlatform ] . CanHostPlatform ( Plat ) )
{
AddNode ( new EditorPlatformNode ( HostPlatform , Plat ) ) ;
}
}
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
bool DoASharedPromotable = false ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
int NumSharedCode = 0 ;
foreach ( var CodeProj in Branch . CodeProjects )
{
var Options = CodeProj . Options ( HostPlatform ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
if ( Options . bIsPromotable & & ! Options . bSeparateGamePromotion )
{
NumSharedCode + + ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
var NonCodeProjectNames = new Dictionary < string , List < UnrealTargetPlatform > > ( ) ;
var NonCodeFormalBuilds = new Dictionary < string , List < TargetRules . GUBPFormalBuild > > ( ) ;
{
var Target = Branch . BaseEngineProject . Properties . Targets [ TargetRules . TargetType . Editor ] ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var Codeless in Target . Rules . GUBP_NonCodeProjects_BaseEditorTypeOnly ( HostPlatform ) )
{
var Proj = Branch . FindGame ( Codeless . Key ) ;
if ( Proj = = null )
{
Log ( System . Diagnostics . TraceEventType . Information , "{0} was listed as a codeless project by GUBP_NonCodeProjects_BaseEditorTypeOnly, however it does not exist in this branch." , Codeless . Key ) ;
}
else if ( Proj . Properties . bIsCodeBasedProject )
{
throw new AutomationException ( "{0} was listed as a codeless project by GUBP_NonCodeProjects_BaseEditorTypeOnly, however it is a code based project." , Codeless . Key ) ;
}
else
{
NonCodeProjectNames . Add ( Codeless . Key , Codeless . Value ) ;
}
}
2014-04-23 18:18:41 -04:00
2014-08-22 13:39:55 -04:00
var TempNonCodeFormalBuilds = Target . Rules . GUBP_GetNonCodeFormalBuilds_BaseEditorTypeOnly ( ) ;
var HostMonos = GetMonolithicPlatformsForUProject ( HostPlatform , Branch . BaseEngineProject , true ) ;
2014-04-23 18:18:41 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var Codeless in TempNonCodeFormalBuilds )
{
if ( NonCodeProjectNames . ContainsKey ( Codeless . Key ) )
{
var PlatList = Codeless . Value ;
var NewPlatList = new List < TargetRules . GUBPFormalBuild > ( ) ;
foreach ( var PlatPair in PlatList )
{
if ( HostMonos . Contains ( PlatPair . TargetPlatform ) )
{
NewPlatList . Add ( PlatPair ) ;
}
}
if ( NewPlatList . Count > 0 )
{
NonCodeFormalBuilds . Add ( Codeless . Key , NewPlatList ) ;
}
}
else
{
Log ( System . Diagnostics . TraceEventType . Information , "{0} was listed as a codeless formal build GUBP_GetNonCodeFormalBuilds_BaseEditorTypeOnly, however it does not exist in this branch." , Codeless . Key ) ;
}
}
}
2014-04-29 21:52:22 -04:00
2014-08-22 13:39:55 -04:00
DoASharedPromotable = NumSharedCode > 0 | | NonCodeProjectNames . Count > 0 | | NonCodeFormalBuilds . Count > 0 ;
2014-04-29 21:52:22 -04:00
2014-08-22 13:39:55 -04:00
if ( ! DoASharedPromotable & & bBuildRocket )
{
throw new AutomationException ( "we were asked to make a rocket build, but this branch does not have a shared promotable." ) ;
}
2014-04-29 21:52:22 -04:00
2014-08-22 13:39:55 -04:00
if ( DoASharedPromotable )
{
AddNode ( new NonUnityTestNode ( HostPlatform ) ) ;
2014-04-29 21:52:22 -04:00
2014-08-22 13:39:55 -04:00
var AgentSharingGroup = "Shared_EditorTests" + HostPlatformNode . StaticGetHostPlatformSuffix ( HostPlatform ) ;
2014-04-29 21:52:22 -04:00
2014-08-22 13:39:55 -04:00
var Options = Branch . BaseEngineProject . Options ( HostPlatform ) ;
2014-04-29 21:52:22 -04:00
2014-08-22 13:39:55 -04:00
if ( ! Options . bIsPromotable | | Options . bSeparateGamePromotion )
{
throw new AutomationException ( "We assume that if we have shared promotable, the base engine is in it." ) ;
}
2014-04-29 21:52:22 -04:00
2014-09-05 21:50:16 -04:00
if ( HostPlatform = = UnrealTargetPlatform . Win64 ) //temp hack till automated testing works on other platforms than Win64
2014-08-22 13:39:55 -04:00
{
2014-05-02 10:44:27 -04:00
2014-08-22 13:39:55 -04:00
var EditorTests = Branch . BaseEngineProject . Properties . Targets [ TargetRules . TargetType . Editor ] . Rules . GUBP_GetEditorTests_EditorTypeOnly ( HostPlatform ) ;
var EditorTestNodes = new List < string > ( ) ;
foreach ( var Test in EditorTests )
{
if ( ! bNoAutomatedTesting )
{
EditorTestNodes . Add ( AddNode ( new UATTestNode ( this , HostPlatform , Branch . BaseEngineProject , Test . Key , Test . Value , AgentSharingGroup ) ) ) ;
foreach ( var NonCodeProject in Branch . NonCodeProjects )
{
if ( ! NonCodeProjectNames . ContainsKey ( NonCodeProject . GameName ) )
{
continue ;
}
if ( HostPlatform = = UnrealTargetPlatform . Mac ) continue ; //temp hack till mac automated testing works
EditorTestNodes . Add ( AddNode ( new UATTestNode ( this , HostPlatform , NonCodeProject , Test . Key , Test . Value , AgentSharingGroup ) ) ) ;
}
}
}
if ( EditorTestNodes . Count > 0 )
{
AddNode ( new GameAggregateNode ( this , HostPlatform , Branch . BaseEngineProject , "AllEditorTests" , EditorTestNodes , 0.0f ) ) ;
}
}
2014-03-14 14:13:41 -04:00
2014-05-02 10:44:27 -04:00
2014-08-22 13:39:55 -04:00
var ServerPlatforms = new List < UnrealTargetPlatform > ( ) ;
var GamePlatforms = new List < UnrealTargetPlatform > ( ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var Kind in BranchInfo . MonolithicKinds )
{
if ( Branch . BaseEngineProject . Properties . Targets . ContainsKey ( Kind ) )
{
var Target = Branch . BaseEngineProject . Properties . Targets [ Kind ] ;
var Platforms = Target . Rules . GUBP_GetPlatforms_MonolithicOnly ( HostPlatform ) ;
if ( Platforms . Contains ( HostPlatform ) )
{
// we want the host platform first since some some pseudodependencies look to see if the shared promotable exists.
Platforms . Remove ( HostPlatform ) ;
Platforms . Insert ( 0 , HostPlatform ) ;
}
foreach ( var Plat in Platforms )
{
if ( ! Platform . Platforms [ HostPlatform ] . CanHostPlatform ( Plat ) )
{
throw new AutomationException ( "Project {0} asked for platform {1} with host {2}, but the host platform cannot build that platform." , Branch . BaseEngineProject . GameName , Plat . ToString ( ) , HostPlatform . ToString ( ) ) ;
}
if ( bNoIOSOnPC & & Plat = = UnrealTargetPlatform . IOS & & HostPlatform = = UnrealTargetPlatform . Win64 )
{
continue ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
if ( ActivePlatforms . Contains ( Plat ) )
{
if ( Kind = = TargetRules . TargetType . Server & & ! ServerPlatforms . Contains ( Plat ) )
{
ServerPlatforms . Add ( Plat ) ;
}
if ( Kind = = TargetRules . TargetType . Game & & ! GamePlatforms . Contains ( Plat ) )
{
GamePlatforms . Add ( Plat ) ;
}
if ( ! GUBPNodes . ContainsKey ( GamePlatformMonolithicsNode . StaticGetFullName ( HostPlatform , Branch . BaseEngineProject , Plat ) ) )
{
AddNode ( new GamePlatformMonolithicsNode ( this , HostPlatform , Branch . BaseEngineProject , Plat ) ) ;
if ( bBuildRocket )
{
AddNode ( new GameMonolithicHeadersNode ( this , HostPlatform , Plat ) ) ;
}
}
}
}
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
var CookedAgentSharingGroup = "Shared_CookedTests" + HostPlatformNode . StaticGetHostPlatformSuffix ( HostPlatform ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
var GameTestNodes = new List < string > ( ) ;
var GameCookNodes = new List < string > ( ) ;
2014-10-09 13:40:13 -04:00
var FormalAgentSharingGroup = "Shared_FormalBuilds" + HostPlatformNode . StaticGetHostPlatformSuffix ( HostPlatform ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
//foreach (var Kind in BranchInfo.MonolithicKinds)//for now, non-code projects don't do client or server.
{
var Kind = TargetRules . TargetType . Game ;
if ( Branch . BaseEngineProject . Properties . Targets . ContainsKey ( Kind ) )
{
var Target = Branch . BaseEngineProject . Properties . Targets [ Kind ] ;
var Platforms = Target . Rules . GUBP_GetPlatforms_MonolithicOnly ( HostPlatform ) ;
foreach ( var Plat in Platforms )
{
if ( ! Platform . Platforms [ HostPlatform ] . CanHostPlatform ( Plat ) )
{
throw new AutomationException ( "Project {0} asked for platform {1} with host {2}, but the host platform cannot build that platform." , Branch . BaseEngineProject . GameName , Plat . ToString ( ) , HostPlatform . ToString ( ) ) ;
}
if ( bNoIOSOnPC & & Plat = = UnrealTargetPlatform . IOS & & HostPlatform = = UnrealTargetPlatform . Win64 )
{
continue ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
if ( ActivePlatforms . Contains ( Plat ) )
{
2014-10-08 10:49:02 -04:00
string CookedPlatform = Platform . Platforms [ Plat ] . GetCookPlatform ( Kind = = TargetRules . TargetType . Server , Kind = = TargetRules . TargetType . Client , "" ) ;
2014-08-22 13:39:55 -04:00
if ( ! GUBPNodes . ContainsKey ( CookNode . StaticGetFullName ( HostPlatform , Branch . BaseEngineProject , CookedPlatform ) ) )
{
GameCookNodes . Add ( AddNode ( new CookNode ( this , HostPlatform , Branch . BaseEngineProject , Plat , CookedPlatform ) ) ) ;
}
if ( ! GUBPNodes . ContainsKey ( GamePlatformCookedAndCompiledNode . StaticGetFullName ( HostPlatform , Branch . BaseEngineProject , Plat ) ) )
{
AddNode ( new GamePlatformCookedAndCompiledNode ( this , HostPlatform , Branch . BaseEngineProject , Plat , false ) ) ;
}
var GameTests = Target . Rules . GUBP_GetGameTests_MonolithicOnly ( HostPlatform , GetAltHostPlatform ( HostPlatform ) , Plat ) ;
var RequiredPlatforms = new List < UnrealTargetPlatform > { Plat } ;
if ( ! bNoAutomatedTesting )
{
var ThisMonoGameTestNodes = new List < string > ( ) ;
foreach ( var Test in GameTests )
{
var TestName = Test . Key + "_" + Plat . ToString ( ) ;
ThisMonoGameTestNodes . Add ( AddNode ( new UATTestNode ( this , HostPlatform , Branch . BaseEngineProject , TestName , Test . Value , CookedAgentSharingGroup , false , RequiredPlatforms ) ) ) ;
}
if ( ThisMonoGameTestNodes . Count > 0 )
{
GameTestNodes . Add ( AddNode ( new GameAggregateNode ( this , HostPlatform , Branch . BaseEngineProject , "CookedTests_" + Plat . ToString ( ) + "_" + Kind . ToString ( ) + HostPlatformNode . StaticGetHostPlatformSuffix ( HostPlatform ) , ThisMonoGameTestNodes , 0.0f ) ) ) ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var NonCodeProject in Branch . NonCodeProjects )
{
if ( ! NonCodeProjectNames . ContainsKey ( NonCodeProject . GameName ) | | ! NonCodeProjectNames [ NonCodeProject . GameName ] . Contains ( Plat ) )
{
continue ;
}
if ( ! GUBPNodes . ContainsKey ( CookNode . StaticGetFullName ( HostPlatform , NonCodeProject , CookedPlatform ) ) )
{
GameCookNodes . Add ( AddNode ( new CookNode ( this , HostPlatform , NonCodeProject , Plat , CookedPlatform ) ) ) ;
}
if ( ! GUBPNodes . ContainsKey ( GamePlatformCookedAndCompiledNode . StaticGetFullName ( HostPlatform , NonCodeProject , Plat ) ) )
{
AddNode ( new GamePlatformCookedAndCompiledNode ( this , HostPlatform , NonCodeProject , Plat , false ) ) ;
if ( NonCodeFormalBuilds . ContainsKey ( NonCodeProject . GameName ) )
{
var PlatList = NonCodeFormalBuilds [ NonCodeProject . GameName ] ;
foreach ( var PlatPair in PlatList )
{
if ( PlatPair . TargetPlatform = = Plat )
{
2014-09-09 13:57:48 -04:00
var NodeName = AddNode ( new FormalBuildNode ( this , NonCodeProject , HostPlatform , new List < UnrealTargetPlatform > ( ) { Plat } , new List < UnrealTargetConfiguration > ( ) { PlatPair . TargetConfig } ) ) ;
// we don't want this delayed
// this would normally wait for the testing phase, we just want to build it right away
RemovePseudodependencyFromNode (
CookNode . StaticGetFullName ( HostPlatform , NonCodeProject , CookedPlatform ) ,
WaitForTestShared . StaticGetFullName ( ) ) ;
RemovePseudodependencyFromNode (
CookNode . StaticGetFullName ( HostPlatform , NonCodeProject , CookedPlatform ) ,
CookNode . StaticGetFullName ( HostPlatform , Branch . BaseEngineProject , CookedPlatform ) ) ;
string BuildAgentSharingGroup = "" ;
2014-08-18 12:09:20 -04:00
if ( Options . bSeparateGamePromotion )
{
2014-09-09 13:57:48 -04:00
BuildAgentSharingGroup = NonCodeProject . GameName + "_MakeFormalBuild_" + Plat . ToString ( ) + HostPlatformNode . StaticGetHostPlatformSuffix ( HostPlatform ) ;
if ( Plat = = UnrealTargetPlatform . IOS | | Plat = = UnrealTargetPlatform . Android ) // These trash build products, so we need to use different agents
2014-09-09 12:18:17 -04:00
{
2014-09-09 13:57:48 -04:00
BuildAgentSharingGroup = "" ;
2014-09-09 12:18:17 -04:00
}
2014-09-09 13:57:48 -04:00
GUBPNodes [ CookNode . StaticGetFullName ( HostPlatform , NonCodeProject , CookedPlatform ) ] . AgentSharingGroup = BuildAgentSharingGroup ;
GUBPNodes [ GamePlatformCookedAndCompiledNode . StaticGetFullName ( HostPlatform , NonCodeProject , Plat ) ] . AgentSharingGroup = BuildAgentSharingGroup ;
GUBPNodes [ NodeName ] . AgentSharingGroup = BuildAgentSharingGroup ;
2014-09-09 12:18:17 -04:00
}
2014-10-09 13:40:13 -04:00
else
{
GUBPNodes [ NodeName ] . AgentSharingGroup = FormalAgentSharingGroup ;
if ( Plat = = UnrealTargetPlatform . XboxOne )
{
GUBPNodes [ NodeName ] . AgentSharingGroup = "" ;
}
}
2014-09-09 13:57:48 -04:00
if ( PlatPair . bTest )
{
AddNode ( new FormalBuildTestNode ( this , NonCodeProject , HostPlatform , Plat , PlatPair . TargetConfig ) ) ;
}
2014-09-09 12:18:17 -04:00
}
}
}
2014-09-09 13:57:48 -04:00
}
2014-08-22 13:39:55 -04:00
if ( ! bNoAutomatedTesting )
{
2014-09-09 13:57:48 -04:00
if ( HostPlatform = = UnrealTargetPlatform . Mac ) continue ; //temp hack till mac automated testing works
var ThisMonoGameTestNodes = new List < string > ( ) ;
foreach ( var Test in GameTests )
{
var TestName = Test . Key + "_" + Plat . ToString ( ) ;
ThisMonoGameTestNodes . Add ( AddNode ( new UATTestNode ( this , HostPlatform , NonCodeProject , TestName , Test . Value , CookedAgentSharingGroup , false , RequiredPlatforms ) ) ) ;
}
if ( ThisMonoGameTestNodes . Count > 0 )
{
GameTestNodes . Add ( AddNode ( new GameAggregateNode ( this , HostPlatform , NonCodeProject , "CookedTests_" + Plat . ToString ( ) + "_" + Kind . ToString ( ) + HostPlatformNode . StaticGetHostPlatformSuffix ( HostPlatform ) , ThisMonoGameTestNodes , 0.0f ) ) ) ;
}
}
}
}
}
}
2014-08-22 13:39:55 -04:00
}
2014-03-14 14:13:41 -04:00
#if false
//for now, non-code projects don't do client or server.
foreach ( var ServerPlatform in ServerPlatforms )
{
var ServerTarget = Branch . BaseEngineProject . Properties . Targets [ TargetRules . TargetType . Server ] ;
foreach ( var GamePlatform in GamePlatforms )
{
var Target = Branch . BaseEngineProject . Properties . Targets [ TargetRules . TargetType . Game ] ;
foreach ( var NonCodeProject in Branch . NonCodeProjects )
{
if ( ! NonCodeProjectNames . ContainsKey ( NonCodeProject . GameName ) | | ! NonCodeProjectNames . ContainsKey ( NonCodeProject . GameName ) | |
! NonCodeProjectNames [ NonCodeProject . GameName ] . Contains ( ServerPlatform ) | | ! NonCodeProjectNames [ NonCodeProject . GameName ] . Contains ( GamePlatform ) )
{
continue ;
}
var ClientServerTests = Target . Rules . GUBP_GetClientServerTests_MonolithicOnly ( HostPlatform , GetAltHostPlatform ( HostPlatform ) , ServerPlatform , GamePlatform ) ;
var RequiredPlatforms = new List < UnrealTargetPlatform > { ServerPlatform } ;
if ( ServerPlatform ! = GamePlatform )
{
RequiredPlatforms . Add ( GamePlatform ) ;
}
foreach ( var Test in ClientServerTests )
{
GameTestNodes . Add ( AddNode ( new UATTestNode ( this , HostPlatform , NonCodeProject , Test . Key + "_" + GamePlatform . ToString ( ) + "_" + ServerPlatform . ToString ( ) , Test . Value , false , RequiredPlatforms , true ) ) ) ;
}
}
}
}
#endif
2014-08-22 13:39:55 -04:00
if ( GameTestNodes . Count > 0 )
{
AddNode ( new GameAggregateNode ( this , HostPlatform , Branch . BaseEngineProject , "AllCookedTests" , GameTestNodes ) ) ;
}
}
2014-10-09 13:40:13 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var CodeProj in Branch . CodeProjects )
{
var Options = CodeProj . Options ( HostPlatform ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
if ( ! Options . bIsPromotable & & ! Options . bTestWithShared )
{
continue ; // we skip things that aren't promotable and aren't tested
}
var AgentShareName = CodeProj . GameName ;
if ( ! Options . bSeparateGamePromotion )
{
AgentShareName = "Shared" ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
AddNode ( new EditorGameNode ( this , HostPlatform , CodeProj ) ) ;
2014-09-05 21:50:16 -04:00
if ( ! bNoAutomatedTesting & & HostPlatform = = UnrealTargetPlatform . Win64 ) //temp hack till automated testing works on other platforms than Win64
2014-08-22 13:39:55 -04:00
{
var EditorTests = CodeProj . Properties . Targets [ TargetRules . TargetType . Editor ] . Rules . GUBP_GetEditorTests_EditorTypeOnly ( HostPlatform ) ;
var EditorTestNodes = new List < string > ( ) ;
string AgentSharingGroup = "" ;
if ( EditorTests . Count > 1 )
{
AgentSharingGroup = AgentShareName + "_EditorTests" + HostPlatformNode . StaticGetHostPlatformSuffix ( HostPlatform ) ;
}
foreach ( var Test in EditorTests )
{
EditorTestNodes . Add ( AddNode ( new UATTestNode ( this , HostPlatform , CodeProj , Test . Key , Test . Value , AgentSharingGroup ) ) ) ;
}
if ( EditorTestNodes . Count > 0 )
{
AddNode ( new GameAggregateNode ( this , HostPlatform , CodeProj , "AllEditorTests" , EditorTestNodes , 0.0f ) ) ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
var CookedAgentSharingGroup = AgentShareName + "_CookedTests" + HostPlatformNode . StaticGetHostPlatformSuffix ( HostPlatform ) ;
2014-10-09 13:40:13 -04:00
var FormalAgentSharingGroup = "Shared_FormalBuilds" + HostPlatformNode . StaticGetHostPlatformSuffix ( HostPlatform ) ;
2014-08-22 13:39:55 -04:00
var ServerPlatforms = new List < UnrealTargetPlatform > ( ) ;
var GamePlatforms = new List < UnrealTargetPlatform > ( ) ;
var GameTestNodes = new List < string > ( ) ;
foreach ( var Kind in BranchInfo . MonolithicKinds )
{
if ( CodeProj . Properties . Targets . ContainsKey ( Kind ) )
{
var Target = CodeProj . Properties . Targets [ Kind ] ;
var Platforms = Target . Rules . GUBP_GetPlatforms_MonolithicOnly ( HostPlatform ) ;
2014-08-18 13:29:39 -04:00
var AdditionalPlatforms = Target . Rules . GUBP_GetBuildOnlyPlatforms_MonolithicOnly ( HostPlatform ) ;
var AllPlatforms = Platforms . Union ( AdditionalPlatforms ) ;
foreach ( var Plat in AllPlatforms )
2014-08-22 13:39:55 -04:00
{
if ( ! Platform . Platforms [ HostPlatform ] . CanHostPlatform ( Plat ) )
{
throw new AutomationException ( "Project {0} asked for platform {1} with host {2}, but the host platform cannot build that platform." , CodeProj . GameName , Plat . ToString ( ) , HostPlatform . ToString ( ) ) ;
}
if ( bNoIOSOnPC & & Plat = = UnrealTargetPlatform . IOS & & HostPlatform = = UnrealTargetPlatform . Win64 )
{
continue ;
}
if ( ActivePlatforms . Contains ( Plat ) )
{
if ( Kind = = TargetRules . TargetType . Server & & ! ServerPlatforms . Contains ( Plat ) )
{
ServerPlatforms . Add ( Plat ) ;
}
if ( Kind = = TargetRules . TargetType . Game & & ! GamePlatforms . Contains ( Plat ) )
{
GamePlatforms . Add ( Plat ) ;
}
if ( ! GUBPNodes . ContainsKey ( GamePlatformMonolithicsNode . StaticGetFullName ( HostPlatform , CodeProj , Plat ) ) )
{
AddNode ( new GamePlatformMonolithicsNode ( this , HostPlatform , CodeProj , Plat ) ) ;
}
2014-08-18 13:29:39 -04:00
if ( ! AdditionalPlatforms . Contains ( Plat ) )
{
2014-09-09 13:57:48 -04:00
string CookedPlatform = Platform . Platforms [ Plat ] . GetCookPlatform ( Kind = = TargetRules . TargetType . Server , Kind = = TargetRules . TargetType . Client , "" ) ;
2014-10-08 10:49:02 -04:00
if ( Target . Rules . GUBP_AlternateCookPlatform ( HostPlatform , CookedPlatform ) ! = "" )
{
CookedPlatform = Target . Rules . GUBP_AlternateCookPlatform ( HostPlatform , CookedPlatform ) ;
}
2014-09-09 13:57:48 -04:00
if ( ! GUBPNodes . ContainsKey ( CookNode . StaticGetFullName ( HostPlatform , CodeProj , CookedPlatform ) ) )
{
AddNode ( new CookNode ( this , HostPlatform , CodeProj , Plat , CookedPlatform ) ) ;
}
if ( ! GUBPNodes . ContainsKey ( GamePlatformCookedAndCompiledNode . StaticGetFullName ( HostPlatform , CodeProj , Plat ) ) )
{
AddNode ( new GamePlatformCookedAndCompiledNode ( this , HostPlatform , CodeProj , Plat , true ) ) ;
}
var FormalBuildConfigs = Target . Rules . GUBP_GetConfigsForFormalBuilds_MonolithicOnly ( HostPlatform ) ;
2014-05-01 07:33:06 -04:00
2014-09-09 13:57:48 -04:00
foreach ( var Config in FormalBuildConfigs )
{
string FormalNodeName = null ;
if ( Kind = = TargetRules . TargetType . Client )
{
if ( Plat = = Config . TargetPlatform )
{
FormalNodeName = AddNode ( new FormalBuildNode ( this , CodeProj , HostPlatform , InClientTargetPlatforms : new List < UnrealTargetPlatform > ( ) { Config . TargetPlatform } , InClientConfigs : new List < UnrealTargetConfiguration > ( ) { Config . TargetConfig } , InClientNotGame : true ) ) ;
}
}
else if ( Kind = = TargetRules . TargetType . Server )
{
if ( Plat = = Config . TargetPlatform )
{
FormalNodeName = AddNode ( new FormalBuildNode ( this , CodeProj , HostPlatform , InServerTargetPlatforms : new List < UnrealTargetPlatform > ( ) { Config . TargetPlatform } , InServerConfigs : new List < UnrealTargetConfiguration > ( ) { Config . TargetConfig } ) ) ;
}
}
else if ( Kind = = TargetRules . TargetType . Game )
{
if ( Plat = = Config . TargetPlatform )
{
FormalNodeName = AddNode ( new FormalBuildNode ( this , CodeProj , HostPlatform , InClientTargetPlatforms : new List < UnrealTargetPlatform > ( ) { Config . TargetPlatform } , InClientConfigs : new List < UnrealTargetConfiguration > ( ) { Config . TargetConfig } ) ) ;
}
}
if ( FormalNodeName ! = null )
{
// we don't want this delayed
// this would normally wait for the testing phase, we just want to build it right away
RemovePseudodependencyFromNode (
CookNode . StaticGetFullName ( HostPlatform , CodeProj , CookedPlatform ) ,
WaitForTestShared . StaticGetFullName ( ) ) ;
RemovePseudodependencyFromNode (
CookNode . StaticGetFullName ( HostPlatform , CodeProj , CookedPlatform ) ,
CookNode . StaticGetFullName ( HostPlatform , Branch . BaseEngineProject , CookedPlatform ) ) ;
string BuildAgentSharingGroup = "" ;
2014-10-09 13:40:13 -04:00
2014-09-09 13:57:48 -04:00
if ( Options . bSeparateGamePromotion )
{
BuildAgentSharingGroup = CodeProj . GameName + "_MakeFormalBuild_" + Plat . ToString ( ) + HostPlatformNode . StaticGetHostPlatformSuffix ( HostPlatform ) ;
if ( Plat = = UnrealTargetPlatform . IOS | | Plat = = UnrealTargetPlatform . Android | | Plat = = UnrealTargetPlatform . XboxOne ) // These trash build products, so we need to use different agents
{
BuildAgentSharingGroup = "" ;
}
GUBPNodes [ CookNode . StaticGetFullName ( HostPlatform , CodeProj , CookedPlatform ) ] . AgentSharingGroup = BuildAgentSharingGroup ;
GUBPNodes [ GamePlatformCookedAndCompiledNode . StaticGetFullName ( HostPlatform , CodeProj , Plat ) ] . AgentSharingGroup = BuildAgentSharingGroup ;
GUBPNodes [ FormalNodeName ] . AgentSharingGroup = BuildAgentSharingGroup ;
}
2014-10-09 13:40:13 -04:00
else
{
GUBPNodes [ FormalNodeName ] . AgentSharingGroup = FormalAgentSharingGroup ;
if ( Plat = = UnrealTargetPlatform . XboxOne )
{
GUBPNodes [ FormalNodeName ] . AgentSharingGroup = "" ;
}
}
2014-09-09 13:57:48 -04:00
if ( Config . bTest )
{
AddNode ( new FormalBuildTestNode ( this , CodeProj , HostPlatform , Plat , Config . TargetConfig ) ) ;
}
}
}
if ( ! bNoAutomatedTesting )
{
if ( HostPlatform = = UnrealTargetPlatform . Mac ) continue ; //temp hack till mac automated testing works
var GameTests = Target . Rules . GUBP_GetGameTests_MonolithicOnly ( HostPlatform , GetAltHostPlatform ( HostPlatform ) , Plat ) ;
var RequiredPlatforms = new List < UnrealTargetPlatform > { Plat } ;
var ThisMonoGameTestNodes = new List < string > ( ) ;
2014-07-31 09:28:43 -04:00
2014-09-09 13:57:48 -04:00
foreach ( var Test in GameTests )
{
var TestNodeName = Test . Key + "_" + Plat . ToString ( ) ;
ThisMonoGameTestNodes . Add ( AddNode ( new UATTestNode ( this , HostPlatform , CodeProj , TestNodeName , Test . Value , CookedAgentSharingGroup , false , RequiredPlatforms ) ) ) ;
}
if ( ThisMonoGameTestNodes . Count > 0 )
{
GameTestNodes . Add ( AddNode ( new GameAggregateNode ( this , HostPlatform , CodeProj , "CookedTests_" + Plat . ToString ( ) + "_" + Kind . ToString ( ) + HostPlatformNode . StaticGetHostPlatformSuffix ( HostPlatform ) , ThisMonoGameTestNodes , 0.0f ) ) ) ;
}
}
}
}
}
}
2014-08-18 13:29:39 -04:00
}
2014-09-09 13:57:48 -04:00
if ( ! bNoAutomatedTesting )
{
foreach ( var ServerPlatform in ServerPlatforms )
{
foreach ( var GamePlatform in GamePlatforms )
{
if ( HostPlatform = = UnrealTargetPlatform . Mac ) continue ; //temp hack till mac automated testing works
var Target = CodeProj . Properties . Targets [ TargetRules . TargetType . Game ] ;
var ClientServerTests = Target . Rules . GUBP_GetClientServerTests_MonolithicOnly ( HostPlatform , GetAltHostPlatform ( HostPlatform ) , ServerPlatform , GamePlatform ) ;
var RequiredPlatforms = new List < UnrealTargetPlatform > { ServerPlatform } ;
if ( ServerPlatform ! = GamePlatform )
{
RequiredPlatforms . Add ( GamePlatform ) ;
}
foreach ( var Test in ClientServerTests )
{
var TestNodeName = Test . Key + "_" + GamePlatform . ToString ( ) + "_" + ServerPlatform . ToString ( ) ;
GameTestNodes . Add ( AddNode ( new UATTestNode ( this , HostPlatform , CodeProj , TestNodeName , Test . Value , CookedAgentSharingGroup , false , RequiredPlatforms ) ) ) ;
}
}
}
if ( GameTestNodes . Count > 0 )
{
AddNode ( new GameAggregateNode ( this , HostPlatform , CodeProj , "AllCookedTests" , GameTestNodes ) ) ;
}
}
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
int NumSharedAllHosts = 0 ;
foreach ( var CodeProj in Branch . CodeProjects )
{
if ( CodeProj . Properties . Targets . ContainsKey ( TargetRules . TargetType . Editor ) )
{
bool AnySeparate = false ;
var PromotedHosts = new List < UnrealTargetPlatform > ( ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var HostPlatform in HostPlatforms )
{
var Options = CodeProj . Options ( HostPlatform ) ;
AnySeparate = AnySeparate | | Options . bSeparateGamePromotion ;
if ( Options . bIsPromotable )
{
if ( ! Options . bSeparateGamePromotion )
{
NumSharedAllHosts + + ;
}
PromotedHosts . Add ( HostPlatform ) ;
}
}
if ( PromotedHosts . Count > 0 )
{
AddNode ( new GameAggregatePromotableNode ( this , PromotedHosts , CodeProj ) ) ;
if ( AnySeparate )
{
AddNode ( new WaitForGamePromotionUserInput ( this , CodeProj , false ) ) ;
AddNode ( new GameLabelPromotableNode ( this , CodeProj , false ) ) ;
AddNode ( new WaitForGamePromotionUserInput ( this , CodeProj , true ) ) ;
AddNode ( new GameLabelPromotableNode ( this , CodeProj , true ) ) ;
}
}
}
}
if ( NumSharedAllHosts > 0 )
{
AddNode ( new GameAggregatePromotableNode ( this , HostPlatforms , Branch . BaseEngineProject ) ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
AddNode ( new SharedAggregatePromotableNode ( this , HostPlatforms ) ) ;
AddNode ( new WaitForSharedPromotionUserInput ( this , false ) ) ;
AddNode ( new SharedLabelPromotableNode ( this , false ) ) ;
AddNode ( new WaitForTestShared ( this ) ) ;
AddNode ( new WaitForSharedPromotionUserInput ( this , true ) ) ;
AddNode ( new SharedLabelPromotableNode ( this , true ) ) ;
}
foreach ( var HostPlatform in HostPlatforms )
{
AddCustomNodes ( HostPlatform ) ;
}
if ( HasNode ( ToolsForCompileNode . StaticGetFullName ( UnrealTargetPlatform . Win64 ) ) )
{
if ( HasNode ( GamePlatformMonolithicsNode . StaticGetFullName ( UnrealTargetPlatform . Mac , Branch . BaseEngineProject , UnrealTargetPlatform . IOS ) ) & & HasNode ( ToolsNode . StaticGetFullName ( UnrealTargetPlatform . Win64 ) ) )
{
//AddNode(new IOSOnPCTestNode(this)); - Disable IOSOnPCTest until a1011 crash is fixed
2014-09-18 14:24:42 -04:00
}
2014-08-22 13:39:55 -04:00
if ( ! bPreflightBuild )
{
AddNode ( new CleanSharedTempStorageNode ( this ) ) ;
}
}
2014-06-30 16:04:59 -04:00
#if false
// this doesn't work for lots of reasons...we can't figure out what the dependencies are until far later
2014-06-13 06:48:43 -04:00
if ( bPreflightBuild )
{
GeneralSuccessNode PreflightSuccessNode = new GeneralSuccessNode ( "Preflight" ) ;
foreach ( var NodeToDo in GUBPNodes )
{
if ( NodeToDo . Value . RunInEC ( ) )
{
PreflightSuccessNode . AddPseudodependency ( NodeToDo . Key ) ;
}
}
AddNode ( PreflightSuccessNode ) ;
2014-04-29 21:53:42 -04:00
}
2014-06-30 16:04:59 -04:00
#endif
2014-08-22 13:39:55 -04:00
foreach ( var NodeToDo in GUBPNodes )
{
foreach ( var Dep in GUBPNodes [ NodeToDo . Key ] . FullNamesOfDependencies )
{
if ( ! GUBPNodes . ContainsKey ( Dep ) )
{
throw new AutomationException ( "Node {0} is not in the full graph. It is a dependency of {1}." , Dep , NodeToDo . Key ) ;
}
if ( Dep = = NodeToDo . Key )
{
throw new AutomationException ( "Node {0} has a self arc." , NodeToDo . Key ) ;
}
}
foreach ( var Dep in GUBPNodes [ NodeToDo . Key ] . FullNamesOfPseudosependencies )
{
if ( ! GUBPNodes . ContainsKey ( Dep ) )
{
throw new AutomationException ( "Node {0} is not in the full graph. It is a pseudodependency of {1}." , Dep , NodeToDo . Key ) ;
}
if ( Dep = = NodeToDo . Key )
{
throw new AutomationException ( "Node {0} has a self pseudoarc." , NodeToDo . Key ) ;
}
}
}
foreach ( var NodeToDo in GUBPNodes )
{
ComputeDependentCISFrequencyQuantumShift ( NodeToDo . Key ) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
if ( bCleanLocalTempStorage ) // shared temp storage can never be wiped
{
DeleteLocalTempStorageManifests ( CmdEnv ) ;
}
2014-05-02 10:44:27 -04:00
2014-08-22 13:39:55 -04:00
GUBPNodesControllingTrigger = new Dictionary < string , string > ( ) ;
GUBPNodesControllingTriggerDotName = new Dictionary < string , string > ( ) ;
2014-05-02 10:44:27 -04:00
2014-08-22 13:39:55 -04:00
var FullNodeList = new Dictionary < string , string > ( ) ;
var FullNodeListSortKey = new Dictionary < string , int > ( ) ;
var FullNodeDirectDependencies = new Dictionary < string , string > ( ) ;
{
Log ( "******* {0} GUBP Nodes" , GUBPNodes . Count ) ;
var SortedNodes = TopologicalSort ( new HashSet < string > ( GUBPNodes . Keys ) , LocalOnly : true , DoNotConsiderCompletion : true ) ;
int Count = 0 ;
foreach ( var Node in SortedNodes )
{
string Note = GetControllingTriggerDotName ( Node ) ;
if ( Note = = "" )
{
Note = CISFrequencyQuantumShiftString ( Node ) ;
}
if ( Note = = "" )
{
Note = "always" ;
}
if ( GUBPNodes [ Node ] . RunInEC ( ) )
{
var Deps = GetECDependencies ( Node ) ;
string All = "" ;
foreach ( var Dep in Deps )
{
if ( All ! = "" )
{
All + = " " ;
}
All + = Dep ;
}
Log ( " {0}: {1} {2}" , Node , Note , All ) ;
FullNodeList . Add ( Node , Note ) ;
FullNodeDirectDependencies . Add ( Node , All ) ;
FullNodeListSortKey . Add ( Node , Count ) ;
Count + + ;
}
else
{
Log ( " {0}: {1} [Aggregate]" , Node , Note ) ;
}
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
bool bOnlyNode = false ;
bool bRelatedToNode = false ;
bool bGraphSubset = false ;
var NodesToDo = new HashSet < string > ( ) ;
2014-09-03 10:12:50 -04:00
2014-08-22 13:39:55 -04:00
{
2014-09-03 10:12:50 -04:00
string NodeSpec = ParseParamValue ( "Node" ) ;
2014-08-22 13:39:55 -04:00
if ( String . IsNullOrEmpty ( NodeSpec ) )
2014-09-03 10:12:50 -04:00
{
2014-08-22 13:39:55 -04:00
NodeSpec = ParseParamValue ( "RelatedToNode" ) ;
if ( ! String . IsNullOrEmpty ( NodeSpec ) )
{
bRelatedToNode = true ;
}
}
if ( String . IsNullOrEmpty ( NodeSpec ) & & CommanderSetup )
{
NodeSpec = ParseParamValue ( "SetupNode" ) ;
if ( String . IsNullOrEmpty ( NodeSpec ) )
{
NodeSpec = ParseParamValue ( "SetupRelatedToNode" ) ;
if ( ! String . IsNullOrEmpty ( NodeSpec ) )
{
bRelatedToNode = true ;
}
}
}
if ( String . IsNullOrEmpty ( NodeSpec ) )
{
NodeSpec = ParseParamValue ( "OnlyNode" ) ;
if ( ! String . IsNullOrEmpty ( NodeSpec ) )
{
bOnlyNode = true ;
}
}
if ( String . IsNullOrEmpty ( NodeSpec ) & & bBuildRocket )
{
// rocket is the shared promotable plus some other stuff and nothing else
bRelatedToNode = true ;
NodeSpec = "Rocket_Aggregate" ;
if ( ! ParseParam ( "RocketValidate" ) )
{
//build a full promotable NodeSpec = SharedAggregatePromotableNode.StaticGetFullName() + "+" + NodeSpec;
}
else if ( ! bFake )
{
NodeSpec = "Rocket_MakeBuild+" + NodeSpec ;
}
}
if ( ! String . IsNullOrEmpty ( NodeSpec ) )
{
bGraphSubset = true ;
if ( NodeSpec . Equals ( "Noop" , StringComparison . InvariantCultureIgnoreCase ) )
{
Log ( "Request for Noop node, done." ) ;
PrintRunTime ( ) ;
return ;
}
List < string > Nodes = new List < string > ( NodeSpec . Split ( '+' ) ) ;
foreach ( var NodeArg in Nodes )
{
var NodeName = NodeArg . Trim ( ) ;
bool bFoundAnything = false ;
if ( ! String . IsNullOrEmpty ( NodeName ) )
{
foreach ( var Node in GUBPNodes )
{
if ( Node . Value . GetFullName ( ) . Equals ( NodeArg , StringComparison . InvariantCultureIgnoreCase ) | |
Node . Value . AgentSharingGroup . Equals ( NodeArg , StringComparison . InvariantCultureIgnoreCase )
)
{
if ( ! NodesToDo . Contains ( Node . Key ) )
{
NodesToDo . Add ( Node . Key ) ;
}
bFoundAnything = true ;
}
}
if ( ! bFoundAnything )
{
throw new AutomationException ( "Could not find node named {0}" , NodeName ) ;
}
}
}
}
}
string GameSpec = ParseParamValue ( "Game" ) ;
if ( ! String . IsNullOrEmpty ( GameSpec ) )
{
bGraphSubset = true ;
List < string > Games = new List < string > ( GameSpec . Split ( '+' ) ) ;
foreach ( var GameArg in Games )
{
var GameName = GameArg . Trim ( ) ;
if ( ! String . IsNullOrEmpty ( GameName ) )
{
foreach ( var GameProj in Branch . CodeProjects )
{
if ( GameProj . GameName . Equals ( GameName , StringComparison . InvariantCultureIgnoreCase ) )
{
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
NodesToDo . Add ( GameAggregatePromotableNode . StaticGetFullName ( GameProj ) ) ;
foreach ( var Node in GUBPNodes )
{
if ( Node . Value . GameNameIfAnyForTempStorage ( ) = = GameProj . GameName )
{
NodesToDo . Add ( Node . Key ) ;
}
}
GameName = null ;
}
}
if ( GameName ! = null )
{
foreach ( var GameProj in Branch . NonCodeProjects )
{
if ( GameProj . GameName . Equals ( GameName , StringComparison . InvariantCultureIgnoreCase ) )
{
foreach ( var Node in GUBPNodes )
{
if ( Node . Value . GameNameIfAnyForTempStorage ( ) = = GameProj . GameName )
{
NodesToDo . Add ( Node . Key ) ;
}
}
GameName = null ;
}
}
}
if ( GameName ! = null )
{
throw new AutomationException ( "Could not find game named {0}" , GameName ) ;
}
}
}
}
if ( NodesToDo . Count = = 0 )
{
Log ( "No nodes specified, adding all nodes" ) ;
foreach ( var Node in GUBPNodes )
{
NodesToDo . Add ( Node . Key ) ;
}
}
else if ( TimeIndex ! = 0 )
{
Log ( "Check to make sure we didn't ask for nodes that will be culled by time index" ) ;
foreach ( var NodeToDo in NodesToDo )
{
if ( TimeIndex % ( 1 < < GUBPNodes [ NodeToDo ] . DependentCISFrequencyQuantumShift ( ) ) ! = 0 )
{
throw new AutomationException ( "You asked specifically for node {0}, but it is culled by the time quantum: TimeIndex = {1}, DependentCISFrequencyQuantumShift = {2}." , NodeToDo , TimeIndex , GUBPNodes [ NodeToDo ] . DependentCISFrequencyQuantumShift ( ) ) ;
}
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
Log ( "Desired Nodes" ) ;
foreach ( var NodeToDo in NodesToDo )
{
Log ( " {0}" , NodeToDo ) ;
}
// if we are doing related to, then find things that depend on the selected nodes
if ( bRelatedToNode )
{
bool bDoneWithDependencies = false ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
while ( ! bDoneWithDependencies )
{
bDoneWithDependencies = true ;
var Fringe = new HashSet < string > ( ) ;
foreach ( var NodeToDo in GUBPNodes )
{
if ( ! NodesToDo . Contains ( NodeToDo . Key ) )
{
foreach ( var Dep in GUBPNodes [ NodeToDo . Key ] . FullNamesOfDependencies )
{
if ( ! GUBPNodes . ContainsKey ( Dep ) )
{
throw new AutomationException ( "Node {0} is not in the graph. It is a dependency of {1}." , Dep , NodeToDo . Key ) ;
}
if ( NodesToDo . Contains ( Dep ) )
{
Fringe . Add ( NodeToDo . Key ) ;
bDoneWithDependencies = false ;
}
}
foreach ( var Dep in GUBPNodes [ NodeToDo . Key ] . FullNamesOfPseudosependencies )
{
if ( ! GUBPNodes . ContainsKey ( Dep ) )
{
throw new AutomationException ( "Node {0} is not in the graph. It is a pseudodependency of {1}." , Dep , NodeToDo . Key ) ;
}
}
}
}
NodesToDo . UnionWith ( Fringe ) ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
// find things that our nodes depend on
if ( ! bOnlyNode )
{
bool bDoneWithDependencies = false ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
while ( ! bDoneWithDependencies )
{
bDoneWithDependencies = true ;
var Fringe = new HashSet < string > ( ) ;
foreach ( var NodeToDo in NodesToDo )
{
foreach ( var Dep in GUBPNodes [ NodeToDo ] . FullNamesOfDependencies )
{
if ( ! GUBPNodes . ContainsKey ( Dep ) )
{
throw new AutomationException ( "Node {0} is not in the graph. It is a dependency of {1}." , Dep , NodeToDo ) ;
}
if ( ! NodesToDo . Contains ( Dep ) )
{
Fringe . Add ( Dep ) ;
bDoneWithDependencies = false ;
}
}
foreach ( var Dep in GUBPNodes [ NodeToDo ] . FullNamesOfPseudosependencies )
{
if ( ! GUBPNodes . ContainsKey ( Dep ) )
{
throw new AutomationException ( "Node {0} is not in the graph. It is a pseudodependency of {1}." , Dep , NodeToDo ) ;
}
}
}
NodesToDo . UnionWith ( Fringe ) ;
}
}
if ( TimeIndex ! = 0 )
{
Log ( "Culling based on time index" ) ;
var NewNodesToDo = new HashSet < string > ( ) ;
foreach ( var NodeToDo in NodesToDo )
{
if ( TimeIndex % ( 1 < < GUBPNodes [ NodeToDo ] . DependentCISFrequencyQuantumShift ( ) ) = = 0 )
{
Log ( " Keeping {0}" , NodeToDo ) ;
NewNodesToDo . Add ( NodeToDo ) ;
}
else
{
Log ( " Rejecting {0}" , NodeToDo ) ;
}
}
NodesToDo = NewNodesToDo ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
if ( CommanderSetup )
{
if ( ! String . IsNullOrEmpty ( ExplicitTrigger ) )
{
bool bFoundIt = false ;
foreach ( var Node in GUBPNodes )
{
if ( Node . Value . GetFullName ( ) . Equals ( ExplicitTrigger , StringComparison . InvariantCultureIgnoreCase ) )
{
if ( Node . Value . TriggerNode ( ) & & Node . Value . RunInEC ( ) )
{
Node . Value . SetAsExplicitTrigger ( ) ;
bFoundIt = true ;
break ;
}
}
}
if ( ! bFoundIt )
{
throw new AutomationException ( "Could not find trigger node named {0}" , ExplicitTrigger ) ;
}
}
else
{
if ( bSkipTriggers )
{
foreach ( var Node in GUBPNodes )
{
if ( Node . Value . TriggerNode ( ) & & Node . Value . RunInEC ( ) )
{
Node . Value . SetAsExplicitTrigger ( ) ;
}
}
}
}
}
2014-08-18 13:29:39 -04:00
if ( bPreflightBuild )
{
Log ( "Culling triggers and downstream for preflight builds " ) ;
var NewNodesToDo = new HashSet < string > ( ) ;
foreach ( var NodeToDo in NodesToDo )
{
var TriggerDot = GetControllingTriggerDotName ( NodeToDo ) ;
if ( TriggerDot = = "" & & ! GUBPNodes [ NodeToDo ] . TriggerNode ( ) )
{
Log ( " Keeping {0}" , NodeToDo ) ;
NewNodesToDo . Add ( NodeToDo ) ;
}
else
{
Log ( " Rejecting {0}" , NodeToDo ) ;
}
}
NodesToDo = NewNodesToDo ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
GUBPNodesCompleted = new Dictionary < string , bool > ( ) ;
GUBPNodesHistory = new Dictionary < string , NodeHistory > ( ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
Log ( "******* Caching completion" ) ;
{
var StartTime = DateTime . UtcNow ;
foreach ( var Node in NodesToDo )
{
Log ( "** {0}" , Node ) ;
NodeIsAlreadyComplete ( Node , LocalOnly ) ; // cache these now to avoid spam later
GetControllingTriggerDotName ( Node ) ;
}
var BuildDuration = ( DateTime . UtcNow - StartTime ) . TotalMilliseconds ;
Log ( "Took {0}s to cache completion for {1} nodes" , BuildDuration / 1000 , NodesToDo . Count ) ;
}
if ( CLString ! = "" & & StoreName . Contains ( CLString ) & & ! ParseParam ( "NoHistory" ) )
{
Log ( "******* Updating history" ) ;
var StartTime = DateTime . UtcNow ;
foreach ( var Node in NodesToDo )
{
if ( ! NodeIsAlreadyComplete ( Node , LocalOnly ) )
{
UpdateNodeHistory ( Node , CLString ) ;
}
}
var BuildDuration = ( DateTime . UtcNow - StartTime ) . TotalMilliseconds ;
Log ( "Took {0}s to get history for {1} nodes" , BuildDuration / 1000 , NodesToDo . Count ) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
var OrdereredToDo = TopologicalSort ( NodesToDo , ExplicitTrigger , LocalOnly ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
// find all unfinished triggers, excepting the one we are triggering right now
var UnfinishedTriggers = new List < string > ( ) ;
if ( ! bSkipTriggers )
{
foreach ( var NodeToDo in OrdereredToDo )
{
if ( GUBPNodes [ NodeToDo ] . TriggerNode ( ) & & ! NodeIsAlreadyComplete ( NodeToDo , LocalOnly ) )
{
if ( String . IsNullOrEmpty ( ExplicitTrigger ) | | ExplicitTrigger ! = NodeToDo )
{
UnfinishedTriggers . Add ( NodeToDo ) ;
}
}
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
Log ( "*********** Desired And Dependent Nodes, in order." ) ;
PrintNodes ( this , OrdereredToDo , LocalOnly , UnfinishedTriggers ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
//check sorting
{
foreach ( var NodeToDo in OrdereredToDo )
{
if ( GUBPNodes [ NodeToDo ] . TriggerNode ( ) & & ( GUBPNodes [ NodeToDo ] . IsSticky ( ) | | NodeIsAlreadyComplete ( NodeToDo , LocalOnly ) ) ) // these sticky triggers are ok, everything is already completed anyway
{
continue ;
}
int MyIndex = OrdereredToDo . IndexOf ( NodeToDo ) ;
foreach ( var Dep in GUBPNodes [ NodeToDo ] . FullNamesOfDependencies )
{
int DepIndex = OrdereredToDo . IndexOf ( Dep ) ;
if ( DepIndex > = MyIndex )
{
throw new AutomationException ( "Topological sort error, node {0} has a dependency of {1} which sorted after it." , NodeToDo , Dep ) ;
}
}
foreach ( var Dep in GUBPNodes [ NodeToDo ] . FullNamesOfPseudosependencies )
{
int DepIndex = OrdereredToDo . IndexOf ( Dep ) ;
if ( DepIndex > = MyIndex )
{
throw new AutomationException ( "Topological sort error, node {0} has a pseduodependency of {1} which sorted after it." , NodeToDo , Dep ) ;
}
}
}
}
2014-06-30 16:04:59 -04:00
2014-08-22 13:39:55 -04:00
string FakeFail = ParseParamValue ( "FakeFail" ) ;
if ( CommanderSetup )
{
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
if ( OrdereredToDo . Count = = 0 )
{
throw new AutomationException ( "No nodes to do!" ) ;
}
var ECProps = new List < string > ( ) ;
ECProps . Add ( String . Format ( "TimeIndex={0}" , TimeIndex ) ) ;
foreach ( var NodePair in FullNodeList )
{
ECProps . Add ( string . Format ( "AllNodes/{0}={1}" , NodePair . Key , NodePair . Value ) ) ;
}
foreach ( var NodePair in FullNodeDirectDependencies )
{
ECProps . Add ( string . Format ( "DirectDependencies/{0}={1}" , NodePair . Key , NodePair . Value ) ) ;
}
foreach ( var NodePair in FullNodeListSortKey )
{
ECProps . Add ( string . Format ( "SortKey/{0}={1}" , NodePair . Key , NodePair . Value ) ) ;
}
var ECJobProps = new List < string > ( ) ;
if ( ExplicitTrigger ! = "" )
{
ECJobProps . Add ( "IsRoot=0" ) ;
}
else
{
ECJobProps . Add ( "IsRoot=1" ) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
var FilteredOrdereredToDo = new List < string > ( ) ;
// remove nodes that have unfinished triggers
foreach ( var NodeToDo in OrdereredToDo )
{
string ControllingTrigger = GetControllingTrigger ( NodeToDo ) ;
bool bNoUnfinishedTriggers = ! UnfinishedTriggers . Contains ( ControllingTrigger ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
if ( bNoUnfinishedTriggers )
{
// if we are triggering, then remove nodes that are not controlled by the trigger or are dependencies of this trigger
if ( ! String . IsNullOrEmpty ( ExplicitTrigger ) )
{
if ( ExplicitTrigger ! = NodeToDo & & ! NodeDependsOn ( NodeToDo , ExplicitTrigger ) & & ! NodeDependsOn ( ExplicitTrigger , NodeToDo ) )
{
continue ; // this wasn't on the chain related to the trigger we are triggering, so it is not relevant
}
}
2014-08-18 13:29:39 -04:00
if ( bPreflightBuild & & ! bSkipTriggers & & GUBPNodes [ NodeToDo ] . TriggerNode ( ) )
{
// in preflight builds, we are either skipping triggers (and running things downstream) or we just stop at triggers and don't make them available for triggering.
continue ;
}
2014-08-22 13:39:55 -04:00
FilteredOrdereredToDo . Add ( NodeToDo ) ;
}
}
OrdereredToDo = FilteredOrdereredToDo ;
Log ( "*********** EC Nodes, in order." ) ;
PrintNodes ( this , OrdereredToDo , LocalOnly , UnfinishedTriggers ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
// here we are just making sure everything before the explicit trigger is completed.
if ( ! String . IsNullOrEmpty ( ExplicitTrigger ) )
{
foreach ( var NodeToDo in FilteredOrdereredToDo )
{
if ( GUBPNodes [ NodeToDo ] . RunInEC ( ) & & ! NodeIsAlreadyComplete ( NodeToDo , LocalOnly ) & & NodeToDo ! = ExplicitTrigger & & ! NodeDependsOn ( ExplicitTrigger , NodeToDo ) ) // if something is already finished, we don't put it into EC
{
throw new AutomationException ( "We are being asked to process node {0}, however, this is an explicit trigger {1}, so everything before it should already be handled. It seems likely that you waited too long to run the trigger. You will have to do a new build from scratch." , NodeToDo , ExplicitTrigger ) ;
}
}
}
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
string LastSticky = "" ;
bool HitNonSticky = false ;
bool bHaveECNodes = false ;
2014-09-03 10:12:50 -04:00
List < string > StepList = new List < string > ( ) ;
StepList . Add ( "use strict;" ) ;
StepList . Add ( "use diagnostics;" ) ;
StepList . Add ( "use ElectricCommander();" ) ;
StepList . Add ( "my $ec = new ElectricCommander;" ) ;
StepList . Add ( "$ec->setTimeout(600);" ) ;
StepList . Add ( "my $batch = $ec->newBatch(\"serial\");" ) ;
2014-08-22 13:39:55 -04:00
// sticky nodes are ones that we run on the main agent. We run then first and they must not be intermixed with parallel jobs
2014-09-03 10:12:50 -04:00
foreach ( var NodeToDo in OrdereredToDo )
{
if ( GUBPNodes [ NodeToDo ] . RunInEC ( ) & & ! NodeIsAlreadyComplete ( NodeToDo , LocalOnly ) ) // if something is already finished, we don't put it into EC
{
bHaveECNodes = true ;
if ( GUBPNodes [ NodeToDo ] . IsSticky ( ) )
{
LastSticky = NodeToDo ;
if ( HitNonSticky & & ! bSkipTriggers )
{
throw new AutomationException ( "Sticky and non-sticky jobs did not sort right." ) ;
}
}
else
{
HitNonSticky = true ;
}
}
}
2014-08-22 13:39:55 -04:00
string ParentPath = ParseParamValue ( "ParentPath" ) ;
2014-09-03 10:12:50 -04:00
string BaseArgs = String . Format ( "$batch->createJobStep({{parentPath => '{0}'" , ParentPath ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
bool bHasNoop = false ;
if ( LastSticky = = "" & & bHaveECNodes )
{
// if we don't have any sticky nodes and we have other nodes, we run a fake noop just to release the resource
2014-09-03 10:12:50 -04:00
string Args = String . Format ( "{0}, subprocedure => 'GUBP_UAT_Node', parallel => '0', jobStepName => 'Noop', actualParameter => [{{actualParameterName => 'NodeName', value => 'Noop'}}, {{actualParametername => 'Sticky', value =>'1' }}], releaseMode => 'release'" , BaseArgs ) ;
StepList . Add ( Args ) ;
2014-08-22 13:39:55 -04:00
bHasNoop = true ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
var FakeECArgs = new List < string > ( ) ;
var AgentGroupChains = new Dictionary < string , List < string > > ( ) ;
foreach ( var NodeToDo in OrdereredToDo )
{
if ( GUBPNodes [ NodeToDo ] . RunInEC ( ) & & ! NodeIsAlreadyComplete ( NodeToDo , LocalOnly ) ) // if something is already finished, we don't put it into EC
{
string MyAgentGroup = GUBPNodes [ NodeToDo ] . AgentSharingGroup ;
if ( MyAgentGroup ! = "" )
{
if ( ! AgentGroupChains . ContainsKey ( MyAgentGroup ) )
{
AgentGroupChains . Add ( MyAgentGroup , new List < string > { NodeToDo } ) ;
}
else
{
AgentGroupChains [ MyAgentGroup ] . Add ( NodeToDo ) ;
}
}
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
foreach ( var NodeToDo in OrdereredToDo )
{
if ( GUBPNodes [ NodeToDo ] . RunInEC ( ) & & ! NodeIsAlreadyComplete ( NodeToDo , LocalOnly ) ) // if something is already finished, we don't put it into EC
{
2014-10-08 16:52:49 -04:00
if ( ( NodeToDo . Contains ( "Test" ) ) & & ! ( NodeToDo . Contains ( "MakeBuild" ) ) & & ! ( NodeToDo . Contains ( "Unity" ) ) & & ! ( NodeToDo . Contains ( "TestBuild" ) ) & & ! ( NodeToDo . Contains ( "Compile" ) ) & & ! ( NodeToDo . Contains ( "Product" ) ) )
2014-08-22 13:39:55 -04:00
{
bHasTests = true ;
}
string EMails ;
var NodeProps = GetECPropsForNode ( NodeToDo , CLString , out EMails ) ;
ECProps . AddRange ( NodeProps ) ;
bool Sticky = GUBPNodes [ NodeToDo ] . IsSticky ( ) ;
bool DoParallel = ! Sticky ;
if ( Sticky & & GUBPNodes [ NodeToDo ] . ECAgentString ( ) ! = "" )
{
throw new AutomationException ( "Node {1} is sticky but has agent requirements." , NodeToDo ) ;
}
string Procedure = GUBPNodes [ NodeToDo ] . ECProcedure ( ) ;
2014-09-03 10:12:50 -04:00
string Args = String . Format ( "{0}, subprocedure => '{1}', parallel => '{2}', jobStepName => '{3}', actualParameter => [{{actualParameterName => 'NodeName', value =>'{4}'}}" ,
2014-08-22 13:39:55 -04:00
BaseArgs , Procedure , DoParallel ? 1 : 0 , NodeToDo , NodeToDo ) ;
string ProcedureParams = GUBPNodes [ NodeToDo ] . ECProcedureParams ( ) ;
if ( ! String . IsNullOrEmpty ( ProcedureParams ) )
{
2014-09-03 10:12:50 -04:00
Args = Args + ProcedureParams ;
2014-08-22 13:39:55 -04:00
}
if ( ( Procedure = = "GUBP_UAT_Trigger" | | Procedure = = "GUBP_Hardcoded_Trigger" ) & & ! String . IsNullOrEmpty ( EMails ) )
{
2014-09-03 10:12:50 -04:00
Args = Args + ", {actualParameterName => 'EmailsForTrigger', value => \'" + EMails + "\'}" ;
2014-08-22 13:39:55 -04:00
}
2014-09-03 10:12:50 -04:00
Args = Args + "]" ;
2014-08-22 13:39:55 -04:00
string PreCondition = "" ;
string RunCondition = "" ;
2014-09-03 10:12:50 -04:00
var UncompletedEcDeps = new List < string > ( ) ;
2014-08-22 13:39:55 -04:00
string MyAgentGroup = GUBPNodes [ NodeToDo ] . AgentSharingGroup ;
bool bDoNestedJobstep = false ;
bool bDoFirstNestedJobstep = false ;
string NodeParentPath = ParentPath ;
string PreconditionParentPath ;
if ( GUBPNodes [ NodeToDo ] . GetFullName ( ) . Contains ( "MakeBuild" ) & & GUBPNodes [ NodeToDo ] . FullNamesOfPseudosependencies . Contains ( SharedLabelPromotableNode . StaticGetFullName ( false ) ) & & ! bGraphSubset )
2014-09-03 10:12:50 -04:00
{
2014-08-22 13:39:55 -04:00
RemovePseudodependencyFromNode ( NodeToDo , SharedLabelPromotableNode . StaticGetFullName ( false ) ) ;
PreconditionParentPath = GetPropertyFromStep ( "/myWorkflow/ParentJob" ) ;
UncompletedEcDeps = GetECDependencies ( NodeToDo ) ;
2014-08-18 13:29:39 -04:00
}
2014-08-22 13:39:55 -04:00
else
2014-08-18 13:29:39 -04:00
{
2014-08-22 13:39:55 -04:00
PreconditionParentPath = ParentPath ;
2014-09-03 10:12:50 -04:00
var EcDeps = GetECDependencies ( NodeToDo ) ;
foreach ( var Dep in EcDeps )
{
if ( GUBPNodes [ Dep ] . RunInEC ( ) & & ! NodeIsAlreadyComplete ( Dep , LocalOnly ) & & OrdereredToDo . Contains ( Dep ) ) // if something is already finished, we don't put it into EC
{
if ( OrdereredToDo . IndexOf ( Dep ) > OrdereredToDo . IndexOf ( NodeToDo ) )
{
throw new AutomationException ( "Topological sort error, node {0} has a dependency of {1} which sorted after it." , NodeToDo , Dep ) ;
}
UncompletedEcDeps . Add ( Dep ) ;
}
}
}
var PreConditionUncompletedEcDeps = UncompletedEcDeps ;
2014-08-22 13:39:55 -04:00
if ( MyAgentGroup ! = "" )
{
bDoNestedJobstep = true ;
NodeParentPath = ParentPath + "/jobSteps[" + MyAgentGroup + "]" ;
2014-04-02 18:09:23 -04:00
2014-08-22 13:39:55 -04:00
PreConditionUncompletedEcDeps = new List < string > ( ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
var MyChain = AgentGroupChains [ MyAgentGroup ] ;
int MyIndex = MyChain . IndexOf ( NodeToDo ) ;
if ( MyIndex > 0 )
{
PreConditionUncompletedEcDeps . Add ( MyChain [ MyIndex - 1 ] ) ;
}
else
{
bDoFirstNestedJobstep = bDoNestedJobstep ;
// to avoid idle agents (and also EC doesn't actually reserve our agent!), we promote all dependencies to the first one
foreach ( var Chain in MyChain )
{
var EcDeps = GetECDependencies ( Chain ) ;
foreach ( var Dep in EcDeps )
{
if ( GUBPNodes [ Dep ] . RunInEC ( ) & & ! NodeIsAlreadyComplete ( Dep , LocalOnly ) & & OrdereredToDo . Contains ( Dep ) ) // if something is already finished, we don't put it into EC
{
if ( OrdereredToDo . IndexOf ( Dep ) > OrdereredToDo . IndexOf ( Chain ) )
{
throw new AutomationException ( "Topological sort error, node {0} has a dependency of {1} which sorted after it." , Chain , Dep ) ;
}
if ( ! MyChain . Contains ( Dep ) & & ! PreConditionUncompletedEcDeps . Contains ( Dep ) )
{
PreConditionUncompletedEcDeps . Add ( Dep ) ;
}
}
}
}
}
}
if ( bHasNoop & & PreConditionUncompletedEcDeps . Count = = 0 )
{
PreConditionUncompletedEcDeps . Add ( "Noop" ) ;
}
if ( PreConditionUncompletedEcDeps . Count > 0 )
{
2014-09-03 10:12:50 -04:00
PreCondition = "\"\\$\" . \"[/javascript if(" ;
2014-08-22 13:39:55 -04:00
// these run "parallel", but we add preconditions to serialize them
int Index = 0 ;
foreach ( var Dep in PreConditionUncompletedEcDeps )
2014-09-03 10:12:50 -04:00
{
PreCondition = PreCondition + "getProperty('" + GetJobStep ( PreconditionParentPath , Dep ) + "/status\') == \'completed\'" ;
2014-08-22 13:39:55 -04:00
Index + + ;
if ( Index ! = PreConditionUncompletedEcDeps . Count )
{
PreCondition = PreCondition + " && " ;
}
}
PreCondition = PreCondition + ") true;]\"" ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
if ( UncompletedEcDeps . Count > 0 )
{
2014-09-03 10:12:50 -04:00
RunCondition = "\"\\$\" . \"[/javascript if(" ;
2014-08-22 13:39:55 -04:00
int Index = 0 ;
foreach ( var Dep in UncompletedEcDeps )
{
2014-09-03 10:12:50 -04:00
RunCondition = RunCondition + "((\'\\$\" . \"[" + GetJobStep ( PreconditionParentPath , Dep ) + "/outcome]\' == \'success\') || " ;
RunCondition = RunCondition + "(\'\\$\" . \"[" + GetJobStep ( PreconditionParentPath , Dep ) + "/outcome]\' == \'warning\'))" ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
Index + + ;
if ( Index ! = UncompletedEcDeps . Count )
{
RunCondition = RunCondition + " && " ;
}
}
2014-09-03 10:12:50 -04:00
RunCondition = RunCondition + ")true; else false;]\"" ;
2014-08-22 13:39:55 -04:00
}
2014-04-02 18:09:23 -04:00
2014-08-22 13:39:55 -04:00
if ( bDoNestedJobstep )
{
if ( bDoFirstNestedJobstep )
{
{
2014-09-03 10:12:50 -04:00
string NestArgs = String . Format ( "$batch->createJobStep({{parentPath => '{0}', jobStepName => '{1}', parallel => '1'" ,
2014-08-22 13:39:55 -04:00
ParentPath , MyAgentGroup ) ;
if ( ! String . IsNullOrEmpty ( PreCondition ) )
{
2014-09-03 10:12:50 -04:00
NestArgs = NestArgs + ", precondition => " + PreCondition ;
2014-08-22 13:39:55 -04:00
}
2014-09-03 10:12:50 -04:00
NestArgs = NestArgs + "});" ;
StepList . Add ( NestArgs ) ;
2014-08-22 13:39:55 -04:00
}
{
2014-09-03 10:12:50 -04:00
string NestArgs = String . Format ( "$batch->createJobStep({{parentPath => '{0}/jobSteps[{1}]', jobStepName => '{2}_GetPool', subprocedure => 'GUBP{3}_AgentShare_GetPool', parallel => '1', actualParameter => [{{actualParameterName => 'AgentSharingGroup', value => '{4}'}}, {{actualParameterName => 'NodeName', value => '{5}'}}]" ,
2014-08-22 13:39:55 -04:00
ParentPath , MyAgentGroup , MyAgentGroup , GUBPNodes [ NodeToDo ] . ECProcedureInfix ( ) , MyAgentGroup , NodeToDo ) ;
if ( ! String . IsNullOrEmpty ( PreCondition ) )
{
2014-09-03 10:12:50 -04:00
NestArgs = NestArgs + ", precondition => " + PreCondition ;
2014-08-22 13:39:55 -04:00
}
2014-09-03 10:12:50 -04:00
NestArgs = NestArgs + "});" ;
StepList . Add ( NestArgs ) ;
2014-08-22 13:39:55 -04:00
}
{
2014-09-03 10:12:50 -04:00
string NestArgs = String . Format ( "$batch->createJobStep({{parentPath => '{0}/jobSteps[{1}]', jobStepName => '{2}_GetAgent', subprocedure => 'GUBP{3}_AgentShare_GetAgent', parallel => '1', exclusiveMode => 'call', resourceName => '{4}', actualParameter => [{{actualParameterName => 'AgentSharingGroup', value => '{5}'}}, {{actualParameterName => 'NodeName', value=> '{6}'}}]" ,
2014-08-22 13:39:55 -04:00
ParentPath , MyAgentGroup , MyAgentGroup , GUBPNodes [ NodeToDo ] . ECProcedureInfix ( ) ,
String . Format ( "$[/myJob/jobSteps[{0}]/ResourcePool]" , MyAgentGroup ) ,
MyAgentGroup , NodeToDo ) ;
{
2014-09-03 10:12:50 -04:00
NestArgs = NestArgs + ", precondition => " ;
NestArgs = NestArgs + "\"\\$\" . \"[/javascript if(" ;
2014-08-22 13:39:55 -04:00
NestArgs = NestArgs + "getProperty('" + PreconditionParentPath + "/jobSteps[" + MyAgentGroup + "]/jobSteps[" + MyAgentGroup + "_GetPool]/status') == 'completed'" ;
NestArgs = NestArgs + ") true;]\"" ;
}
2014-09-03 10:12:50 -04:00
NestArgs = NestArgs + "});" ;
StepList . Add ( NestArgs ) ;
2014-08-22 13:39:55 -04:00
}
{
2014-09-03 10:12:50 -04:00
PreCondition = "\"\\$\" . \"[/javascript if(" ;
2014-08-22 13:39:55 -04:00
PreCondition = PreCondition + "getProperty('" + PreconditionParentPath + "/jobSteps[" + MyAgentGroup + "]/jobSteps[" + MyAgentGroup + "_GetAgent]/status') == 'completed'" ;
PreCondition = PreCondition + ") true;]\"" ;
}
}
2014-09-03 10:12:50 -04:00
Args = Args . Replace ( String . Format ( "parentPath => '{0}'" , ParentPath ) , String . Format ( "parentPath => '{0}'" , NodeParentPath ) ) ;
2014-08-22 13:39:55 -04:00
Args = Args . Replace ( "UAT_Node_Parallel_AgentShare" , "UAT_Node_Parallel_AgentShare3" ) ;
}
2014-08-18 13:29:39 -04:00
2014-08-22 13:39:55 -04:00
if ( ! String . IsNullOrEmpty ( PreCondition ) )
{
2014-09-03 10:12:50 -04:00
Args = Args + ", precondition => " + PreCondition ;
2014-08-22 13:39:55 -04:00
}
if ( ! String . IsNullOrEmpty ( RunCondition ) )
{
2014-09-03 10:12:50 -04:00
Args = Args + ", condition => " + RunCondition ;
2014-08-22 13:39:55 -04:00
}
2014-04-23 17:54:46 -04:00
#if false
// this doesn't work because it includes precondition time
2014-04-23 17:51:55 -04:00
if ( GUBPNodes [ NodeToDo ] . TimeoutInMinutes ( ) > 0 )
{
Args = Args + String . Format ( " --timeLimitUnits minutes --timeLimit {0}" , GUBPNodes [ NodeToDo ] . TimeoutInMinutes ( ) ) ;
}
2014-04-23 17:54:46 -04:00
#endif
2014-08-22 13:39:55 -04:00
if ( Sticky & & NodeToDo = = LastSticky )
{
2014-09-03 10:12:50 -04:00
Args = Args + ", releaseMode => 'release'" ;
2014-08-22 13:39:55 -04:00
}
2014-09-03 10:12:50 -04:00
Args = Args + "});" ;
StepList . Add ( Args ) ;
2014-08-22 13:39:55 -04:00
if ( bFakeEC & &
! UnfinishedTriggers . Contains ( NodeToDo ) & &
( GUBPNodes [ NodeToDo ] . ECProcedure ( ) . StartsWith ( "GUBP_UAT_Node" ) | | GUBPNodes [ NodeToDo ] . ECProcedure ( ) . StartsWith ( "GUBP_Mac_UAT_Node" ) ) // other things we really can't test
) // unfinished triggers are never run directly by EC, rather it does another job setup
{
string Arg = String . Format ( "gubp -Node={0} -FakeEC {1} {2} {3} {4} {5}" ,
NodeToDo ,
bFake ? "-Fake" : "" ,
ParseParam ( "AllPlatforms" ) ? "-AllPlatforms" : "" ,
ParseParam ( "UnfinishedTriggersFirst" ) ? "-UnfinishedTriggersFirst" : "" ,
ParseParam ( "UnfinishedTriggersParallel" ) ? "-UnfinishedTriggersParallel" : "" ,
ParseParam ( "WithMac" ) ? "-WithMac" : ""
) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
string Node = ParseParamValue ( "-Node" ) ;
if ( ! String . IsNullOrEmpty ( Node ) )
{
Arg = Arg + " -Node=" + Node ;
}
if ( ! String . IsNullOrEmpty ( FakeFail ) )
{
Arg = Arg + " -FakeFail=" + FakeFail ;
}
FakeECArgs . Add ( Arg ) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
if ( MyAgentGroup ! = "" & & ! bDoNestedJobstep )
{
var MyChain = AgentGroupChains [ MyAgentGroup ] ;
int MyIndex = MyChain . IndexOf ( NodeToDo ) ;
if ( MyIndex = = MyChain . Count - 1 )
{
2014-09-03 10:12:50 -04:00
var RelPreCondition = "\"\\$\" . \"[/javascript if(" ;
2014-08-22 13:39:55 -04:00
// this runs "parallel", but we a precondition to serialize it
RelPreCondition = RelPreCondition + "getProperty('" + PreconditionParentPath + "/jobSteps[" + NodeToDo + "]/status') == 'completed'" ;
RelPreCondition = RelPreCondition + ") true;]\"" ;
// we need to release the resource
2014-09-03 10:12:50 -04:00
string RelArgs = String . Format ( "{0}, subprocedure => 'GUBP_Release_AgentShare', parallel => '1', jobStepName => 'Release_{1}', actualParameter => [{{actualParameterName => 'AgentSharingGroup', valued => '{2}'}}], releaseMode => 'release', precondition => '{3}'" ,
2014-08-22 13:39:55 -04:00
BaseArgs , MyAgentGroup , MyAgentGroup , RelPreCondition ) ;
2014-09-03 10:12:50 -04:00
StepList . Add ( RelArgs ) ;
2014-08-22 13:39:55 -04:00
}
}
}
}
2014-09-03 10:12:50 -04:00
WriteECPerl ( StepList ) ;
2014-08-22 13:39:55 -04:00
ECProps . Add ( String . Format ( "HasTests={0}" , bHasTests ) ) ;
{
ECProps . Add ( "GUBP_LoadedProps=1" ) ;
string BranchDefFile = CommandUtils . CombinePaths ( CommandUtils . CmdEnv . LogFolder , "BranchDef.properties" ) ;
CommandUtils . WriteAllLines ( BranchDefFile , ECProps . ToArray ( ) ) ;
RunECTool ( String . Format ( "setProperty \"/myWorkflow/BranchDefFile\" \"{0}\"" , BranchDefFile . Replace ( "\\" , "\\\\" ) ) ) ;
}
{
ECProps . Add ( "GUBP_LoadedJobProps=1" ) ;
string BranchJobDefFile = CommandUtils . CombinePaths ( CommandUtils . CmdEnv . LogFolder , "BranchJobDef.properties" ) ;
CommandUtils . WriteAllLines ( BranchJobDefFile , ECProps . ToArray ( ) ) ;
RunECTool ( String . Format ( "setProperty \"/myJob/BranchJobDefFile\" \"{0}\"" , BranchJobDefFile . Replace ( "\\" , "\\\\" ) ) ) ;
}
if ( bFakeEC )
{
foreach ( var Args in FakeECArgs )
{
RunUAT ( CmdEnv , Args ) ;
}
}
Log ( "Commander setup only, done." ) ;
PrintRunTime ( ) ;
return ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
}
if ( ParseParam ( "SaveGraph" ) )
{
SaveGraphVisualization ( OrdereredToDo ) ;
}
if ( bListOnly )
{
Log ( "List only, done." ) ;
return ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
var BuildProductToNodeMap = new Dictionary < string , string > ( ) ;
foreach ( var NodeToDo in OrdereredToDo )
{
if ( GUBPNodes [ NodeToDo ] . BuildProducts ! = null | | GUBPNodes [ NodeToDo ] . AllDependencyBuildProducts ! = null )
{
throw new AutomationException ( "topological sort error" ) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
GUBPNodes [ NodeToDo ] . AllDependencyBuildProducts = new List < string > ( ) ;
GUBPNodes [ NodeToDo ] . AllDependencies = new List < string > ( ) ;
foreach ( var Dep in GUBPNodes [ NodeToDo ] . FullNamesOfDependencies )
{
GUBPNodes [ NodeToDo ] . AddAllDependent ( Dep ) ;
if ( GUBPNodes [ Dep ] . AllDependencies = = null )
{
if ( ! bOnlyNode )
{
throw new AutomationException ( "Node {0} was not processed yet3? Processing {1}" , Dep , NodeToDo ) ;
}
}
foreach ( var DepDep in GUBPNodes [ Dep ] . AllDependencies )
{
GUBPNodes [ NodeToDo ] . AddAllDependent ( DepDep ) ;
}
if ( GUBPNodes [ Dep ] . BuildProducts = = null )
{
if ( ! bOnlyNode )
{
throw new AutomationException ( "Node {0} was not processed yet? Processing {1}" , Dep , NodeToDo ) ;
}
}
else
{
foreach ( var Prod in GUBPNodes [ Dep ] . BuildProducts )
{
GUBPNodes [ NodeToDo ] . AddDependentBuildProduct ( Prod ) ;
}
if ( GUBPNodes [ Dep ] . AllDependencyBuildProducts = = null )
{
throw new AutomationException ( "Node {0} was not processed yet2? Processing {1}" , Dep , NodeToDo ) ;
}
foreach ( var Prod in GUBPNodes [ Dep ] . AllDependencyBuildProducts )
{
GUBPNodes [ NodeToDo ] . AddDependentBuildProduct ( Prod ) ;
}
}
}
2014-04-25 12:35:08 -04:00
2014-08-22 13:39:55 -04:00
string NodeStoreName = StoreName + "-" + GUBPNodes [ NodeToDo ] . GetFullName ( ) ;
string GameNameIfAny = GUBPNodes [ NodeToDo ] . GameNameIfAnyForTempStorage ( ) ;
string StorageRootIfAny = GUBPNodes [ NodeToDo ] . RootIfAnyForTempStorage ( ) ;
if ( bFake )
{
StorageRootIfAny = "" ; // we don't rebase fake runs since those are entirely "records of success", which are always in the logs folder
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
// this is kinda complicated
bool SaveSuccessRecords = ( IsBuildMachine | | bFakeEC ) & & // no real reason to make these locally except for fakeEC tests
( ! GUBPNodes [ NodeToDo ] . TriggerNode ( ) | | GUBPNodes [ NodeToDo ] . IsSticky ( ) ) // trigger nodes are run twice, one to start the new workflow and once when it is actually triggered, we will save reconds for the latter
& & ( GUBPNodes [ NodeToDo ] . RunInEC ( ) | | ! GUBPNodes [ NodeToDo ] . IsAggregate ( ) ) ; //aggregates not in EC can be "run" multiple times, so we can't track those
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
Log ( "***** Running GUBP Node {0} -> {1} : {2}" , GUBPNodes [ NodeToDo ] . GetFullName ( ) , GameNameIfAny , NodeStoreName ) ;
if ( NodeIsAlreadyComplete ( NodeToDo , LocalOnly ) )
{
if ( NodeToDo = = VersionFilesNode . StaticGetFullName ( ) & & ! IsBuildMachine )
{
Log ( "***** NOT ****** Retrieving GUBP Node {0} from {1}; it is the version files." , GUBPNodes [ NodeToDo ] . GetFullName ( ) , NodeStoreName ) ;
GUBPNodes [ NodeToDo ] . BuildProducts = new List < string > ( ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
}
else
{
Log ( "***** Retrieving GUBP Node {0} from {1}" , GUBPNodes [ NodeToDo ] . GetFullName ( ) , NodeStoreName ) ;
bool WasLocal ;
GUBPNodes [ NodeToDo ] . BuildProducts = RetrieveFromTempStorage ( CmdEnv , NodeStoreName , out WasLocal , GameNameIfAny , StorageRootIfAny ) ;
if ( ! WasLocal )
{
GUBPNodes [ NodeToDo ] . PostLoadFromSharedTempStorage ( this ) ;
}
}
}
else
{
if ( SaveSuccessRecords )
{
SaveStatus ( NodeToDo , StartedTempStorageSuffix , NodeStoreName , bSaveSharedTempStorage , GameNameIfAny ) ;
}
try
{
if ( ! String . IsNullOrEmpty ( FakeFail ) & & FakeFail . Equals ( NodeToDo , StringComparison . InvariantCultureIgnoreCase ) )
{
throw new AutomationException ( "Failing node {0} by request." , NodeToDo ) ;
}
if ( bFake )
{
Log ( "***** FAKE!! Building GUBP Node {0} for {1}" , NodeToDo , NodeStoreName ) ;
GUBPNodes [ NodeToDo ] . DoFakeBuild ( this ) ;
}
else
{
Log ( "***** Building GUBP Node {0} for {1}" , NodeToDo , NodeStoreName ) ;
GUBPNodes [ NodeToDo ] . DoBuild ( this ) ;
}
if ( ! GUBPNodes [ NodeToDo ] . IsAggregate ( ) )
{
StoreToTempStorage ( CmdEnv , NodeStoreName , GUBPNodes [ NodeToDo ] . BuildProducts , ! bSaveSharedTempStorage , GameNameIfAny , StorageRootIfAny ) ;
2014-04-25 12:35:08 -04:00
2014-08-22 13:39:55 -04:00
if ( ParseParam ( "StompCheck" ) )
{
foreach ( var Dep in GUBPNodes [ NodeToDo ] . AllDependencies )
{
try
{
bool WasLocal ;
RetrieveFromTempStorage ( CmdEnv , NodeStoreName , out WasLocal , GameNameIfAny , StorageRootIfAny ) ;
if ( ! WasLocal )
{
throw new AutomationException ( "Retrieve was not local?" ) ;
}
}
catch ( Exception Ex )
{
throw new AutomationException ( "Node {0} stomped Node {1} Ex: {2}" , NodeToDo , Dep , LogUtils . FormatException ( Ex ) ) ;
}
}
}
2014-04-25 12:35:08 -04:00
2014-08-22 13:39:55 -04:00
}
}
catch ( Exception Ex )
{
if ( SaveSuccessRecords )
{
UpdateNodeHistory ( NodeToDo , CLString ) ;
SaveStatus ( NodeToDo , FailedTempStorageSuffix , NodeStoreName , bSaveSharedTempStorage , GameNameIfAny , ParseParamValue ( "MyJobStepId" ) ) ;
UpdateECProps ( NodeToDo , CLString ) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
Log ( "{0}" , ExceptionToString ( Ex ) ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
if ( GUBPNodesHistory . ContainsKey ( NodeToDo ) )
{
var History = GUBPNodesHistory [ NodeToDo ] ;
Log ( "Changes since last green *********************************" ) ;
Log ( "" ) ;
Log ( "" ) ;
Log ( "" ) ;
PrintDetailedChanges ( History ) ;
Log ( "End changes since last green" ) ;
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
string FailInfo = "" ;
FailInfo + = "********************************* Main log file" ;
FailInfo + = Environment . NewLine + Environment . NewLine ;
FailInfo + = LogUtils . GetLogTail ( ) ;
FailInfo + = Environment . NewLine + Environment . NewLine + Environment . NewLine ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
string OtherLog = "See logfile for details: '" ;
if ( FailInfo . Contains ( OtherLog ) )
{
string LogFile = FailInfo . Substring ( FailInfo . IndexOf ( OtherLog ) + OtherLog . Length ) ;
if ( LogFile . Contains ( "'" ) )
{
LogFile = CombinePaths ( CmdEnv . LogFolder , LogFile . Substring ( 0 , LogFile . IndexOf ( "'" ) ) ) ;
if ( FileExists_NoExceptions ( LogFile ) )
{
FailInfo + = "********************************* Sub log file " + LogFile ;
FailInfo + = Environment . NewLine + Environment . NewLine ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
FailInfo + = LogUtils . GetLogTail ( LogFile ) ;
FailInfo + = Environment . NewLine + Environment . NewLine + Environment . NewLine ;
}
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
string Filename = CombinePaths ( CmdEnv . LogFolder , "LogTailsAndChanges.log" ) ;
WriteAllText ( Filename , FailInfo ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
throw ( Ex ) ;
}
if ( SaveSuccessRecords )
{
UpdateNodeHistory ( NodeToDo , CLString ) ;
SaveStatus ( NodeToDo , SucceededTempStorageSuffix , NodeStoreName , bSaveSharedTempStorage , GameNameIfAny ) ;
UpdateECProps ( NodeToDo , CLString ) ;
}
}
foreach ( var Product in GUBPNodes [ NodeToDo ] . BuildProducts )
{
if ( BuildProductToNodeMap . ContainsKey ( Product ) )
{
throw new AutomationException ( "Overlapping build product: {0} and {1} both produce {2}" , BuildProductToNodeMap [ Product ] , NodeToDo , Product ) ;
}
BuildProductToNodeMap . Add ( Product , NodeToDo ) ;
}
}
2014-03-14 14:13:41 -04:00
2014-08-22 13:39:55 -04:00
PrintRunTime ( ) ;
}
string StartedTempStorageSuffix = "_Started" ;
string FailedTempStorageSuffix = "_Failed" ;
string SucceededTempStorageSuffix = "_Succeeded" ;
2014-03-14 14:13:41 -04:00
}