You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
- Windows will be first to use it, but in a future CL, with toolchain separate from Windows SDK - Cleaned up some of the PlatformSDK API to have fewer public members (mainly so the functions that receive multiple versions can be automatically populated with the current single version functions in the subclasses) - Updated the Turnkey menu to handle multiple versions #jira none #rb david.harvey #preflight 62508cd8f10bcc0f4fa8b5d1 [CL 19692492 by Josh Adams in ue5-main branch]
871 lines
28 KiB
C#
871 lines
28 KiB
C#
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Globalization;
|
|
using EpicGames.Core;
|
|
using AutomationTool;
|
|
using UnrealBuildTool;
|
|
using UnrealBuildBase;
|
|
using System.Diagnostics;
|
|
|
|
namespace Turnkey
|
|
{
|
|
static class TurnkeyUtils
|
|
{
|
|
// object that commands, etc can use to access UAT functionality
|
|
static public BuildCommand CommandUtilHelper;
|
|
|
|
// replacement for Environment.ExitCode
|
|
static public ExitCode ExitCode = ExitCode.Success;
|
|
|
|
static public void Initialize(IOProvider InIOProvider, BuildCommand InCommandUtilHelper)
|
|
{
|
|
IOProvider = InIOProvider;
|
|
CommandUtilHelper = InCommandUtilHelper;
|
|
|
|
// set up some lists
|
|
SetVariable("AllPlatforms", string.Join(",", UnrealTargetPlatform.GetValidPlatformNames()));
|
|
|
|
// walk over all the SDKs and get their AutoSDK string
|
|
IEnumerable<string> AutoSDKPlatforms = UEBuildPlatformSDK.AllPlatformSDKObjects.Select(x => x.GetAutoSDKPlatformName()).Distinct();
|
|
SetVariable("AutoSDKPlatforms", string.Join(",", AutoSDKPlatforms));
|
|
|
|
// TurnkeyUtils.Log("AllPlatforms = {0}", GetVariableValue("AllPlatforms"));
|
|
// TurnkeyUtils.Log("AutoSDKPlatforms = {0}", GetVariableValue("AutoSDKPlatforms"));
|
|
|
|
SetVariable("HOST_PLATFORM_NAME", HostPlatform.Current.HostEditorPlatform.ToString());
|
|
}
|
|
|
|
#region Turnkey Variables
|
|
|
|
static Dictionary<string, string> TurnkeyVariables = new Dictionary<string, string>();
|
|
|
|
public static string SetVariable(string Key, string Value)
|
|
{
|
|
string Previous;
|
|
TurnkeyVariables.TryGetValue(Key, out Previous);
|
|
TurnkeyVariables[Key] = Value;
|
|
return Previous;
|
|
}
|
|
public static string GetVariableValue(string Key)
|
|
{
|
|
string Value;
|
|
if (TurnkeyVariables.TryGetValue(Key, out Value) || TurnkeySettings.GetSetUserSettings().TryGetValue(Key, out Value))
|
|
{
|
|
return Value;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static void ClearVariable(string Key)
|
|
{
|
|
TurnkeyVariables.Remove(Key);
|
|
}
|
|
public static bool HasVariable(string Key)
|
|
{
|
|
return TurnkeyVariables.ContainsKey(Key);
|
|
}
|
|
|
|
public static string ExpandVariables(string Str, bool bUseOnlyTurnkeyVariables = false)
|
|
{
|
|
// don't crash on null
|
|
if (Str == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
string ExpandedUserVariables = UnrealBuildTool.Utils.ExpandVariables(Str, TurnkeySettings.GetSetUserSettings(), true);
|
|
return UnrealBuildTool.Utils.ExpandVariables(ExpandedUserVariables, TurnkeyVariables, bUseOnlyTurnkeyVariables);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Commandline Handling
|
|
|
|
public static bool ParseParam(string Param, string[] ExtraOptions)
|
|
{
|
|
// our internal extraoptions still have - in front, but CommandUtilHelper won't have the dashes
|
|
return CommandUtils.ParseParam(ExtraOptions, "-" + Param) || CommandUtilHelper.ParseParam(Param);
|
|
}
|
|
|
|
public static string ParseParamValue(string Param, string Default, string[] ExtraOptions)
|
|
{
|
|
// our internal extraoptions still have - in front, but CommandUtilHelper won't have the dashes
|
|
string Value = CommandUtils.ParseParamValue(ExtraOptions, "-" + Param, null);
|
|
if (Value == null)
|
|
{
|
|
Value = CommandUtilHelper.ParseParamValue(Param, Default);
|
|
}
|
|
|
|
return Value == null ? Default : Value;
|
|
}
|
|
|
|
private static List<UnrealTargetPlatform> GetAllValidPlatforms(List<UnrealTargetPlatform> SourcePlatforms=null)
|
|
{
|
|
if (SourcePlatforms == null)
|
|
{
|
|
SourcePlatforms = UnrealTargetPlatform.GetValidPlatforms().ToList();
|
|
}
|
|
|
|
return SourcePlatforms.Where(x => UEBuildPlatformSDK.GetSDKForPlatform(x.ToString()) != null).ToList();
|
|
}
|
|
|
|
public static List<UnrealTargetPlatform> GetPlatformsFromCommandLineOrUser(string[] CommandOptions, List<UnrealTargetPlatform> PossiblePlatforms)
|
|
{
|
|
string PlatformString = TurnkeyUtils.ParseParamValue("Platform", null, CommandOptions);
|
|
bool bUnattended = TurnkeyUtils.ParseParam("Unattended", CommandOptions);
|
|
|
|
// Remove known bad platforms
|
|
PossiblePlatforms = GetAllValidPlatforms(PossiblePlatforms);
|
|
|
|
// sort by name
|
|
PossiblePlatforms.Sort((x, y) => string.Compare(x.ToString(), y.ToString()));
|
|
|
|
List<UnrealTargetPlatform> Platforms = new List<UnrealTargetPlatform>();
|
|
// prompt user for a platform
|
|
if (PlatformString == null)
|
|
{
|
|
if (bUnattended)
|
|
{
|
|
// can't ask
|
|
return null;
|
|
}
|
|
|
|
// default to last platform chosen
|
|
string LastPlatform = TurnkeySettings.GetUserSettingIfSet("User_LastSelectedPlatform", "");
|
|
|
|
List<string> PlatformOptions = PossiblePlatforms.ConvertAll(x => x.ToString());
|
|
PlatformOptions.Add("All of the Above");
|
|
|
|
int Default = PlatformOptions.FindIndex(x => x.Equals(LastPlatform, StringComparison.OrdinalIgnoreCase));
|
|
int PlatformChoice = TurnkeyUtils.ReadInputInt("Choose a platform:", PlatformOptions, true, Default == -1 ? -1 : Default + 1);
|
|
|
|
if (PlatformChoice == 0)
|
|
{
|
|
return null;
|
|
}
|
|
// All platforms means to install every platform with an installer
|
|
if (PlatformChoice == PlatformOptions.Count)
|
|
{
|
|
Platforms = PossiblePlatforms;
|
|
}
|
|
else
|
|
{
|
|
Platforms.Add(PossiblePlatforms[PlatformChoice - 1]);
|
|
// remember for next time
|
|
TurnkeySettings.SetUserSetting("User_LastSelectedPlatform", PossiblePlatforms[PlatformChoice - 1].ToString());
|
|
}
|
|
}
|
|
else if (PlatformString.ToLower() == "all")
|
|
{
|
|
Platforms = PossiblePlatforms;
|
|
}
|
|
else
|
|
{
|
|
string[] Tokens = PlatformString.Split("+".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
foreach (string Token in Tokens)
|
|
{
|
|
UnrealTargetPlatform Platform;
|
|
if (!UnrealTargetPlatform.TryParse(Token, out Platform))
|
|
{
|
|
TurnkeyUtils.Log("Platform {0} is unknown", Token);
|
|
continue;
|
|
}
|
|
|
|
// if the platform isn't in the possible list, then don't add it
|
|
if (PossiblePlatforms.Contains(Platform))
|
|
{
|
|
Platforms.Add(Platform);
|
|
}
|
|
}
|
|
}
|
|
|
|
return Platforms.OrderBy(x => x.ToString()).ToList();
|
|
}
|
|
|
|
private enum ProjectMode
|
|
{
|
|
Normal,
|
|
Templates,
|
|
Sandbox,
|
|
Misc,
|
|
Samples,
|
|
Collaboration,
|
|
Personal,
|
|
Recent,
|
|
}
|
|
|
|
public static FileReference GetProjectFromCommandLineOrUser(string[] CommandOptions)
|
|
{
|
|
ProjectMode CurrentMode = ProjectMode.Normal;
|
|
|
|
string Project = TurnkeyUtils.GetVariableValue("Project");
|
|
string LastProject = TurnkeySettings.GetUserSettingIfSet("User_LastSelectedProject", "");
|
|
|
|
// create and initialize a dictionary of type to project list
|
|
Dictionary<ProjectMode, List<FileReference>> ProjectsByType = new Dictionary<ProjectMode, List<FileReference>>();
|
|
foreach (ProjectMode Mode in Enum.GetValues(typeof(ProjectMode)))
|
|
{
|
|
ProjectsByType.Add(Mode, new List<FileReference>());
|
|
}
|
|
|
|
// look up old manual projects
|
|
string ManualProjectString = TurnkeySettings.GetUserSettingIfSet("User_ManualProjects", "");
|
|
List<string> ManualProjects = ManualProjectString.Split(";", StringSplitOptions.RemoveEmptyEntries).ToList();
|
|
ProjectsByType[ProjectMode.Recent].AddRange(ManualProjects.Select(x => new FileReference(x)).ToList());
|
|
// start on Recent page if last one was a manual project
|
|
if (ProjectsByType[ProjectMode.Recent].Any(x => x.FullName.Equals(LastProject, StringComparison.OrdinalIgnoreCase)))
|
|
{
|
|
CurrentMode = ProjectMode.Recent;
|
|
}
|
|
|
|
// sort the discovered projects
|
|
foreach (FileReference NativeProject in NativeProjects.EnumerateProjectFiles())
|
|
{
|
|
DirectoryReference ProjectDir = NativeProject.Directory;
|
|
ProjectMode Mode = ProjectMode.Normal;
|
|
|
|
if (ProjectDir.ContainsName("StarterContent", 0) || ProjectDir.ContainsName("ContentExamples", 0))
|
|
{
|
|
Mode = ProjectMode.Misc;
|
|
}
|
|
else if (ProjectDir.ContainsName("Sandbox", 0))
|
|
{
|
|
Mode = ProjectMode.Sandbox;
|
|
}
|
|
else if (ProjectDir.ContainsName("Templates", 0))
|
|
{
|
|
Mode = ProjectMode.Templates;
|
|
}
|
|
else if (ProjectDir.ContainsName("Samples", 0))
|
|
{
|
|
Mode = ProjectMode.Samples;
|
|
}
|
|
else if (ProjectDir.ContainsName("Collaboration", 0))
|
|
{
|
|
Mode = ProjectMode.Collaboration;
|
|
}
|
|
|
|
// if the last project was this project, then use this as the starting type
|
|
if (LastProject != null && NativeProject.GetFileNameWithoutAnyExtensions().Equals(LastProject, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
CurrentMode = Mode;
|
|
}
|
|
ProjectsByType[Mode].Add(NativeProject);
|
|
}
|
|
|
|
// now look for the My Documents location
|
|
DirectoryReference PersonalProjects = new DirectoryReference(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Unreal Projects"));
|
|
foreach (DirectoryReference PersonalProjectDir in DirectoryReference.EnumerateDirectories(PersonalProjects))
|
|
{
|
|
FileReference PersonalProjectFile = DirectoryReference.EnumerateFiles(PersonalProjectDir, "*.uproject").FirstOrDefault();
|
|
if (PersonalProjectFile != null)
|
|
{
|
|
ProjectsByType[ProjectMode.Personal].Add(PersonalProjectFile);
|
|
}
|
|
}
|
|
|
|
|
|
while (string.IsNullOrEmpty(Project))
|
|
{
|
|
// get list of project names from the dictionary
|
|
List<string> ProjectNames = new List<string>();
|
|
|
|
// add options to switch mode
|
|
Dictionary<int, ProjectMode> IndexToMode = new Dictionary<int, ProjectMode>();
|
|
foreach (ProjectMode Mode in Enum.GetValues(typeof(ProjectMode)))
|
|
{
|
|
if (Mode != CurrentMode)
|
|
{
|
|
IndexToMode.Add(ProjectNames.Count, Mode);
|
|
ProjectNames.Add(string.Format("[Show {0} Projects]", Mode.ToString()));
|
|
}
|
|
}
|
|
|
|
// now show the projects in this mode
|
|
ProjectNames.AddRange(ProjectsByType[CurrentMode].Select(x => (CurrentMode == ProjectMode.Recent) ? x.FullName : x.GetFileNameWithoutAnyExtensions()));
|
|
|
|
// and finally a manual entry option
|
|
if (RuntimePlatform.IsWindows)
|
|
{
|
|
ProjectNames.Add("[Browse...]");
|
|
}
|
|
else
|
|
{
|
|
ProjectNames.Add("[Enter Path To .uproject...]");
|
|
}
|
|
|
|
int Default = LastProject == null ? -1 : ProjectNames.FindIndex(x => x.Equals(LastProject, StringComparison.OrdinalIgnoreCase));
|
|
int Choice = TurnkeyUtils.ReadInputInt(string.Format("Choose a {0} project to execute, or select a set of projects to list. (You can skip this by specifying -project=XXX on the commandline)", CurrentMode), ProjectNames, true, Default == -1 ? -1 : Default + 1);
|
|
if (Choice == 0)
|
|
{
|
|
return null;
|
|
}
|
|
// skip cancel
|
|
Choice = Choice - 1;
|
|
|
|
// look for manual entry option
|
|
if (Choice == ProjectNames.Count - 1)
|
|
{
|
|
if (OperatingSystem.IsWindows())
|
|
{
|
|
string ChosenFile = null;
|
|
System.Threading.Thread t = new System.Threading.Thread(x =>
|
|
{
|
|
Debug.Assert(OperatingSystem.IsWindowsVersionAtLeast(7));
|
|
ChosenFile = UnrealWindowsForms.Utils.ShowOpenFileDialogAndReturnFilename("Project Files (*.uproject)|*.uproject");
|
|
});
|
|
|
|
t.SetApartmentState(System.Threading.ApartmentState.STA);
|
|
t.Start();
|
|
t.Join();
|
|
|
|
if (ChosenFile == null)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (true)
|
|
{
|
|
string ProjectChoice = TurnkeyUtils.ReadInput("Enter path to .uproject file:");
|
|
if (!File.Exists(ProjectChoice))
|
|
{
|
|
bool bResponse = TurnkeyUtils.GetUserConfirmation(string.Format("'{0}' doesn't exist. Would you like to enter another path?", ProjectChoice), false);
|
|
if (bResponse == false)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Project = ProjectChoice;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if we got a valid vhoice, remember it
|
|
if (!string.IsNullOrEmpty(Project))
|
|
{
|
|
// remember this for next run
|
|
// case insensitive Contains
|
|
if (!ManualProjects.Any(x => x.Equals(Project, StringComparison.OrdinalIgnoreCase)))
|
|
{
|
|
ManualProjects.Add(Project);
|
|
}
|
|
TurnkeySettings.SetUserSetting("User_ManualProjects", string.Join(";", ManualProjects));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if the choice was a mode switch, get the mode
|
|
if (IndexToMode.TryGetValue(Choice, out CurrentMode))
|
|
{
|
|
continue;
|
|
}
|
|
Project = ProjectNames[Choice];
|
|
}
|
|
}
|
|
|
|
// remember project for next run
|
|
TurnkeySettings.SetUserSetting("User_LastSelectedProject", Project);
|
|
|
|
return ProjectUtils.FindProjectFileFromName(Project);
|
|
}
|
|
|
|
private static DeviceInfo GetDeviceByPlatformAndName(UnrealTargetPlatform Platform, string DeviceName)
|
|
{
|
|
try
|
|
{
|
|
return AutomationTool.Platform.GetPlatform(Platform).GetDeviceByName(DeviceName);
|
|
}
|
|
catch (Exception Ex)
|
|
{
|
|
TurnkeyUtils.Log($"An error occurred trying to access device {DeviceName} for platform {Platform}: {Ex.Message}");
|
|
|
|
// swallow errors and just return no device
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private static DeviceInfo[] GetDevicesForPlatform(UnrealTargetPlatform Platform)
|
|
{
|
|
try
|
|
{
|
|
DeviceInfo[] Devices = AutomationTool.Platform.GetPlatform(Platform).GetDevices();
|
|
|
|
// in the null case, return an empty array, for cleaner code for callers
|
|
return Devices != null ? Devices : new DeviceInfo[] { };
|
|
}
|
|
catch (Exception Ex)
|
|
{
|
|
TurnkeyUtils.Log($"An error occurred trying to access all devices for platform {Platform}: {Ex.Message}");
|
|
|
|
// swallow errors and just return no devices
|
|
return new DeviceInfo[] { } ;
|
|
}
|
|
}
|
|
|
|
|
|
public static List<DeviceInfo> GetDevicesFromCommandLineOrUser(string[] CommandOptions, UnrealTargetPlatform Platform)
|
|
{
|
|
return GetDevicesFromCommandLineOrUser(CommandOptions, new List<UnrealTargetPlatform>() { Platform });
|
|
}
|
|
//public static DeviceInfo GetDeviceFromCommandLineOrUser(string[] CommandOptions, UnrealTargetPlatform Platform)
|
|
//{
|
|
// Dictionary<UnrealTargetPlatform, List<DeviceInfo>> PlatformsAndDevices = GetDevicesFromCommandLineOrUser(CommandOptions, Platform);
|
|
//}
|
|
|
|
public static List<DeviceInfo> GetDevicesFromCommandLineOrUser(string[] CommandOptions, List<UnrealTargetPlatform> PossiblePlatforms)
|
|
{
|
|
List<DeviceInfo> ChosenDevices = null;
|
|
|
|
// look at any devices on the commandline, and see if they have platforms or not
|
|
string DeviceList = TurnkeyUtils.ParseParamValue("Device", null, CommandOptions);
|
|
List<string> SplitDeviceList = null;
|
|
if (DeviceList != null && DeviceList.ToLower() != "all")
|
|
{
|
|
SplitDeviceList = DeviceList.Split("+".ToCharArray()).ToList();
|
|
|
|
// look if they have platform@ tags
|
|
bool bAnyHavePlatform = SplitDeviceList.Any(x => x.Contains("@"));
|
|
if (bAnyHavePlatform)
|
|
{
|
|
if (!SplitDeviceList.All(x => x.Contains("@")))
|
|
{
|
|
throw new AutomationException("If any device in -device has a platform indicator ('Platform@Device'), they must all have a platform indicator");
|
|
}
|
|
|
|
// now split it up for devices for each platform
|
|
foreach (string DeviceToken in SplitDeviceList)
|
|
{
|
|
string[] Tokens = DeviceToken.Split("@".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
|
|
if (Tokens.Length != 2)
|
|
{
|
|
throw new AutomationException("{0} did not have the Platform@Device format", DeviceToken);
|
|
}
|
|
UnrealTargetPlatform Platform;
|
|
if (!UnrealTargetPlatform.TryParse(Tokens[0], out Platform))
|
|
{
|
|
TurnkeyUtils.Log("Platform indicator {0} is an invalid platform, skipping", Tokens[0]);
|
|
continue;
|
|
}
|
|
|
|
string DeviceName = Tokens[1];
|
|
|
|
// track it
|
|
if (ChosenDevices == null)
|
|
{
|
|
ChosenDevices = new List<DeviceInfo>();
|
|
}
|
|
|
|
if (DeviceName.ToLower() == "all")
|
|
{
|
|
ChosenDevices.AddRange(GetDevicesForPlatform(Platform));
|
|
}
|
|
else
|
|
{
|
|
DeviceInfo Device = GetDeviceByPlatformAndName(Platform, DeviceName);
|
|
if (Device != null)
|
|
{
|
|
ChosenDevices.Add(Device);
|
|
}
|
|
}
|
|
}
|
|
SplitDeviceList = null;
|
|
}
|
|
}
|
|
|
|
// if we didn't get some platforms already from -device list, then get or ask the user for platforms
|
|
if (ChosenDevices == null)
|
|
{
|
|
ChosenDevices = new List<DeviceInfo>();
|
|
List<UnrealTargetPlatform> ChosenPlatforms;
|
|
|
|
// use all platforms (with -device=all), or ask user if needed (GetPlatformsFromCommandLineOrUser would look at -platform=all, not -device=all)
|
|
// if -platform was specified, use the function to get just the specified ones
|
|
if (DeviceList != null && DeviceList.ToLower() == "all" && TurnkeyUtils.ParseParamValue("Platform", null, CommandOptions) == null)
|
|
{
|
|
ChosenPlatforms = GetAllValidPlatforms(PossiblePlatforms);
|
|
}
|
|
// if there's only one platform possible, use it
|
|
else if (PossiblePlatforms != null && PossiblePlatforms.Count == 1)
|
|
{
|
|
ChosenPlatforms = PossiblePlatforms;
|
|
}
|
|
else
|
|
{
|
|
ChosenPlatforms = TurnkeyUtils.GetPlatformsFromCommandLineOrUser(CommandOptions, PossiblePlatforms);
|
|
}
|
|
|
|
if (ChosenPlatforms == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (ChosenPlatforms.Count > 1 && SplitDeviceList != null && !(SplitDeviceList.Count == 1 && SplitDeviceList[0].ToLower() == "all"))
|
|
{
|
|
throw new AutomationException("When using -Device without platform specifiers ('Platform@Device'), a single platform must be specified (unless -Device=All is used)");
|
|
}
|
|
|
|
// get all the devices for the platforms
|
|
if (!string.IsNullOrEmpty(DeviceList) && DeviceList.ToLower() == "all")
|
|
{
|
|
foreach (UnrealTargetPlatform Platform in ChosenPlatforms)
|
|
{
|
|
ChosenDevices.AddRange(GetDevicesForPlatform(Platform));
|
|
}
|
|
}
|
|
// now if the list of devices was given, then attempt to find them in the platform
|
|
else if (SplitDeviceList != null && SplitDeviceList.Count > 0)
|
|
{
|
|
foreach (UnrealTargetPlatform Platform in ChosenPlatforms)
|
|
{
|
|
foreach (string DeviceName in SplitDeviceList)
|
|
{
|
|
DeviceInfo Device = GetDeviceByPlatformAndName(Platform, DeviceName);
|
|
if (Device != null)
|
|
{
|
|
ChosenDevices.Add(Device);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// otherwise ask user for device
|
|
else
|
|
{
|
|
List<string> Options = new List<string>();
|
|
List<DeviceInfo> PossibleDevices = new List<DeviceInfo>();
|
|
|
|
foreach (UnrealTargetPlatform Platform in ChosenPlatforms)
|
|
{
|
|
foreach (DeviceInfo Device in GetDevicesForPlatform(Platform))
|
|
{
|
|
PossibleDevices.Add(Device);
|
|
Options.Add(string.Format("[{0} {1}] {2}", Platform, Device.Type, Device.Name));
|
|
}
|
|
}
|
|
|
|
if (PossibleDevices.Count == 0)
|
|
{
|
|
Log("Unable to find any devices for platform(s): {0}", string.Join(", ", ChosenPlatforms));
|
|
return null;
|
|
}
|
|
|
|
// get the choice
|
|
int Choice = TurnkeyUtils.ReadInputInt("Select a device:", Options, true);
|
|
|
|
if (Choice == 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
// finally, add it to the proper list
|
|
ChosenDevices.Add(PossibleDevices[Choice - 1]);
|
|
}
|
|
}
|
|
|
|
// if we ended up with some platforms, but no devices, just return null
|
|
return (ChosenDevices != null && ChosenDevices.Count > 0) ? ChosenDevices : null;
|
|
}
|
|
|
|
public static void GetPlatformsAndDevicesFromCommandLineOrUser(string[] CommandOptions, bool bSkipAskUserForDevice, out List<UnrealTargetPlatform> Platforms, out List<DeviceInfo> Devices, List<UnrealTargetPlatform> AllowedPlatforms=null)
|
|
{
|
|
Platforms = new List<UnrealTargetPlatform>();
|
|
Devices = new List<DeviceInfo>();
|
|
|
|
string DeviceString = TurnkeyUtils.ParseParamValue("Device", null, CommandOptions);
|
|
if (string.IsNullOrEmpty(DeviceString))
|
|
{
|
|
Platforms.AddRange(TurnkeyUtils.GetPlatformsFromCommandLineOrUser(CommandOptions, AllowedPlatforms));
|
|
// restrict devices to this platform
|
|
AllowedPlatforms = Platforms;
|
|
}
|
|
|
|
// if there's no -device param, and we don't want to ask user for a device, skip this
|
|
if (!string.IsNullOrEmpty(DeviceString) || !bSkipAskUserForDevice)
|
|
{
|
|
List<DeviceInfo> ChosenDevices = TurnkeyUtils.GetDevicesFromCommandLineOrUser(CommandOptions, AllowedPlatforms);
|
|
|
|
if (ChosenDevices != null)
|
|
{
|
|
Devices = ChosenDevices;
|
|
// pull the platforms out of the devices we have chosen
|
|
Platforms = Devices.Select(x => x.Platform).ToHashSet().ToList();
|
|
}
|
|
}
|
|
}
|
|
|
|
public static string GetGenericOption(string[] CommandOptions, List<string> Options, string CommandLineOption)
|
|
{
|
|
return GetGenericOption(CommandOptions, Options, CommandLineOption, out _);
|
|
}
|
|
|
|
public static string GetGenericOption(string[] CommandOptions, List<string> Options, string CommandLineOption, out bool bWasOnCommandLine)
|
|
{
|
|
string ChosenValue = TurnkeyUtils.ParseParamValue(CommandLineOption, null, CommandOptions);
|
|
|
|
if (ChosenValue != null)
|
|
{
|
|
bWasOnCommandLine = true;
|
|
}
|
|
else
|
|
{
|
|
bWasOnCommandLine = false;
|
|
|
|
// default to previous selection if any
|
|
string CachedOptionName = "User_LastSelectedGeneric_" + CommandLineOption;
|
|
string LastSelectedOption = TurnkeySettings.GetUserSettingIfSet(CachedOptionName, "");
|
|
int Default = Options.FindIndex(x => x.Equals(LastSelectedOption, StringComparison.OrdinalIgnoreCase));
|
|
|
|
int Choice = ReadInputInt($"Choose the {CommandLineOption}:", Options, true, Default == -1 ? -1 : Default + 1);
|
|
if (Choice == 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
ChosenValue = Options[Choice - 1];
|
|
|
|
// remember for next time
|
|
TurnkeySettings.SetUserSetting(CachedOptionName, ChosenValue);
|
|
}
|
|
|
|
return ChosenValue;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Env vars
|
|
|
|
private static IDictionary[] SavedEnvVars = new System.Collections.IDictionary[2];
|
|
private static Dictionary<string, string> EnvVarsToSaveToBatchFile = new Dictionary<string, string>();
|
|
|
|
public static void StartTrackingExternalEnvVarChanges()
|
|
{
|
|
SavedEnvVars[0] = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User);
|
|
SavedEnvVars[1] = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine);
|
|
}
|
|
|
|
public static void EndTrackingExternalEnvVarChanges()
|
|
{
|
|
System.Collections.IDictionary[] NewEnvVars =
|
|
{
|
|
Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User),
|
|
Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine),
|
|
};
|
|
|
|
TurnkeyUtils.Log("Scanning for envvar changes...");
|
|
|
|
// look for differences
|
|
for (int Index = 0; Index < NewEnvVars.Length; Index++)
|
|
{
|
|
IDictionary NewSet = NewEnvVars[Index];
|
|
IDictionary PreviousSet = SavedEnvVars[Index];
|
|
|
|
foreach (DictionaryEntry Pair in NewSet)
|
|
{
|
|
Object PrevValue = PreviousSet[Pair.Key];
|
|
string NewKey = Pair.Key as string;
|
|
string NewValue= Pair.Value as string;
|
|
|
|
// if we have a new or changed value, apply it to the process
|
|
if (PrevValue == null || string.Compare(PrevValue as string, NewValue) != 0)
|
|
{
|
|
TurnkeyUtils.Log(" Updating process env var {0} to {1}", Pair.Key, Pair.Value);
|
|
Environment.SetEnvironmentVariable(NewKey, NewValue, EnvironmentVariableTarget.Process);
|
|
// remember to save to batch file
|
|
EnvVarsToSaveToBatchFile[NewKey] = NewValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
TurnkeyUtils.Log("... done! ");
|
|
if (EnvVarsToSaveToBatchFile.Count > 0)
|
|
{
|
|
StringBuilder BatchContents = new StringBuilder();
|
|
foreach (var Pair in EnvVarsToSaveToBatchFile)
|
|
{
|
|
BatchContents.AppendLine("set {0}={1}", Pair.Key, Pair.Value);
|
|
TurnkeyUtils.Log(" Recording variable to set by caller {0}={1}", Pair.Key, Pair.Value);
|
|
}
|
|
|
|
// write out a batch file for the caller of this to call to update vars, including all changes from previous commands
|
|
string BatchPath = ExpandVariables("$(EngineDir)/Intermediate/Turnkey/PostTurnkeyVariables.bat");
|
|
TurnkeyUtils.Log(" Writing updated envvars to {0}", BatchPath);
|
|
Directory.CreateDirectory(Path.GetDirectoryName(BatchPath));
|
|
File.WriteAllText(BatchPath, BatchContents.ToString());
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Regex Matching
|
|
|
|
static bool TryConvertToUint64(string InValue, out UInt64 OutValue)
|
|
{
|
|
if (InValue.StartsWith("0x"))
|
|
{
|
|
// must skip ovr the 0x
|
|
return UInt64.TryParse(InValue.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out OutValue);
|
|
}
|
|
return UInt64.TryParse(InValue, out OutValue);
|
|
}
|
|
|
|
public static bool IsValueValid(string Value, string AllowedValues, AutomationTool.Platform Platform)
|
|
{
|
|
if (string.IsNullOrEmpty(Value))
|
|
{
|
|
return false;
|
|
}
|
|
if (string.IsNullOrEmpty(AllowedValues))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// use a regex if the allowed string starts with "regex:"
|
|
if (AllowedValues.StartsWith("regex:", StringComparison.InvariantCultureIgnoreCase))
|
|
{
|
|
return Regex.IsMatch(Value, AllowedValues.Substring(6));
|
|
}
|
|
|
|
// range type needs to have values that can convert to an integer (in base 10 or 16 with 0x)
|
|
if (AllowedValues.StartsWith("range:", StringComparison.InvariantCultureIgnoreCase))
|
|
{
|
|
// match for "[Min]-[Max]" ([] meaning optional), and Min or Max can be a hex or decimal number,
|
|
// and it must match the entire string, so, 0-10.0 would not match
|
|
Match StreamMatch = new Regex(@"^(0x[0-9a-fA-F]*|[0-9]*)-(0x[0-9a-fA-F]*|[0-9]*)$").Match(AllowedValues.Substring(6));
|
|
|
|
if (!StreamMatch.Success)
|
|
{
|
|
TurnkeyUtils.Log("Warning: range: type [{0}] was in a bad format. Must be a range of one or two positive integers in decimal or hex (ex: '0x1000-0x2000', or '435-')");
|
|
return false;
|
|
}
|
|
|
|
// convert inputs to uint (unless already converted above by platform)
|
|
UInt64 ValueInt = 0;
|
|
if (!TryConvertToUint64(Value, out ValueInt) && !UEBuildPlatformSDK.GetSDKForPlatform(Platform.PlatformType.ToString()).TryConvertVersionToInt(Value, out ValueInt))
|
|
{
|
|
TurnkeyUtils.Log("Warning: range: input value [{0}] was not an unsigned integer, and platform couldn't convert it", Value);
|
|
return false;
|
|
}
|
|
|
|
// min and max are optional, so use 0 and MaxValue if they aren't
|
|
string MinString = StreamMatch.Groups[1].Value;
|
|
string MaxString = StreamMatch.Groups[2].Value;
|
|
UInt64 Min = 0, Max = UInt64.MaxValue;
|
|
if (!string.IsNullOrEmpty(MinString))
|
|
{
|
|
// Regex verified they are in a good format, so we can use Parse
|
|
TryConvertToUint64(MinString, out Min);
|
|
}
|
|
if (!string.IsNullOrEmpty(MaxString))
|
|
{
|
|
TryConvertToUint64(MaxString, out Max);
|
|
}
|
|
|
|
// finally perform the comparison
|
|
return ValueInt >= Min && ValueInt <= Max;
|
|
}
|
|
|
|
// otherwise, perform a string comparison
|
|
return string.Compare(Value, AllowedValues, true) == 0;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IO
|
|
static private IOProvider IOProvider;
|
|
|
|
public static void Log(string Message)
|
|
{
|
|
IOProvider.Log(Message, bAppendNewLine: true);
|
|
}
|
|
public static void Log(ref StringBuilder Message)
|
|
{
|
|
IOProvider.Log(Message.ToString(), bAppendNewLine: false);
|
|
Message.Clear();
|
|
}
|
|
public static void Log(string Message, params object[] Params)
|
|
{
|
|
IOProvider.Log(string.Format(Message, Params), bAppendNewLine: true);
|
|
}
|
|
|
|
public static void Report(string Message)
|
|
{
|
|
IOProvider.Report(Message, bAppendNewLine: true);
|
|
}
|
|
public static void Report(ref StringBuilder Message)
|
|
{
|
|
IOProvider.Report(Message.ToString(), bAppendNewLine: false);
|
|
Message.Clear();
|
|
}
|
|
public static void Report(string Message, params object[] Params)
|
|
{
|
|
IOProvider.Report(string.Format(Message, Params), bAppendNewLine: true);
|
|
}
|
|
|
|
public static void PauseForUser(string Message, params object[] Params)
|
|
{
|
|
IOProvider.PauseForUser(string.Format(Message, Params), bAppendNewLine: true);
|
|
}
|
|
|
|
public static string ReadInput(string Prompt, string Default = "")
|
|
{
|
|
return IOProvider.ReadInput(Prompt, Default, bAppendNewLine: true);
|
|
}
|
|
public static int ReadInputInt(ref StringBuilder Prompt, List<string> Options, bool bIsCancellable, int DefaultValue = -1)
|
|
{
|
|
string PromptString = Prompt.ToString();
|
|
Prompt.Clear();
|
|
return IOProvider.ReadInputInt(PromptString, Options, bIsCancellable, DefaultValue, bAppendNewLine: false);
|
|
}
|
|
public static int ReadInputInt(string Prompt, List<string> Options, bool bIsCancellable, int DefaultValue = -1)
|
|
{
|
|
return IOProvider.ReadInputInt(Prompt, Options, bIsCancellable, DefaultValue, bAppendNewLine: true);
|
|
}
|
|
|
|
public static bool GetUserConfirmation(string Message, bool bDefaultValue)
|
|
{
|
|
return IOProvider.GetUserConfirmation(Message, bDefaultValue, true );
|
|
}
|
|
#endregion
|
|
|
|
#region Temp files [move to LocalCache]
|
|
static List<string> PathsToCleanup = new List<string>();
|
|
public static void AddPathToCleanup(string Path)
|
|
{
|
|
PathsToCleanup.Add(Path);
|
|
}
|
|
|
|
public static void CleanupPaths()
|
|
{
|
|
TurnkeyUtils.Log("Cleaning Temp Paths...");
|
|
|
|
// cleanup any delay-cleanup files and directories
|
|
foreach (string Path in PathsToCleanup)
|
|
{
|
|
if (Directory.Exists(Path))
|
|
{
|
|
InternalUtils.SafeDeleteDirectory(Path);
|
|
}
|
|
else if (File.Exists(Path))
|
|
{
|
|
InternalUtils.SafeDeleteFile(Path);
|
|
}
|
|
}
|
|
|
|
PathsToCleanup.Clear();
|
|
}
|
|
#endregion
|
|
}
|
|
}
|