2020-07-29 14:40:30 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
using System ;
using System.Collections.Generic ;
using System.Text ;
using System.Xml.Serialization ;
using System.IO ;
2020-12-21 23:07:37 -04:00
using EpicGames.Core ;
2020-07-29 14:40:30 -04:00
using UnrealBuildTool ;
using AutomationTool ;
using System.Linq ;
using System.Text.RegularExpressions ;
namespace Turnkey
{
public class CopySource
{
// @todo turnkey: for some reason the TypeConverter stuff setup in UnrealTargetPlatform isn't kicking in to convert from string to UTP, so do it a manual way
[XmlAttribute("HostPlatform")]
public string HostPlatformString = null ;
[XmlIgnore]
public UnrealTargetPlatform ? Platform = null ;
[XmlAttribute]
// if this is set, then the actual copy operation will use this,m
public string CopyOverride = null ;
[XmlText]
public string Operation ;
/// <summary>
/// Needs a parameterless constructor for Xml deserialization
/// </summary>
public CopySource ( )
{ }
public CopySource ( CopySource Other )
{
HostPlatformString = Other . HostPlatformString ;
Platform = Other . Platform ;
CopyOverride = Other . CopyOverride ;
Operation = Other . Operation ;
}
public string GetOperation ( )
{
return TurnkeyUtils . ExpandVariables ( CopyOverride ! = null ? CopyOverride : Operation ) ;
}
public void PostDeserialize ( )
{
if ( ! string . IsNullOrEmpty ( HostPlatformString ) )
{
Platform = UnrealTargetPlatform . Parse ( HostPlatformString ) ;
}
// perform early expansion, important for $(ThisManifestDir) which is valid only during deserialization
// but don't use any other variables yet, because UAT could have bad values in Environment
CopyOverride = TurnkeyUtils . ExpandVariables ( CopyOverride , bUseOnlyTurnkeyVariables : true ) ? . Trim ( ) ;
Operation = TurnkeyUtils . ExpandVariables ( Operation , bUseOnlyTurnkeyVariables : true ) ? . Trim ( ) ;
}
public bool ShouldExecute ( )
{
return ! Platform . HasValue | | Platform = = HostPlatform . Current . HostEditorPlatform ;
}
public bool NeedsExpansion ( out string OperationForExpansion )
{
const string Prefix = "fileexpansion:" ;
bool bNeedsExpansion = ShouldExecute ( ) & & Operation . StartsWith ( Prefix , StringComparison . InvariantCultureIgnoreCase ) ;
// get the bit after the expansion tag
OperationForExpansion = bNeedsExpansion ? Operation . Substring ( Prefix . Length ) : null ;
return bNeedsExpansion ;
}
public bool NeedsExpansion ( )
{
return NeedsExpansion ( out _ ) ;
}
}
public class FileSource
{
public enum SourceType
{
BuildOnly ,
AutoSdk ,
RunOnly ,
Full ,
Flash ,
Misc ,
2020-08-24 08:54:52 -04:00
Build ,
2020-07-29 14:40:30 -04:00
} ;
#region Fields
[XmlElement("Platform")]
public string PlatformString = null ;
[XmlIgnore]
private List < UnrealTargetPlatform > Platforms ;
2022-04-08 15:34:51 -04:00
[XmlElement("Type")]
public string TypeString = null ;
[XmlIgnore]
public SourceType Type = SourceType . Full ;
[XmlIgnore]
public string SpecificSDKType = null ;
2020-07-29 14:40:30 -04:00
[XmlElement("Source")]
public CopySource [ ] Sources = null ;
2022-04-08 15:34:51 -04:00
2020-07-29 14:40:30 -04:00
public string Version = null ;
2020-07-29 17:10:58 -04:00
public string Name = null ;
2020-07-29 14:40:30 -04:00
public string AllowedFlashDeviceTypes = null ;
2020-08-24 08:54:52 -04:00
// Project for Build types to filter on
public string Project ;
public string BuildPlatformEnumerationSuffix ;
2020-07-29 14:40:30 -04:00
2021-02-03 14:18:15 -04:00
public static FileSource CreateCodeSpecifiedSource ( string Name , string Version , UnrealTargetPlatform Platform )
{
FileSource NewSource = new FileSource ( ) ;
NewSource . PlatformString = Platform . ToString ( ) ;
NewSource . Platforms = new List < UnrealTargetPlatform > ( ) { Platform } ;
NewSource . Name = Name ;
NewSource . Version = Version ;
NewSource . Sources = new CopySource [ ] { } ;
2020-07-29 14:40:30 -04:00
2021-02-03 14:18:15 -04:00
return NewSource ;
}
2020-07-29 14:40:30 -04:00
public FileSource CloneForExpansion ( string NewValue , Action < FileSource , string > Setter )
{
FileSource Clone = new FileSource ( ) ;
Clone . PlatformString = PlatformString ;
2022-04-08 15:34:51 -04:00
Clone . TypeString = TypeString ;
2020-07-29 14:40:30 -04:00
Clone . Version = Version ;
2020-07-29 17:10:58 -04:00
Clone . Name = Name ;
2020-07-29 14:40:30 -04:00
Clone . AllowedFlashDeviceTypes = AllowedFlashDeviceTypes ;
2020-08-24 08:54:52 -04:00
Clone . Project = Project ;
Clone . BuildPlatformEnumerationSuffix = BuildPlatformEnumerationSuffix ;
2020-07-29 14:40:30 -04:00
if ( NewValue ! = null )
{
Setter ( Clone , NewValue ) ;
}
if ( Sources ! = null )
{
List < CopySource > NewSources = new List < CopySource > ( ) ;
foreach ( CopySource Source in Sources )
{
// if we want to execute the installer, then copy it over
if ( Source . ShouldExecute ( ) )
{
NewSources . Add ( new CopySource ( Source ) ) ;
}
}
Clone . Sources = NewSources . ToArray ( ) ;
}
Clone . PostDeserialize ( ) ;
return Clone ;
}
#endregion
//
//
// static string[] ExtendedVariables =
// {
// "Project",
// };
//
//
// [Flags]
// public enum LocalAvailability
// {
// None = 0,
// AutoSdk_VariableExists = 1,
// AutoSdk_ValidVersionExists = 2,
// AutoSdk_InvalidVersionExists = 4,
// // InstalledSdk_BuildOnlyWasInstalled = 8,
// InstalledSdk_ValidVersionExists = 16,
// InstalledSdk_InvalidVersionExists = 32,
// Platform_ValidHostPrerequisites = 64,
// Platform_InvalidHostPrerequisites = 128,
// }
//
//
//
public bool NeedsFileExpansion ( )
{
return Sources . Any ( x = > x . NeedsExpansion ( ) ) ;
}
public bool SupportsPlatform ( UnrealTargetPlatform Platform )
{
return Platforms . Contains ( Platform ) ;
}
2020-08-24 08:54:52 -04:00
public bool IsSdkType ( )
{
return Type = = SourceType . BuildOnly | | Type = = SourceType . AutoSdk | | Type = = SourceType . RunOnly | | Type = = SourceType . Full | | Type = = SourceType . Flash ;
}
2020-07-29 14:40:30 -04:00
public bool IsVersionValid ( UnrealTargetPlatform Platform , DeviceInfo Device = null )
{
2020-08-24 08:54:52 -04:00
// Non-Sdk types are always valid, although this isn't meant for them
if ( ! IsSdkType ( ) )
2020-07-29 14:40:30 -04:00
{
return true ;
}
if ( ! SupportsPlatform ( Platform ) )
{
return false ;
}
// if (!CheckForExtendedVariables(false))
// {
// // user canceled a choice
// return false;
// }
//
if ( Type = = SourceType . Flash )
{
2020-09-23 11:47:14 -04:00
UEBuildPlatformSDK SDK = UEBuildPlatformSDK . GetSDKForPlatform ( Platform . ToString ( ) ) ;
2022-04-08 15:34:51 -04:00
// if we are specific to any particular device type, use one of them to pass to the validation function (different device types may have different SDK versions)
string DeviceTypeHint = string . IsNullOrEmpty ( AllowedFlashDeviceTypes ) ? null : AllowedFlashDeviceTypes . Split ( "," ) . First ( ) ;
bool bIsValid = SDK . IsSoftwareVersionValid ( Version , DeviceTypeHint ) ;
2020-07-29 14:40:30 -04:00
// if we were passed a device, also check if this Sdk is valid for that device
2020-09-23 11:47:14 -04:00
if ( Device ! = null )
2020-07-29 14:40:30 -04:00
{
2020-09-23 11:47:14 -04:00
bIsValid & = TurnkeyUtils . IsValueValid ( Device . Type , AllowedFlashDeviceTypes , AutomationTool . Platform . GetPlatform ( Platform ) ) ;
2020-07-29 14:40:30 -04:00
}
return bIsValid ;
}
else
{
2022-04-08 15:34:51 -04:00
string SDKTypeHint = SpecificSDKType ? ? Type . ToString ( ) ;
return UEBuildPlatformSDK . GetSDKForPlatform ( Platform . ToString ( ) ) . IsVersionValid ( Version , SDKTypeHint ) ;
2020-07-29 14:40:30 -04:00
}
}
public UnrealTargetPlatform [ ] GetPlatforms ( )
{
return Platforms . ToArray ( ) ;
}
public string GetCopySourceOperation ( )
{
// use the one matching copy source for this host platform, or null if there isn't one
return Sources . FirstOrDefault ( x = > x . ShouldExecute ( ) ) ? . GetOperation ( ) ;
}
2021-11-07 23:43:01 -05:00
static public FileSource ChooseBest ( List < FileSource > Sdks , UEBuildPlatformSDK PlatformSDK )
{
if ( Sdks = = null )
{
return null ;
}
FileSource Best = null ;
UInt64 MainVersionInt ;
PlatformSDK . TryConvertVersionToInt ( PlatformSDK . GetMainVersion ( ) , out MainVersionInt ) ;
foreach ( FileSource Sdk in Sdks )
{
if ( Best = = null )
{
Best = Sdk ;
}
else
{
// bigger version is better
UInt64 ThisVersion , BestVersion ;
if ( PlatformSDK . TryConvertVersionToInt ( Sdk . Version , out ThisVersion ) & & PlatformSDK . TryConvertVersionToInt ( Best . Version , out BestVersion ) )
{
// there is no MainVersion for flash (yet), so don't take it into account
if ( Sdk . Type = = SourceType . Flash )
{
if ( ThisVersion > BestVersion )
{
Best = Sdk ;
}
}
// always use MainVersion, otherwise, use largest version if MainVersion hasn't been found
else if ( ThisVersion = = MainVersionInt | | ( BestVersion ! = MainVersionInt & & ThisVersion > BestVersion ) )
{
Best = Sdk ;
}
}
}
}
return Best ;
}
2022-04-08 15:34:51 -04:00
static public FileSource FindMatchingSdk ( AutomationTool . Platform Platform , SourceType [ ] TypePriority , bool bSelectBest , string DeviceType = null , string CurrentSdk = null , string SpecificType = null )
2020-07-29 14:40:30 -04:00
{
UEBuildPlatformSDK SDK = UEBuildPlatformSDK . GetSDKForPlatform ( Platform . PlatformType . ToString ( ) ) ;
foreach ( SourceType Type in TypePriority )
{
List < FileSource > Sdks = TurnkeyManifest . FilterDiscoveredFileSources ( Platform . IniPlatformType , Type ) ;
// check valid versions/device types
// Sdks = Sdks.FindAll(x => x.Version == null || (Type == SourceType.Flash ? TurnkeyUtils.IsValueValid(x.Version, Platform.GetAllowedSoftwareVersions(), Platform) : SDK.IsVersionValid(x.Version, bForAutoSDK: x.Type == SourceType.AutoSdk)));
Sdks = Sdks . FindAll ( x = > x . Version = = null | |
( Type = = SourceType . Flash ?
2022-04-08 15:34:51 -04:00
SDK . IsSoftwareVersionValid ( x . Version , DeviceType ) :
SDK . IsVersionValid ( x . Version , ( bSelectBest & & x . Type = = SourceType . AutoSdk ) ? "AutoSDK" : SpecificType ? ? "Sdk" )
2020-07-29 14:40:30 -04:00
) ) ;
if ( DeviceType ! = null )
{
Sdks = Sdks . FindAll ( x = > TurnkeyUtils . IsValueValid ( DeviceType , x . AllowedFlashDeviceTypes , Platform ) ) ;
}
2022-04-08 15:34:51 -04:00
if ( SpecificType ! = null )
{
Sdks = Sdks . FindAll ( x = > TurnkeyUtils . IsValueValid ( SpecificType , x . SpecificSDKType , Platform ) ) ;
}
2020-07-29 14:40:30 -04:00
// if none were found try next type
if ( Sdks . Count = = 0 )
{
continue ;
}
// if one was found return it!
if ( Sdks . Count = = 1 )
{
return Sdks [ 0 ] ;
}
// the best for a AutoSdk is the one that matches the desired version exactly
2021-11-07 23:43:01 -05:00
FileSource Best = ChooseBest ( Sdks , SDK ) ;
2020-07-29 14:40:30 -04:00
if ( bSelectBest )
{
// select best one if requested
return Best ;
}
2022-01-21 11:08:21 -05:00
// find the current sdk, if any
FileSource Current = null ;
if ( CurrentSdk ! = null )
{
Current = Sdks . Find ( x = > x . Version = = CurrentSdk ) ;
}
// helper for getting the display name for the sdks as they are presented to the user
string GetDisplayName ( FileSource Sdk )
{
string Result = Sdk . Name ;
if ( Current ! = null & & Sdk = = Current )
{
Result + = " (current)" ;
}
if ( Sdk = = Best )
{
Result + = " [Best Choice]" ;
}
return Result ;
}
2020-07-29 14:40:30 -04:00
// if unable to pick one automatically, ask the user
int BestIndex = Sdks . IndexOf ( Best ) ;
2022-01-21 11:08:21 -05:00
int Choice = TurnkeyUtils . ReadInputInt ( "Multiple Sdks found that could be installed. Please select one:" , Sdks . Select ( x = > GetDisplayName ( x ) ) . ToList ( ) , true , BestIndex > = 0 ? BestIndex + 1 : - 1 ) ;
2020-07-29 14:40:30 -04:00
// we take canceling to mean to try the next type
if ( Choice = = 0 )
{
continue ;
}
return Sdks [ Choice - 1 ] ;
}
// if we never found anything, fail
return null ;
}
2022-07-19 05:00:41 -04:00
public bool DownloadOrInstall ( UnrealTargetPlatform Platform , ITurnkeyContext TurnkeyContext , DeviceInfo Device , bool bUnattended , bool bSdkAlreadyInstalled )
2020-07-29 14:40:30 -04:00
{
// standard variables
TurnkeyUtils . SetVariable ( "Platform" , Platform . ToString ( ) ) ;
TurnkeyUtils . SetVariable ( "Version" , Version ) ;
if ( Type = = SourceType . AutoSdk )
{
// AutoSdk has some extra setup needed
2021-02-08 17:07:27 -04:00
return SdkUtils . SetupAutoSdk ( this , TurnkeyContext , Platform , bUnattended ) ;
2020-07-29 14:40:30 -04:00
}
2021-02-03 14:18:15 -04:00
// if we have sources, make sure we can download something. if we have a null Sources, that indicates
// it was code generated, and we don't need to download anything
if ( Sources . Length ! = 0 )
{
// this will set the $(CopyOutputPath) variable which the Sdks will generally need to use
2021-02-08 17:07:27 -04:00
string DownloadedSDK = TurnkeyContext . RetrieveFileSource ( this ) ;
2021-02-03 14:18:15 -04:00
if ( string . IsNullOrEmpty ( DownloadedSDK ) )
{
2021-02-08 17:07:27 -04:00
// TurnkeyContext.ReportError($"Unable to download anInstaller for {Platform}. Your Studio's TurnkeyManifest.xml file(s) may need to be fixed.");
2021-02-03 14:18:15 -04:00
return false ;
}
}
2021-01-26 05:30:58 -04:00
// let the platform decide how to install
2022-07-19 05:00:41 -04:00
return AutomationTool . Platform . GetPlatform ( Platform ) . InstallSDK ( TurnkeyUtils . CommandUtilHelper , TurnkeyContext , Device , bUnattended , bSdkAlreadyInstalled ) ;
2020-07-29 14:40:30 -04:00
}
//
// // for all platforms this supports, get all devices
// public DeviceInfo[] GetAllPossibleDevices()
// {
// List<DeviceInfo> AllDevices = new List<DeviceInfo>();
// foreach (var Pair in AutomationPlatforms)
// {
// DeviceInfo[] Devices = Pair.Value.GetDevices();
// if (Devices != null)
// {
// AllDevices.AddRange(Devices);
// }
// }
// return AllDevices.ToArray();
// }
//
// public DeviceInfo GetDevice(UnrealTargetPlatform Platform, string DeviceName)
// {
// DeviceInfo[] Devices = AutomationPlatforms[Platform].GetDevices();
// if (Devices != null)
// {
// return Array.Find(AutomationPlatforms[Platform].GetDevices(), y => (DeviceName == null && y.bIsDefault) || (DeviceName != null && string.Compare(y.Name, DeviceName, true) == 0));
// }
// return null;
// }
// public bool IsValid(UnrealTargetPlatform Platform, string DeviceName = null)
// {
// if (!SupportsPlatform(Platform))
// {
// return false;
// }
//
// if (!CheckForExtendedVariables(false))
// {
// // user canceled a choice
// return false;
// }
//
// if (Type == SourceType.Flash)
// {
// bool bIsValid = TurnkeyUtils.IsValueValid(Version, AutomationPlatforms[Platform].GetAllowedSoftwareVersions(), AutomationPlatforms[Platform]);
// // if we were passed a device, also check if this Sdk is valid for that device
// // if (DeviceName != null)
// {
// DeviceInfo Device = GetDevice(Platform, DeviceName);
// bIsValid = bIsValid && Device != null && TurnkeyUtils.IsValueValid(Device.Type, AllowedFlashDeviceTypes, AutomationPlatforms[Platform]);
// }
// return bIsValid;
// }
// else
// {
// return UEBuildPlatformSDK.GetSDKForPlatform(Platform.ToString()).IsVersionValid(Version, bForAutoSDK:(Type == SourceType.AutoSdk));
// }
// }
//
// public bool Install(UnrealTargetPlatform Platform, DeviceInfo Device=null, bool bUnattended=false, bool bSkipAutoSdkSetup=false)
// {
// if (Type ==SourceType.AutoSdk && !bSkipAutoSdkSetup)
// {
// // AutoSdk has some extra setup needed
// if (SdkInfo.ConditionalSetupAutoSdk(this, Platform, bUnattended))
// {
// return true;
// }
// }
//
// if (!CheckForExtendedVariables(true))
// {
// // user canceled a choice
// return false;
// }
//
// // standard variables
// TurnkeyUtils.SetVariable("Platform", Platform.ToString());
// TurnkeyUtils.SetVariable("Version", Version);
//
// if (Device != null)
// {
// TurnkeyUtils.SetVariable("DeviceName", Device.Name);
// TurnkeyUtils.SetVariable("DeviceId", Device.Id);
// TurnkeyUtils.SetVariable("DeviceType", Device.Type);
// }
//
// // custom sdk installation is enabled if ChosenSdk.CustomVersionId is !null
// if (CustomSdkId != null)
// {
// // copy files down, which are needed to check if whatever is installed is up to date (only do it once)
// if (CustomVersionLocalFiles == null && CustomSdkInputFiles != null)
// {
// foreach (CopyAndRun CustomCopy in CustomSdkInputFiles)
// {
// if (CustomCopy.ShouldExecute())
// {
// if (CustomVersionLocalFiles != null)
// {
// throw new AutomationTool.AutomationException("CustomSdkInputFiles specified multiple locations to be copied for this platform, which is not supported (only one value of $(CustomVersionLocalFiles) allowed)");
// }
//
// CustomCopy.Execute();
// CustomVersionLocalFiles = TurnkeyUtils.GetVariableValue("CopyOutputPath");
// }
// }
// }
//
// // in case the custom sdk modifies global env vars, make sure we capture them
// TurnkeyUtils.StartTrackingExternalEnvVarChanges();
//
// // re-set the path to local files
// TurnkeyUtils.SetVariable("CustomVersionLocalFiles", CustomVersionLocalFiles);
// AutomationPlatforms[Platform].CustomVersionUpdate(CustomSdkId, TurnkeyUtils.ExpandVariables(CustomSdkParams), new CopyProviderRetriever());
//
// TurnkeyUtils.EndTrackingExternalEnvVarChanges();
// }
//
// // now run any installers
// if (Installers == null)
// {
// // if there were no installers, then we succeeded
// return true;
// }
//
// bool bSucceeded = true;
// foreach (CopyAndRun Install in Installers)
// {
// // build only types we keep in a nice directory structure in the PermanentStorage (if the copy provider allows for choosing destination)
// if (Type ==SourceType.BuildOnly)
// {
// // download subdir is based on platform
// string SubDir = string.Format("{0}/{1}", Platform.ToString(), Version);
// bSucceeded = bSucceeded && Install.Execute(CopyExecuteSpecialMode.UsePermanentStorage, SubDir);
// }
// else
// {
// // !@todo turnkey : verify it worked
// bSucceeded = bSucceeded && Install.Execute();
// }
// }
//
// return bSucceeded;
// }
//
// public static bool ConditionalSetupAutoSdk(SdkInfo Sdk, UnrealTargetPlatform Platform, bool bUnattended)
// {
// bool bAttemptAutoSdkSetup = false;
// bool bSetupEnvVarAfterInstall = false;
// if (Environment.GetEnvironmentVariable("UE_SDKS_ROOT") != null)
// {
// bAttemptAutoSdkSetup = true;
// }
// else
// {
// if (!bUnattended)
// {
// // @todo turnkey - have studio settings
2021-06-24 08:56:32 -04:00
// bool bResponse = TurnkeyUtils.GetUserConfirmation("AutoSdks are not setup, but your studio has support. Would you like to set it up now?", true);
// if (bResponse)
2020-07-29 14:40:30 -04:00
// {
// bAttemptAutoSdkSetup = true;
// bSetupEnvVarAfterInstall = true;
// }
// }
// }
//
// if (bAttemptAutoSdkSetup)
// {
// AutomationTool.Platform AutomationPlatform = AutomationTool.Platform.GetPlatform(Platform);
//
// TurnkeyUtils.Log("{0}: AutoSdk is setup on this computer, will look for available AutoSdk to download", Platform);
//
// // make sure this is unset so that we can know if it worked or not after install
// TurnkeyUtils.ClearVariable("CopyOutputPath");
//
// // now download it (AutoSdks don't "install") on download
// // @todo turnkey: handle errors, handle p4 going to wrong location, handle one Sdk for multiple platforms
// Sdk.Install(Platform, null, bUnattended, bSkipAutoSdkSetup:true);
//
// if (bSetupEnvVarAfterInstall)
// {
//
// // this is where we synced the Sdk to
// string InstalledRoot = TurnkeyUtils.GetVariableValue("CopyOutputPath");
//
// // failed to install, nothing we can do
// if (string.IsNullOrEmpty(InstalledRoot))
// {
2021-06-17 01:49:34 -04:00
// TurnkeyUtils.ExitCode = ExitCode.Error_SDKNotFound;
2020-07-29 14:40:30 -04:00
// return false;
// }
//
// // walk up to one above Host* directory
// DirectoryInfo AutoSdkSearch;
// if (Directory.Exists(InstalledRoot))
// {
// AutoSdkSearch = new DirectoryInfo(InstalledRoot);
// }
// else
// {
// AutoSdkSearch = new FileInfo(InstalledRoot).Directory;
// }
// while (AutoSdkSearch.Name != "Host" + HostPlatform.Current.HostEditorPlatform.ToString())
// {
// AutoSdkSearch = AutoSdkSearch.Parent;
// }
//
// // now go one up to the parent of Host
// AutoSdkSearch = AutoSdkSearch.Parent;
//
// string AutoSdkDir = AutoSdkSearch.FullName;
// if (!bUnattended)
// {
// string Response = TurnkeyUtils.ReadInput("Enter directory for root of AutoSdks. Use detected value, or enter another:", AutoSdkSearch.FullName);
// if (string.IsNullOrEmpty(Response))
// {
// return false;
// }
// }
//
// // set the env var, globally
// TurnkeyUtils.StartTrackingExternalEnvVarChanges();
// Environment.SetEnvironmentVariable("UE_SDKS_ROOT", AutoSdkDir);
// Environment.SetEnvironmentVariable("UE_SDKS_ROOT", AutoSdkDir, EnvironmentVariableTarget.User);
// TurnkeyUtils.EndTrackingExternalEnvVarChanges();
//
// }
//
// // and now activate it in case we need it this run
// TurnkeyUtils.Log("Re-activating AutoSDK '{0}'...", Sdk.DisplayName);
//
2020-12-21 23:07:37 -04:00
// EpicGames.Core.UEBuildPlatformSDK.GetSDKForPlatform(Platform.ToString()).ReactivateAutoSDK();
2020-07-29 14:40:30 -04:00
//
// return true;
// }
//
// return false;
// }
//
//
//
//
//
//
//
//
// private bool CheckForExtendedVariables(bool bIncludeCustomSdk)
// {
// foreach (string Var in ExtendedVariables)
// {
// if (!TurnkeyUtils.HasVariable(Var))
// {
// if (NeedsVariableToBeSet(Var, bIncludeCustomSdk))
// {
// // ask for it!
// TurnkeyUtils.Log("An Sdk ({0}) needs a extended variable ({1}) to be set that isn't set. Asking now...", DisplayName, Var);
//
// if (Var == "Project")
// {
// // we need a project, so choose one now
// List<string> Options = new List<string>();
// Options.Add("Engine");
// Options.Add("FortniteGame");
//
// // we force the user to select something
// int Choice = TurnkeyUtils.ReadInputInt("Select a Project:", Options, true);
//
// if (Choice == 0)
// {
// return false;
// }
//
// // set the projectname
// TurnkeyUtils.SetVariable(Var, Options[Choice - 1]);
// }
// }
// }
// }
//
// return true;
// }
//
// private bool NeedsVariableToBeSet(string Variable, bool bIncludeCustomSdk)
// {
// string Format = "$(" + Variable + ")";
// bool bContainsVar = false;
// if (bIncludeCustomSdk && CustomSdkId != null)
// {
// bContainsVar = bContainsVar || (CustomSdkParams != null && CustomSdkParams.Contains(Format));
// if (CustomSdkInputFiles != null)
// {
// foreach (CopyAndRun CustomInput in CustomSdkInputFiles)
// {
// bContainsVar = bContainsVar || (CustomInput.Copy != null && CustomInput.Copy.Contains(Format));
// bContainsVar = bContainsVar || (CustomInput.CommandPath != null && CustomInput.CommandPath.Contains(Format));
// bContainsVar = bContainsVar || (CustomInput.CommandLine != null && CustomInput.CommandLine.Contains(Format));
// }
// }
// }
// if (Installers != null)
// {
// foreach (CopyAndRun Installer in Installers)
// {
// bContainsVar = bContainsVar || (Installer.Copy != null && Installer.Copy.Contains(Format));
// bContainsVar = bContainsVar || (Installer.CommandPath != null && Installer.CommandPath.Contains(Format));
// bContainsVar = bContainsVar || (Installer.CommandLine != null && Installer.CommandLine.Contains(Format));
// }
// }
//
// return bContainsVar;
// }
//
//
//
//
static private Regex ExpansionRegex = new Regex ( @"^listexpansion:(\w*)=(.*)$" ) ;
private List < FileSource > CheckForListExpansions ( List < FileSource > Sources , Func < FileSource , string > Getter , Action < FileSource , string > Setter )
{
List < FileSource > NewSources = new List < FileSource > ( ) ;
foreach ( FileSource Source in Sources )
{
string Value = Getter ( Source ) ;
if ( Value = = null )
{
NewSources . Add ( Source ) ;
continue ;
}
// get the value in question from the lambda, and see if it's what we are looking for
Match Result = ExpansionRegex . Match ( Value ) ; // Getter(Source));
if ( Result . Success )
{
// get the variable we are going to replace in the expansions
string ExpansionVar = Result . Groups [ 1 ] . Value ;
// remember the old value, in case it had one
string OldVarValue = TurnkeyUtils . GetVariableValue ( ExpansionVar ) ;
string [ ] NewValues = TurnkeyUtils . ExpandVariables ( Result . Groups [ 2 ] . Value ) . Split ( "," . ToCharArray ( ) ) ;
foreach ( string NewValue in NewValues )
{
TurnkeyUtils . SetVariable ( ExpansionVar , NewValue ) ;
// now when we make a clone, it will have the ExpansionVar set, and will be used
FileSource NewSource = Source . CloneForExpansion ( NewValue , Setter ) ;
NewSources . Add ( NewSource ) ;
}
// and retore it
TurnkeyUtils . SetVariable ( ExpansionVar , OldVarValue ) ;
}
else
{
NewSources . Add ( Source ) ;
}
}
return NewSources ;
}
internal List < FileSource > ConditionalExpandLists ( )
{
List < FileSource > Expansions = new List < FileSource > ( ) { this } ;
Expansions = CheckForListExpansions ( Expansions , x = > x . PlatformString , ( x , y ) = > x . PlatformString = y ) ;
Expansions = CheckForListExpansions ( Expansions , x = > x . Version , ( x , y ) = > x . Version = y ) ;
Expansions = CheckForListExpansions ( Expansions , x = > x . AllowedFlashDeviceTypes , ( x , y ) = > x . AllowedFlashDeviceTypes = y ) ;
2020-08-24 08:54:52 -04:00
Expansions = CheckForListExpansions ( Expansions , x = > x . Project , ( x , y ) = > x . Project = y ) ;
2020-07-29 14:40:30 -04:00
// return null if nothing was actually expanded!
if ( Expansions . Count = = 1 & & Expansions [ 0 ] = = this )
{
return null ;
}
return Expansions ;
}
internal List < FileSource > ExpandCopySource ( )
{
List < FileSource > ResultExpansions = new List < FileSource > ( ) ;
// get Expansions for this host platform
CopySource ExpandingSource = null ;
string ExpansionOperation = null ;
foreach ( CopySource Source in Sources )
{
if ( Source . NeedsExpansion ( out ExpansionOperation ) )
{
if ( ExpandingSource ! = null )
{
2020-07-29 17:10:58 -04:00
throw new AutomationTool . AutomationException ( "FileSource {0} had multiple expansions active on this platform. This is not allowed" , Name ) ;
2020-07-29 14:40:30 -04:00
}
ExpandingSource = Source ;
}
}
// something wasn't right, leave
if ( ExpansionOperation = = null )
{
return ResultExpansions ;
}
// fixup the Operation like so:
// fileexpansion:perforce://depot/CarefullyRedist/HostWin64/SomePlatform/$[ExpVersion]/Setup.*
// becomes:
// perforce://depot/CarefullyRedist/HostWin64/SomePlatform/*/Setup.*
string FixedSourceOperation = ExpansionOperation ;
int CaptureLocation ;
Dictionary < int , string > LocationToVariableMap = new Dictionary < int , string > ( ) ;
while ( ( CaptureLocation = ExpansionOperation . IndexOf ( "$[" ) ) ! = - 1 )
{
int CaptureEnd = ExpansionOperation . IndexOf ( "]" , CaptureLocation ) ;
if ( CaptureEnd = = - 1 )
{
throw new AutomationTool . AutomationException ( "FileSource operation {0} had malformed capture variables" , ExpandingSource . Operation ) ;
}
string Variable = ExpansionOperation . Substring ( CaptureLocation + 2 , ( CaptureEnd - CaptureLocation ) - 2 ) ;
// track the location to figure out the index of the * (the index will be index of the *)
LocationToVariableMap . Add ( CaptureLocation , Variable ) ;
string CaptureVar = string . Format ( "$[{0}]" , Variable ) ;
ExpansionOperation = ExpansionOperation . Replace ( CaptureVar , "*" ) ;
FixedSourceOperation = FixedSourceOperation . Replace ( CaptureVar , string . Format ( "$({0})" , Variable ) ) ;
} ;
ExpandingSource . Operation = FixedSourceOperation ;
// now go back and figure out the index of the variables
int StarLocation = - 1 ;
int StarIndex = 0 ;
Dictionary < int , string > StarIndexToVariableMap = new Dictionary < int , string > ( ) ;
while ( ( StarLocation = ExpansionOperation . IndexOf ( "*" , StarLocation + 1 ) ) ! = - 1 )
{
string Variable ;
if ( LocationToVariableMap . TryGetValue ( StarLocation , out Variable ) )
{
StarIndexToVariableMap . Add ( StarIndex , Variable ) ;
}
StarIndex + + ;
}
// now enumerate and get the values
List < List < string > > Expansions = new List < List < string > > ( ) ;
string [ ] ExpandedInstallerResults = CopyProvider . ExecuteEnumerate ( ExpansionOperation , Expansions ) ;
// expansion may not work, expand it to nothing
if ( ExpandedInstallerResults = = null )
{
return ResultExpansions ;
}
if ( Expansions . Count ! = ExpandedInstallerResults . Length )
{
throw new AutomationException ( string . Format ( "Bad expansions output from CopyProvider ({0} returned {1} count, expected {2}, from {3}" ,
ExpansionOperation , Expansions . Count , ExpandedInstallerResults . Length , string . Join ( ", " , ExpandedInstallerResults ) ) ) ;
}
// @todo turnkey: this will be used in Builds also, make it a function with a lambda
// make a new SdkInfo for each expansion
int MaxIndex = 0 ;
for ( int ResultIndex = 0 ; ResultIndex < ExpandedInstallerResults . Length ; ResultIndex + + )
{
// set captured variables to the values returned from the enumeration
TurnkeyUtils . SetVariable ( "Expansion" , ExpandedInstallerResults [ ResultIndex ] ) ;
// @todo turnkey: if there were multiple captures for the same variable name, make sure they are the same value: googledrive:/Foo/[$Ver]/Bar_[$Ver].zip
for ( int ExpansionIndex = 0 ; ExpansionIndex < Expansions [ ResultIndex ] . Count ; ExpansionIndex + + )
{
string Variable ;
if ( StarIndexToVariableMap . TryGetValue ( ExpansionIndex , out Variable ) )
{
TurnkeyUtils . SetVariable ( Variable , Expansions [ ResultIndex ] [ ExpansionIndex ] ) ;
}
}
// remember how many we beed to unset
MaxIndex = Math . Max ( MaxIndex , Expansions [ ResultIndex ] . Count ) ;
// make a new Sdk for each result in the expansion
ResultExpansions . Add ( CloneForExpansion ( null , null ) ) ;
}
// clear temp variables
TurnkeyUtils . ClearVariable ( "Expansion" ) ;
StarIndexToVariableMap . Values . ToList ( ) . ForEach ( x = > TurnkeyUtils . ClearVariable ( x ) ) ;
return ResultExpansions ;
}
internal void PostDeserialize ( )
{
2022-04-08 15:34:51 -04:00
// if the Type is a platform specific type, then
if ( ! Enum . TryParse < SourceType > ( TypeString , out Type ) )
{
Type = SourceType . Full ;
SpecificSDKType = TypeString ;
}
2020-07-29 14:40:30 -04:00
// validate
2020-08-24 08:54:52 -04:00
if ( Version = = null & & IsSdkType ( ) )
2020-07-29 14:40:30 -04:00
{
2020-08-24 08:54:52 -04:00
throw new AutomationTool . AutomationException ( "FileSource {0} needs to have a version specified, since it's an Sdk type" , Name ) ;
2020-07-29 14:40:30 -04:00
}
if ( Sources = = null )
{
2020-07-29 17:10:58 -04:00
throw new AutomationTool . AutomationException ( "FileSource {0} has no acutal Source operations specified! This is a setup error." , Name ) ;
2020-07-29 14:40:30 -04:00
}
PlatformString = TurnkeyUtils . ExpandVariables ( PlatformString , true ) ;
Platforms = new List < UnrealTargetPlatform > ( ) ;
if ( PlatformString ! = null )
{
string [ ] PlatformStrings = PlatformString . ToLower ( ) . Split ( "," . ToCharArray ( ) ) ;
// parse into runtime usable values
foreach ( string Plat in PlatformStrings )
{
if ( UnrealTargetPlatform . IsValidName ( Plat ) )
{
UnrealTargetPlatform TargetPlat = UnrealTargetPlatform . Parse ( Plat ) ;
Platforms . Add ( TargetPlat ) ;
}
else
{
// allow for shared SDK "platform" types (we use the AutoSDK platform name in the SDK object to determine the shared SDK "platform"
2022-04-08 15:34:51 -04:00
foreach ( UEBuildPlatformSDK SDK in UEBuildPlatformSDK . AllPlatformSDKObjects )
2020-07-29 14:40:30 -04:00
{
// if the platforms contains a AutoSDK platform that doesn't match a real platform name, add the platform to the set
if ( PlatformStrings . Contains ( SDK . GetAutoSDKPlatformName ( ) . ToLower ( ) ) )
{
Platforms . Add ( UnrealTargetPlatform . Parse ( SDK . PlatformName ) ) ;
}
}
}
}
}
Version = TurnkeyUtils . ExpandVariables ( Version , true ) ;
2020-07-29 17:10:58 -04:00
Name = TurnkeyUtils . ExpandVariables ( Name , true ) ;
2020-07-29 14:40:30 -04:00
2020-07-29 17:10:58 -04:00
if ( string . IsNullOrEmpty ( Name ) )
2020-07-29 14:40:30 -04:00
{
2020-07-29 17:10:58 -04:00
Name = string . Format ( "{0} {1}" , PlatformString , Version ) ;
2020-07-29 14:40:30 -04:00
}
AllowedFlashDeviceTypes = TurnkeyUtils . ExpandVariables ( AllowedFlashDeviceTypes , true ) ;
Array . ForEach ( Sources , x = > x . PostDeserialize ( ) ) ;
}
private string Indent ( int Num )
{
return new string ( ' ' , Num ) ;
}
public override string ToString ( )
{
return ToString ( 0 ) ;
}
public string ToString ( int BaseIndent )
{
StringBuilder Builder = new StringBuilder ( ) ;
2020-07-29 17:10:58 -04:00
Builder . AppendLine ( "{1}Name: {0}" , Name , Indent ( BaseIndent ) ) ;
2020-07-29 14:40:30 -04:00
Builder . AppendLine ( "{1}Version: {0}" , Version = = null ? "<Any>" : Version , Indent ( BaseIndent + 2 ) ) ;
Builder . AppendLine ( "{1}Platform: {0}" , Platforms = = null ? "" : string . Join ( "," , Platforms ) , Indent ( BaseIndent + 2 ) ) ;
Builder . AppendLine ( "{1}Type: {0}" , Type , Indent ( BaseIndent + 2 ) ) ;
if ( Type = = SourceType . Flash )
{
Builder . AppendLine ( "{1}AllowedFlashDeviceTypes: {0}" , AllowedFlashDeviceTypes , Indent ( BaseIndent + 2 ) ) ;
}
Builder . AppendLine ( "{0}Installers:" , Indent ( BaseIndent + 2 ) ) ;
foreach ( CopySource Copy in Sources )
{
Builder . AppendLine ( "{1}HostPlatform: {0}" , Copy . Platform , Indent ( BaseIndent + 4 ) ) ;
Builder . AppendLine ( "{1}CopyOperation: {0}" , Copy . Operation , Indent ( BaseIndent + 6 ) ) ;
if ( Copy . CopyOverride ! = null )
{
Builder . AppendLine ( "{1}CopyOverride: {0}" , Copy . CopyOverride , Indent ( BaseIndent + 6 ) ) ;
}
}
return Builder . ToString ( ) . TrimEnd ( ) ;
}
}
}