/// <summary> /// Compiles all script modules. /// </summary> /// <param name="Modules">Module project filenames.</param> private static void CompileModules(List <string> Modules) { string DependencyFile = Path.Combine(CommandUtils.CmdEnv.EngineSavedFolder, "UATModuleHashes.xml"); if (AreDependenciesUpToDate(Modules, DependencyFile) && !GlobalCommandLine.IgnoreDependencies) { Log.TraceInformation("Dependencies are up to date. Skipping compile."); return; } Log.TraceInformation("Dependencies are out of date. Compiling scripts...."); // clean old assemblies CleanupScriptsAssemblies(); DateTime StartTime = DateTime.Now; string BuildTool = CommandUtils.CmdEnv.MsBuildExe; // msbuild (standard on windows, in mono >=5.0 is preferred due to speed and parallel compilation) bool UseParallelMsBuild = Path.GetFileNameWithoutExtension(BuildTool).ToLower() == "msbuild"; if (UseParallelMsBuild) { string ModulesList = string.Join(";", Modules); // Mono has an issue where arugments with semicolons or commas can't be passed through to // as arguments so we need to manually construct a temp file with the list of modules // see (https://github.com/Microsoft/msbuild/issues/471) var UATProjTemplate = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, @"Engine\Source\Programs\AutomationTool\Scripts\UAT.proj"); var UATProjFile = Path.Combine(CommandUtils.CmdEnv.EngineSavedFolder, "UATTempProj.proj"); string ProjContents = File.ReadAllText(UATProjTemplate); ProjContents = ProjContents.Replace("$(Modules)", ModulesList); Directory.CreateDirectory(Path.GetDirectoryName(UATProjFile)); File.WriteAllText(UATProjFile, ProjContents); string MsBuildVerbosity = Log.OutputLevel >= LogEventType.Verbose ? "minimal" : "quiet"; var CmdLine = String.Format("\"{0}\" /p:Configuration={1} /verbosity:{2} /nologo", UATProjFile, BuildConfig, MsBuildVerbosity); // suppress the run command because it can be long and intimidating, making the logs around this code harder to read. var Result = CommandUtils.Run(BuildTool, CmdLine, Options: CommandUtils.ERunOptions.Default | CommandUtils.ERunOptions.NoLoggingOfRunCommand | CommandUtils.ERunOptions.LoggingOfRunDuration); if (Result.ExitCode != 0) { throw new AutomationException(String.Format("Failed to build \"{0}\":{1}{2}", UATProjFile, Environment.NewLine, Result.Output)); } } else { // Make sure DefaultScriptsDLLName is compiled first var DefaultScriptsProjName = Path.ChangeExtension(DefaultScriptsDLLName, "csproj"); // Primary modules must be built first List <string> PrimaryModules = Modules.Where(M => M.IndexOf(DefaultScriptsProjName, StringComparison.InvariantCultureIgnoreCase) >= 0).ToList(); foreach (var ModuleName in PrimaryModules) { Log.TraceInformation("Building script module: {0}", ModuleName); try { CompileScriptModule(ModuleName); } catch (Exception Ex) { CommandUtils.LogError(LogUtils.FormatException(Ex)); throw new AutomationException("Failed to compile module {0}", ModuleName); } break; } // Second pass, compile everything else List <string> SecondaryModules = Modules.Where(M => !PrimaryModules.Contains(M)).ToList(); // Non-parallel method foreach (var ModuleName in SecondaryModules) { Log.TraceInformation("Building script module: {0}", ModuleName); try { CompileScriptModule(ModuleName); } catch (Exception Ex) { CommandUtils.LogError(LogUtils.FormatException(Ex)); throw new AutomationException("Failed to compile module {0}", ModuleName); } } } TimeSpan Duration = DateTime.Now - StartTime; Log.TraceInformation("Compiled {0} modules in {1} secs", Modules.Count, Duration.TotalSeconds); HashCollection NewHashes = HashModules(Modules); if (NewHashes == null) { Log.TraceWarning("Failed to save dependency info!"); } else { NewHashes.SaveToFile(DependencyFile); Log.TraceVerbose("Wrote depencencies to {0}", DependencyFile); } }