private static void RunClientWithServer(List <DeploymentContext> DeployContextList, string ServerLogFile, IProcessResult ServerProcess, string ClientApp, string ClientCmdLine, ERunOptions ClientRunFlags, string ClientLogFile, ProjectParams Params) { IProcessResult ClientProcess = null; var OtherClients = new List <IProcessResult>(); 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) { LogInformation("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"))) { LogInformation("Starting Client for unattended test...."); ClientProcess = Run(ClientApp, ClientCmdLine + " -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++) { LogInformation("Starting Extra Client...."); OtherClients.Add(Run(ClientApp, ClientCmdLine, null, ClientRunFlags | ERunOptions.NoWaitForExit)); } } while (!FileExists(ClientLogFile) && !ClientProcess.HasExited) { LogInformation("Waiting for client logging process to start...{0}", ClientLogFile); Thread.Sleep(2000); } if (!ClientProcess.HasExited) { Thread.Sleep(2000); LogInformation("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) { LogInformation("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) { LogInformation("Welcomed by server or client loaded, lets wait ten minutes..."); Thread.Sleep(60000 * 10); } else { LogInformation("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); LogError("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 (AllClientOutput.Contains("Game Engine Initialized") || AllClientOutput.Contains("Unreal Network File Server is ready")) { LogInformation("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++) { LogInformation("Starting Extra Client...."); IProcessResult NewClient = SC.StageTargetPlatform.RunClient(ClientRunFlags | ERunOptions.NoWaitForExit, ClientApp, ClientCmdLine, Params); OtherClients.Add(NewClient); } } } } else if (ClientProcess == null && !ServerProcess.HasExited) { LogInformation("Waiting for server to start...."); Thread.Sleep(2000); } if (String.IsNullOrEmpty(Output) == false) { Console.Write(Output); } if (ClientProcess != null && ClientProcess.HasExited) { LogInformation("Client exited, stopping server...."); if (!GlobalCommandLine.NoKill) { ServerProcess.StopProcess(); } bKeepReading = false; } return(bKeepReading); // Keep reading }); } LogInformation("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."); } } }
/// <summary> /// Runs external program. /// </summary> /// <param name="App">Program filename.</param> /// <param name="CommandLine">Commandline</param> /// <param name="Input">Optional Input for the program (will be provided as stdin)</param> /// <param name="Options">Defines the options how to run. See ERunOptions.</param> /// <param name="Env">Environment to pass to program.</param> /// <param name="FilterCallback">Callback to filter log spew before output.</param> /// <returns>Object containing the exit code of the program as well as it's stdout output.</returns> public static IProcessResult Run(string App, string CommandLine = null, string Input = null, ERunOptions Options = ERunOptions.Default, Dictionary <string, string> Env = null, ProcessResult.SpewFilterCallbackType SpewFilterCallback = null) { App = ConvertSeparators(PathSeparator.Default, App); // Get the log name before allowing the platform to modify the app/command-line. We want mono apps to be written to a log named after the application and appear with the application prefix rather than "mono:". string LogName = Path.GetFileNameWithoutExtension(App); HostPlatform.Current.SetupOptionsForRun(ref App, ref Options, ref CommandLine); if (App == "ectool" || App == "zip" || App == "xcodebuild") { Options &= ~ERunOptions.AppMustExist; } // Check if the application exists, including the PATH directories. if (Options.HasFlag(ERunOptions.AppMustExist) && !FileExists(Options.HasFlag(ERunOptions.NoLoggingOfRunCommand) ? true : false, App)) { bool bExistsInPath = false; if (!App.Contains(Path.DirectorySeparatorChar) && !App.Contains(Path.AltDirectorySeparatorChar)) { string[] PathDirectories = Environment.GetEnvironmentVariable("PATH").Split(Path.PathSeparator); foreach (string PathDirectory in PathDirectories) { string TryApp = Path.Combine(PathDirectory, App); if (FileExists(Options.HasFlag(ERunOptions.NoLoggingOfRunCommand), TryApp)) { App = TryApp; bExistsInPath = true; break; } } } if (!bExistsInPath) { throw new AutomationException("BUILD FAILED: Couldn't find the executable to Run: {0}", App); } } var StartTime = DateTime.UtcNow; UnrealBuildTool.LogEventType SpewVerbosity = Options.HasFlag(ERunOptions.SpewIsVerbose) ? UnrealBuildTool.LogEventType.Verbose : UnrealBuildTool.LogEventType.Console; if (!Options.HasFlag(ERunOptions.NoLoggingOfRunCommand)) { LogWithVerbosity(SpewVerbosity, "Run: " + App + " " + (String.IsNullOrEmpty(CommandLine) ? "" : CommandLine)); } IProcessResult Result = ProcessManager.CreateProcess(App, Options.HasFlag(ERunOptions.AllowSpew), LogName, Env, SpewVerbosity: SpewVerbosity, SpewFilterCallback: SpewFilterCallback); Process Proc = Result.ProcessObject; bool bRedirectStdOut = (Options & ERunOptions.NoStdOutRedirect) != ERunOptions.NoStdOutRedirect; Proc.StartInfo.FileName = App; Proc.StartInfo.Arguments = String.IsNullOrEmpty(CommandLine) ? "" : CommandLine; Proc.StartInfo.UseShellExecute = false; if (bRedirectStdOut) { Proc.StartInfo.RedirectStandardOutput = true; Proc.StartInfo.RedirectStandardError = true; Proc.OutputDataReceived += Result.StdOut; Proc.ErrorDataReceived += Result.StdErr; } Proc.StartInfo.RedirectStandardInput = Input != null; Proc.StartInfo.CreateNoWindow = true; if ((Options & ERunOptions.UTF8Output) == ERunOptions.UTF8Output) { Proc.StartInfo.StandardOutputEncoding = new System.Text.UTF8Encoding(false, false); } Proc.Start(); if (bRedirectStdOut) { Proc.BeginOutputReadLine(); Proc.BeginErrorReadLine(); } if (String.IsNullOrEmpty(Input) == false) { Proc.StandardInput.WriteLine(Input); Proc.StandardInput.Close(); } if (!Options.HasFlag(ERunOptions.NoWaitForExit)) { Result.WaitForExit(); var BuildDuration = (DateTime.UtcNow - StartTime).TotalMilliseconds; AddRunTime(App, (int)(BuildDuration)); Result.ExitCode = Proc.ExitCode; if (!Options.HasFlag(ERunOptions.NoLoggingOfRunCommand) || Options.HasFlag(ERunOptions.LoggingOfRunDuration)) { LogWithVerbosity(SpewVerbosity, "Run: Took {0}s to run {1}, ExitCode={2}", BuildDuration / 1000, Path.GetFileName(App), Result.ExitCode); } Result.OnProcessExited(); Result.DisposeProcess(); } else { Result.ExitCode = -1; } return(Result); }
/// <summary> /// Runs external program. /// </summary> /// <param name="App">Program filename.</param> /// <param name="CommandLine">Commandline</param> /// <param name="Input">Optional Input for the program (will be provided as stdin)</param> /// <param name="Options">Defines the options how to run. See ERunOptions.</param> /// <param name="Env">Environment to pass to program.</param> /// <param name="FilterCallback">Callback to filter log spew before output.</param> /// <returns>Object containing the exit code of the program as well as it's stdout output.</returns> public static IProcessResult Run(string App, string CommandLine = null, string Input = null, ERunOptions Options = ERunOptions.Default, Dictionary <string, string> Env = null, ProcessResult.SpewFilterCallbackType SpewFilterCallback = null, string Identifier = null) { App = ConvertSeparators(PathSeparator.Default, App); HostPlatform.Current.SetupOptionsForRun(ref App, ref Options, ref CommandLine); if (App == "ectool" || App == "zip" || App == "xcodebuild") { Options &= ~ERunOptions.AppMustExist; } // Check if the application exists, including the PATH directories. if (Options.HasFlag(ERunOptions.AppMustExist) && !FileExists(Options.HasFlag(ERunOptions.NoLoggingOfRunCommand) ? true : false, App)) { string ResolvedPath = WhichApp(App); if (string.IsNullOrEmpty(ResolvedPath)) { throw new AutomationException("BUILD FAILED: Couldn't find the executable to run: {0}", App); } App = ResolvedPath; } var StartTime = DateTime.UtcNow; LogEventType SpewVerbosity = Options.HasFlag(ERunOptions.SpewIsVerbose) ? LogEventType.Verbose : LogEventType.Console; if (!Options.HasFlag(ERunOptions.NoLoggingOfRunCommand)) { LogWithVerbosity(SpewVerbosity, "Running: " + App + " " + (String.IsNullOrEmpty(CommandLine) ? "" : CommandLine)); } string PrevIndent = null; if (Options.HasFlag(ERunOptions.AllowSpew)) { PrevIndent = Tools.DotNETCommon.Log.Indent; Tools.DotNETCommon.Log.Indent += " "; } IProcessResult Result = ProcessManager.CreateProcess(App, Options.HasFlag(ERunOptions.AllowSpew), !Options.HasFlag(ERunOptions.NoStdOutCapture), Env, SpewVerbosity: SpewVerbosity, SpewFilterCallback: SpewFilterCallback); try { Process Proc = Result.ProcessObject; bool bRedirectStdOut = (Options & ERunOptions.NoStdOutRedirect) != ERunOptions.NoStdOutRedirect; Proc.StartInfo.FileName = App; Proc.StartInfo.Arguments = String.IsNullOrEmpty(CommandLine) ? "" : CommandLine; Proc.StartInfo.UseShellExecute = false; if (bRedirectStdOut) { Proc.StartInfo.RedirectStandardOutput = true; Proc.StartInfo.RedirectStandardError = true; Proc.OutputDataReceived += Result.StdOut; Proc.ErrorDataReceived += Result.StdErr; } Proc.StartInfo.RedirectStandardInput = Input != null; Proc.StartInfo.CreateNoWindow = (Options & ERunOptions.NoHideWindow) == 0; if ((Options & ERunOptions.UTF8Output) == ERunOptions.UTF8Output) { Proc.StartInfo.StandardOutputEncoding = new System.Text.UTF8Encoding(false, false); } Proc.Start(); if (bRedirectStdOut) { Proc.BeginOutputReadLine(); Proc.BeginErrorReadLine(); } if (String.IsNullOrEmpty(Input) == false) { Proc.StandardInput.WriteLine(Input); Proc.StandardInput.Close(); } if (!Options.HasFlag(ERunOptions.NoWaitForExit)) { Result.WaitForExit(); } else { Result.ExitCode = -1; } } finally { if (PrevIndent != null) { Tools.DotNETCommon.Log.Indent = PrevIndent; } } if (!Options.HasFlag(ERunOptions.NoWaitForExit)) { var BuildDuration = (DateTime.UtcNow - StartTime).TotalMilliseconds; //AddRunTime(App, (int)(BuildDuration)); Result.ExitCode = Result.ProcessObject.ExitCode; if (!Options.HasFlag(ERunOptions.NoLoggingOfRunCommand) || Options.HasFlag(ERunOptions.LoggingOfRunDuration)) { LogWithVerbosity(SpewVerbosity, "Took {0}s to run {1}, ExitCode={2}", BuildDuration / 1000, Path.GetFileName(App), Result.ExitCode); } Result.OnProcessExited(); Result.DisposeProcess(); } return(Result); }
/// <summary> /// Runs external program and writes the output to a logfile. /// </summary> /// <param name="App">Executable to run</param> /// <param name="CommandLine">Commandline to pass on to the executable</param> /// <param name="Logfile">Full path to the logfile, where the application output should be written to.</param> /// <param name="Input">Optional Input for the program (will be provided as stdin)</param> /// <param name="Options">Defines the options how to run. See ERunOptions.</param> /// <param name="FilterCallback">Callback to filter log spew before output.</param> public static string RunAndLog(string App, string CommandLine, string Logfile = null, int MaxSuccessCode = 0, string Input = null, ERunOptions Options = ERunOptions.Default, Dictionary <string, string> EnvVars = null, ProcessResult.SpewFilterCallbackType SpewFilterCallback = null) { IProcessResult Result = Run(App, CommandLine, Input, Options, EnvVars, SpewFilterCallback); if (!String.IsNullOrEmpty(Result.Output) && Logfile != null) { WriteToFile(Logfile, Result.Output); } else if (Logfile == null) { Logfile = "[No logfile specified]"; } else { Logfile = "[None!, no output produced]"; } if (Result.ExitCode > MaxSuccessCode || Result.ExitCode < 0) { throw new CommandFailedException((ExitCode)Result.ExitCode, String.Format("Command failed (Result:{3}): {0} {1}. See logfile for details: '{2}' ", App, CommandLine, Path.GetFileName(Logfile), Result.ExitCode)) { OutputFormat = AutomationExceptionOutputFormat.Minimal }; } if (!String.IsNullOrEmpty(Result.Output)) { return(Result.Output); } return(""); }
public override IProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { if (UnrealBuildTool.BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac) { if (Params.Devices.Count != 1) { throw new AutomationException("Can only run on a single specified device, but {0} were specified", Params.Devices.Count); } // This code only cares about connected devices so just call the run loop a few times to get the existing connected devices MobileDeviceInstanceManager.Initialize(MobileDeviceConnected, MobileDeviceDisconnected); for(int i = 0; i < 4; ++i) { System.Threading.Thread.Sleep(1); CoreFoundationRunLoop.RunLoopRunInMode(CoreFoundationRunLoop.kCFRunLoopDefaultMode(), 0.25, 0); } /* string AppDirectory = string.Format("{0}/Payload/{1}.app", Path.GetDirectoryName(Params.ProjectGameExeFilename), Path.GetFileNameWithoutExtension(Params.ProjectGameExeFilename)); string GameName = Path.GetFileNameWithoutExtension (ClientApp); if (GameName.Contains ("-IOS-")) { GameName = GameName.Substring (0, GameName.IndexOf ("-IOS-")); } string GameApp = AppDirectory + "/" + GameName; bWasGenerated = false; XcodeProj = EnsureXcodeProjectExists (Params.RawProjectPath, CmdEnv.LocalRoot, Params.ShortProjectName, GetDirectoryName(Params.RawProjectPath), Params.IsCodeBasedProject, out bWasGenerated); string Arguments = "UBT_NO_POST_DEPLOY=true /usr/bin/xcrun xcodebuild test -project \"" + XcodeProj + "\""; Arguments += " -scheme '"; Arguments += GameName; Arguments += " - iOS'"; Arguments += " -configuration " + Params.ClientConfigsToBuild [0].ToString(); Arguments += " -destination 'platform=iOS,id=" + Params.Device.Substring(Params.Device.IndexOf("@")+1) + "'"; Arguments += " TEST_HOST=\""; Arguments += GameApp; Arguments += "\" BUNDLE_LOADER=\""; Arguments += GameApp + "\"";*/ string BundleIdentifier = ""; if (File.Exists(Params.BaseStageDirectory + "/"+ PlatformName + "/Info.plist")) { string Contents = File.ReadAllText(Params.BaseStageDirectory + "/" + PlatformName + "/Info.plist"); int Pos = Contents.IndexOf("CFBundleIdentifier"); Pos = Contents.IndexOf("<string>", Pos) + 8; int EndPos = Contents.IndexOf("</string>", Pos); BundleIdentifier = Contents.Substring(Pos, EndPos - Pos); } string Arguments = "/usr/bin/instruments"; Arguments += " -w '" + Params.DeviceNames[0] + "'"; Arguments += " -t 'Activity Monitor'"; Arguments += " -D \"" + Params.BaseStageDirectory + "/" + PlatformName + "/launch.trace\""; Arguments += " '" + BundleIdentifier + "'"; IProcessResult ClientProcess = Run ("/usr/bin/env", Arguments, null, ClientRunFlags | ERunOptions.NoWaitForExit); return new IOSClientProcess(ClientProcess, Params.DeviceNames[0]); } else { IProcessResult Result = new ProcessResult("DummyApp", null, false, null); Result.ExitCode = 0; return Result; } }
public override ProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { if (!File.Exists(ClientApp)) { if (Directory.Exists(ClientApp + ".app")) { ClientApp += ".app/Contents/MacOS/" + Path.GetFileName(ClientApp); } else { Int32 BaseDirLen = Params.BaseStageDirectory.Length; string StageSubDir = ClientApp.Substring(BaseDirLen, ClientApp.IndexOf("/", BaseDirLen + 1) - BaseDirLen); ClientApp = CombinePaths(Params.BaseStageDirectory, StageSubDir, Params.ShortProjectName + ".app/Contents/MacOS/" + Params.ShortProjectName); } } PushDir(Path.GetDirectoryName(ClientApp)); // Always start client process and don't wait for exit. ProcessResult ClientProcess = Run(ClientApp, ClientCmdLine, null, ClientRunFlags | ERunOptions.NoWaitForExit); PopDir(); return ClientProcess; }
/// <summary> /// Runs external program and writes the output to a logfile. /// </summary> /// <param name="App">Executable to run</param> /// <param name="CommandLine">Commandline to pass on to the executable</param> /// <param name="Logfile">Full path to the logfile, where the application output should be written to.</param> /// <param name="Input">Optional Input for the program (will be provided as stdin)</param> /// <param name="Options">Defines the options how to run. See ERunOptions.</param> public static string RunAndLog(string App, string CommandLine, string Logfile = null, int MaxSuccessCode = 0, string Input = null, ERunOptions Options = ERunOptions.Default) { ProcessResult Result = Run(App, CommandLine, Input, Options); if (Result.Output.Length > 0 && Logfile != null) { WriteToFile(Logfile, Result.Output); } else if (Logfile == null) { Logfile = "[No logfile specified]"; } else { Logfile = "[None!, no output produced]"; } if (Result > MaxSuccessCode || Result < 0) { ErrorReporter.Error(String.Format("Command failed (Result:{3}): {0} {1}. See logfile for details: '{2}' ", App, CommandLine, Path.GetFileName(Logfile), Result.ExitCode), Result.ExitCode); throw new AutomationException(String.Format("Command failed (Result:{3}): {0} {1}. See logfile for details: '{2}' ", App, CommandLine, Path.GetFileName(Logfile), Result.ExitCode)); } if (Result.Output.Length > 0) { return(Result.Output); } return(""); }
/// <summary> /// Runs external program and writes the output to a logfile. /// </summary> /// <param name="App">Executable to run</param> /// <param name="CommandLine">Commandline to pass on to the executable</param> /// <param name="Logfile">Full path to the logfile, where the application output should be written to.</param> /// <param name="Input">Optional Input for the program (will be provided as stdin)</param> /// <param name="Options">Defines the options how to run. See ERunOptions.</param> public static string RunAndLog(string App, string CommandLine, string Logfile = null, int MaxSuccessCode = 0, string Input = null, ERunOptions Options = ERunOptions.Default, Dictionary<string, string> EnvVars = null) { ProcessResult Result = Run(App, CommandLine, Input, Options, EnvVars); if (Result.Output.Length > 0 && Logfile != null) { WriteToFile(Logfile, Result.Output); } else if (Logfile == null) { Logfile = "[No logfile specified]"; } else { Logfile = "[None!, no output produced]"; } if (Result > MaxSuccessCode || Result < 0) { throw new AutomationException((ErrorCodes)Result.ExitCode, String.Format("Command failed (Result:{3}): {0} {1}. See logfile for details: '{2}' ", App, CommandLine, Path.GetFileName(Logfile), Result.ExitCode)); } if (Result.Output.Length > 0) { return Result.Output; } return ""; }
/// <summary> /// Runs external program. /// </summary> /// <param name="App">Program filename.</param> /// <param name="CommandLine">Commandline</param> /// <param name="Input">Optional Input for the program (will be provided as stdin)</param> /// <param name="Options">Defines the options how to run. See ERunOptions.</param> /// <param name="Env">Environment to pass to program.</param> /// <returns>Object containing the exit code of the program as well as it's stdout output.</returns> public static ProcessResult Run(string App, string CommandLine = null, string Input = null, ERunOptions Options = ERunOptions.Default, Dictionary <string, string> Env = null) { App = ConvertSeparators(PathSeparator.Default, App); HostPlatform.Current.SetupOptionsForRun(ref App, ref Options, ref CommandLine); if (App == "ectool" || App == "zip" || App == "xcodebuild") { Options &= ~ERunOptions.AppMustExist; } if (Options.HasFlag(ERunOptions.AppMustExist) && !FileExists(Options.HasFlag(ERunOptions.NoLoggingOfRunCommand) ? true : false, App)) { throw new AutomationException("BUILD FAILED: Couldn't find the executable to Run: {0}", App); } var StartTime = DateTime.UtcNow; TraceEventType SpewVerbosity = Options.HasFlag(ERunOptions.SpewIsVerbose) ? TraceEventType.Verbose : TraceEventType.Information; if (!Options.HasFlag(ERunOptions.NoLoggingOfRunCommand)) { Log(SpewVerbosity, "Run: " + App + " " + (String.IsNullOrEmpty(CommandLine) ? "" : CommandLine)); } ProcessResult Result = ProcessManager.CreateProcess(App, Options.HasFlag(ERunOptions.AllowSpew), Path.GetFileNameWithoutExtension(App), Env, SpewVerbosity: SpewVerbosity); Process Proc = Result.ProcessObject; bool bRedirectStdOut = (Options & ERunOptions.NoStdOutRedirect) != ERunOptions.NoStdOutRedirect; Proc.StartInfo.FileName = App; Proc.StartInfo.Arguments = String.IsNullOrEmpty(CommandLine) ? "" : CommandLine; Proc.StartInfo.UseShellExecute = false; if (bRedirectStdOut) { Proc.StartInfo.RedirectStandardOutput = true; Proc.StartInfo.RedirectStandardError = true; Proc.OutputDataReceived += Result.StdOut; Proc.ErrorDataReceived += Result.StdErr; } Proc.StartInfo.RedirectStandardInput = Input != null; Proc.StartInfo.CreateNoWindow = true; if ((Options & ERunOptions.UTF8Output) == ERunOptions.UTF8Output) { Proc.StartInfo.StandardOutputEncoding = new System.Text.UTF8Encoding(false, false); } Proc.Start(); if (bRedirectStdOut) { Proc.BeginOutputReadLine(); Proc.BeginErrorReadLine(); } if (String.IsNullOrEmpty(Input) == false) { Proc.StandardInput.WriteLine(Input); Proc.StandardInput.Close(); } if (!Options.HasFlag(ERunOptions.NoWaitForExit)) { Result.WaitForExit(); var BuildDuration = (DateTime.UtcNow - StartTime).TotalMilliseconds; AddRunTime(App, (int)(BuildDuration)); Result.ExitCode = Proc.ExitCode; if (!Options.HasFlag(ERunOptions.NoLoggingOfRunCommand)) { Log(SpewVerbosity, "Run: Took {0}s to run {1}, ExitCode={2}", BuildDuration / 1000, Path.GetFileName(App), Result.ExitCode); } Result.OnProcessExited(); Result.DisposeProcess(); } else { Result.ExitCode = -1; } return(Result); }
/// <summary> /// Runs external program and writes the output to a logfile. /// </summary> /// <param name="Env">Environment to use.</param> /// <param name="App">Executable to run</param> /// <param name="CommandLine">Commandline to pass on to the executable</param> /// <param name="LogName">Name of the logfile ( if null, executable name is used )</param> /// <param name="Input">Optional Input for the program (will be provided as stdin)</param> /// <param name="Options">Defines the options how to run. See ERunOptions.</param> public static void RunAndLog(CommandEnvironment Env, string App, string CommandLine, string LogName = null, int MaxSuccessCode = 0, string Input = null, ERunOptions Options = ERunOptions.Default) { RunAndLog(App, CommandLine, GetRunAndLogLogName(Env, App, LogName), MaxSuccessCode, Input, Options); }
public override ProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { string ApkName = ClientApp + GetArchitecture(Params) + ".apk"; if (!File.Exists(ApkName)) { ApkName = GetFinalApkName(Params, Path.GetFileNameWithoutExtension(ClientApp), false); } Console.WriteLine("Apk='{0}', CLientApp='{1}', ExeName='{2}'", ApkName, ClientApp, Params.ProjectGameExeFilename); // run aapt to get the name of the intent string PackageName = GetPackageInfo(ApkName, false); if (PackageName == null) { throw new AutomationException("Failed to get package name from " + ClientApp); } string AdbCommand = GetAdbCommand(Params); string CommandLine = "shell am start -n " + PackageName + "/com.epicgames.ue4.GameActivity"; // start the app on device! ProcessResult ClientProcess = Run(CmdEnv.CmdExe, AdbCommand + CommandLine, null, ClientRunFlags); return ClientProcess; }
/// <summary> /// Runs a commandlet using Engine/Binaries/Win64/UE4Editor-Cmd.exe. /// </summary> /// <param name="ProjectName">Project name.</param> /// <param name="UE4Exe">The name of the UE4 Editor executable to use.</param> /// <param name="Commandlet">Commandlet name.</param> /// <param name="Parameters">Command line parameters (without -run=)</param> public static void RunCommandlet(string ProjectName, string UE4Exe, string Commandlet, string Parameters = null) { Log("Running UE4Editor {0} for project {1}", Commandlet, ProjectName); var CWD = Path.GetDirectoryName(UE4Exe); string EditorExe = UE4Exe; if (String.IsNullOrEmpty(CWD)) { EditorExe = HostPlatform.Current.GetUE4ExePath(UE4Exe); CWD = CombinePaths(CmdEnv.LocalRoot, HostPlatform.Current.RelativeBinariesFolder); } PushDir(CWD); string LocalLogFile = LogUtils.GetUniqueLogName(CombinePaths(CmdEnv.EngineSavedFolder, Commandlet)); Log("Commandlet log file is {0}", LocalLogFile); string Args = String.Format( "{0} -run={1} {2} -abslog={3} -stdout -FORCELOGFLUSH -CrashForUAT -unattended {5}{4}", (ProjectName == null) ? "" : CommandUtils.MakePathSafeToUseWithCommandLine(ProjectName), Commandlet, String.IsNullOrEmpty(Parameters) ? "" : Parameters, CommandUtils.MakePathSafeToUseWithCommandLine(LocalLogFile), IsBuildMachine ? "-buildmachine" : "", GlobalCommandLine.Verbose ? "-AllowStdOutLogVerbosity" : "" ); ERunOptions Opts = ERunOptions.Default; if (GlobalCommandLine.UTF8Output) { Args += " -UTF8Output"; Opts |= ERunOptions.UTF8Output; } var RunResult = Run(EditorExe, Args, Options: Opts); PopDir(); // Draw attention to signal exit codes on Posix systems, rather than just printing the exit code if (RunResult.ExitCode > 128 && RunResult.ExitCode < 128 + 32) { if (RunResult.ExitCode == 139) { CommandUtils.LogError("Editor terminated abnormally due to a segmentation fault"); } else { CommandUtils.LogError("Editor terminated abnormally with signal {0}", RunResult.ExitCode - 128); } } // Copy the local commandlet log to the destination folder. string DestLogFile = LogUtils.GetUniqueLogName(CombinePaths(CmdEnv.LogFolder, Commandlet)); if (!CommandUtils.CopyFile_NoExceptions(LocalLogFile, DestLogFile)) { CommandUtils.LogWarning("Commandlet {0} failed to copy the local log file from {1} to {2}. The log file will be lost.", Commandlet, LocalLogFile, DestLogFile); } // Whether it was copied correctly or not, delete the local log as it was only a temporary file. CommandUtils.DeleteFile_NoExceptions(LocalLogFile); if (RunResult.ExitCode != 0) { throw new AutomationException("BUILD FAILED: Failed while running {0} for {1}; see log {2}", Commandlet, ProjectName, DestLogFile); } }
public override ProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { // look for browser var ConfigCache = new UnrealBuildTool.ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", Path.GetDirectoryName(Params.RawProjectPath), CombinePaths(CmdEnv.LocalRoot, "Engine")); string DeviceSection; if (Utils.IsRunningOnMono) { DeviceSection = "HTML5DevicesMac"; } else { DeviceSection = "HTML5DevicesWindows"; } string browserPath; string DeviceName = Params.Device.Split('@')[1]; DeviceName = DeviceName.Substring(0, DeviceName.LastIndexOf(" on ")); bool ok = ConfigCache.GetString(DeviceSection, DeviceName, out browserPath); if (!ok) { throw new System.Exception("Incorrect browser configuration in HTML5Engine.ini "); } // open the webpage string directory = Path.GetDirectoryName(ClientApp); string url = Path.GetFileName(ClientApp) + ".html"; // Are we running via cook on the fly server? // find our http url - This is awkward because RunClient doesn't have real information that NFS is running or not. bool IsCookOnTheFly = false; // 9/24/2014 @fixme - All this is convoluted, clean up. // looks like cookonthefly commandline stopped adding protocol or the port :/ hard coding to DEFAULT_TCP_FILE_SERVING_PORT+1 (DEFAULT_HTTP_FILE_SERVING_PORT) // This will fail if the NFS server is started with a different port - we need to modify driver .cs script to pass in IP/Port data correctly. if (ClientCmdLine.Contains("filehostip")) { IsCookOnTheFly = true; url = "http://127.0.0.1:41898/" + url; } if (IsCookOnTheFly) { url += "?cookonthefly=true"; } else { url = "http://127.0.0.1:8000/" + url; // this will be killed UBT instances dies. string input = String.Format(" -m SimpleHTTPServer 8000"); string PythonPath = HTML5SDKInfo.PythonPath(); ProcessResult Result = ProcessManager.CreateProcess(PythonPath, true, "html5server.log"); Result.ProcessObject.StartInfo.FileName = PythonPath; Result.ProcessObject.StartInfo.UseShellExecute = false; Result.ProcessObject.StartInfo.RedirectStandardOutput = true; Result.ProcessObject.StartInfo.RedirectStandardInput = true; Result.ProcessObject.StartInfo.WorkingDirectory = directory; Result.ProcessObject.StartInfo.Arguments = input; Result.ProcessObject.Start(); Result.ProcessObject.OutputDataReceived += delegate(object sender, System.Diagnostics.DataReceivedEventArgs e) { System.Console.WriteLine(e.Data); }; System.Console.WriteLine("Starting Browser Process"); // safari specific hack. string argument = url; if (browserPath.Contains("Safari") && Utils.IsRunningOnMono) { argument = ""; } // Chrome issue. Firefox may work like this in the future bool bBrowserWillSpawnProcess = browserPath.Contains("chrome") || (browserPath.Contains("Google Chrome") && Utils.IsRunningOnMono); ProcessResult SubProcess = null; ProcessResult ClientProcess = Run(browserPath, argument, null, ClientRunFlags | ERunOptions.NoWaitForExit); var ProcStartTime = ClientProcess.ProcessObject.StartTime; var ProcName = ClientProcess.ProcessObject.ProcessName; ClientProcess.ProcessObject.EnableRaisingEvents = true; ClientProcess.ProcessObject.Exited += delegate(System.Object o, System.EventArgs e) { System.Console.WriteLine("Browser Process Ended (PID={0})", ClientProcess.ProcessObject.Id); var bFoundChildProcess = false; if (bBrowserWillSpawnProcess) { // Chrome spawns a process from the tab it opens and then lets the process we spawned die, so // catch that process and attach to that instead. var CurrentProcesses = Process.GetProcesses(); foreach (var item in CurrentProcesses) { if (item.Id != ClientProcess.ProcessObject.Id && item.ProcessName == ProcName && item.StartTime >= ProcStartTime && item.StartTime <= ClientProcess.ProcessObject.ExitTime) { var PID = item.Id; System.Console.WriteLine("Found Process {0} with PID {1} which started at {2}. Waiting on that process to end.", item.ProcessName, item.Id, item.StartTime.ToString()); SubProcess = new ProcessResult(item.ProcessName, item, true, item.ProcessName); item.EnableRaisingEvents = true; item.Exited += delegate(System.Object o2, System.EventArgs e2) { System.Console.WriteLine("Browser Process Ended (PID={0}) - Killing Webserver", PID); Result.ProcessObject.StandardInput.Close(); Result.ProcessObject.Kill(); }; bFoundChildProcess = true; } } } if (!bFoundChildProcess) { System.Console.WriteLine("- Killing Webserver PID({0})", Result.ProcessObject.Id); Result.ProcessObject.StandardInput.Close(); Result.ProcessObject.Kill(); } }; if (bBrowserWillSpawnProcess) { //Wait for it to do so... ClientProcess.ProcessObject.WaitForExit(); ClientProcess = SubProcess; } // safari needs a hack. // http://superuser.com/questions/689315/run-safari-from-terminal-with-given-url-address-without-open-command if (browserPath.Contains("Safari") && Utils.IsRunningOnMono) { // ClientProcess.ProcessObject.WaitForInputIdle (); Thread.Sleep(2000); Process.Start("/usr/bin/osascript", " -e 'tell application \"Safari\" to open location \"" + url + "\"'"); } return(ClientProcess); } System.Console.WriteLine("Browser Path " + browserPath); ProcessResult BrowserProcess = Run(browserPath, url, null, ClientRunFlags | ERunOptions.NoWaitForExit); return(BrowserProcess); }
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); SC.StageTargetPlatform.PostRunClient(ClientProcess, Params); if (ClientProcess.ExitCode != 0) { throw new AutomationException("Client exited with error code: " + ClientProcess.ExitCode); } } } }
/// <summary> /// Runs external program. /// </summary> /// <param name="App">Program filename.</param> /// <param name="CommandLine">Commandline</param> /// <param name="Input">Optional Input for the program (will be provided as stdin)</param> /// <param name="Options">Defines the options how to run. See ERunOptions.</param> /// <param name="Env">Environment to pass to program.</param> /// <returns>Object containing the exit code of the program as well as it's stdout output.</returns> public static ProcessResult Run(string App, string CommandLine = null, string Input = null, ERunOptions Options = ERunOptions.Default, Dictionary<string, string> Env = null) { App = ConvertSeparators(PathSeparator.Default, App); HostPlatform.Current.SetupOptionsForRun(ref App, ref Options, ref CommandLine); if (App == "ectool" || App == "zip") { Options &= ~ERunOptions.AppMustExist; } if (Options.HasFlag(ERunOptions.AppMustExist) && !FileExists(Options.HasFlag(ERunOptions.NoLoggingOfRunCommand) ? true : false, App)) { throw new AutomationException("BUILD FAILED: Couldn't find the executable to Run: {0}", App); } var StartTime = DateTime.UtcNow; if (!Options.HasFlag(ERunOptions.NoLoggingOfRunCommand)) { Log("Run: " + App + " " + (String.IsNullOrEmpty(CommandLine) ? "" : CommandLine)); } ProcessResult Result = ProcessManager.CreateProcess(Options.HasFlag(ERunOptions.AllowSpew), Path.GetFileNameWithoutExtension(App), Env); Process Proc = Result.ProcessObject; bool bRedirectStdOut = (Options & ERunOptions.NoStdOutRedirect) != ERunOptions.NoStdOutRedirect; Proc.EnableRaisingEvents = false; Proc.StartInfo.FileName = App; Proc.StartInfo.Arguments = String.IsNullOrEmpty(CommandLine) ? "" : CommandLine; Proc.StartInfo.UseShellExecute = false; if (bRedirectStdOut) { Proc.StartInfo.RedirectStandardOutput = true; Proc.StartInfo.RedirectStandardError = true; Proc.OutputDataReceived += Result.StdOut; Proc.ErrorDataReceived += Result.StdErr; } Proc.StartInfo.RedirectStandardInput = Input != null; Proc.StartInfo.CreateNoWindow = true; Proc.Start(); if (bRedirectStdOut) { Proc.BeginOutputReadLine(); Proc.BeginErrorReadLine(); } if (String.IsNullOrEmpty(Input) == false) { Proc.StandardInput.WriteLine(Input); Proc.StandardInput.Close(); } if (!Options.HasFlag(ERunOptions.NoWaitForExit)) { Result.WaitForExit(); var BuildDuration = (DateTime.UtcNow - StartTime).TotalMilliseconds; AddRunTime(App, (int)(BuildDuration)); if (!Options.HasFlag(ERunOptions.NoLoggingOfRunCommand)) { Log("Run: Took {0}s to run " + Path.GetFileName(App), BuildDuration / 1000); } Result.ExitCode = Proc.ExitCode; if (UnrealBuildTool.Utils.IsRunningOnMono) { // Mono's detection of process exit status is broken. It doesn't clean up after the process and it doesn't call Exited callback. Proc.Dispose(); ProcessManager.NewProcess_Exited(Proc, null); } } else { Result.ExitCode = -1; } return Result; }
/// <summary> /// Runs external program. /// </summary> /// <param name="App">Program filename.</param> /// <param name="CommandLine">Commandline</param> /// <param name="Input">Optional Input for the program (will be provided as stdin)</param> /// <param name="Options">Defines the options how to run. See ERunOptions.</param> /// <param name="Env">Environment to pass to program.</param> /// <returns>Object containing the exit code of the program as well as it's stdout output.</returns> public static ProcessResult Run(string App, string CommandLine = null, string Input = null, ERunOptions Options = ERunOptions.Default, Dictionary<string, string> Env = null) { App = ConvertSeparators(PathSeparator.Default, App); HostPlatform.Current.SetupOptionsForRun(ref App, ref Options, ref CommandLine); if (App == "ectool" || App == "zip" || App == "xcodebuild") { Options &= ~ERunOptions.AppMustExist; } if (Options.HasFlag(ERunOptions.AppMustExist) && !FileExists(Options.HasFlag(ERunOptions.NoLoggingOfRunCommand) ? true : false, App)) { throw new AutomationException("BUILD FAILED: Couldn't find the executable to Run: {0}", App); } var StartTime = DateTime.UtcNow; TraceEventType SpewVerbosity = Options.HasFlag(ERunOptions.SpewIsVerbose) ? TraceEventType.Verbose : TraceEventType.Information; if (!Options.HasFlag(ERunOptions.NoLoggingOfRunCommand)) { Log(SpewVerbosity,"Run: " + App + " " + (String.IsNullOrEmpty(CommandLine) ? "" : CommandLine)); } ProcessResult Result = ProcessManager.CreateProcess(App, Options.HasFlag(ERunOptions.AllowSpew), Path.GetFileNameWithoutExtension(App), Env, SpewVerbosity:SpewVerbosity); Process Proc = Result.ProcessObject; bool bRedirectStdOut = (Options & ERunOptions.NoStdOutRedirect) != ERunOptions.NoStdOutRedirect; Proc.StartInfo.FileName = App; Proc.StartInfo.Arguments = String.IsNullOrEmpty(CommandLine) ? "" : CommandLine; Proc.StartInfo.UseShellExecute = false; if (bRedirectStdOut) { Proc.StartInfo.RedirectStandardOutput = true; Proc.StartInfo.RedirectStandardError = true; Proc.OutputDataReceived += Result.StdOut; Proc.ErrorDataReceived += Result.StdErr; } Proc.StartInfo.RedirectStandardInput = Input != null; Proc.StartInfo.CreateNoWindow = true; if ((Options & ERunOptions.UTF8Output) == ERunOptions.UTF8Output) { Proc.StartInfo.StandardOutputEncoding = new System.Text.UTF8Encoding(false, false); } Proc.Start(); if (bRedirectStdOut) { Proc.BeginOutputReadLine(); Proc.BeginErrorReadLine(); } if (String.IsNullOrEmpty(Input) == false) { Proc.StandardInput.WriteLine(Input); Proc.StandardInput.Close(); } if (!Options.HasFlag(ERunOptions.NoWaitForExit)) { Result.WaitForExit(); var BuildDuration = (DateTime.UtcNow - StartTime).TotalMilliseconds; AddRunTime(App, (int)(BuildDuration)); Result.ExitCode = Proc.ExitCode; if (!Options.HasFlag(ERunOptions.NoLoggingOfRunCommand) || Options.HasFlag(ERunOptions.LoggingOfRunDuration)) { Log(SpewVerbosity,"Run: Took {0}s to run {1}, ExitCode={2}", BuildDuration / 1000, Path.GetFileName(App), Result.ExitCode); } Result.OnProcessExited(); Result.DisposeProcess(); } else { Result.ExitCode = -1; } return Result; }
private ProcessResult RunAdbCommand(ProjectParams Params, string Args, string Input = null, ERunOptions Options = ERunOptions.Default) { string AdbCommand = Environment.ExpandEnvironmentVariables("%ANDROID_HOME%/platform-tools/adb" + (Utils.IsRunningOnMono ? "" : ".exe")); return(Run(AdbCommand, GetAdbCommandLine(Params, Args), Input, Options)); }
public override ProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { return null; }
public override IProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { // look for browser string BrowserPath = Params.Devices[0].Replace("HTML5@", ""); // open the webpage Int32 ServerPort = 8000; // HTML5LaunchHelper default var ConfigCache = UnrealBuildTool.ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, DirectoryReference.FromFile(Params.RawProjectPath), UnrealTargetPlatform.HTML5); ConfigCache.GetInt32("/Script/HTML5PlatformEditor.HTML5TargetSettings", "DeployServerPort", out ServerPort); // LaunchOn via Editor or FrontEnd string WorkingDirectory = Path.GetDirectoryName(ClientApp); string url = Path.GetFileName(ClientApp) + ".html"; // WARNING: splitting the following situation // if cookonthefly is used: tell the browser to use the PROXY at DEFAULT_HTTP_FILE_SERVING_PORT // leave the normal HTML5LaunchHelper port (ServerPort) alone -- otherwise it will collide with the PROXY port if (ClientCmdLine.Contains("filehostip")) { url += "?cookonthefly=true"; Int32 ProxyPort = 41898; // DEFAULT_HTTP_FILE_SERVING_PORT url = String.Format("http://localhost:{0}/{1}", ProxyPort, url); } else { url = String.Format("http://localhost:{0}/{1}", ServerPort, url); } // Check HTML5LaunchHelper source for command line args var LowerBrowserPath = BrowserPath.ToLower(); var ProfileDirectory = Path.Combine(Utils.GetUserSettingDirectory().FullName, "UE4_HTML5", "user"); string BrowserCommandline = url; if (LowerBrowserPath.Contains("chrome")) { ProfileDirectory = Path.Combine(ProfileDirectory, "chrome"); // removing [--enable-logging] otherwise, chrome breaks with a bunch of the following errors: // > ERROR:process_info.cc(631)] range at 0x7848406c00000000, size 0x1a4 fully unreadable // leaving this note here for future reference: UE-45078 BrowserCommandline += " " + String.Format("--user-data-dir=\\\"{0}\\\" --no-first-run", ProfileDirectory); } else if (LowerBrowserPath.Contains("firefox")) { ProfileDirectory = Path.Combine(ProfileDirectory, "firefox"); BrowserCommandline += " " + String.Format("-no-remote -profile \\\"{0}\\\"", ProfileDirectory); } if (UnrealBuildTool.BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Linux) { // TODO: test on other platforms to remove this if() check if (!Directory.Exists(ProfileDirectory)) { Directory.CreateDirectory(ProfileDirectory); } } string LauncherArguments = string.Format(" -Browser=\"{0}\" + -BrowserCommandLine=\"{1}\" -ServerPort=\"{2}\" -ServerRoot=\"{3}\" ", new object[] { BrowserPath, BrowserCommandline, ServerPort, WorkingDirectory }); var LaunchHelperPath = CombinePaths(CmdEnv.LocalRoot, "Engine/Binaries/DotNET/HTML5LaunchHelper.exe"); IProcessResult BrowserProcess = Run(LaunchHelperPath, LauncherArguments, null, ClientRunFlags | ERunOptions.NoWaitForExit); return(BrowserProcess); }
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) { LogConsole("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"))) { LogConsole("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++) { LogConsole("Starting Extra Client...."); OtherClients.Add(Run(ClientApp, ClientCmdLine, null, ClientRunFlags | ERunOptions.NoWaitForExit)); } } while (!FileExists(ClientLogFile) && !ClientProcess.HasExited) { LogConsole("Waiting for client logging process to start...{0}", ClientLogFile); Thread.Sleep(2000); } if (!ClientProcess.HasExited) { Thread.Sleep(2000); LogConsole("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) { LogConsole("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) { LogConsole("Welcomed by server or client loaded, lets wait ten minutes..."); Thread.Sleep(60000 * 10); } else { LogConsole("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); LogError("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"))) { LogConsole("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++) { LogConsole("Starting Extra Client...."); ProcessResult NewClient = SC.StageTargetPlatform.RunClient(ClientRunFlags | ERunOptions.NoWaitForExit, ClientApp, ClientCmdLine, Params); OtherClients.Add(NewClient); } } } } else if (ClientProcess == null && !ServerProcess.HasExited) { LogConsole("Waiting for server to start...."); Thread.Sleep(2000); } if (String.IsNullOrEmpty(Output) == false) { Console.Write(Output); } if (ClientProcess != null && ClientProcess.HasExited) { LogConsole("Client exited, stopping server...."); if (!GlobalCommandLine.NoKill) { ServerProcess.StopProcess(); } bKeepReading = false; } return bKeepReading; // Keep reading }); } LogConsole("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."); } } }
public override ProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { // look for browser var ConfigCache = new UnrealBuildTool.ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", Path.GetDirectoryName(Params.RawProjectPath), CombinePaths(CmdEnv.LocalRoot, "Engine")); bool ok = false; List <string> Devices; string browserPath = ""; string DeviceName = Params.Device.Split('@')[1]; DeviceName = DeviceName.Substring(0, DeviceName.LastIndexOf(" on ")); if (ConfigCache.GetArray("/Script/HTML5PlatformEditor.HTML5SDKSettings", "DeviceMap", out Devices)) { foreach (var Dev in Devices) { var Matched = Regex.Match(Dev, "\\(DeviceName=\"(.*)\",DevicePath=\\(FilePath=\"(.*)\"\\)\\)", RegexOptions.IgnoreCase); if (Matched.Success && Matched.Groups[1].ToString() == DeviceName) { browserPath = Matched.Groups[2].ToString(); ok = true; break; } } } if (!ok && HTML5SDKInfo.bAllowFallbackSDKSettings) { string DeviceSection; if (Utils.IsRunningOnMono) { DeviceSection = "HTML5DevicesMac"; } else { DeviceSection = "HTML5DevicesWindows"; } ok = ConfigCache.GetString(DeviceSection, DeviceName, out browserPath); } if (!ok) { throw new System.Exception("Incorrect browser configuration in HTML5Engine.ini "); } // open the webpage Int32 ServerPort = 8000; ConfigCache.GetInt32("/Script/HTML5PlatformEditor.HTML5TargetSettings", "DeployServerPort", out ServerPort); string WorkingDirectory = Path.GetDirectoryName(ClientApp); string url = Path.GetFileName(ClientApp) + ".html"; string args = "-m "; // Are we running via cook on the fly server? // find our http url - This is awkward because RunClient doesn't have real information that NFS is running or not. bool IsCookOnTheFly = false; // 9/24/2014 @fixme - All this is convoluted, clean up. // looks like cookonthefly commandline stopped adding protocol or the port :/ hard coding to DEFAULT_TCP_FILE_SERVING_PORT+1 (DEFAULT_HTTP_FILE_SERVING_PORT) // This will fail if the NFS server is started with a different port - we need to modify driver .cs script to pass in IP/Port data correctly. if (ClientCmdLine.Contains("filehostip")) { IsCookOnTheFly = true; url = "http://127.0.0.1:41898/" + url; } if (IsCookOnTheFly) { url += "?cookonthefly=true"; } else { url = String.Format("http://127.0.0.1:{0}/{1}", ServerPort, url); args += String.Format("-h -s {0} ", ServerPort); } // Check HTML5LaunchHelper source for command line args var LowerBrowserPath = browserPath.ToLower(); args += String.Format("-b \"{0}\" -p \"{1}\" -w \"{2}\" ", browserPath, HTML5SDKInfo.PythonPath(), WorkingDirectory); args += url + " "; var ProfileDirectory = Path.Combine(Utils.GetUserSettingDirectory(), "UE4_HTML5", "user"); if (LowerBrowserPath.Contains("chrome")) { args += String.Format("--user-data-dir=\"{0}\" --enable-logging --no-first-run", Path.Combine(ProfileDirectory, "chrome")); } else if (LowerBrowserPath.Contains("firefox")) { args += String.Format("-no-remote -profile \"{0}\"", Path.Combine(ProfileDirectory, "firefox")); } //else if (browserPath.Contains("Safari")) {} var LaunchHelperPath = CombinePaths(CmdEnv.LocalRoot, "Engine/Binaries/DotNET/HTML5LaunchHelper.exe"); ProcessResult BrowserProcess = Run(LaunchHelperPath, args, null, ClientRunFlags | ERunOptions.NoWaitForExit); return(BrowserProcess); }
public override ProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { // look for browser var ConfigCache = new UnrealBuildTool.ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", Path.GetDirectoryName(Params.RawProjectPath), CombinePaths(CmdEnv.LocalRoot, "Engine")); string DeviceSection; if ( Utils.IsRunningOnMono ) { DeviceSection = "HTML5DevicesMac"; } else { DeviceSection = "HTML5DevicesWindows"; } string browserPath; string DeviceName = Params.Device.Split('@')[1]; DeviceName = DeviceName.Substring(0, DeviceName.LastIndexOf(" on ")); bool ok = ConfigCache.GetString(DeviceSection, DeviceName, out browserPath); if (!ok) throw new System.Exception ("Incorrect browser configuration in HTML5Engine.ini "); // open the webpage string directory = Path.GetDirectoryName(ClientApp); string url = Path.GetFileName(ClientApp) +".html"; // Are we running via cook on the fly server? // find our http url - This is awkward because RunClient doesn't have real information that NFS is running or not. bool IsCookOnTheFly = false; // 9/24/2014 @fixme - All this is convoluted, clean up. // looks like cookonthefly commandline stopped adding protocol or the port :/ hard coding to DEFAULT_TCP_FILE_SERVING_PORT+1 (DEFAULT_HTTP_FILE_SERVING_PORT) // This will fail if the NFS server is started with a different port - we need to modify driver .cs script to pass in IP/Port data correctly. if (ClientCmdLine.Contains("filehostip")) { IsCookOnTheFly = true; url = "http://127.0.0.1:41898/" + url; } if (IsCookOnTheFly) { url += "?cookonthefly=true"; } else { url = "http://127.0.0.1:8000/" + url; // this will be killed UBT instances dies. string input = String.Format(" -m SimpleHTTPServer 8000"); string PythonPath = HTML5SDKInfo.PythonPath(); ProcessResult Result = ProcessManager.CreateProcess(PythonPath, true, "html5server.log"); Result.ProcessObject.StartInfo.FileName = PythonPath; Result.ProcessObject.StartInfo.UseShellExecute = false; Result.ProcessObject.StartInfo.RedirectStandardOutput = true; Result.ProcessObject.StartInfo.RedirectStandardInput = true; Result.ProcessObject.StartInfo.WorkingDirectory = directory; Result.ProcessObject.StartInfo.Arguments = input; Result.ProcessObject.Start(); Result.ProcessObject.OutputDataReceived += delegate(object sender, System.Diagnostics.DataReceivedEventArgs e) { System.Console.WriteLine(e.Data); }; System.Console.WriteLine("Starting Browser Process"); // safari specific hack. string argument = url; if (browserPath.Contains ("Safari") && Utils.IsRunningOnMono) argument = ""; // Chrome issue. Firefox may work like this in the future bool bBrowserWillSpawnProcess = browserPath.Contains("chrome") || (browserPath.Contains("Google Chrome") && Utils.IsRunningOnMono); ProcessResult SubProcess = null; ProcessResult ClientProcess = Run(browserPath, argument, null, ClientRunFlags | ERunOptions.NoWaitForExit); var ProcStartTime = ClientProcess.ProcessObject.StartTime; var ProcName = ClientProcess.ProcessObject.ProcessName; ClientProcess.ProcessObject.EnableRaisingEvents = true; ClientProcess.ProcessObject.Exited += delegate(System.Object o, System.EventArgs e) { System.Console.WriteLine("Browser Process Ended (PID={0})", ClientProcess.ProcessObject.Id); var bFoundChildProcess = false; if (bBrowserWillSpawnProcess) { // Chrome spawns a process from the tab it opens and then lets the process we spawned die, so // catch that process and attach to that instead. var CurrentProcesses = Process.GetProcesses(); foreach (var item in CurrentProcesses) { if (item.Id != ClientProcess.ProcessObject.Id && item.ProcessName == ProcName && item.StartTime >= ProcStartTime && item.StartTime <= ClientProcess.ProcessObject.ExitTime) { var PID = item.Id; System.Console.WriteLine("Found Process {0} with PID {1} which started at {2}. Waiting on that process to end.", item.ProcessName, item.Id, item.StartTime.ToString()); SubProcess = new ProcessResult(item.ProcessName, item, true, item.ProcessName); item.EnableRaisingEvents = true; item.Exited += delegate(System.Object o2, System.EventArgs e2) { System.Console.WriteLine("Browser Process Ended (PID={0}) - Killing Webserver", PID); Result.ProcessObject.StandardInput.Close(); Result.ProcessObject.Kill(); }; bFoundChildProcess = true; } } } if (!bFoundChildProcess) { System.Console.WriteLine("- Killing Webserver PID({0})", Result.ProcessObject.Id); Result.ProcessObject.StandardInput.Close(); Result.ProcessObject.Kill(); } }; if (bBrowserWillSpawnProcess) { //Wait for it to do so... ClientProcess.ProcessObject.WaitForExit(); ClientProcess = SubProcess; } // safari needs a hack. // http://superuser.com/questions/689315/run-safari-from-terminal-with-given-url-address-without-open-command if (browserPath.Contains ("Safari") && Utils.IsRunningOnMono) { // ClientProcess.ProcessObject.WaitForInputIdle (); Thread.Sleep (2000); Process.Start("/usr/bin/osascript"," -e 'tell application \"Safari\" to open location \"" + url + "\"'" ); } return ClientProcess; } System.Console.WriteLine("Browser Path " + browserPath); ProcessResult BrowserProcess = Run(browserPath, url, null, ClientRunFlags | ERunOptions.NoWaitForExit); return BrowserProcess; }
public override ProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { // look for firefox string[] PossiblePaths = new string[] { Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"Nightly\firefox.exe"), Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), @"Nightly\firefox.exe"), Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"Mozilla Firefox\firefox.exe"), Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), @"Mozilla Firefox\firefox.exe"), }; // set up a directory for temp profile string FirefoxProfileCommand = " -no-remote "; // look for the best firefox to tun string FirefoxPath = null; foreach (string PossiblePath in PossiblePaths) { if (File.Exists(PossiblePath)) { FirefoxPath = PossiblePath; break; } } // if we didn't find one, just use the shell to open it if (FirefoxPath == null) { FirefoxPath = CmdEnv.CmdExe; FirefoxProfileCommand = " "; } // open the webpage // what to do with the commandline!?? string HTMLPath = Path.ChangeExtension(ClientApp, "html"); if ( !File.Exists(HTMLPath) ) // its probably a content only game - then it exists in the UE4 directory and not in the game directory. HTMLPath = Path.Combine(CombinePaths(CmdEnv.LocalRoot, "Engine"), "Binaries", "HTML5", Path.GetFileName(HTMLPath)); ProcessResult ClientProcess = Run(FirefoxPath, FirefoxProfileCommand + HTMLPath , null, ClientRunFlags | ERunOptions.NoWaitForExit); return ClientProcess; }
/// <summary> /// Runs external program and writes the output to a logfile. /// </summary> /// <param name="Env">Environment to use.</param> /// <param name="App">Executable to run</param> /// <param name="CommandLine">Commandline to pass on to the executable</param> /// <param name="LogName">Name of the logfile ( if null, executable name is used )</param> /// <param name="Input">Optional Input for the program (will be provided as stdin)</param> /// <param name="Options">Defines the options how to run. See ERunOptions.</param> /// <param name="FilterCallback">Callback to filter log spew before output.</param> public static void RunAndLog(CommandEnvironment Env, string App, string CommandLine, string LogName = null, int MaxSuccessCode = 0, string Input = null, ERunOptions Options = ERunOptions.Default, Dictionary <string, string> EnvVars = null, ProcessResult.SpewFilterCallbackType SpewFilterCallback = null) { RunAndLog(App, CommandLine, GetRunAndLogOnlyName(Env, App, LogName), MaxSuccessCode, Input, Options, EnvVars, SpewFilterCallback); }
// -------------------------------------------------------------------------------- // RunProjectCommand.Automation.cs public override IProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { // look for browser string BrowserPath = Params.Devices[0].Replace("HTML5@", ""); // open the webpage Int32 ServerPort = 8000; // HTML5LaunchHelper default var ConfigCache = UnrealBuildTool.ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, DirectoryReference.FromFile(Params.RawProjectPath), UnrealTargetPlatform.HTML5); ConfigCache.GetInt32("/Script/HTML5PlatformEditor.HTML5TargetSettings", "DeployServerPort", out ServerPort); // LaunchOn via Editor or FrontEnd string WorkingDirectory = Path.GetDirectoryName(ClientApp); string url = Path.GetFileName(ClientApp) + ".html"; // UE-64628: seems proxy port is no longer used anymore -- leaving details here for future reference... // // WARNING: splitting the following situation // // if cookonthefly is used: tell the browser to use the PROXY at DEFAULT_HTTP_FILE_SERVING_PORT // // leave the normal HTML5LaunchHelper port (ServerPort) alone -- otherwise it will collide with the PROXY port if (ClientCmdLine.Contains("filehostip")) { url += "?cookonthefly=true"; // Int32 ProxyPort = 41898; // DEFAULT_HTTP_FILE_SERVING_PORT // url = String.Format("http://localhost:{0}/{1}", ProxyPort, url); } // else // { url = String.Format("http://localhost:{0}/{1}", ServerPort, url); // } // Check HTML5LaunchHelper source for command line args var LowerBrowserPath = BrowserPath.ToLower(); var ProfileDirectory = Path.Combine(Utils.GetUserSettingDirectory().FullName, "UE4_HTML5", "user"); string BrowserCommandline = url; if (LowerBrowserPath.Contains("chrome")) { ProfileDirectory = Path.Combine(ProfileDirectory, "chrome"); // removing [--enable-logging] otherwise, chrome breaks with a bunch of the following errors: // > ERROR:process_info.cc(631)] range at 0x7848406c00000000, size 0x1a4 fully unreadable // leaving this note here for future reference: UE-45078 BrowserCommandline += " " + String.Format("--user-data-dir=\\\"{0}\\\" --no-first-run", ProfileDirectory); } else if (LowerBrowserPath.Contains("firefox")) { ProfileDirectory = Path.Combine(ProfileDirectory, "firefox"); BrowserCommandline += " " + String.Format("-no-remote -profile \\\"{0}\\\"", ProfileDirectory); } else if (LowerBrowserPath.Contains("safari")) { // NOT SUPPORTED: cannot have a separate UE4 profile for safari // -- this "can" be done with a different user (e.g. guest) account... // (which is not a turn key solution that can be done within UE4) // -- some have tried using symlinks to "mimic" this // https://discussions.apple.com/thread/3327990 // -- but, none of these are fool proof with an existing/running safari instance // -- also, "Safari Extensions JS" has been officially deprecated as of Safari 12 // (in favor of using "Safari App Extension") // https://developer.apple.com/documentation/safariextensions // this means, Safari "LaunchOn" (UE4 Editor -> Launch -> Safari) will run with your FULL // Safari profile -- so, all of your "previously opened" tabs will all also be opened... } // TODO: test on other platforms to remove this first if() check if (UnrealBuildTool.BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Linux) { if (!Directory.Exists(ProfileDirectory)) { Directory.CreateDirectory(ProfileDirectory); } } string LauncherArguments = string.Format(" -Browser=\"{0}\" + -BrowserCommandLine=\"{1}\" -ServerPort=\"{2}\" -ServerRoot=\"{3}\" ", new object[] { BrowserPath, BrowserCommandline, ServerPort, WorkingDirectory }); var LaunchHelperPath = CombinePaths(CmdEnv.LocalRoot, "Engine/Binaries/DotNET/HTML5LaunchHelper.exe"); IProcessResult BrowserProcess = Run(LaunchHelperPath, LauncherArguments, null, ClientRunFlags | ERunOptions.NoWaitForExit); return(BrowserProcess); }
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"; bool bCommandlet = false; 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"; } // If running a commandlet, just detect a normal exit else if (ClientCmdLine.IndexOf("-run=", StringComparison.InvariantCultureIgnoreCase) >= 0) { LookFor = "Game engine shut down"; bCommandlet = true; } { string AllClientOutput = ""; int LastAutoFailIndex = -1; IProcessResult ClientProcess = null; FileStream ClientProcessLog = null; StreamReader ClientLogReader = null; LogInformation("Starting Client for unattended test...."); ClientProcess = Run(ClientApp, ClientCmdLine + " -testexit=\"" + LookFor + "\"", null, ClientRunFlags | ERunOptions.NoWaitForExit); while (!FileExists(ClientLogFile) && !ClientProcess.HasExited) { LogInformation("Waiting for client logging process to start...{0}", ClientLogFile); Thread.Sleep(2000); } if (FileExists(ClientLogFile)) { Thread.Sleep(2000); LogInformation("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; LogInformation("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); LogError("Automated test failed ({0}).", Test); LastAutoFailIndex = FailIndex; } } } // Detect commandlet failure else if (bCommandlet) { const string ResultLog = "Commandlet->Main return this error code: "; int ResultStart = AllClientOutput.LastIndexOf(ResultLog); int ResultValIdx = ResultStart + ResultLog.Length; if (ResultStart >= 0 && ResultValIdx < AllClientOutput.Length && AllClientOutput.Substring(ResultValIdx, 1) == "1") { // Parse the full commandlet warning/error summary string FullSummary = ""; int SummaryStart = AllClientOutput.LastIndexOf("Warning/Error Summary"); if (SummaryStart >= 0 && SummaryStart < ResultStart) { FullSummary = AllClientOutput.Substring(SummaryStart, ResultStart - SummaryStart); } if (FullSummary.Length > 0) { LogError("Commandlet failed, summary:" + Environment.NewLine + FullSummary); } else { LogError("Commandlet failed."); } } } } else if (bClientExited && (DateTime.UtcNow - ExitTime).TotalSeconds > 30) { LogInformation("Client exited and has been quiet for 30 seconds...exiting"); bKeepReading = false; } } if (ClientProcess != null && !ClientProcess.HasExited) { LogInformation("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) { LogInformation("Stopping client..."); ClientProcess.StopProcess(); Thread.Sleep(10000); } while (!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]; IProcessResult 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); SC.StageTargetPlatform.PostRunClient(ClientProcess, Params); // any non-zero exit code should propagate an exception. The Virtual function above may have // already thrown a more specific exception or given a more specific ErrorCode, but this catches the rest. if (ClientProcess.ExitCode != 0) { throw new AutomationException("Client exited with error code: " + ClientProcess.ExitCode); } } } }
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 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 = SC.ProjectArgForCommandLines + " "; var PlatformName = Params.ClientTargetPlatforms[0].ToString(); if (Params.Cook || Params.CookOnTheFly) { List <FileReference> Exes = SC.StageTargetPlatform.GetExecutableNames(SC); ClientApp = Exes[0].FullName; if (!String.IsNullOrEmpty(Params.ClientCommandline)) { TempCmdLine += Params.ClientCommandline + " "; } else { 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.CookOnTheFlyStreaming) { 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)) { if (Params.SignedPak) { TempCmdLine += "-signedpak "; } else { TempCmdLine += "-pak "; } } else if (!Params.Stage) { var SandboxPath = CombinePaths(SC.RuntimeProjectRootDir.FullName, "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"); if (!Params.EditorTest) { TempCmdLine += "-game " + Params.MapToRun + " "; } else { TempCmdLine += 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 >= 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;runtests " + Params.RunAutomationTest + "\" "; } else if (Params.RunAutomationTests) { TempCmdLine += "-execcmds=\"automation list;runall\" "; } if (SC.StageTargetPlatform.UseAbsLog) { TempCmdLine += "-abslog=" + CommandUtils.MakePathSafeToUseWithCommandLine(ClientLogFile) + " "; } if (SC.StageTargetPlatform.PlatformType == UnrealTargetPlatform.Win32 || SC.StageTargetPlatform.PlatformType == UnrealTargetPlatform.Win64) { TempCmdLine += "-Messaging -Windowed "; } else { TempCmdLine += "-Messaging "; } if (Params.NullRHI && SC.StageTargetPlatform.PlatformType != UnrealTargetPlatform.Mac) // all macs have GPUs, and currently the mac dies with nullrhi { TempCmdLine += "-nullrhi "; } TempCmdLine += SC.StageTargetPlatform.GetLaunchExtraCommandLine(Params); TempCmdLine += "-CrashForUAT "; TempCmdLine += Params.RunCommandline; // todo: move this into the platform if (SC.StageTargetPlatform.LaunchViaUFE) { ClientCmdLine = "-run=Launch "; ClientCmdLine += "-Device=" + Params.Devices[0]; for (int DeviceIndex = 1; DeviceIndex < Params.Devices.Count; DeviceIndex++) { ClientCmdLine += "+" + Params.Devices[DeviceIndex]; } ClientCmdLine += " "; ClientCmdLine += "-Exe=\"" + ClientApp + "\" "; ClientCmdLine += "-Targetplatform=" + Params.ClientTargetPlatforms[0].ToString() + " "; ClientCmdLine += "-Params=\"" + TempCmdLine + "\""; ClientApp = CombinePaths(CmdEnv.LocalRoot, "Engine/Binaries/Win64/UnrealFrontend.exe"); LogInformation("Launching via UFE:"); LogInformation("\tClientCmdLine: " + ClientCmdLine + ""); } else { ClientCmdLine = TempCmdLine; } }
public override ProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { return(null); }
public override ProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { if (UnrealBuildTool.BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac) { /* string AppDirectory = string.Format("{0}/Payload/{1}.app", Path.GetDirectoryName(Params.ProjectGameExeFilename), Path.GetFileNameWithoutExtension(Params.ProjectGameExeFilename)); string GameName = Path.GetFileNameWithoutExtension (ClientApp); if (GameName.Contains ("-IOS-")) { GameName = GameName.Substring (0, GameName.IndexOf ("-IOS-")); } string GameApp = AppDirectory + "/" + GameName; bWasGenerated = false; XcodeProj = EnsureXcodeProjectExists (Params.RawProjectPath, CmdEnv.LocalRoot, Params.ShortProjectName, GetDirectoryName(Params.RawProjectPath), Params.IsCodeBasedProject, out bWasGenerated); string Arguments = "UBT_NO_POST_DEPLOY=true /usr/bin/xcrun xcodebuild test -project \"" + XcodeProj + "\""; Arguments += " -scheme '"; Arguments += GameName; Arguments += " - iOS'"; Arguments += " -configuration " + Params.ClientConfigsToBuild [0].ToString(); Arguments += " -destination 'platform=iOS,id=" + Params.Device.Substring(4) + "'"; Arguments += " TEST_HOST=\""; Arguments += GameApp; Arguments += "\" BUNDLE_LOADER=\""; Arguments += GameApp + "\"";*/ string BundleIdentifier = ""; if (File.Exists(Params.BaseStageDirectory + "/IOS/Info.plist")) { string Contents = File.ReadAllText(Params.BaseStageDirectory + "/IOS/Info.plist"); int Pos = Contents.IndexOf("CFBundleIdentifier"); Pos = Contents.IndexOf("<string>", Pos) + 8; int EndPos = Contents.IndexOf("</string>", Pos); BundleIdentifier = Contents.Substring(Pos, EndPos - Pos); } string Arguments = "/usr/bin/instruments"; Arguments += " -w '" + Params.Device.Substring (4) + "'"; Arguments += " -t 'Activity Monitor'"; Arguments += " -D \"" + Params.BaseStageDirectory + "/IOS/launch.trace\""; Arguments += " '" + BundleIdentifier + "'"; ProcessResult ClientProcess = Run ("/usr/bin/env", Arguments, null, ClientRunFlags | ERunOptions.NoWaitForExit); return ClientProcess; } else { ProcessResult Result = new ProcessResult("DummyApp", null, false, null); Result.ExitCode = 0; return Result; } }
public override ProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { if (UnrealBuildTool.ExternalExecution.GetRuntimePlatform () == UnrealTargetPlatform.Mac) { string AppDirectory = string.Format("{0}/Payload/{1}.app", Path.GetDirectoryName(Params.ProjectGameExeFilename), Path.GetFileNameWithoutExtension(Params.ProjectGameExeFilename)); string GameName = Path.GetFileNameWithoutExtension (ClientApp); string GameApp = AppDirectory + "/" + GameName; bool bWasGenerated = false; string XcodeProj = EnsureXcodeProjectExists (Params.RawProjectPath, out bWasGenerated); string Arguments = "UBT_NO_POST_DEPLOY=true /usr/bin/xcrun xcodebuild test -project \"" + XcodeProj + "\""; Arguments += " -scheme '"; Arguments += GameName; Arguments += " - iOS (Run)'"; Arguments += " -configuration " + Params.ClientConfigsToBuild [0].ToString(); Arguments += " -destination 'platform=iOS,id=" + Params.Device.Substring(4) + "'"; Arguments += " TEST_HOST=\""; Arguments += GameApp; Arguments += "\" BUNDLE_LOADER=\""; Arguments += GameApp + "\""; ProcessResult ClientProcess = Run ("/usr/bin/env", Arguments, null, ClientRunFlags | ERunOptions.NoWaitForExit); return ClientProcess; } else { return base.RunClient(ClientRunFlags, ClientApp, ClientCmdLine, Params); } }
/// <summary> /// Run the client application on the platform /// </summary> /// <param name="ClientRunFlags"></param> /// <param name="ClientApp"></param> /// <param name="ClientCmdLine"></param> public virtual ProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { PushDir(Path.GetDirectoryName(ClientApp)); // Always start client process and don't wait for exit. ProcessResult ClientProcess = Run(ClientApp, ClientCmdLine, null, ClientRunFlags | ERunOptions.NoWaitForExit); PopDir(); return ClientProcess; }
/// <summary> /// Runs external program. /// </summary> /// <param name="App">Program filename.</param> /// <param name="CommandLine">Commandline</param> /// <param name="Input">Optional Input for the program (will be provided as stdin)</param> /// <param name="Options">Defines the options how to run. See ERunOptions.</param> /// <param name="Env">Environment to pass to program.</param> /// <param name="FilterCallback">Callback to filter log spew before output.</param> /// <returns>Object containing the exit code of the program as well as it's stdout output.</returns> public static IProcessResult Run(string App, string CommandLine = null, string Input = null, ERunOptions Options = ERunOptions.Default, Dictionary<string, string> Env = null, ProcessResult.SpewFilterCallbackType SpewFilterCallback = null) { App = ConvertSeparators(PathSeparator.Default, App); // Get the log name before allowing the platform to modify the app/command-line. We want mono apps to be written to a log named after the application and appear with the application prefix rather than "mono:". string LogName = Path.GetFileNameWithoutExtension(App); HostPlatform.Current.SetupOptionsForRun(ref App, ref Options, ref CommandLine); if (App == "ectool" || App == "zip" || App == "xcodebuild") { Options &= ~ERunOptions.AppMustExist; } // Check if the application exists, including the PATH directories. if (Options.HasFlag(ERunOptions.AppMustExist) && !FileExists(Options.HasFlag(ERunOptions.NoLoggingOfRunCommand) ? true : false, App)) { bool bExistsInPath = false; if(!App.Contains(Path.DirectorySeparatorChar) && !App.Contains(Path.AltDirectorySeparatorChar)) { string[] PathDirectories = Environment.GetEnvironmentVariable("PATH").Split(Path.PathSeparator); foreach(string PathDirectory in PathDirectories) { string TryApp = Path.Combine(PathDirectory, App); if(FileExists(Options.HasFlag(ERunOptions.NoLoggingOfRunCommand), TryApp)) { App = TryApp; bExistsInPath = true; break; } } } if(!bExistsInPath) { throw new AutomationException("BUILD FAILED: Couldn't find the executable to Run: {0}", App); } } var StartTime = DateTime.UtcNow; UnrealBuildTool.LogEventType SpewVerbosity = Options.HasFlag(ERunOptions.SpewIsVerbose) ? UnrealBuildTool.LogEventType.Verbose : UnrealBuildTool.LogEventType.Console; if (!Options.HasFlag(ERunOptions.NoLoggingOfRunCommand)) { LogWithVerbosity(SpewVerbosity,"Run: " + App + " " + (String.IsNullOrEmpty(CommandLine) ? "" : CommandLine)); } IProcessResult Result = ProcessManager.CreateProcess(App, Options.HasFlag(ERunOptions.AllowSpew), LogName, Env, SpewVerbosity:SpewVerbosity, SpewFilterCallback: SpewFilterCallback); Process Proc = Result.ProcessObject; bool bRedirectStdOut = (Options & ERunOptions.NoStdOutRedirect) != ERunOptions.NoStdOutRedirect; Proc.StartInfo.FileName = App; Proc.StartInfo.Arguments = String.IsNullOrEmpty(CommandLine) ? "" : CommandLine; Proc.StartInfo.UseShellExecute = false; if (bRedirectStdOut) { Proc.StartInfo.RedirectStandardOutput = true; Proc.StartInfo.RedirectStandardError = true; Proc.OutputDataReceived += Result.StdOut; Proc.ErrorDataReceived += Result.StdErr; } Proc.StartInfo.RedirectStandardInput = Input != null; Proc.StartInfo.CreateNoWindow = true; if ((Options & ERunOptions.UTF8Output) == ERunOptions.UTF8Output) { Proc.StartInfo.StandardOutputEncoding = new System.Text.UTF8Encoding(false, false); } Proc.Start(); if (bRedirectStdOut) { Proc.BeginOutputReadLine(); Proc.BeginErrorReadLine(); } if (String.IsNullOrEmpty(Input) == false) { Proc.StandardInput.WriteLine(Input); Proc.StandardInput.Close(); } if (!Options.HasFlag(ERunOptions.NoWaitForExit)) { Result.WaitForExit(); var BuildDuration = (DateTime.UtcNow - StartTime).TotalMilliseconds; AddRunTime(App, (int)(BuildDuration)); Result.ExitCode = Proc.ExitCode; if (!Options.HasFlag(ERunOptions.NoLoggingOfRunCommand) || Options.HasFlag(ERunOptions.LoggingOfRunDuration)) { LogWithVerbosity(SpewVerbosity,"Run: Took {0}s to run {1}, ExitCode={2}", BuildDuration / 1000, Path.GetFileName(App), Result.ExitCode); } Result.OnProcessExited(); Result.DisposeProcess(); } else { Result.ExitCode = -1; } return Result; }
/// <summary> /// Runs external program and writes the output to a logfile. /// </summary> /// <param name="Env">Environment to use.</param> /// <param name="App">Executable to run</param> /// <param name="CommandLine">Commandline to pass on to the executable</param> /// <param name="LogName">Name of the logfile ( if null, executable name is used )</param> /// <param name="Input">Optional Input for the program (will be provided as stdin)</param> /// <param name="Options">Defines the options how to run. See ERunOptions.</param> public static void RunAndLog(CommandEnvironment Env, string App, string CommandLine, string LogName = null, int MaxSuccessCode = 0, string Input = null, ERunOptions Options = ERunOptions.Default, Dictionary<string, string> EnvVars = null) { RunAndLog(App, CommandLine, GetRunAndLogLogName(Env, App, LogName), MaxSuccessCode, Input, Options, EnvVars); }
/// <summary> /// Runs external program and writes the output to a logfile. /// </summary> /// <param name="Env">Environment to use.</param> /// <param name="App">Executable to run</param> /// <param name="CommandLine">Commandline to pass on to the executable</param> /// <param name="LogName">Name of the logfile ( if null, executable name is used )</param> /// <param name="Input">Optional Input for the program (will be provided as stdin)</param> /// <param name="Options">Defines the options how to run. See ERunOptions.</param> /// <param name="FilterCallback">Callback to filter log spew before output.</param> public static void RunAndLog(CommandEnvironment Env, string App, string CommandLine, string LogName = null, int MaxSuccessCode = 0, string Input = null, ERunOptions Options = ERunOptions.Default, Dictionary<string, string> EnvVars = null, ProcessResult.SpewFilterCallbackType SpewFilterCallback = null) { RunAndLog(App, CommandLine, GetRunAndLogOnlyName(Env, App, LogName), MaxSuccessCode, Input, Options, EnvVars, SpewFilterCallback); }
public override ProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { // look for browser var ConfigCache = new UnrealBuildTool.ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", Path.GetDirectoryName(Params.RawProjectPath), CombinePaths(CmdEnv.LocalRoot, "Engine")); bool ok = false; List<string> Devices; string browserPath = ""; string DeviceName = Params.Device.Split('@')[1]; DeviceName = DeviceName.Substring(0, DeviceName.LastIndexOf(" on ")); if (ConfigCache.GetArray("/Script/HTML5PlatformEditor.HTML5SDKSettings", "DeviceMap", out Devices)) { foreach (var Dev in Devices) { var Matched = Regex.Match(Dev, "\\(DeviceName=\"(.*)\",DevicePath=\\(FilePath=\"(.*)\"\\)\\)", RegexOptions.IgnoreCase); if (Matched.Success && Matched.Groups[1].ToString() == DeviceName) { browserPath = Matched.Groups[2].ToString(); ok = true; break; } } } if (!ok && HTML5SDKInfo.bAllowFallbackSDKSettings) { string DeviceSection; if (Utils.IsRunningOnMono) { DeviceSection = "HTML5DevicesMac"; } else { DeviceSection = "HTML5DevicesWindows"; } ok = ConfigCache.GetString(DeviceSection, DeviceName, out browserPath); } if (!ok) { throw new System.Exception("Incorrect browser configuration in HTML5Engine.ini "); } // open the webpage Int32 ServerPort = 8000; ConfigCache.GetInt32("/Script/HTML5PlatformEditor.HTML5TargetSettings", "DeployServerPort", out ServerPort); string WorkingDirectory = Path.GetDirectoryName(ClientApp); string url = Path.GetFileName(ClientApp) +".html"; // Are we running via cook on the fly server? // find our http url - This is awkward because RunClient doesn't have real information that NFS is running or not. bool IsCookOnTheFly = false; // 9/24/2014 @fixme - All this is convoluted, clean up. // looks like cookonthefly commandline stopped adding protocol or the port :/ hard coding to DEFAULT_TCP_FILE_SERVING_PORT+1 (DEFAULT_HTTP_FILE_SERVING_PORT) // This will fail if the NFS server is started with a different port - we need to modify driver .cs script to pass in IP/Port data correctly. if (ClientCmdLine.Contains("filehostip")) { IsCookOnTheFly = true; url = "http://127.0.0.1:41898/" + url; } if (IsCookOnTheFly) { url += "?cookonthefly=true"; } else { url = String.Format("http://{2}:{0}/{1}", ServerPort, url, Environment.MachineName); } // Check HTML5LaunchHelper source for command line args var LowerBrowserPath = browserPath.ToLower(); var ProfileDirectory = Path.Combine(Utils.GetUserSettingDirectory(), "UE4_HTML5", "user"); string BrowserCommandline = url; if (LowerBrowserPath.Contains("chrome")) { BrowserCommandline += " " + String.Format("--user-data-dir=\"{0}\" --enable-logging --no-first-run", Path.Combine(ProfileDirectory, "chrome")); } else if (LowerBrowserPath.Contains("firefox")) { BrowserCommandline += " " + String.Format("-no-remote -profile \"{0}\"", Path.Combine(ProfileDirectory, "firefox")); } string LauncherArguments = string.Format( " -Browser=\"{0}\" + -BrowserCommandLine=\"{1}\" -ServerPort=\"{2}\" -ServerRoot=\"{3}\" ", new object[] { browserPath,BrowserCommandline,ServerPort,WorkingDirectory }); var LaunchHelperPath = CombinePaths(CmdEnv.LocalRoot, "Engine/Binaries/DotNET/HTML5LaunchHelper.exe"); ProcessResult BrowserProcess = Run(LaunchHelperPath, LauncherArguments, null, ClientRunFlags | ERunOptions.NoWaitForExit); return BrowserProcess; }
public override IProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { string BatchPath = GetBatchPath(Params, null); return(Run(BatchPath, ClientCmdLine, null, ERunOptions.Default)); }
public override ProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { // look for browser var ConfigCache = new UnrealBuildTool.ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", Path.GetDirectoryName(Params.RawProjectPath), CombinePaths(CmdEnv.LocalRoot, "Engine")); string DeviceSection; if ( Utils.IsRunningOnMono ) { DeviceSection = "HTML5DevicesMac"; } else { DeviceSection = "HTML5DevicesWindows"; } string browserPath; string DeviceName = Params.Device.Split('@')[1]; DeviceName = DeviceName.Substring(0, DeviceName.LastIndexOf(" on ")); bool ok = ConfigCache.GetString(DeviceSection, DeviceName, out browserPath); if (!ok) throw new System.Exception ("Incorrect browser configuration in HTML5Engine.ini "); // open the webpage string directory = Path.GetDirectoryName(ClientApp); string url = Path.GetFileName(ClientApp) +".html"; // Are we running via cook on the fly server? // find our http url - This is awkward because RunClient doesn't have real information that NFS is running or not. bool IsCookOnTheFly = false; // 9/24/2014 @fixme - All this is convoluted, clean up. // looks like cookonthefly commandline stopped adding protocol or the port :/ hard coding to DEFAULT_TCP_FILE_SERVING_PORT+1 (DEFAULT_HTTP_FILE_SERVING_PORT) // This will fail if the NFS server is started with a different port - we need to modify driver .cs script to pass in IP/Port data correctly. if (ClientCmdLine.Contains("filehostip")) { IsCookOnTheFly = true; url = "http://127.0.0.1:41898/" + url; } if (IsCookOnTheFly) { url += "?cookonthefly=true"; } else { var EmscriptenSettings = ReadEmscriptenSettings(); url = "http://127.0.0.1:8000/" + url; // this will be killed UBT instances dies. string input = String.Format(" -m SimpleHTTPServer 8000"); string PythonName = null; // Check the .emscripten file for a possible python path if (EmscriptenSettings.ContainsKey("PYTHON")) { PythonName = EmscriptenSettings["PYTHON"]; Log("Found python path {0} in emscripten file", PythonName); } // The AutoSDK defines this env var as part of its install. See setup.bat/unsetup.bat // If it's missing then just assume that python lives on the path if (PythonName == null && Environment.GetEnvironmentVariable("PYTHON") != null) { PythonName = Environment.GetEnvironmentVariable("PYTHON"); Log("Found python path {0} in PYTHON Environment Variable", PythonName); } // Check if the exe exists if (!System.IO.File.Exists(PythonName)) { Log("Either no python path can be found or it doesn't exist. Using python on PATH"); PythonName = Utils.IsRunningOnMono ? "python" : "python.exe"; } ProcessResult Result = ProcessManager.CreateProcess(PythonName, true, "html5server.log"); Result.ProcessObject.StartInfo.FileName = PythonName; Result.ProcessObject.StartInfo.UseShellExecute = false; Result.ProcessObject.StartInfo.RedirectStandardOutput = true; Result.ProcessObject.StartInfo.RedirectStandardInput = true; Result.ProcessObject.StartInfo.WorkingDirectory = directory; Result.ProcessObject.StartInfo.Arguments = input; Result.ProcessObject.Start(); Result.ProcessObject.OutputDataReceived += delegate(object sender, System.Diagnostics.DataReceivedEventArgs e) { System.Console.WriteLine(e.Data); }; System.Console.WriteLine("Starting Browser Process"); // safari specific hack. string argument = url; if (browserPath.Contains ("Safari") && Utils.IsRunningOnMono) argument = ""; ProcessResult ClientProcess = Run(browserPath, argument, null, ClientRunFlags | ERunOptions.NoWaitForExit); ClientProcess.ProcessObject.EnableRaisingEvents = true; ClientProcess.ProcessObject.Exited += delegate(System.Object o, System.EventArgs e) { System.Console.WriteLine("Browser Process Ended - Killing Webserver"); // send kill. Result.ProcessObject.StandardInput.Close(); Result.ProcessObject.Kill(); }; // safari needs a hack. // http://superuser.com/questions/689315/run-safari-from-terminal-with-given-url-address-without-open-command if (browserPath.Contains ("Safari") && Utils.IsRunningOnMono) { // ClientProcess.ProcessObject.WaitForInputIdle (); Thread.Sleep (2000); Process.Start("/usr/bin/osascript"," -e 'tell application \"Safari\" to open location \"" + url + "\"'" ); } return ClientProcess; } System.Console.WriteLine("Browser Path " + browserPath); ProcessResult BrowserProcess = Run(browserPath, url, null, ClientRunFlags | ERunOptions.NoWaitForExit); return BrowserProcess; }
public override ProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { if (UnrealBuildTool.BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac) { string AppDirectory = string.Format("{0}/Payload/{1}.app", Path.GetDirectoryName(Params.ProjectGameExeFilename), Path.GetFileNameWithoutExtension(Params.ProjectGameExeFilename)); string GameName = Path.GetFileNameWithoutExtension (ClientApp); if (GameName.Contains ("-IOS-")) { GameName = GameName.Substring (0, GameName.IndexOf ("-IOS-")); } string GameApp = AppDirectory + "/" + GameName; bool bWasGenerated = false; string XcodeProj = EnsureXcodeProjectExists (Params.RawProjectPath, CmdEnv.LocalRoot, Params.ShortProjectName, GetDirectoryName(Params.RawProjectPath), Params.IsCodeBasedProject, out bWasGenerated); string Arguments = "UBT_NO_POST_DEPLOY=true /usr/bin/xcrun xcodebuild test -project \"" + XcodeProj + "\""; Arguments += " -scheme '"; Arguments += GameName; Arguments += " - iOS'"; Arguments += " -configuration " + Params.ClientConfigsToBuild [0].ToString(); Arguments += " -destination 'platform=iOS,id=" + Params.Device.Substring(4) + "'"; Arguments += " TEST_HOST=\""; Arguments += GameApp; Arguments += "\" BUNDLE_LOADER=\""; Arguments += GameApp + "\""; ProcessResult ClientProcess = Run ("/usr/bin/env", Arguments, null, ClientRunFlags | ERunOptions.NoWaitForExit); return ClientProcess; } else { // get the CFBundleIdentifier and modify the command line int Pos = ClientCmdLine.IndexOf("-Exe=") + 6; int EndPos = ClientCmdLine.IndexOf("-Targetplatform=") - 2; string Exe = ClientCmdLine.Substring(Pos, EndPos - Pos); // check for Info.plist if (string.IsNullOrEmpty(Params.StageDirectoryParam)) { // need to crack open the ipa and read it from there - todo } else { if (File.Exists(Params.BaseStageDirectory+"/IOS/Info.plist")) { string Contents = File.ReadAllText(Params.BaseStageDirectory + "/IOS/Info.plist"); Pos = Contents.IndexOf("CFBundleIdentifier"); Pos = Contents.IndexOf("<string>", Pos) + 8; EndPos = Contents.IndexOf("</string>", Pos); string id = Contents.Substring(Pos, EndPos - Pos); id = id.Substring(id.LastIndexOf(".") + 1); ClientCmdLine = ClientCmdLine.Replace(Exe, id + ".stub"); } } return base.RunClient(ClientRunFlags, ClientApp, ClientCmdLine, Params); } }
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"; bool bCommandlet = false; 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"; } // If running a commandlet, just detect a normal exit else if (ClientCmdLine.IndexOf("-run=", StringComparison.InvariantCultureIgnoreCase) >= 0) { LookFor = "Game engine shut down"; bCommandlet = true; } { string AllClientOutput = ""; int LastAutoFailIndex = -1; ProcessResult ClientProcess = null; FileStream ClientProcessLog = null; StreamReader ClientLogReader = null; LogConsole("Starting Client for unattended test...."); ClientProcess = Run(ClientApp, ClientCmdLine + " -FORCELOGFLUSH -testexit=\"" + LookFor + "\"", null, ClientRunFlags | ERunOptions.NoWaitForExit); while (!FileExists(ClientLogFile) && !ClientProcess.HasExited) { LogConsole("Waiting for client logging process to start...{0}", ClientLogFile); Thread.Sleep(2000); } if (FileExists(ClientLogFile)) { Thread.Sleep(2000); LogConsole("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; LogConsole("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); LogError("Automated test failed ({0}).", Test); LastAutoFailIndex = FailIndex; } } } // Detect commandlet failure else if (bCommandlet) { const string ResultLog = "Commandlet->Main return this error code: "; int ResultStart = AllClientOutput.LastIndexOf(ResultLog); int ResultValIdx = ResultStart + ResultLog.Length; if (ResultStart >= 0 && ResultValIdx < AllClientOutput.Length && AllClientOutput.Substring(ResultValIdx, 1) == "1") { // Parse the full commandlet warning/error summary string FullSummary = ""; int SummaryStart = AllClientOutput.LastIndexOf("Warning/Error Summary"); if (SummaryStart >= 0 && SummaryStart < ResultStart) { FullSummary = AllClientOutput.Substring(SummaryStart, ResultStart - SummaryStart); } if (FullSummary.Length > 0) { LogError("Commandlet failed, summary:" + Environment.NewLine + FullSummary); } else { LogError("Commandlet failed."); } } } } else if (bClientExited && (DateTime.UtcNow - ExitTime).TotalSeconds > 30) { LogConsole("Client exited and has been quiet for 30 seconds...exiting"); bKeepReading = false; } } if (ClientProcess != null && !ClientProcess.HasExited) { LogConsole("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) { LogConsole("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); SC.StageTargetPlatform.PostRunClient(ClientProcess, Params); // any non-zero exit code should propagate an exception. The Virtual function above may have // already thrown a more specific exception or given a more specific ErrorCode, but this catches the rest. if (ClientProcess.ExitCode != 0) { throw new AutomationException("Client exited with error code: " + ClientProcess.ExitCode); } } } }
public override ProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { string DeviceArchitecture = GetBestDeviceArchitecture(Params); string GPUArchitecture = ""; string ApkName = ClientApp + DeviceArchitecture + ".apk"; if (!File.Exists(ApkName)) { ApkName = GetFinalApkName(Params, Path.GetFileNameWithoutExtension(ClientApp), true, DeviceArchitecture, GPUArchitecture); } Console.WriteLine("Apk='{0}', ClientApp='{1}', ExeName='{2}'", ApkName, ClientApp, Params.ProjectGameExeFilename); // run aapt to get the name of the intent string PackageName = GetPackageInfo(ApkName, false); if (PackageName == null) { ErrorReporter.Error("Failed to get package name from " + ClientApp, (int)ErrorCodes.Error_FailureGettingPackageInfo); throw new AutomationException("Failed to get package name from " + ClientApp); } string AdbCommand = GetAdbCommand(Params); string CommandLine = "shell am start -n " + PackageName + "/com.epicgames.ue4.GameActivity"; if (Params.Prebuilt) { // clear the log Run(CmdEnv.CmdExe, AdbCommand + "logcat -c"); } // Send a command to unlock the device before we try to run it string UnlockCommandLine = "shell input keyevent 82"; Run(CmdEnv.CmdExe, AdbCommand + UnlockCommandLine, null); // start the app on device! ProcessResult ClientProcess = Run(CmdEnv.CmdExe, AdbCommand + CommandLine, null, ClientRunFlags); if (Params.Prebuilt) { // save the output to the staging directory string LogPath = Path.Combine(Params.BaseStageDirectory, "Android\\logs"); string LogFilename = Path.Combine(LogPath, "devicelog" + Params.Device + ".log"); string ServerLogFilename = Path.Combine(CmdEnv.LogFolder, "devicelog" + Params.Device + ".log"); Directory.CreateDirectory(LogPath); // check if the game is still running // time out if it takes to long DateTime StartTime = DateTime.Now; int TimeOutSeconds = Params.RunTimeoutSeconds; while (true) { ProcessResult ProcessesResult = Run(CmdEnv.CmdExe, AdbCommand + "shell ps", null, ERunOptions.SpewIsVerbose); string RunningProcessList = ProcessesResult.Output; if (!RunningProcessList.Contains(PackageName)) { break; } Thread.Sleep(10); TimeSpan DeltaRunTime = DateTime.Now - StartTime; if ((DeltaRunTime.TotalSeconds > TimeOutSeconds) && (TimeOutSeconds != 0)) { Log("Device: " + Params.Device + " timed out while waiting for run to finish"); break; } } // this is just to get the ue4 log to go to the output Run(CmdEnv.CmdExe, AdbCommand + "logcat -d -s UE4 -s Debug"); // get the log we actually want to save ProcessResult LogFileProcess = Run(CmdEnv.CmdExe, AdbCommand + "logcat -d", null, ERunOptions.AppMustExist); File.WriteAllText(LogFilename, LogFileProcess.Output); File.WriteAllText(ServerLogFilename, LogFileProcess.Output); } return(ClientProcess); }
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.CookOnTheFlyStreaming) { 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;runtests " + Params.RunAutomationTest + "\" "; } else if (Params.RunAutomationTests) { TempCmdLine += "-execcmds=\"automation list;runall\" "; } if (SC.StageTargetPlatform.UseAbsLog) { 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 "; } if (Params.Deploy && SC.StageTargetPlatform.PlatformType == UnrealTargetPlatform.PS4) { TempCmdLine += "-deployedbuild "; } 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"); LogConsole("Launching via UFE:"); LogConsole("\tClientCmdLine: " + ClientCmdLine + ""); } else { ClientCmdLine = TempCmdLine; } }
/// <summary> /// Runs a commandlet using Engine/Binaries/Win64/UE4Editor-Cmd.exe. /// </summary> /// <param name="ProjectFile">Project name.</param> /// <param name="UE4Exe">The name of the UE4 Editor executable to use.</param> /// <param name="Commandlet">Commandlet name.</param> /// <param name="Parameters">Command line parameters (without -run=)</param> public static void RunCommandlet(FileReference ProjectName, string UE4Exe, string Commandlet, string Parameters = null) { Log("Running UE4Editor {0} for project {1}", Commandlet, ProjectName); var CWD = Path.GetDirectoryName(UE4Exe); string EditorExe = UE4Exe; if (String.IsNullOrEmpty(CWD)) { EditorExe = HostPlatform.Current.GetUE4ExePath(UE4Exe); CWD = CombinePaths(CmdEnv.LocalRoot, HostPlatform.Current.RelativeBinariesFolder); } PushDir(CWD); DateTime StartTime = DateTime.UtcNow; string LocalLogFile = LogUtils.GetUniqueLogName(CombinePaths(CmdEnv.EngineSavedFolder, Commandlet)); Log("Commandlet log file is {0}", LocalLogFile); string Args = String.Format( "{0} -run={1} {2} -abslog={3} -stdout -CrashForUAT -unattended {5}{4}", (ProjectName == null) ? "" : CommandUtils.MakePathSafeToUseWithCommandLine(ProjectName.FullName), Commandlet, String.IsNullOrEmpty(Parameters) ? "" : Parameters, CommandUtils.MakePathSafeToUseWithCommandLine(LocalLogFile), IsBuildMachine ? "-buildmachine" : "", (GlobalCommandLine.Verbose || GlobalCommandLine.AllowStdOutLogVerbosity) ? "-AllowStdOutLogVerbosity " : "" ); ERunOptions Opts = ERunOptions.Default; if (GlobalCommandLine.UTF8Output) { Args += " -UTF8Output"; Opts |= ERunOptions.UTF8Output; } var RunResult = Run(EditorExe, Args, Options: Opts); PopDir(); // Draw attention to signal exit codes on Posix systems, rather than just printing the exit code if (RunResult.ExitCode > 128 && RunResult.ExitCode < 128 + 32) { if (RunResult.ExitCode == 139) { CommandUtils.LogError("Editor terminated abnormally due to a segmentation fault"); } else { CommandUtils.LogError("Editor terminated abnormally with signal {0}", RunResult.ExitCode - 128); } } // If we're running on a Mac, dump all the *.crash files that were generated while the editor was running. if (HostPlatform.Current.HostEditorPlatform == UnrealTargetPlatform.Mac) { // If the exit code indicates the main process crashed, introduce a small delay because the crash report is written asynchronously. // If we exited normally, still check without waiting in case SCW or some other child process crashed. if (RunResult.ExitCode > 128) { CommandUtils.Log("Pausing before checking for crash logs..."); Thread.Sleep(10 * 1000); } // Create a list of directories containing crash logs, and add the system log folder List <string> CrashDirs = new List <string>(); CrashDirs.Add("/Library/Logs/DiagnosticReports"); // Add the user's log directory too string HomeDir = Environment.GetEnvironmentVariable("HOME"); if (!String.IsNullOrEmpty(HomeDir)) { CrashDirs.Add(Path.Combine(HomeDir, "Library/Logs/DiagnosticReports")); } // Check each directory for crash logs List <FileInfo> CrashFileInfos = new List <FileInfo>(); foreach (string CrashDir in CrashDirs) { try { DirectoryInfo CrashDirInfo = new DirectoryInfo(CrashDir); if (CrashDirInfo.Exists) { CrashFileInfos.AddRange(CrashDirInfo.EnumerateFiles("*.crash", SearchOption.TopDirectoryOnly).Where(x => x.LastWriteTimeUtc >= StartTime)); } } catch (UnauthorizedAccessException) { // Not all account types can access /Library/Logs/DiagnosticReports } } // Dump them all to the log foreach (FileInfo CrashFileInfo in CrashFileInfos) { // snmpd seems to often crash (suspect due to it being starved of CPU cycles during cooks) if (!CrashFileInfo.Name.StartsWith("snmpd_")) { CommandUtils.Log("Found crash log - {0}", CrashFileInfo.FullName); try { string[] Lines = File.ReadAllLines(CrashFileInfo.FullName); foreach (string Line in Lines) { CommandUtils.Log("Crash: {0}", Line); } } catch (Exception Ex) { CommandUtils.LogWarning("Failed to read file ({0})", Ex.Message); } } } } // Copy the local commandlet log to the destination folder. string DestLogFile = LogUtils.GetUniqueLogName(CombinePaths(CmdEnv.LogFolder, Commandlet)); if (!CommandUtils.CopyFile_NoExceptions(LocalLogFile, DestLogFile)) { CommandUtils.LogWarning("Commandlet {0} failed to copy the local log file from {1} to {2}. The log file will be lost.", Commandlet, LocalLogFile, DestLogFile); } string ProjectStatsDirectory = CombinePaths((ProjectName == null)? CombinePaths(CmdEnv.LocalRoot, "Engine") : Path.GetDirectoryName(ProjectName.FullName), "Saved", "Stats"); if (Directory.Exists(ProjectStatsDirectory)) { string DestCookerStats = CmdEnv.LogFolder; foreach (var StatsFile in Directory.EnumerateFiles(ProjectStatsDirectory, "*.csv")) { if (!CommandUtils.CopyFile_NoExceptions(StatsFile, CombinePaths(DestCookerStats, Path.GetFileName(StatsFile)))) { CommandUtils.LogWarning("Commandlet {0} failed to copy the local log file from {1} to {2}. The log file will be lost.", Commandlet, StatsFile, CombinePaths(DestCookerStats, Path.GetFileName(StatsFile))); } } } // else // { // CommandUtils.LogWarning("Failed to find directory {0} will not save stats", ProjectStatsDirectory); // } // Whether it was copied correctly or not, delete the local log as it was only a temporary file. CommandUtils.DeleteFile_NoExceptions(LocalLogFile); if (RunResult.ExitCode != 0) { throw new CommandletException(DestLogFile, RunResult.ExitCode, "BUILD FAILED: Failed while running {0} for {1}; see log {2}", Commandlet, ProjectName, DestLogFile); } }
public override ProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { // look for browser string BrowserPath = Params.Device.Replace("HTML5@", ""); // open the webpage Int32 ServerPort = 8000; var ConfigCache = new UnrealBuildTool.ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", Path.GetDirectoryName(Params.RawProjectPath), CombinePaths(CmdEnv.LocalRoot, "Engine")); ConfigCache.GetInt32("/Script/HTML5PlatformEditor.HTML5TargetSettings", "DeployServerPort", out ServerPort); string WorkingDirectory = Path.GetDirectoryName(ClientApp); string url = Path.GetFileName(ClientApp) +".html"; // Are we running via cook on the fly server? // find our http url - This is awkward because RunClient doesn't have real information that NFS is running or not. bool IsCookOnTheFly = false; // 9/24/2014 @fixme - All this is convoluted, clean up. // looks like cookonthefly commandline stopped adding protocol or the port :/ hard coding to DEFAULT_TCP_FILE_SERVING_PORT+1 (DEFAULT_HTTP_FILE_SERVING_PORT) // This will fail if the NFS server is started with a different port - we need to modify driver .cs script to pass in IP/Port data correctly. if (ClientCmdLine.Contains("filehostip")) { IsCookOnTheFly = true; url = "http://127.0.0.1:41898/" + url; } if (IsCookOnTheFly) { url += "?cookonthefly=true"; } else { url = String.Format("http://localhost:{0}/{1}", ServerPort, url); } // Check HTML5LaunchHelper source for command line args var LowerBrowserPath = BrowserPath.ToLower(); var ProfileDirectory = Path.Combine(Utils.GetUserSettingDirectory(), "UE4_HTML5", "user"); string BrowserCommandline = url; if (LowerBrowserPath.Contains("chrome")) { BrowserCommandline += " " + String.Format("--user-data-dir=\"{0}\" --enable-logging --no-first-run", Path.Combine(ProfileDirectory, "chrome")); } else if (LowerBrowserPath.Contains("firefox")) { BrowserCommandline += " " + String.Format("-no-remote -profile \"{0}\"", Path.Combine(ProfileDirectory, "firefox")); } string LauncherArguments = string.Format(" -Browser=\"{0}\" + -BrowserCommandLine=\"{1}\" -ServerPort=\"{2}\" -ServerRoot=\"{3}\" ", new object[] { BrowserPath, BrowserCommandline, ServerPort, WorkingDirectory }); var LaunchHelperPath = CombinePaths(CmdEnv.LocalRoot, "Engine/Binaries/DotNET/HTML5LaunchHelper.exe"); ProcessResult BrowserProcess = Run(LaunchHelperPath, LauncherArguments, null, ClientRunFlags | ERunOptions.NoWaitForExit); return BrowserProcess; }
private static void RunStandaloneClient(List<DeploymentContext> DeployContextList, string ClientLogFile, ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params) { if (Params.Unattended) { int Timeout = 60 * 30; if (Params.RunAutomationTests) { Timeout = 6 * 60 * 60; } using (var Watchdog = new WatchdogTimer(Timeout)) { string AllClientOutput = ""; ProcessResult ClientProcess = null; FileStream ClientProcessLog = null; StreamReader ClientLogReader = null; Log("Starting Client for unattended test...."); ClientProcess = Run(ClientApp, ClientCmdLine + " -FORCELOGFLUSH", 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); } if (ClientProcess.HasExited || ClientLogReader == null) { throw new AutomationException("Client exited before we asked it to."); } bool bKeepReading = true; bool WelcomedCorrectly = false; while (!ClientProcess.HasExited && bKeepReading) { while (!ClientLogReader.EndOfStream && bKeepReading && !ClientProcess.HasExited) { string ClientOutput = ClientLogReader.ReadToEnd(); if (!String.IsNullOrEmpty(ClientOutput)) { AllClientOutput += ClientOutput; Console.Write(ClientOutput); 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"; } if (AllClientOutput.Contains(LookFor)) { Log("Client loaded, lets wait 30 seconds..."); Thread.Sleep(30000); if (!ClientProcess.HasExited) { WelcomedCorrectly = true; } Log("Test complete..."); bKeepReading = false; } else if (Params.RunAutomationTests) { int FailIndex = AllClientOutput.IndexOf("Automation Test Failed"); int ParenIndex = AllClientOutput.LastIndexOf(")"); if (FailIndex >= 0 && ParenIndex > FailIndex) { 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); } #if true Log("Stopping client..."); ClientProcess.StopProcess(); if (IsBuildMachine) { Thread.Sleep(70000); } #endif throw new AutomationException("Automated test failed ({0}).", Test); } } } } } if (ClientProcess != null && !ClientProcess.HasExited) { Log("Stopping client..."); ClientProcess.StopProcess(); } // this is hack that prevents a hang if (IsBuildMachine) { Thread.Sleep(70000); } 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); } } }