Files
UnrealEngineUWP/Engine/Source/Programs/AutomationTool/Scripts/RunProjectCommand.Automation.cs

1024 lines
31 KiB
C#
Raw Normal View History

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
using System.Reflection;
using System.Linq;
using System.Net.NetworkInformation;
using System.Collections;
using AutomationTool;
using UnrealBuildTool;
/// <summary>
/// Helper command to run a game.
/// </summary>
/// <remarks>
/// Uses the following command line params:
/// -cooked
/// -cookonthefly
/// -dedicatedserver
/// -win32
/// -noclient
/// -logwindow
/// </remarks>
public partial class Project : CommandUtils
{
#region Fields
/// <summary>
/// Thread used to read client log file.
/// </summary>
private static Thread ClientLogReaderThread = null;
/// <summary>
/// Process for the server, can be set by the cook command when a cook on the fly server is used
/// </summary>
public static ProcessResult ServerProcess;
#endregion
#region Run Command
// debug commands for the engine to crash
public static string[] CrashCommands =
{
"crash",
"CHECK",
"GPF",
"ASSERT",
"ENSURE",
"RENDERCRASH",
"RENDERCHECK",
"RENDERGPF",
"THREADCRASH",
"THREADCHECK",
"THREADGPF",
};
/// <summary>
/// For not-installed runs, returns a temp log folder to make sure it doesn't fall into sandbox paths
/// </summary>
/// <returns></returns>
private static string GetLogFolderOutsideOfSandbox()
{
return GlobalCommandLine.Installed ?
CmdEnv.LogFolder :
CombinePaths(Path.GetTempPath(), CommandUtils.EscapePath(CmdEnv.LocalRoot), "Logs");
}
/// <summary>
/// Fot not-installed runs, copies all logs from the temp log folder back to the UAT log folder.
/// </summary>
private static void CopyLogsBackToLogFolder()
{
if (!GlobalCommandLine.Installed)
{
var LogFolderOutsideOfSandbox = GetLogFolderOutsideOfSandbox();
var TempLogFiles = FindFiles_NoExceptions("*", false, LogFolderOutsideOfSandbox);
foreach (var LogFilename in TempLogFiles)
{
var DestFilename = CombinePaths(CmdEnv.LogFolder, Path.GetFileName(LogFilename));
CopyFile_NoExceptions(LogFilename, DestFilename);
}
}
}
public static void Run(ProjectParams Params)
{
Params.ValidateAndLog();
if (!Params.Run)
{
return;
}
Log("********** RUN COMMAND STARTED **********");
var LogFolderOutsideOfSandbox = GetLogFolderOutsideOfSandbox();
if (!GlobalCommandLine.Installed && ServerProcess == null)
{
// In the installed runs, this is the same folder as CmdEnv.LogFolder so delete only in not-installed
DeleteDirectory(LogFolderOutsideOfSandbox);
CreateDirectory(LogFolderOutsideOfSandbox);
}
var ServerLogFile = CombinePaths(LogFolderOutsideOfSandbox, "Server.log");
var ClientLogFile = CombinePaths(LogFolderOutsideOfSandbox, Params.EditorTest ? "Editor.log" : "Client.log");
try
{
RunInternal(Params, ServerLogFile, ClientLogFile);
}
catch
{
throw;
}
finally
{
CopyLogsBackToLogFolder();
}
Log("********** RUN COMMAND COMPLETED **********");
}
private static void RunInternal(ProjectParams Params, string ServerLogFile, string ClientLogFile)
{
// Setup server process if required.
if (Params.DedicatedServer && !Params.SkipServer)
{
if (Params.ServerTargetPlatforms.Count > 0)
{
UnrealTargetPlatform ServerPlatform = Params.ServerTargetPlatforms[0];
ServerProcess = RunDedicatedServer(Params, ServerLogFile, Params.RunCommandline);
// With dedicated server, the client connects to local host to load a map.
if (ServerPlatform == UnrealTargetPlatform.Linux)
{
Params.MapToRun = Params.ServerDeviceAddress;
}
else
{
Params.MapToRun = "127.0.0.1";
}
}
else
{
throw new AutomationException("Failed to run, server target platform not specified");
}
}
else if (Params.FileServer && !Params.SkipServer)
{
ServerProcess = RunFileServer(Params, ServerLogFile, Params.RunCommandline);
}
if (ServerProcess != null)
{
Log("Waiting a few seconds for the server to start...");
Thread.Sleep(5000);
}
if (!Params.NoClient)
{
Log("Starting Client....");
var SC = CreateDeploymentContext(Params, false);
ERunOptions ClientRunFlags;
string ClientApp;
string ClientCmdLine;
SetupClientParams(SC, Params, ClientLogFile, out ClientRunFlags, out ClientApp, out ClientCmdLine);
// Run the client.
if (ServerProcess != null)
{
RunClientWithServer(SC, ServerLogFile, ServerProcess, ClientApp, ClientCmdLine, ClientRunFlags, ClientLogFile, Params);
}
else
{
RunStandaloneClient(SC, ClientLogFile, ClientRunFlags, ClientApp, ClientCmdLine, Params);
}
}
}
#endregion
#region Client
private static void RunStandaloneClient(List<DeploymentContext> DeployContextList, string ClientLogFile, ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params)
{
if (Params.Unattended)
{
string LookFor = "Bringing up level for play took";
if (Params.RunAutomationTest != "")
{
LookFor = "Automation Test Succeeded";
}
else if (Params.RunAutomationTests)
{
LookFor = "Automation Test Queue Empty";
}
else if (Params.EditorTest)
{
LookFor = "Asset discovery search completed in";
}
{
string AllClientOutput = "";
int LastAutoFailIndex = -1;
ProcessResult ClientProcess = null;
FileStream ClientProcessLog = null;
StreamReader ClientLogReader = null;
Log("Starting Client for unattended test....");
ClientProcess = Run(ClientApp, ClientCmdLine + " -FORCELOGFLUSH -testexit=\"" + LookFor + "\"", null, ClientRunFlags | ERunOptions.NoWaitForExit);
while (!FileExists(ClientLogFile) && !ClientProcess.HasExited)
{
Log("Waiting for client logging process to start...{0}", ClientLogFile);
Thread.Sleep(2000);
}
if (FileExists(ClientLogFile))
{
Thread.Sleep(2000);
Log("Client logging process started...{0}", ClientLogFile);
ClientProcessLog = File.Open(ClientLogFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
ClientLogReader = new StreamReader(ClientProcessLog);
}
if (ClientLogReader == null)
{
throw new AutomationException("Client exited without creating a log file.");
}
bool bKeepReading = true;
bool WelcomedCorrectly = false;
bool bClientExited = false;
DateTime ExitTime = DateTime.UtcNow;
while (bKeepReading)
{
if (!bClientExited && ClientProcess.HasExited)
{
ExitTime = DateTime.UtcNow;
bClientExited = true;
}
string ClientOutput = ClientLogReader.ReadToEnd();
if (!String.IsNullOrEmpty(ClientOutput))
{
if (bClientExited)
{
ExitTime = DateTime.UtcNow; // as long as it is spewing, we reset the timer
}
AllClientOutput += ClientOutput;
Console.Write(ClientOutput);
if (AllClientOutput.LastIndexOf(LookFor) > AllClientOutput.IndexOf(LookFor))
{
WelcomedCorrectly = true;
Log("Test complete...");
bKeepReading = false;
}
else if (Params.RunAutomationTests)
{
int FailIndex = AllClientOutput.LastIndexOf("Automation Test Failed");
int ParenIndex = AllClientOutput.LastIndexOf(")");
if (FailIndex >= 0 && ParenIndex > FailIndex && FailIndex > LastAutoFailIndex)
{
string Tail = AllClientOutput.Substring(FailIndex);
int CloseParenIndex = Tail.IndexOf(")");
int OpenParenIndex = Tail.IndexOf("(");
string Test = "";
if (OpenParenIndex >= 0 && CloseParenIndex > OpenParenIndex)
{
Test = Tail.Substring(OpenParenIndex + 1, CloseParenIndex - OpenParenIndex - 1);
Log(System.Diagnostics.TraceEventType.Error, "Automated test failed ({0}).", Test);
LastAutoFailIndex = FailIndex;
}
}
}
}
else if (bClientExited && (DateTime.UtcNow - ExitTime).TotalSeconds > 30)
{
Log("Client exited and has been quiet for 30 seconds...exiting");
bKeepReading = false;
}
}
if (ClientProcess != null && !ClientProcess.HasExited)
{
Log("Client is supposed to exit, lets wait a while for it to exit naturally...");
for (int i = 0; i < 120 && !ClientProcess.HasExited; i++)
{
Thread.Sleep(1000);
}
}
if (ClientProcess != null && !ClientProcess.HasExited)
{
Log("Stopping client...");
ClientProcess.StopProcess();
Thread.Sleep(10000);
}
while (ClientLogReader != null && !ClientLogReader.EndOfStream)
{
string ClientOutput = ClientLogReader.ReadToEnd();
if (!String.IsNullOrEmpty(ClientOutput))
{
Console.Write(ClientOutput);
}
}
if (!WelcomedCorrectly)
{
throw new AutomationException("Client exited before we asked it to.");
}
}
}
else
{
var SC = DeployContextList[0];
ProcessResult ClientProcess = SC.StageTargetPlatform.RunClient(ClientRunFlags, ClientApp, ClientCmdLine, Params);
if (ClientProcess != null)
{
// If the client runs without StdOut redirect we're going to read the log output directly from log file on
// a separate thread.
if ((ClientRunFlags & ERunOptions.NoStdOutRedirect) == ERunOptions.NoStdOutRedirect)
{
ClientLogReaderThread = new System.Threading.Thread(ClientLogReaderProc);
ClientLogReaderThread.Start(new object[] { ClientLogFile, ClientProcess });
}
do
{
Thread.Sleep(100);
}
while (ClientProcess.HasExited == false);
if (ClientProcess.ExitCode != 0)
{
throw new AutomationException("Client exited with error code: " + ClientProcess.ExitCode);
}
}
}
}
private static void RunClientWithServer(List<DeploymentContext> DeployContextList, string ServerLogFile, ProcessResult ServerProcess, string ClientApp, string ClientCmdLine, ERunOptions ClientRunFlags, string ClientLogFile, ProjectParams Params)
{
ProcessResult ClientProcess = null;
var OtherClients = new List<ProcessResult>();
bool WelcomedCorrectly = false;
int NumClients = Params.NumClients;
string AllClientOutput = "";
int LastAutoFailIndex = -1;
if (Params.Unattended)
{
string LookFor = "Bringing up level for play took";
if (Params.DedicatedServer)
{
LookFor = "Welcomed by server";
}
else if (Params.RunAutomationTest != "")
{
LookFor = "Automation Test Succeeded";
}
else if (Params.RunAutomationTests)
{
LookFor = "Automation Test Queue Empty";
}
{
while (!FileExists(ServerLogFile) && !ServerProcess.HasExited)
{
Log("Waiting for logging process to start...");
Thread.Sleep(2000);
}
Thread.Sleep(1000);
string AllServerOutput = "";
using (FileStream ProcessLog = File.Open(ServerLogFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
StreamReader LogReader = new StreamReader(ProcessLog);
bool bKeepReading = true;
FileStream ClientProcessLog = null;
StreamReader ClientLogReader = null;
// Read until the process has exited.
while (!ServerProcess.HasExited && bKeepReading)
{
while (!LogReader.EndOfStream && bKeepReading && ClientProcess == null)
{
string Output = LogReader.ReadToEnd();
if (!String.IsNullOrEmpty(Output))
{
AllServerOutput += Output;
if (ClientProcess == null &&
(AllServerOutput.Contains("Game Engine Initialized") || AllServerOutput.Contains("Unreal Network File Server is ready")))
{
Log("Starting Client for unattended test....");
ClientProcess = Run(ClientApp, ClientCmdLine + " -FORCELOGFLUSH -testexit=\"" + LookFor + "\"", null, ClientRunFlags | ERunOptions.NoWaitForExit);
//@todo no testing is done on these
if (NumClients > 1 && NumClients < 9)
{
for (int i = 1; i < NumClients; i++)
{
Log("Starting Extra Client....");
OtherClients.Add(Run(ClientApp, ClientCmdLine, null, ClientRunFlags | ERunOptions.NoWaitForExit));
}
}
while (!FileExists(ClientLogFile) && !ClientProcess.HasExited)
{
Log("Waiting for client logging process to start...{0}", ClientLogFile);
Thread.Sleep(2000);
}
if (!ClientProcess.HasExited)
{
Thread.Sleep(2000);
Log("Client logging process started...{0}", ClientLogFile);
ClientProcessLog = File.Open(ClientLogFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
ClientLogReader = new StreamReader(ClientProcessLog);
}
}
else if (ClientProcess == null && !ServerProcess.HasExited)
{
Log("Waiting for server to start....");
Thread.Sleep(2000);
}
if (ClientProcess != null && ClientProcess.HasExited)
{
ServerProcess.StopProcess();
throw new AutomationException("Client exited before we asked it to.");
}
}
}
if (ClientLogReader != null)
{
if (ClientProcess.HasExited)
{
ServerProcess.StopProcess();
throw new AutomationException("Client exited or closed the log before we asked it to.");
}
while (!ClientProcess.HasExited && !ServerProcess.HasExited && bKeepReading)
{
while (!ClientLogReader.EndOfStream && bKeepReading && !ServerProcess.HasExited && !ClientProcess.HasExited)
{
string ClientOutput = ClientLogReader.ReadToEnd();
if (!String.IsNullOrEmpty(ClientOutput))
{
AllClientOutput += ClientOutput;
Console.Write(ClientOutput);
if (AllClientOutput.LastIndexOf(LookFor) > AllClientOutput.IndexOf(LookFor))
{
if (Params.FakeClient)
{
Log("Welcomed by server or client loaded, lets wait ten minutes...");
Thread.Sleep(60000 * 10);
}
else
{
Log("Welcomed by server or client loaded, lets wait 30 seconds...");
Thread.Sleep(30000);
}
WelcomedCorrectly = true;
bKeepReading = false;
}
else if (Params.RunAutomationTests)
{
int FailIndex = AllClientOutput.LastIndexOf("Automation Test Failed");
int ParenIndex = AllClientOutput.LastIndexOf(")");
if (FailIndex >= 0 && ParenIndex > FailIndex && FailIndex > LastAutoFailIndex)
{
string Tail = AllClientOutput.Substring(FailIndex);
int CloseParenIndex = Tail.IndexOf(")");
int OpenParenIndex = Tail.IndexOf("(");
string Test = "";
if (OpenParenIndex >= 0 && CloseParenIndex > OpenParenIndex)
{
Test = Tail.Substring(OpenParenIndex + 1, CloseParenIndex - OpenParenIndex - 1);
Log(System.Diagnostics.TraceEventType.Error, "Automated test failed ({0}).", Test);
LastAutoFailIndex = FailIndex;
}
}
}
}
}
}
}
}
}
}
}
else
{
LogFileReaderProcess(ServerLogFile, ServerProcess, (string Output) =>
{
bool bKeepReading = true;
if (ClientProcess == null && !String.IsNullOrEmpty(Output))
{
AllClientOutput += Output;
if (ClientProcess == null && (AllClientOutput.Contains("Game Engine Initialized") || AllClientOutput.Contains("Unreal Network File Server is ready")))
{
Log("Starting Client....");
var SC = DeployContextList[0];
ClientProcess = SC.StageTargetPlatform.RunClient(ClientRunFlags | ERunOptions.NoWaitForExit, ClientApp, ClientCmdLine, Params);
// ClientProcess = Run(ClientApp, ClientCmdLine, null, ClientRunFlags | ERunOptions.NoWaitForExit);
if (NumClients > 1 && NumClients < 9)
{
for (int i = 1; i < NumClients; i++)
{
Log("Starting Extra Client....");
ProcessResult NewClient = SC.StageTargetPlatform.RunClient(ClientRunFlags | ERunOptions.NoWaitForExit, ClientApp, ClientCmdLine, Params);
OtherClients.Add(NewClient);
}
}
}
}
else if (ClientProcess == null && !ServerProcess.HasExited)
{
Log("Waiting for server to start....");
Thread.Sleep(2000);
}
if (String.IsNullOrEmpty(Output) == false)
{
Console.Write(Output);
}
if (ClientProcess != null && ClientProcess.HasExited)
{
Log("Client exited, stopping server....");
if (!GlobalCommandLine.NoKill)
{
ServerProcess.StopProcess();
}
bKeepReading = false;
}
return bKeepReading; // Keep reading
});
}
Log("Server exited....");
if (ClientProcess != null && !ClientProcess.HasExited)
{
ClientProcess.StopProcess();
}
foreach (var OtherClient in OtherClients)
{
if (OtherClient != null && !OtherClient.HasExited)
{
OtherClient.StopProcess();
}
}
if (Params.Unattended)
{
if (!WelcomedCorrectly)
{
throw new AutomationException("Server or client exited before we asked it to.");
}
}
}
private static void SetupClientParams(List<DeploymentContext> DeployContextList, ProjectParams Params, string ClientLogFile, out ERunOptions ClientRunFlags, out string ClientApp, out string ClientCmdLine)
{
if (Params.ClientTargetPlatforms.Count == 0)
{
throw new AutomationException("No ClientTargetPlatform set for SetupClientParams.");
}
// var DeployContextList = CreateDeploymentContext(Params, false);
if (DeployContextList.Count == 0)
{
throw new AutomationException("No DeployContextList for SetupClientParams.");
}
var SC = DeployContextList[0];
// Get client app name and command line.
ClientRunFlags = ERunOptions.AllowSpew | ERunOptions.AppMustExist;
ClientApp = "";
ClientCmdLine = "";
string TempCmdLine = "";
var PlatformName = Params.ClientTargetPlatforms[0].ToString();
if (Params.Cook || Params.CookOnTheFly)
{
List<string> Exes = SC.StageTargetPlatform.GetExecutableNames(SC, true);
ClientApp = Exes[0];
if (SC.StageTargetPlatform.PlatformType != UnrealTargetPlatform.IOS)
{
TempCmdLine += SC.ProjectArgForCommandLines + " ";
}
TempCmdLine += Params.MapToRun + " ";
if (Params.CookOnTheFly || Params.FileServer)
{
TempCmdLine += "-filehostip=";
bool FirstParam = true;
if (UnrealBuildTool.BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac)
{
NetworkInterface[] Interfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach (NetworkInterface adapter in Interfaces)
{
if (adapter.NetworkInterfaceType != NetworkInterfaceType.Loopback)
{
IPInterfaceProperties IP = adapter.GetIPProperties();
for (int Index = 0; Index < IP.UnicastAddresses.Count; ++Index)
{
if (IP.UnicastAddresses[Index].IsDnsEligible && IP.UnicastAddresses[Index].Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
if (!IsNullOrEmpty(Params.Port))
{
foreach (var Port in Params.Port)
{
if (!FirstParam)
{
TempCmdLine += "+";
}
FirstParam = false;
string[] PortProtocol = Port.Split(new char[] { ':' });
if (PortProtocol.Length > 1)
{
TempCmdLine += String.Format("{0}://{1}:{2}", PortProtocol[0], IP.UnicastAddresses[Index].Address.ToString(), PortProtocol[1]);
}
else
{
TempCmdLine += IP.UnicastAddresses[Index].Address.ToString();
TempCmdLine += ":";
TempCmdLine += Params.Port;
}
}
}
else
{
if (!FirstParam)
{
TempCmdLine += "+";
}
FirstParam = false;
// use default port
TempCmdLine += IP.UnicastAddresses[Index].Address.ToString();
}
}
}
}
}
}
else
{
NetworkInterface[] Interfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach (NetworkInterface adapter in Interfaces)
{
if (adapter.OperationalStatus == OperationalStatus.Up)
{
IPInterfaceProperties IP = adapter.GetIPProperties();
for (int Index = 0; Index < IP.UnicastAddresses.Count; ++Index)
{
if (IP.UnicastAddresses[Index].IsDnsEligible)
{
if (!IsNullOrEmpty(Params.Port))
{
foreach (var Port in Params.Port)
{
if (!FirstParam)
{
TempCmdLine += "+";
}
FirstParam = false;
string[] PortProtocol = Port.Split(new char[] { ':' });
if (PortProtocol.Length > 1)
{
TempCmdLine += String.Format("{0}://{1}:{2}", PortProtocol[0], IP.UnicastAddresses[Index].Address.ToString(), PortProtocol[1]);
}
else
{
TempCmdLine += IP.UnicastAddresses[Index].Address.ToString();
TempCmdLine += ":";
TempCmdLine += Params.Port;
}
}
}
else
{
if (!FirstParam)
{
TempCmdLine += "+";
}
FirstParam = false;
// use default port
TempCmdLine += IP.UnicastAddresses[Index].Address.ToString();
}
}
}
}
}
}
const string LocalHost = "127.0.0.1";
if (!IsNullOrEmpty(Params.Port))
{
foreach (var Port in Params.Port)
{
if (!FirstParam)
{
TempCmdLine += "+";
}
FirstParam = false;
string[] PortProtocol = Port.Split(new char[] { ':' });
if (PortProtocol.Length > 1)
{
TempCmdLine += String.Format("{0}://{1}:{2}", PortProtocol[0], LocalHost, PortProtocol[1]);
}
else
{
TempCmdLine += LocalHost;
TempCmdLine += ":";
TempCmdLine += Params.Port;
}
}
}
else
{
if (!FirstParam)
{
TempCmdLine += "+";
}
FirstParam = false;
// use default port
TempCmdLine += LocalHost;
}
TempCmdLine += " ";
if (!Params.Stage)
{
TempCmdLine += "-streaming ";
}
else if (SC.StageTargetPlatform.PlatformType != UnrealTargetPlatform.IOS)
{
// per josh, allowcaching is deprecated/doesn't make sense for iOS.
TempCmdLine += "-allowcaching ";
}
}
else if (Params.UsePak(SC.StageTargetPlatform) || Params.SignedPak)
{
if (Params.SignedPak)
{
TempCmdLine += "-signedpak ";
}
else
{
TempCmdLine += "-pak ";
}
}
else if (!Params.Stage)
{
var SandboxPath = CombinePaths(SC.RuntimeProjectRootDir, "Saved", "Cooked", SC.CookPlatform);
if (!SC.StageTargetPlatform.LaunchViaUFE)
{
TempCmdLine += "-sandbox=" + CommandUtils.MakePathSafeToUseWithCommandLine(SandboxPath) + " ";
}
else
{
TempCmdLine += "-sandbox=\'" + SandboxPath + "\' ";
}
}
}
else
{
ClientApp = CombinePaths(CmdEnv.LocalRoot, "Engine/Binaries", PlatformName, "UE4Editor.exe");
TempCmdLine += SC.ProjectArgForCommandLines + " ";
if (!Params.EditorTest)
{
TempCmdLine += "-game " + Params.MapToRun + " ";
}
}
if (Params.LogWindow)
{
// Without NoStdOutRedirect '-log' doesn't log anything to the window
ClientRunFlags |= ERunOptions.NoStdOutRedirect;
TempCmdLine += "-log ";
}
else
{
TempCmdLine += "-stdout ";
}
if (Params.Unattended)
{
TempCmdLine += "-unattended ";
}
if (IsBuildMachine || Params.Unattended)
{
TempCmdLine += "-buildmachine ";
}
if (Params.CrashIndex > 0)
{
int RealIndex = Params.CrashIndex - 1;
if (RealIndex < 0 || RealIndex >= CrashCommands.Count())
{
throw new AutomationException("CrashIndex {0} is out of range...max={1}", Params.CrashIndex, CrashCommands.Count());
}
TempCmdLine += String.Format("-execcmds=\"debug {0}\" ", CrashCommands[RealIndex]);
}
else if (Params.RunAutomationTest != "")
{
TempCmdLine += "-execcmds=\"automation list, automation run " + Params.RunAutomationTest + "\" ";
}
else if (Params.RunAutomationTests)
{
TempCmdLine += "-execcmds=\"automation list, automation runall\" ";
}
if (!SC.StageTargetPlatform.LaunchViaUFE)
{
TempCmdLine += "-abslog=" + CommandUtils.MakePathSafeToUseWithCommandLine(ClientLogFile) + " ";
}
if (SC.StageTargetPlatform.PlatformType != UnrealTargetPlatform.IOS)
{
TempCmdLine += "-Messaging -nomcp -Windowed ";
}
else
{
// skip arguments which don't make sense for iOS
TempCmdLine += "-Messaging -nomcp ";
}
if (Params.NullRHI && SC.StageTargetPlatform.PlatformType != UnrealTargetPlatform.Mac) // all macs have GPUs, and currently the mac dies with nullrhi
{
TempCmdLine += "-nullrhi ";
}
TempCmdLine += "-CrashForUAT ";
TempCmdLine += Params.RunCommandline;
// todo: move this into the platform
if (SC.StageTargetPlatform.LaunchViaUFE)
{
ClientCmdLine = "-run=Launch ";
ClientCmdLine += "-Device=" + Params.Device + " ";
ClientCmdLine += "-Exe=\"" + ClientApp + "\" ";
ClientCmdLine += "-Targetplatform=" + Params.ClientTargetPlatforms[0].ToString() + " ";
ClientCmdLine += "-Params=\"" + TempCmdLine + "\"";
ClientApp = CombinePaths(CmdEnv.LocalRoot, "Engine/Binaries/Win64/UnrealFrontend.exe");
Log("Launching via UFE:");
Log("\tClientCmdLine: " + ClientCmdLine + "");
}
else
{
ClientCmdLine = TempCmdLine;
}
}
#endregion
#region Client Thread
private static void ClientLogReaderProc(object ArgsContainer)
{
var Args = ArgsContainer as object[];
var ClientLogFile = (string)Args[0];
var ClientProcess = (ProcessResult)Args[1];
LogFileReaderProcess(ClientLogFile, ClientProcess, (string Output) =>
{
if (String.IsNullOrEmpty(Output) == false)
{
Log(Output);
}
return true;
});
}
#endregion
#region Servers
private static ProcessResult RunDedicatedServer(ProjectParams Params, string ServerLogFile, string AdditionalCommandLine)
{
ProjectParams ServerParams = new ProjectParams(Params);
ServerParams.Device = Params.ServerDevice;
if (ServerParams.ServerTargetPlatforms.Count == 0)
{
throw new AutomationException("No ServerTargetPlatform set for RunDedicatedServer.");
}
var DeployContextList = CreateDeploymentContext(ServerParams, true);
if (DeployContextList.Count == 0)
{
throw new AutomationException("No DeployContextList for RunDedicatedServer.");
}
var SC = DeployContextList[0];
var ServerApp = CombinePaths(CmdEnv.LocalRoot, "Engine/Binaries/Win64/UE4Editor.exe");
if (ServerParams.Cook)
{
List<string> Exes = SC.StageTargetPlatform.GetExecutableNames(SC);
ServerApp = Exes[0];
}
var Args = ServerParams.Cook ? "" : (SC.ProjectArgForCommandLines + " ");
Console.WriteLine(Params.ServerDeviceAddress);
UnrealTargetPlatform ServerPlatform = ServerParams.ServerTargetPlatforms[0];
if (ServerParams.Cook && ServerPlatform == UnrealTargetPlatform.Linux && !String.IsNullOrEmpty(ServerParams.ServerDeviceAddress))
{
ServerApp = @"C:\Windows\system32\cmd.exe";
string plinkPath = CombinePaths(Environment.GetEnvironmentVariable("LINUX_ROOT"), "bin/PLINK.exe ");
string exePath = CombinePaths(SC.ShortProjectName, "Binaries", ServerPlatform.ToString(), SC.ShortProjectName + "Server");
if (ServerParams.ServerConfigsToBuild[0] != UnrealTargetConfiguration.Development)
{
exePath += "-" + ServerPlatform.ToString() + "-" + ServerParams.ServerConfigsToBuild[0].ToString();
}
exePath = CombinePaths("LinuxServer", exePath.ToLower()).Replace("\\", "/");
Args = String.Format("/k {0} -batch -ssh -t -i {1} {2}@{3} {4} {5} {6} -server -Messaging", plinkPath, ServerParams.DevicePassword, ServerParams.DeviceUsername, ServerParams.ServerDeviceAddress, exePath, Args, ServerParams.MapToRun);
}
else
{
var Map = ServerParams.MapToRun;
if (!String.IsNullOrEmpty(ServerParams.AdditionalServerMapParams))
{
Map += ServerParams.AdditionalServerMapParams;
}
if (Params.FakeClient)
{
Map += "?fake";
}
Args += String.Format("{0} -server -abslog={1} -unattended -FORCELOGFLUSH -log -Messaging -nomcp", Map, CommandUtils.MakePathSafeToUseWithCommandLine(ServerLogFile));
}
if (ServerParams.UsePak(SC.StageTargetPlatform) || ServerParams.SignedPak)
{
if (ServerParams.SignedPak)
{
Args += " -signedpak";
}
else
{
Args += " -pak";
}
}
if (IsBuildMachine || Params.Unattended)
{
Args += " -buildmachine";
}
Args += " -CrashForUAT";
Args += " " + AdditionalCommandLine;
if (ServerParams.Cook && ServerPlatform == UnrealTargetPlatform.Linux && !String.IsNullOrEmpty(ServerParams.ServerDeviceAddress))
{
Args += String.Format(" 2>&1 > {0}", ServerLogFile);
}
PushDir(Path.GetDirectoryName(ServerApp));
var Result = Run(ServerApp, Args, null, ERunOptions.AllowSpew | ERunOptions.NoWaitForExit | ERunOptions.AppMustExist | ERunOptions.NoStdOutRedirect);
PopDir();
return Result;
}
private static ProcessResult RunCookOnTheFlyServer(string ProjectName, string ServerLogFile, string TargetPlatform, string AdditionalCommandLine)
{
var ServerApp = HostPlatform.Current.GetUE4ExePath("UE4Editor.exe");
var Args = String.Format("{0} -run=cook -targetplatform={1} -cookonthefly -unattended -CrashForUAT -FORCELOGFLUSH -log",
CommandUtils.MakePathSafeToUseWithCommandLine(ProjectName),
TargetPlatform);
if (!String.IsNullOrEmpty(ServerLogFile))
{
Args += " -abslog=" + CommandUtils.MakePathSafeToUseWithCommandLine(ServerLogFile);
}
if (IsBuildMachine)
{
Args += " -buildmachine";
}
Args += " " + AdditionalCommandLine;
// Run the server (Without NoStdOutRedirect -log doesn't log anything to the window)
PushDir(Path.GetDirectoryName(ServerApp));
var Result = Run(ServerApp, Args, null, ERunOptions.AllowSpew | ERunOptions.NoWaitForExit | ERunOptions.AppMustExist | ERunOptions.NoStdOutRedirect);
PopDir();
return Result;
}
private static ProcessResult RunFileServer(ProjectParams Params, string ServerLogFile, string AdditionalCommandLine)
{
#if false
// this section of code would provide UFS with a more accurate file mapping
var SC = new StagingContext(Params, false);
CreateStagingManifest(SC);
MaybeConvertToLowerCase(Params, SC);
var UnrealFileServerResponseFile = new List<string>();
foreach (var Pair in SC.UFSStagingFiles)
{
string Src = Pair.Key;
string Dest = Pair.Value;
Dest = CombinePaths(PathSeparator.Slash, SC.UnrealFileServerInternalRoot, Dest);
UnrealFileServerResponseFile.Add("\"" + Src + "\" \"" + Dest + "\"");
}
string UnrealFileServerResponseFileName = CombinePaths(CmdEnv.LogFolder, "UnrealFileServerList.txt");
File.WriteAllLines(UnrealFileServerResponseFileName, UnrealFileServerResponseFile);
#endif
var UnrealFileServerExe = HostPlatform.Current.GetUE4ExePath("UnrealFileServer.exe");
Log("Running UnrealFileServer *******");
var Args = String.Format("{0} -abslog={1} -unattended -CrashForUAT -FORCELOGFLUSH -log {2}",
CommandUtils.MakePathSafeToUseWithCommandLine(Params.RawProjectPath),
CommandUtils.MakePathSafeToUseWithCommandLine(ServerLogFile),
AdditionalCommandLine);
if (IsBuildMachine)
{
Args += " -buildmachine";
}
PushDir(Path.GetDirectoryName(UnrealFileServerExe));
var Result = Run(UnrealFileServerExe, Args, null, ERunOptions.AllowSpew | ERunOptions.NoWaitForExit | ERunOptions.AppMustExist | ERunOptions.NoStdOutRedirect);
PopDir();
return Result;
}
#endregion
}