/// <summary> /// Kills all running processes. /// </summary> public static void KillAll() { List <IProcess> ProcessesToKill = new List <IProcess>(); lock (SyncObject) { foreach (var ProcResult in ActiveProcesses) { if (!ProcResult.HasExited) { ProcessesToKill.Add(ProcResult); } } ActiveProcesses.Clear(); } // Remove processes that can't be killed for (int ProcessIndex = ProcessesToKill.Count - 1; ProcessIndex >= 0; --ProcessIndex) { var ProcessName = ProcessesToKill[ProcessIndex].GetProcessName(); if (!String.IsNullOrEmpty(ProcessName) && !CanBeKilled(ProcessName)) { CommandUtils.LogLog("Ignoring process \"{0}\" because it can't be killed.", ProcessName); ProcessesToKill.RemoveAt(ProcessIndex); } } if (ProcessesToKill.Count > 0) { CommandUtils.LogLog("Trying to kill {0} spawned processes.", ProcessesToKill.Count); foreach (var Proc in ProcessesToKill) { CommandUtils.LogLog(" {0}", Proc.GetProcessName()); } if (CommandUtils.IsBuildMachine) { for (int Cnt = 0; Cnt < 9; Cnt++) { bool AllDone = true; foreach (var Proc in ProcessesToKill) { try { if (!Proc.HasExited) { AllDone = false; CommandUtils.LogLog("Waiting for process: {0}", Proc.GetProcessName()); } } catch (Exception) { CommandUtils.LogWarning("Exception Waiting for process"); AllDone = false; } } try { if (ProcessResult.HasAnyDescendants(Process.GetCurrentProcess())) { AllDone = false; CommandUtils.LogInformation("Waiting for descendants of main process..."); } } catch (Exception Ex) { CommandUtils.LogWarning("Exception Waiting for descendants of main process. " + Ex); AllDone = false; } if (AllDone) { break; } Thread.Sleep(10000); } } foreach (var Proc in ProcessesToKill) { var ProcName = Proc.GetProcessName(); try { if (!Proc.HasExited) { CommandUtils.LogLog("Killing process: {0}", ProcName); Proc.StopProcess(false); } } catch (Exception Ex) { CommandUtils.LogWarning("Exception while trying to kill process {0}:", ProcName); CommandUtils.LogWarning(LogUtils.FormatException(Ex)); } } try { if (CommandUtils.IsBuildMachine && ProcessResult.HasAnyDescendants(Process.GetCurrentProcess())) { CommandUtils.LogLog("current process still has descendants, trying to kill them..."); ProcessResult.KillAllDescendants(Process.GetCurrentProcess()); } } catch (Exception) { CommandUtils.LogWarning("Exception killing descendants of main process"); } } }
/// <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); }
/// <summary> /// Runs UAT recursively /// </summary> /// <param name="Env">Environment to use.</param> /// <param name="CommandLine">Commandline to pass on to the executable</param> public static string RunUAT(CommandEnvironment Env, string CommandLine) { // this doesn't do much, but it does need to make sure log folders are reasonable and don't collide string BaseLogSubdir = "Recur"; if (!String.IsNullOrEmpty(CommandLine)) { int Space = CommandLine.IndexOf(" "); if (Space > 0) { BaseLogSubdir = BaseLogSubdir + "_" + CommandLine.Substring(0, Space); } else { BaseLogSubdir = BaseLogSubdir + "_" + CommandLine; } } int Index = 0; BaseLogSubdir = BaseLogSubdir.Trim(); string DirOnlyName = BaseLogSubdir; string LogSubdir = CombinePaths(CmdEnv.LogFolder, DirOnlyName, ""); while (true) { var ExistingFiles = FindFiles(DirOnlyName + "*", false, CmdEnv.LogFolder); if (ExistingFiles.Length == 0) { break; } Index++; if (Index == 1000) { throw new AutomationException("Couldn't seem to create a log subdir {0}", LogSubdir); } DirOnlyName = String.Format("{0}_{1}_", BaseLogSubdir, Index); LogSubdir = CombinePaths(CmdEnv.LogFolder, DirOnlyName, ""); } string LogFile = CombinePaths(CmdEnv.LogFolder, DirOnlyName + ".log"); Log("Recursive UAT Run, in log folder {0}, main log file {1}", LogSubdir, LogFile); CreateDirectory(LogSubdir); string App = CmdEnv.UATExe; Log("Running {0} {1}", App, CommandLine); var OSEnv = new Dictionary <string, string>(); OSEnv.Add(AutomationTool.EnvVarNames.LogFolder, LogSubdir); OSEnv.Add("uebp_UATMutexNoWait", "1"); if (!IsBuildMachine) { OSEnv.Add(AutomationTool.EnvVarNames.LocalRoot, ""); // if we don't clear this out, it will think it is a build machine; it will rederive everything } ProcessResult Result = Run(App, CommandLine, null, ERunOptions.Default, OSEnv); if (Result.Output.Length > 0) { WriteToFile(LogFile, Result.Output); } else { WriteToFile(LogFile, "[None!, no output produced]"); } Log("Flattening log folder {0}", LogSubdir); var Files = FindFiles("*", true, LogSubdir); string MyLogFolder = CombinePaths(CmdEnv.LogFolder, ""); foreach (var ThisFile in Files) { if (!ThisFile.StartsWith(MyLogFolder, StringComparison.InvariantCultureIgnoreCase)) { throw new AutomationException("Can't rebase {0} because it doesn't start with {1}", ThisFile, MyLogFolder); } string NewFilename = ThisFile.Substring(MyLogFolder.Length).Replace("/", "_").Replace("\\", "_"); NewFilename = CombinePaths(CmdEnv.LogFolder, NewFilename); if (FileExists_NoExceptions(NewFilename)) { throw new AutomationException("Destination log file already exists? {0}", NewFilename); } CopyFile(ThisFile, NewFilename); if (!FileExists_NoExceptions(NewFilename)) { throw new AutomationException("Destination log file could not be copied {0}", NewFilename); } DeleteFile_NoExceptions(ThisFile); } DeleteDirectory_NoExceptions(LogSubdir); if (Result != 0) { throw new AutomationException(String.Format("Recursive UAT Command failed (Result:{3}): {0} {1}. See logfile for details: '{2}' ", App, CommandLine, Path.GetFileName(LogFile), Result.ExitCode)); } return(LogFile); }
/// <summary> /// Allow platform specific clean-up or detection after client has run /// </summary> /// <param name="ClientRunFlags"></param> public virtual void PostRunClient(ProcessResult Result, ProjectParams Params) { // do nothing in the default case }