/// <summary> /// Gets a parameter from the command line if it hasn't been specified in the constructor. /// If the command line is not available, default value will be used. /// </summary> /// <param name="Command">Command to parse the command line for. Can be null.</param> /// <param name="SpecifiedValue">Value specified in the constructor (or not)</param> /// <param name="Default">Default value.</param> /// <param name="ParamNames">Command line parameter names to parse.</param> /// <returns>Parameter value.</returns> bool GetParamValueIfNotSpecified(CommandUtils Command, bool? SpecifiedValue, bool Default, params string[] ParamNames) { if (SpecifiedValue.HasValue) { return SpecifiedValue.Value; } else if (Command != null) { foreach (var Param in ParamNames) { if (Command.ParseParam(Param)) { return true; } } } return Default; }
public override void SetupOptionsForRun(ref string AppName, ref CommandUtils.ERunOptions Options, ref string CommandLine) { if (AppName == "sh" || AppName == "xbuild" || AppName == "codesign") { Options &= ~CommandUtils.ERunOptions.AppMustExist; } if (AppName == "xbuild") { AppName = "xbuild"; CommandLine = (String.IsNullOrEmpty(CommandLine) ? "" : CommandLine) + " /verbosity:quiet /nologo"; // For some reason AutomationScripts.Automation.csproj has ToolsVersion set // to 11.0, which is no available on linux, so force ToolsVersion to 4.0 CommandLine += " /tv:4.0"; // Pass #define MONO to all the automation scripts (see XboxOne) CommandLine += " /p:DefineConstants=MONO"; // Some projects have TargetFrameworkProfile=Client which causes warnings on Linux // so force it to empty. CommandLine += " /p:TargetFrameworkProfile="; } if (AppName.EndsWith(".exe") || ((AppName.Contains("/Binaries/Win64/") || AppName.Contains("/Binaries/Linux/")) && string.IsNullOrEmpty(Path.GetExtension(AppName)))) { if (AppName.Contains("/Binaries/Win64/") || AppName.Contains("/Binaries/Linux/")) { AppName = AppName.Replace("/Binaries/Win64/", "/Binaries/Linux/"); AppName = AppName.Replace("-cmd.exe", ""); AppName = AppName.Replace("-Cmd.exe", ""); AppName = AppName.Replace(".exe", ""); } else { // It's a C# app, so run it with Mono CommandLine = "\"" + AppName + "\" " + (String.IsNullOrEmpty(CommandLine) ? "" : CommandLine); AppName = "mono"; Options &= ~CommandUtils.ERunOptions.AppMustExist; } } }
/// <summary> /// Gets optional parameter from the command line if it hasn't been specified in the constructor. /// If the command line is not available or the command has not been specified in the command line, default value will be used. /// </summary> /// <param name="Command">Command to parse the command line for. Can be null.</param> /// <param name="SpecifiedValue">Value specified in the constructor (or not)</param> /// <param name="Default">Default value.</param> /// <param name="TrueParam">Name of a parameter that sets the value to 'true', for example: -clean</param> /// <param name="FalseParam">Name of a parameter that sets the value to 'false', for example: -noclean</param> /// <returns>Parameter value or default value if the paramater has not been specified</returns> bool? GetOptionalParamValueIfNotSpecified(CommandUtils Command, bool? SpecifiedValue, bool? Default, string TrueParam, string FalseParam) { if (SpecifiedValue.HasValue) { return SpecifiedValue.Value; } else if (Command != null) { bool? Value = null; if (!String.IsNullOrEmpty(TrueParam) && Command.ParseParam(TrueParam)) { Value = true; } else if (!String.IsNullOrEmpty(FalseParam) && Command.ParseParam(FalseParam)) { Value = false; } if (Value.HasValue) { return Value; } } return Default; }
/// <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 virtual bool PublishSymbols(DirectoryReference SymbolStoreDirectory, List <FileReference> Files, string Product, string BuildVersion = null) { CommandUtils.LogWarning("PublishSymbols() has not been implemented for {0}", PlatformType.ToString()); return(false); }
/// <summary> /// Attempts to autodetect project properties. /// </summary> /// <param name="RawProjectPath">Full project path.</param> /// <returns>Project properties.</returns> private static ProjectProperties DetectProjectProperties(FileReference RawProjectPath, List <UnrealTargetPlatform> ClientTargetPlatforms, bool AssetNativizationRequested) { var Properties = new ProjectProperties(); Properties.RawProjectPath = RawProjectPath; // detect if the project is content only, but has non-default build settings List <string> ExtraSearchPaths = null; if (RawProjectPath != null) { if (RequiresTempTarget(RawProjectPath, ClientTargetPlatforms, AssetNativizationRequested)) { GenerateTempTarget(RawProjectPath); Properties.bWasGenerated = true; ExtraSearchPaths = new List <string>(); string TempTargetDir = CommandUtils.CombinePaths(Path.GetDirectoryName(RawProjectPath.FullName), "Intermediate", "Source"); ExtraSearchPaths.Add(TempTargetDir); // in case the RulesCompiler (what we use to find all the // Target.cs files) has already cached the contents of this // directory, then we need to invalidate that cache (so // it'll find/use the new Target.cs file) RulesCompiler.InvalidateRulesFileCache(TempTargetDir); } else if (File.Exists(Path.Combine(Path.GetDirectoryName(RawProjectPath.FullName), "Intermediate", "Source", Path.GetFileNameWithoutExtension(RawProjectPath.FullName) + ".Target.cs"))) { File.Delete(Path.Combine(Path.GetDirectoryName(RawProjectPath.FullName), "Intermediate", "Source", Path.GetFileNameWithoutExtension(RawProjectPath.FullName) + ".Target.cs")); } } if (CommandUtils.CmdEnv.HasCapabilityToCompile) { DetectTargetsForProject(Properties, ExtraSearchPaths); Properties.bIsCodeBasedProject = !CommandUtils.IsNullOrEmpty(Properties.Targets) || !CommandUtils.IsNullOrEmpty(Properties.Programs); } else { // should never ask for engine targets if we can't compile if (RawProjectPath == null) { throw new AutomationException("Cannot determine engine targets if we can't compile."); } Properties.bIsCodeBasedProject = Properties.bWasGenerated; // if there's a Source directory with source code in it, then mark us as having source code string SourceDir = CommandUtils.CombinePaths(Path.GetDirectoryName(RawProjectPath.FullName), "Source"); if (Directory.Exists(SourceDir)) { string[] CppFiles = Directory.GetFiles(SourceDir, "*.cpp", SearchOption.AllDirectories); string[] HFiles = Directory.GetFiles(SourceDir, "*.h", SearchOption.AllDirectories); Properties.bIsCodeBasedProject |= (CppFiles.Length > 0 || HFiles.Length > 0); } } // check to see if the uproject loads modules, only if we haven't already determined it is a code based project if (!Properties.bIsCodeBasedProject && RawProjectPath != null) { string uprojectStr = File.ReadAllText(RawProjectPath.FullName); Properties.bIsCodeBasedProject = uprojectStr.Contains("\"Modules\""); } // Get all ini files if (RawProjectPath != null) { CommandUtils.LogVerbose("Loading ini files for {0}", RawProjectPath); var EngineDirectory = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine"); foreach (UnrealTargetPlatform TargetPlatformType in Enum.GetValues(typeof(UnrealTargetPlatform))) { if (TargetPlatformType != UnrealTargetPlatform.Unknown) { var Config = ConfigCacheIni.CreateConfigCacheIni(TargetPlatformType, "Engine", RawProjectPath.Directory, new DirectoryReference(EngineDirectory)); Properties.EngineConfigs.Add(TargetPlatformType, Config); } } foreach (UnrealTargetPlatform TargetPlatformType in Enum.GetValues(typeof(UnrealTargetPlatform))) { if (TargetPlatformType != UnrealTargetPlatform.Unknown) { var Config = ConfigCacheIni.CreateConfigCacheIni(TargetPlatformType, "Game", RawProjectPath.Directory); Properties.GameConfigs.Add(TargetPlatformType, Config); } } } return(Properties); }
private void SetLocalRootPath() { var LocalRootPath = CommandUtils.ConvertSeparators(PathSeparator.Slash, RootFromUATLocation(UATExe)); CommandUtils.ConditionallySetEnvVar(EnvVarNames.LocalRoot, LocalRootPath); }
/// <summary> /// Constructor. Be sure to use this.ParamName to set the actual property name as parameter names and property names /// overlap here. /// If a parameter value is not set, it will be parsed from the command line if the command is null, the default value will be used. /// </summary> public ProjectParams( string RawProjectPath, CommandUtils Command = null, string Device = null, string MapToRun = null, string Port = null, string RunCommandline = null, string StageCommandline = null, string BundleName = null, string StageDirectoryParam = null, string UE4Exe = null, string SignPak = null, List<UnrealTargetConfiguration> ClientConfigsToBuild = null, List<UnrealTargetConfiguration> ServerConfigsToBuild = null, ParamList<string> MapsToCook = null, ParamList<string> DirectoriesToCook = null, ParamList<string> ClientCookedTargets = null, ParamList<string> EditorTargets = null, ParamList<string> ServerCookedTargets = null, List<UnrealTargetPlatform> ClientTargetPlatforms = null, List<UnrealTargetPlatform> ServerTargetPlatforms = null, bool? Build = null, bool? Cook = null, string CookFlavor = null, bool? Run = null, bool? SkipServer = null, bool? Clean = null, bool? Compressed = null, bool? UseDebugParamForEditorExe = null, bool? IterativeCooking = null, bool? CookOnTheFly = null, bool? CrashReporter = null, bool? DedicatedServer = null, bool? Client = null, bool? Deploy = null, bool? FileServer = null, bool? Foreign = null, bool? ForeignCode = null, bool? LogWindow = null, bool? NoCleanStage = null, bool? NoClient = null, bool? NoDebugInfo = null, bool? NoXGE = null, bool? Package = null, bool? Pak = null, bool? SignedPak = null, bool? NullRHI = null, bool? FakeClient = null, bool? EditorTest = null, bool? RunAutomationTests = null, string RunAutomationTest = null, int? CrashIndex = null, bool? Rocket = null, bool? SkipCook = null, bool? SkipCookOnTheFly = null, bool? SkipPak = null, bool? SkipStage = null, bool? Stage = null, bool? Manifests = null, bool? Unattended = null, int? NumClients = null, bool? Archive = null, string ArchiveDirectoryParam = null, ParamList<string> ProgramTargets = null, bool? Distribution = null ) { // //// Use this.Name with properties and fields! // this.RawProjectPath = RawProjectPath; if (MapsToCook != null) { this.MapsToCook = MapsToCook; } if (DirectoriesToCook != null) { this.DirectoriesToCook = DirectoriesToCook; } if (ClientCookedTargets != null) { this.ClientCookedTargets = ClientCookedTargets; } if (ServerCookedTargets != null) { this.ServerCookedTargets = ServerCookedTargets; } if (EditorTargets != null) { this.EditorTargets = EditorTargets; } if (ProgramTargets != null) { this.ProgramTargets = ProgramTargets; } // Parse command line params for client platforms "-TargetPlatform=", "-Platform=" and also "-Win64", "-Mac" etc. this.ClientTargetPlatforms = SetupTargetPlatforms(Command, ClientTargetPlatforms, new ParamList<UnrealTargetPlatform>() {UnrealTargetPlatform.Win64}, true, "TargetPlatform", "Platform"); // Parse command line params for server paltforms "-ServerTargetPlatform", "-ServerPlatform"; "-Win64" etc is not allowed here this.ServerTargetPlatforms = SetupTargetPlatforms(Command, ServerTargetPlatforms, this.ClientTargetPlatforms, false, "ServerTargetPlatform", "ServerPlatform"); this.Build = GetParamValueIfNotSpecified(Command, Build, this.Build, "build"); this.Run = GetParamValueIfNotSpecified(Command, Run, this.Run, "run"); this.Cook = GetParamValueIfNotSpecified(Command, Cook, this.Cook, "cook"); this.CookFlavor = ParseParamValueIfNotSpecified(Command, CookFlavor, "cookflavor", String.Empty); this.SkipCook = GetParamValueIfNotSpecified(Command, SkipCook, this.SkipCook, "skipcook"); if (this.SkipCook) { this.Cook = true; } this.Clean = GetOptionalParamValueIfNotSpecified(Command, Clean, this.Clean, "clean", null); this.SignPak = ParseParamValueIfNotSpecified(Command, SignPak, "signpak", String.Empty); this.SignedPak = !String.IsNullOrEmpty(this.SignPak) || GetParamValueIfNotSpecified(Command, SignedPak, this.SignedPak, "signedpak"); this.Pak = this.SignedPak || GetParamValueIfNotSpecified(Command, Pak, this.Pak, "pak"); this.SkipPak = GetParamValueIfNotSpecified(Command, SkipPak, this.SkipPak, "skippak"); if (this.SkipPak) { this.Pak = true; } this.NoXGE = GetParamValueIfNotSpecified(Command, NoXGE, this.NoXGE, "noxge"); this.CookOnTheFly = GetParamValueIfNotSpecified(Command, CookOnTheFly, this.CookOnTheFly, "cookonthefly"); this.Compressed = GetParamValueIfNotSpecified(Command, Compressed, this.Compressed, "compressed"); this.UseDebugParamForEditorExe = GetParamValueIfNotSpecified(Command, UseDebugParamForEditorExe, this.UseDebugParamForEditorExe, "UseDebugParamForEditorExe"); this.IterativeCooking = GetParamValueIfNotSpecified(Command, IterativeCooking, this.IterativeCooking, "iterativecooking", "iterate"); this.SkipCookOnTheFly = GetParamValueIfNotSpecified(Command, SkipCookOnTheFly, this.SkipCookOnTheFly, "skipcookonthefly"); this.FileServer = GetParamValueIfNotSpecified(Command, FileServer, this.FileServer, "fileserver"); this.DedicatedServer = GetParamValueIfNotSpecified(Command, DedicatedServer, this.DedicatedServer, "dedicatedserver", "server"); this.Client = GetParamValueIfNotSpecified(Command, Client, this.Client, "client"); if( this.Client ) { this.DedicatedServer = true; } this.NoClient = GetParamValueIfNotSpecified(Command, NoClient, this.NoClient, "noclient"); this.LogWindow = GetParamValueIfNotSpecified(Command, LogWindow, this.LogWindow, "logwindow"); this.Stage = GetParamValueIfNotSpecified(Command, Stage, this.Stage, "stage"); this.SkipStage = GetParamValueIfNotSpecified(Command, SkipStage, this.SkipStage, "skipstage"); if (this.SkipStage) { this.Stage = true; } this.StageDirectoryParam = ParseParamValueIfNotSpecified(Command, StageDirectoryParam, "stagingdirectory", String.Empty).Trim(new char[]{'\"'}); this.Manifests = GetParamValueIfNotSpecified(Command, Manifests, this.Manifests, "manifests"); this.Archive = GetParamValueIfNotSpecified(Command, Archive, this.Archive, "archive"); this.ArchiveDirectoryParam = ParseParamValueIfNotSpecified(Command, ArchiveDirectoryParam, "archivedirectory", String.Empty); this.Distribution = GetParamValueIfNotSpecified(Command, Distribution, this.Distribution, "distribution"); this.NoDebugInfo = GetParamValueIfNotSpecified(Command, NoDebugInfo, this.NoDebugInfo, "nodebuginfo"); this.NoCleanStage = GetParamValueIfNotSpecified(Command, NoCleanStage, this.NoCleanStage, "nocleanstage"); this.MapToRun = ParseParamValueIfNotSpecified(Command, MapToRun, "map", String.Empty); this.Foreign = GetParamValueIfNotSpecified(Command, Foreign, this.Foreign, "foreign"); this.ForeignCode = GetParamValueIfNotSpecified(Command, ForeignCode, this.ForeignCode, "foreigncode"); this.StageCommandline = ParseParamValueIfNotSpecified(Command, StageCommandline, "cmdline"); this.BundleName = ParseParamValueIfNotSpecified(Command, BundleName, "bundlename"); this.RunCommandline = ParseParamValueIfNotSpecified(Command, RunCommandline, "addcmdline"); this.Package = GetParamValueIfNotSpecified(Command, Package, this.Package, "package"); this.Deploy = GetParamValueIfNotSpecified(Command, Deploy, this.Deploy, "deploy"); this.Device = ParseParamValueIfNotSpecified(Command, Device, "device", String.Empty).Trim(new char[]{'\"'}); this.ServerDevice = ParseParamValueIfNotSpecified(Command, ServerDevice, "serverdevice", this.Device); this.Port = ParseParamValueIfNotSpecified(Command, Port, "port", String.Empty); this.NullRHI = GetParamValueIfNotSpecified(Command, NullRHI, this.NullRHI, "nullrhi"); this.FakeClient = GetParamValueIfNotSpecified(Command, FakeClient, this.FakeClient, "fakeclient"); this.EditorTest = GetParamValueIfNotSpecified(Command, EditorTest, this.EditorTest, "editortest"); this.RunAutomationTest = ParseParamValueIfNotSpecified(Command, RunAutomationTest, "RunAutomationTest"); this.RunAutomationTests = this.RunAutomationTest != "" || GetParamValueIfNotSpecified(Command, RunAutomationTests, this.RunAutomationTests, "RunAutomationTests"); this.SkipServer = GetParamValueIfNotSpecified(Command, SkipServer, this.SkipServer, "skipserver"); this.Rocket = GetParamValueIfNotSpecified(Command, Rocket, this.Rocket || GlobalCommandLine.Rocket, "rocket"); this.UE4Exe = ParseParamValueIfNotSpecified(Command, UE4Exe, "ue4exe", "UE4Editor-Cmd.exe"); this.Unattended = GetParamValueIfNotSpecified(Command, Unattended, this.Unattended, "unattended"); this.DeviceUsername = ParseParamValueIfNotSpecified(Command, DeviceUsername, "deviceuser", String.Empty); this.DevicePassword = ParseParamValueIfNotSpecified(Command, DevicePassword, "devicepass", String.Empty); this.CrashReporter = GetParamValueIfNotSpecified(Command, CrashReporter, this.CrashReporter, "crashreporter"); if (ClientConfigsToBuild == null) { if (Command != null) { var ClientConfig = Command.ParseParamValue("clientconfig"); if (ClientConfig != null) { this.ClientConfigsToBuild = new List<UnrealTargetConfiguration>(); var Configs = new ParamList<string>(ClientConfig.Split('+')); foreach (var ConfigName in Configs) { this.ClientConfigsToBuild.Add((UnrealTargetConfiguration)Enum.Parse(typeof(UnrealTargetConfiguration), ConfigName, true)); } } } } else { this.ClientConfigsToBuild = ClientConfigsToBuild; } if (ServerConfigsToBuild == null) { if (Command != null) { var ServerConfig = Command.ParseParamValue("serverconfig"); if (ServerConfig != null && ServerConfigsToBuild == null) { this.ServerConfigsToBuild = new List<UnrealTargetConfiguration>(); var Configs = new ParamList<string>(ServerConfig.Split('+')); foreach (var ConfigName in Configs) { this.ServerConfigsToBuild.Add((UnrealTargetConfiguration)Enum.Parse(typeof(UnrealTargetConfiguration), ConfigName, true)); } } } } else { this.ServerConfigsToBuild = ServerConfigsToBuild; } if (NumClients.HasValue) { this.NumClients = NumClients.Value; } else if (Command != null) { this.NumClients = Command.ParseParamInt("numclients"); } if (CrashIndex.HasValue) { this.CrashIndex = CrashIndex.Value; } else if (Command != null) { this.CrashIndex = Command.ParseParamInt("CrashIndex"); } AutodetectSettings(false); ValidateAndLog(); }
public override void SetupOptionsForRun(ref string AppName, ref CommandUtils.ERunOptions Options, ref string CommandLine) { if (AppName == "sh" || AppName == "xbuild" || AppName == "codesign") { Options &= ~CommandUtils.ERunOptions.AppMustExist; } if (AppName == "xbuild") { AppName = "sh"; CommandLine = "-c 'xbuild " + (String.IsNullOrEmpty(CommandLine) ? "" : CommandLine) + " /p:DefineConstants=MONO /verbosity:quiet /nologo |grep -i error; if [ $? -ne 1 ]; then exit 1; else exit 0; fi'"; } if (AppName.EndsWith(".exe") || ((AppName.Contains("/Binaries/Win64/") || AppName.Contains("/Binaries/Mac/")) && string.IsNullOrEmpty(Path.GetExtension(AppName)))) { if (AppName.Contains("/Binaries/Win64/") || AppName.Contains("/Binaries/Mac/")) { AppName = AppName.Replace("/Binaries/Win64/", "/Binaries/Mac/"); AppName = AppName.Replace("-cmd.exe", ""); AppName = AppName.Replace("-Cmd.exe", ""); AppName = AppName.Replace(".exe", ""); string AppFilename = Path.GetFileName(AppName); if (!CommandUtils.FileExists(AppName)) { AppName = AppName + ".app/Contents/MacOS/" + AppFilename; } } else { // It's a C# app, so run it with Mono CommandLine = "\"" + AppName + "\" " + (String.IsNullOrEmpty(CommandLine) ? "" : CommandLine); AppName = "mono"; Options &= ~CommandUtils.ERunOptions.AppMustExist; } } }
public static int Main(string[] Arguments) { // Ensure UTF8Output flag is respected, since we are initializing logging early in the program. if (CommandUtils.ParseParam(Arguments, "-Utf8output")) { Console.OutputEncoding = new System.Text.UTF8Encoding(false, false); } // Parse the log level argument if (CommandUtils.ParseParam(Arguments, "-Verbose")) { Log.OutputLevel = LogEventType.Verbose; } if (CommandUtils.ParseParam(Arguments, "-VeryVerbose")) { Log.OutputLevel = LogEventType.VeryVerbose; } // Initialize the log system, buffering the output until we can create the log file StartupTraceListener StartupListener = new StartupTraceListener(); Trace.Listeners.Add(StartupListener); // Configure log timestamps Log.IncludeTimestamps = CommandUtils.ParseParam(Arguments, "-Timestamps"); // Enter the main program section ExitCode ReturnCode = ExitCode.Success; try { // Set the working directory to the UE4 root Environment.CurrentDirectory = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetOriginalLocation()), "..", "..", "..")); // Ensure we can resolve any external assemblies as necessary. string PathToBinariesDotNET = Path.GetDirectoryName(Assembly.GetEntryAssembly().GetOriginalLocation()); AssemblyUtils.InstallAssemblyResolver(PathToBinariesDotNET); AssemblyUtils.InstallRecursiveAssemblyResolver(PathToBinariesDotNET); // Initialize the host platform layer HostPlatform.Initialize(); // Log the operating environment. Since we usually compile to AnyCPU, we may be executed using different system paths under WOW64. Log.TraceVerbose("{2}: Running on {0} as a {1}-bit process.", HostPlatform.Current.GetType().Name, Environment.Is64BitProcess ? 64 : 32, DateTime.UtcNow.ToString("o")); // Log if we're running from the launcher string ExecutingAssemblyLocation = Assembly.GetExecutingAssembly().Location; if (string.Compare(ExecutingAssemblyLocation, Assembly.GetEntryAssembly().GetOriginalLocation(), StringComparison.OrdinalIgnoreCase) != 0) { Log.TraceVerbose("Executed from AutomationToolLauncher ({0})", ExecutingAssemblyLocation); } Log.TraceVerbose("CWD={0}", Environment.CurrentDirectory); // Hook up exit callbacks AppDomain Domain = AppDomain.CurrentDomain; Domain.ProcessExit += Domain_ProcessExit; Domain.DomainUnload += Domain_ProcessExit; HostPlatform.Current.SetConsoleCtrlHandler(CtrlHandlerDelegateInstance); // Log the application version FileVersionInfo Version = AssemblyUtils.ExecutableVersion; Log.TraceVerbose("{0} ver. {1}", Version.ProductName, Version.ProductVersion); // Don't allow simultaneous execution of AT (in the same branch) ReturnCode = InternalUtils.RunSingleInstance(() => MainProc(Arguments, StartupListener)); } catch (AutomationException Ex) { // Output the message in the desired format if (Ex.OutputFormat == AutomationExceptionOutputFormat.Silent) { Log.TraceLog("{0}", ExceptionUtils.FormatExceptionDetails(Ex)); } else if (Ex.OutputFormat == AutomationExceptionOutputFormat.Minimal) { Log.TraceInformation("{0}", Ex.ToString().Replace("\n", "\n ")); Log.TraceLog("{0}", ExceptionUtils.FormatExceptionDetails(Ex)); } else { Log.WriteException(Ex, LogUtils.FinalLogFileName); } // Take the exit code from the exception ReturnCode = Ex.ErrorCode; } catch (Exception Ex) { // Use a default exit code Log.WriteException(Ex, LogUtils.FinalLogFileName); ReturnCode = ExitCode.Error_Unknown; } finally { // In all cases, do necessary shut down stuff, but don't let any additional exceptions leak out while trying to shut down. // Make sure there's no directories on the stack. NoThrow(() => CommandUtils.ClearDirStack(), "Clear Dir Stack"); // Try to kill process before app domain exits to leave the other KillAll call to extreme edge cases NoThrow(() => { if (ShouldKillProcesses && !Utils.IsRunningOnMono) { ProcessManager.KillAll(); } }, "Kill All Processes"); // Write the exit code Log.TraceInformation("AutomationTool exiting with ExitCode={0} ({1})", (int)ReturnCode, ReturnCode); // Can't use NoThrow here because the code logs exceptions. We're shutting down logging! Trace.Close(); } return((int)ReturnCode); }
/// <summary> /// Print the contents of the graph /// </summary> /// <param name="NodeToState">Mapping of node to its current state</param> /// <param name="Options">Options for how to print the graph</param> public void Print(HashSet <Node> CompletedNodes, GraphPrintOptions Options) { // Get a list of all the triggers, including the null global one List <ManualTrigger> AllTriggers = new List <ManualTrigger>(); AllTriggers.Add(null); AllTriggers.AddRange(NameToTrigger.Values.OrderBy(x => x.QualifiedName)); // Output all the triggers in order CommandUtils.Log(""); CommandUtils.Log("Graph:"); foreach (ManualTrigger Trigger in AllTriggers) { // Filter everything by this trigger Dictionary <AgentGroup, Node[]> FilteredGroupToNodes = new Dictionary <AgentGroup, Node[]>(); foreach (AgentGroup Group in Groups) { Node[] Nodes = Group.Nodes.Where(x => x.ControllingTrigger == Trigger).ToArray(); if (Nodes.Length > 0) { FilteredGroupToNodes[Group] = Nodes; } } // Skip this trigger if there's nothing to display if (FilteredGroupToNodes.Count == 0) { continue; } // Print the trigger name CommandUtils.Log(" Trigger: {0}", (Trigger == null)? "None" : Trigger.QualifiedName); if (Trigger != null && Options.HasFlag(GraphPrintOptions.ShowNotifications)) { foreach (string User in Trigger.NotifyUsers) { CommandUtils.Log(" notify> {0}", User); } } // Output all the groups for this trigger foreach (AgentGroup Group in Groups) { Node[] Nodes; if (FilteredGroupToNodes.TryGetValue(Group, out Nodes)) { CommandUtils.Log(" Group: {0} ({1})", Group.Name, String.Join(";", Group.PossibleTypes)); foreach (Node Node in Nodes) { CommandUtils.Log(" Node: {0}{1}", Node.Name, CompletedNodes.Contains(Node)? " (completed)" : ""); if (Options.HasFlag(GraphPrintOptions.ShowDependencies)) { HashSet <Node> InputDependencies = new HashSet <Node>(Node.GetDirectInputDependencies()); foreach (Node InputDependency in InputDependencies) { CommandUtils.Log(" input> {0}", InputDependency.Name); } HashSet <Node> OrderDependencies = new HashSet <Node>(Node.GetDirectOrderDependencies()); foreach (Node OrderDependency in OrderDependencies.Except(InputDependencies)) { CommandUtils.Log(" after> {0}", OrderDependency.Name); } } if (Options.HasFlag(GraphPrintOptions.ShowNotifications)) { string Label = Node.bNotifyOnWarnings? "warnings" : "errors"; foreach (string User in Node.NotifyUsers) { CommandUtils.Log(" {0}> {1}", Label, User); } foreach (string Submitter in Node.NotifySubmitters) { CommandUtils.Log(" {0}> submitters to {1}", Label, Submitter); } } } } } } CommandUtils.Log(""); // Print out all the aggregates string[] AggregateNames = AggregateNameToNodes.Keys.OrderBy(x => x).ToArray(); if (AggregateNames.Length > 0) { CommandUtils.Log("Aggregates:"); foreach (string AggregateName in AggregateNames) { CommandUtils.Log(" {0}", AggregateName); } CommandUtils.Log(""); } }
/// <summary> /// Entry point for the commandlet /// </summary> public override void ExecuteBuild() { string OutputDir = ParseParamValue("OutputDir"); string ContentOnlyPlatformsString = ParseParamValue("ContentOnlyPlatforms"); IEnumerable <UnrealTargetPlatform> ContentOnlyPlatforms = Enumerable.Empty <UnrealTargetPlatform>(); if (!String.IsNullOrWhiteSpace(ContentOnlyPlatformsString)) { ContentOnlyPlatforms = ContentOnlyPlatformsString.Split(';').Where(x => !String.IsNullOrWhiteSpace(x)).Select(x => (UnrealTargetPlatform)Enum.Parse(typeof(UnrealTargetPlatform), x)); } string AnalyticsTypeOverride = ParseParamValue("AnalyticsTypeOverride"); // Write InstalledBuild.txt to indicate Engine is installed string InstalledBuildFile = CommandUtils.CombinePaths(OutputDir, "Engine/Build/InstalledBuild.txt"); CommandUtils.CreateDirectory(CommandUtils.GetDirectoryName(InstalledBuildFile)); CommandUtils.WriteAllText(InstalledBuildFile, ""); string OutputEnginePath = Path.Combine(OutputDir, "Engine"); string OutputBaseEnginePath = Path.Combine(OutputEnginePath, "Config", "BaseEngine.ini"); FileAttributes OutputAttributes = FileAttributes.ReadOnly; List <String> IniLines = new List <String>(); // Should always exist but if not, we don't need extra line if (File.Exists(OutputBaseEnginePath)) { OutputAttributes = File.GetAttributes(OutputBaseEnginePath); IniLines.Add(""); } else { CommandUtils.CreateDirectory(CommandUtils.GetDirectoryName(OutputBaseEnginePath)); CommandUtils.WriteAllText(OutputBaseEnginePath, ""); OutputAttributes = File.GetAttributes(OutputBaseEnginePath) | OutputAttributes; } // Create list of platform configurations installed in a Rocket build List <InstalledPlatformInfo.InstalledPlatformConfiguration> InstalledConfigs = new List <InstalledPlatformInfo.InstalledPlatformConfiguration>(); foreach (UnrealTargetPlatform CodeTargetPlatform in Enum.GetValues(typeof(UnrealTargetPlatform))) { UEBuildPlatform BuildPlatform = UEBuildPlatform.GetBuildPlatform(CodeTargetPlatform, true); if (BuildPlatform != null) { string Architecture = BuildPlatform.CreateContext(null).GetActiveArchitecture(); // Try to parse additional Architectures from the command line string Architectures = ParseParamValue(CodeTargetPlatform.ToString() + "Architectures"); string GPUArchitectures = ParseParamValue(CodeTargetPlatform.ToString() + "GPUArchitectures"); // Build a list of pre-compiled architecture combinations for this platform if any List <string> AllArchNames; if (!String.IsNullOrWhiteSpace(Architectures) && !String.IsNullOrWhiteSpace(GPUArchitectures)) { AllArchNames = (from Arch in Architectures.Split('+') from GPUArch in GPUArchitectures.Split('+') select "-" + Arch + "-" + GPUArch).ToList(); } else if (!String.IsNullOrWhiteSpace(Architectures)) { AllArchNames = Architectures.Split('+').ToList(); } else { AllArchNames = new List <string>(); } // Check whether this platform should only be used for content based projects EProjectType ProjectType = ContentOnlyPlatforms.Contains(CodeTargetPlatform) ? EProjectType.Content : EProjectType.Any; // Allow Content only platforms to be shown as options in all projects bool bCanBeDisplayed = ProjectType == EProjectType.Content; foreach (UnrealTargetConfiguration CodeTargetConfiguration in Enum.GetValues(typeof(UnrealTargetConfiguration))) { // Need to check for development receipt as we use that for the Engine code in DebugGame UnrealTargetConfiguration EngineConfiguration = (CodeTargetConfiguration == UnrealTargetConfiguration.DebugGame) ? UnrealTargetConfiguration.Development : CodeTargetConfiguration; string ReceiptFileName = TargetReceipt.GetDefaultPath(OutputEnginePath, "UE4Game", CodeTargetPlatform, EngineConfiguration, Architecture); if (File.Exists(ReceiptFileName)) { // Strip the output folder so that this can be used on any machine ReceiptFileName = new FileReference(ReceiptFileName).MakeRelativeTo(new DirectoryReference(OutputDir)); // If we have pre-compiled architectures for this platform then add an entry for each of these - // there isn't a receipt for each architecture like some other platforms if (AllArchNames.Count > 0) { foreach (string Arch in AllArchNames) { InstalledConfigs.Add(new InstalledPlatformInfo.InstalledPlatformConfiguration(CodeTargetConfiguration, CodeTargetPlatform, TargetRules.TargetType.Game, Arch, ReceiptFileName, ProjectType, bCanBeDisplayed)); } } else { InstalledConfigs.Add(new InstalledPlatformInfo.InstalledPlatformConfiguration(CodeTargetConfiguration, CodeTargetPlatform, TargetRules.TargetType.Game, Architecture, ReceiptFileName, ProjectType, bCanBeDisplayed)); } } } } } UnrealBuildTool.InstalledPlatformInfo.WriteConfigFileEntries(InstalledConfigs, ref IniLines); if (!String.IsNullOrEmpty(AnalyticsTypeOverride)) { // Write Custom Analytics type setting IniLines.Add(""); IniLines.Add("[Analytics]"); IniLines.Add(String.Format("UE4TypeOverride=\"{0}\"", AnalyticsTypeOverride)); } // Make sure we can write to the the config file File.SetAttributes(OutputBaseEnginePath, OutputAttributes & ~FileAttributes.ReadOnly); File.AppendAllLines(OutputBaseEnginePath, IniLines); File.SetAttributes(OutputBaseEnginePath, OutputAttributes); }
public override void ExecuteBuild() { // Parse the target list string[] Targets = ParseParamValues("Target"); if (Targets.Length == 0) { throw new AutomationException("No targets specified (eg. -Target=\"UE4Editor Win64 Development\")"); } // Parse the archive path string ArchivePath = ParseParamValue("Archive"); if (ArchivePath != null && (!ArchivePath.StartsWith("//") || ArchivePath.Sum(x => (x == '/')? 1 : 0) < 4)) { throw new AutomationException("Archive path is not a valid depot filename"); } // Prepare the build agenda UE4Build.BuildAgenda Agenda = new UE4Build.BuildAgenda(); foreach (string Target in Targets) { string[] Tokens = Target.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); UnrealTargetPlatform Platform; UnrealTargetConfiguration Configuration; if (Tokens.Length < 3 || !Enum.TryParse(Tokens[1], true, out Platform) || !Enum.TryParse(Tokens[2], true, out Configuration)) { throw new AutomationException("Invalid target '{0}' - expected <TargetName> <Platform> <Configuration>"); } Agenda.AddTarget(Tokens[0], Platform, Configuration, InAddArgs: String.Join(" ", Tokens.Skip(3))); } // Build everything UE4Build Builder = new UE4Build(this); Builder.Build(Agenda, InUpdateVersionFiles: ArchivePath != null); // Include the build products for UAT and UBT if required if (ParseParam("WithUAT")) { Builder.AddUATFilesToBuildProducts(); } if (ParseParam("WithUBT")) { Builder.AddUBTFilesToBuildProducts(); } // Archive the build products if (ArchivePath != null) { // Create an output folder string OutputFolder = Path.Combine(CommandUtils.CmdEnv.LocalRoot, "ArchiveForUGS"); Directory.CreateDirectory(OutputFolder); // Create a temp folder for storing stripped PDB files string SymbolsFolder = Path.Combine(OutputFolder, "Symbols"); Directory.CreateDirectory(SymbolsFolder); // Get the Windows toolchain Platform WindowsTargetPlatform = Platform.GetPlatform(UnrealTargetPlatform.Win64); // Figure out all the files for the archive string ZipFileName = Path.Combine(OutputFolder, "Archive.zip"); using (Ionic.Zip.ZipFile Zip = new Ionic.Zip.ZipFile()) { Zip.UseZip64WhenSaving = Ionic.Zip.Zip64Option.Always; foreach (string BuildProduct in Builder.BuildProductFiles) { if (!File.Exists(BuildProduct)) { throw new AutomationException("Missing build product: {0}", BuildProduct); } if (BuildProduct.EndsWith(".pdb", StringComparison.InvariantCultureIgnoreCase)) { string StrippedFileName = CommandUtils.MakeRerootedFilePath(BuildProduct, CommandUtils.CmdEnv.LocalRoot, SymbolsFolder); Directory.CreateDirectory(Path.GetDirectoryName(StrippedFileName)); WindowsTargetPlatform.StripSymbols(new FileReference(BuildProduct), new FileReference(StrippedFileName)); Zip.AddFile(StrippedFileName, Path.GetDirectoryName(CommandUtils.StripBaseDirectory(StrippedFileName, SymbolsFolder))); } else { Zip.AddFile(BuildProduct, Path.GetDirectoryName(CommandUtils.StripBaseDirectory(BuildProduct, CommandUtils.CmdEnv.LocalRoot))); } } // Create the zip file Console.WriteLine("Writing {0}...", ZipFileName); Zip.Save(ZipFileName); } // Submit it to Perforce if required if (CommandUtils.AllowSubmit) { // Delete any existing clientspec for submitting string ClientName = Environment.MachineName + "_BuildForUGS"; // Create a brand new one P4ClientInfo Client = new P4ClientInfo(); Client.Owner = CommandUtils.P4Env.User; Client.Host = Environment.MachineName; Client.Stream = ArchivePath.Substring(0, ArchivePath.IndexOf('/', ArchivePath.IndexOf('/', 2) + 1)); Client.RootPath = Path.Combine(OutputFolder, "Perforce"); Client.Name = ClientName; Client.Options = P4ClientOption.NoAllWrite | P4ClientOption.NoClobber | P4ClientOption.NoCompress | P4ClientOption.Unlocked | P4ClientOption.NoModTime | P4ClientOption.RmDir; Client.LineEnd = P4LineEnd.Local; P4.CreateClient(Client, AllowSpew: false); // Create a new P4 connection for this workspace P4Connection SubmitP4 = new P4Connection(Client.Owner, Client.Name, P4Env.P4Port); SubmitP4.Revert("-k //..."); // Figure out where the zip file has to go in Perforce P4WhereRecord WhereZipFile = SubmitP4.Where(ArchivePath, false).FirstOrDefault(x => !x.bUnmap && x.Path != null); if (WhereZipFile == null) { throw new AutomationException("Couldn't locate {0} in this workspace"); } // Get the latest version of it int NewCL = SubmitP4.CreateChange(Description: String.Format("[CL {0}] Updated binaries", P4Env.Changelist)); SubmitP4.Sync(String.Format("-k \"{0}\"", ArchivePath), AllowSpew: false); CommandUtils.CopyFile(ZipFileName, WhereZipFile.Path); SubmitP4.Add(NewCL, String.Format("\"{0}\"", ArchivePath)); SubmitP4.Edit(NewCL, String.Format("\"{0}\"", ArchivePath)); // Submit it int SubmittedCL; SubmitP4.Submit(NewCL, out SubmittedCL); if (SubmittedCL <= 0) { throw new AutomationException("Submit failed."); } Console.WriteLine("Submitted in changelist {0}", SubmittedCL); } } }
public override void ExecuteBuild() { string RootDirParam = ParseParamValue("RootDir", null); if (RootDirParam == null) { throw new AutomationException("Missing -BaseDir=... parameter"); } string CreatedBy = ParseParamValue("CreatedBy", null); string CreatedByUrl = ParseParamValue("CreatedByUrl", null); bool bForce = ParseParam("Force"); foreach (FileReference PluginFile in DirectoryReference.EnumerateFiles(new DirectoryReference(RootDirParam), "*.uplugin", System.IO.SearchOption.AllDirectories)) { LogInformation("Reading {0}", PluginFile); string InputText = File.ReadAllText(PluginFile.FullName); // Parse the descriptor PluginDescriptor Descriptor; try { Descriptor = new PluginDescriptor(JsonObject.Parse(InputText)); } catch (JsonParseException Ex) { LogError("Unable to parse {0}: {1}", PluginFile, Ex.ToString()); continue; } // Update the fields if (CreatedBy != null && Descriptor.CreatedBy != CreatedBy) { LogInformation(" Updating 'CreatedBy' field from '{0}' to '{1}'", Descriptor.CreatedBy ?? "<empty>", CreatedBy); Descriptor.CreatedBy = CreatedBy; } if (CreatedByUrl != null) { LogInformation(" Updating 'CreatedByURL' field from '{0}' to '{1}'", Descriptor.CreatedByURL ?? "<empty>", CreatedByUrl); Descriptor.CreatedByURL = CreatedByUrl; } // Format the output text StringBuilder Output = new StringBuilder(); using (JsonWriter Writer = new JsonWriter(new StringWriter(Output))) { Writer.WriteObjectStart(); Descriptor.Write(Writer); Writer.WriteObjectEnd(); } // Compare the output and input; write it if it differs string OutputText = Output.ToString(); if (InputText != OutputText) { if (CommandUtils.IsReadOnly(PluginFile.FullName)) { if (!bForce) { LogWarning("File is read only; skipping write."); continue; } CommandUtils.SetFileAttributes(PluginFile.FullName, ReadOnly: false); } LogInformation(" Writing updated file.", PluginFile); FileReference.WriteAllText(PluginFile, OutputText); } } }
/// <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> /// Finds and/or compiles all script files and assemblies. /// </summary> /// <param name="ScriptsForProjectFileName">Path to the current project. May be null, in which case we compile scripts for all projects.</param> /// <param name="AdditionalScriptsFolders">Additional script fodlers to look for source files in.</param> public void FindAndCompileAllScripts(string ScriptsForProjectFileName, List <string> AdditionalScriptsFolders) { bool DoCompile = false; if (GlobalCommandLine.Compile) { DoCompile = true; } // Change to Engine\Source (if exists) to properly discover all UBT classes var OldCWD = Environment.CurrentDirectory; var UnrealBuildToolCWD = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine", "Source"); if (Directory.Exists(UnrealBuildToolCWD)) { Environment.CurrentDirectory = UnrealBuildToolCWD; } // Register all the classes inside UBT Log.TraceVerbose("Registering UBT Classes."); UnrealBuildTool.UnrealBuildTool.RegisterAllUBTClasses(); Environment.CurrentDirectory = OldCWD; // Compile only if not disallowed. if (DoCompile && !String.IsNullOrEmpty(CommandUtils.CmdEnv.MsBuildExe)) { CleanupScriptsAssemblies(); FindAndCompileScriptModules(ScriptsForProjectFileName, AdditionalScriptsFolders); } var ScriptAssemblies = new List <Assembly>(); LoadPreCompiledScriptAssemblies(ScriptAssemblies); // Setup platforms Platform.InitializePlatforms(ScriptAssemblies.ToArray()); // Instantiate all the automation classes for interrogation Log.TraceVerbose("Creating commands."); ScriptCommands = new CaselessDictionary <Type>(); foreach (var CompiledScripts in ScriptAssemblies) { try { foreach (var ClassType in CompiledScripts.GetTypes()) { if (ClassType.IsSubclassOf(typeof(BuildCommand)) && ClassType.IsAbstract == false) { if (ScriptCommands.ContainsKey(ClassType.Name) == false) { ScriptCommands.Add(ClassType.Name, ClassType); } else { Log.TraceWarning("Unable to add command {0} twice. Previous: {1}, Current: {2}", ClassType.Name, ClassType.AssemblyQualifiedName, ScriptCommands[ClassType.Name].AssemblyQualifiedName); } } } } catch (Exception Ex) { throw new AutomationException("Failed to add commands from {0}. {1}", CompiledScripts, Ex); } } }
/// <summary> /// Sets any additional options for running an executable. /// </summary> /// <param name="AppName"></param> /// <param name="Options"></param> /// <param name="CommandLine"></param> public abstract void SetupOptionsForRun(ref string AppName, ref CommandUtils.ERunOptions Options, ref string CommandLine);
protected virtual void InitEnvironment(P4Connection Connection, CommandEnvironment CmdEnv) { // // P4 Environment // P4Port = CommandUtils.GetEnvVar(EnvVarNames.P4Port); ClientRoot = CommandUtils.GetEnvVar(EnvVarNames.ClientRoot); User = CommandUtils.GetEnvVar(EnvVarNames.User); ChangelistStringInternal = CommandUtils.GetEnvVar(EnvVarNames.Changelist, null); Client = CommandUtils.GetEnvVar(EnvVarNames.Client); BuildRootP4 = CommandUtils.GetEnvVar(EnvVarNames.BuildRootP4); if (BuildRootP4.EndsWith("/", StringComparison.InvariantCultureIgnoreCase) || BuildRootP4.EndsWith("\\", StringComparison.InvariantCultureIgnoreCase)) { // We expect the build root to not end with a path separator BuildRootP4 = BuildRootP4.Substring(0, BuildRootP4.Length - 1); CommandUtils.SetEnvVar(EnvVarNames.BuildRootP4, BuildRootP4); } BuildRootEscaped = CommandUtils.GetEnvVar(EnvVarNames.BuildRootEscaped); LabelToSync = CommandUtils.GetEnvVar(EnvVarNames.LabelToSync); if (((CommandUtils.P4Enabled || CommandUtils.IsBuildMachine) && (ClientRoot == String.Empty || User == String.Empty || (String.IsNullOrEmpty(ChangelistStringInternal) && CommandUtils.IsBuildMachine) || Client == String.Empty || BuildRootP4 == String.Empty))) { Log.TraceInformation("P4Enabled={0}", CommandUtils.P4Enabled); Log.TraceInformation("ClientRoot={0}", ClientRoot); Log.TraceInformation("User={0}", User); Log.TraceInformation("ChangelistString={0}", ChangelistStringInternal); Log.TraceInformation("Client={0}", Client); Log.TraceInformation("BuildRootP4={0}", BuildRootP4); throw new AutomationException("BUILD FAILED Perforce Environment is not set up correctly. Please check your environment variables."); } LabelPrefix = BuildRootP4 + "/"; if (CommandUtils.P4Enabled) { if (CommandUtils.IsBuildMachine || ChangelistStringInternal != null) { // We may not always need the changelist number if we're not a build machine. // In local runs, changelist initialization can be really slow! VerifyChangelistStringAndSetChangelistNumber(); } // Setup branch name string DepotSuffix = "//depot/"; if (BuildRootP4.StartsWith(DepotSuffix)) { BranchName = BuildRootP4.Substring(DepotSuffix.Length); } else { throw new AutomationException("Needs update to work with a stream"); } if (String.IsNullOrWhiteSpace(BranchName)) { throw new AutomationException("BUILD FAILED no branch name."); } } LogSettings(); }
/// <summary> /// Constructor. Be sure to use this.ParamName to set the actual property name as parameter names and property names /// overlap here. /// If a parameter value is not set, it will be parsed from the command line if the command is null, the default value will be used. /// </summary> public ProjectParams( string RawProjectPath, CommandUtils Command = null, string Device = null, string MapToRun = null, string AdditionalServerMapParams = null, ParamList<string> Port = null, string RunCommandline = null, string StageCommandline = null, string BundleName = null, string StageDirectoryParam = null, bool? StageNonMonolithic = null, string UE4Exe = null, string SignPak = null, List<UnrealTargetConfiguration> ClientConfigsToBuild = null, List<UnrealTargetConfiguration> ServerConfigsToBuild = null, ParamList<string> MapsToCook = null, ParamList<string> DirectoriesToCook = null, string InternationalizationPreset = null, ParamList<string> CulturesToCook = null, ParamList<string> ClientCookedTargets = null, ParamList<string> EditorTargets = null, ParamList<string> ServerCookedTargets = null, List<UnrealTargetPlatform> ClientTargetPlatforms = null, Dictionary<UnrealTargetPlatform, UnrealTargetPlatform> ClientDependentPlatformMap = null, List<UnrealTargetPlatform> ServerTargetPlatforms = null, Dictionary<UnrealTargetPlatform, UnrealTargetPlatform> ServerDependentPlatformMap = null, bool? Build = null, bool? Cook = null, string CookFlavor = null, bool? Run = null, bool? SkipServer = null, bool? Clean = null, bool? Compressed = null, bool? UseDebugParamForEditorExe = null, bool? IterativeCooking = null, bool? CookAll = null, bool? CookMapsOnly = null, bool? CookOnTheFly = null, bool? CookOnTheFlyStreaming = null, bool? UnversionedCookedContent = null, string AdditionalCookerOptions = null, string BasedOnReleaseVersion = null, string CreateReleaseVersion = null, bool? GeneratePatch = null, string DLCName = null, bool? DLCIncludeEngineContent = null, bool? NewCook = null, bool? OldCook = null, bool? CrashReporter = null, bool? DedicatedServer = null, bool? Client = null, bool? Deploy = null, bool? FileServer = null, bool? Foreign = null, bool? ForeignCode = null, bool? LogWindow = null, bool? NoCleanStage = null, bool? NoClient = null, bool? NoDebugInfo = null, bool? NoXGE = null, bool? Package = null, bool? Pak = null, bool? Prereqs = null, bool? NoBootstrapExe = null, bool? SignedPak = null, bool? NullRHI = null, bool? FakeClient = null, bool? EditorTest = null, bool? RunAutomationTests = null, string RunAutomationTest = null, int? CrashIndex = null, bool? Rocket = null, bool? SkipCook = null, bool? SkipCookOnTheFly = null, bool? SkipPak = null, bool? SkipStage = null, bool? Stage = null, bool? Manifests = null, bool? CreateChunkInstall = null, bool? Unattended = null, int? NumClients = null, bool? Archive = null, string ArchiveDirectoryParam = null, bool? ArchiveMetaData = null, ParamList<string> ProgramTargets = null, bool? Distribution = null, bool? Prebuilt = null, int? RunTimeoutSeconds = null, string SpecifiedArchitecture = null, bool? IterativeDeploy = null, bool? FastCook = null, bool? IgnoreCookErrors = null ) { // //// Use this.Name with properties and fields! // this.RawProjectPath = RawProjectPath; if (DirectoriesToCook != null) { this.DirectoriesToCook = DirectoriesToCook; } this.InternationalizationPreset = ParseParamValueIfNotSpecified(Command, InternationalizationPreset, "i18npreset"); if (CulturesToCook != null) { this.CulturesToCook = CulturesToCook; } if (ClientCookedTargets != null) { this.ClientCookedTargets = ClientCookedTargets; } if (ServerCookedTargets != null) { this.ServerCookedTargets = ServerCookedTargets; } if (EditorTargets != null) { this.EditorTargets = EditorTargets; } if (ProgramTargets != null) { this.ProgramTargets = ProgramTargets; } // Parse command line params for client platforms "-TargetPlatform=Win64+Mac", "-Platform=Win64+Mac" and also "-Win64", "-Mac" etc. if (ClientDependentPlatformMap != null) { this.ClientDependentPlatformMap = ClientDependentPlatformMap; } this.ClientTargetPlatforms = SetupTargetPlatforms(ref this.ClientDependentPlatformMap, Command, ClientTargetPlatforms, new ParamList<UnrealTargetPlatform>() { HostPlatform.Current.HostEditorPlatform }, true, "TargetPlatform", "Platform"); // Parse command line params for server platforms "-ServerTargetPlatform=Win64+Mac", "-ServerPlatform=Win64+Mac". "-Win64" etc is not allowed here if (ServerDependentPlatformMap != null) { this.ServerDependentPlatformMap = ServerDependentPlatformMap; } this.ServerTargetPlatforms = SetupTargetPlatforms(ref this.ServerDependentPlatformMap, Command, ServerTargetPlatforms, this.ClientTargetPlatforms, false, "ServerTargetPlatform", "ServerPlatform"); this.Build = GetParamValueIfNotSpecified(Command, Build, this.Build, "build"); this.Run = GetParamValueIfNotSpecified(Command, Run, this.Run, "run"); this.Cook = GetParamValueIfNotSpecified(Command, Cook, this.Cook, "cook"); this.CookFlavor = ParseParamValueIfNotSpecified(Command, CookFlavor, "cookflavor", String.Empty); this.NewCook = GetParamValueIfNotSpecified(Command, NewCook, this.NewCook, "NewCook"); this.OldCook = GetParamValueIfNotSpecified(Command, OldCook, this.OldCook, "OldCook"); this.CreateReleaseVersion = ParseParamValueIfNotSpecified(Command, CreateReleaseVersion, "createreleaseversion", String.Empty); this.BasedOnReleaseVersion = ParseParamValueIfNotSpecified(Command, BasedOnReleaseVersion, "basedonreleaseversion", String.Empty); this.GeneratePatch = GetParamValueIfNotSpecified(Command, GeneratePatch, this.GeneratePatch, "GeneratePatch"); this.AdditionalCookerOptions = ParseParamValueIfNotSpecified(Command, AdditionalCookerOptions, "AdditionalCookerOptions", String.Empty); this.DLCName = ParseParamValueIfNotSpecified(Command, DLCName, "DLCName", String.Empty); this.DLCIncludeEngineContent = GetParamValueIfNotSpecified(Command, DLCIncludeEngineContent, this.DLCIncludeEngineContent, "DLCIncludeEngineContent"); this.SkipCook = GetParamValueIfNotSpecified(Command, SkipCook, this.SkipCook, "skipcook"); if (this.SkipCook) { this.Cook = true; } this.Clean = GetOptionalParamValueIfNotSpecified(Command, Clean, this.Clean, "clean", null); this.SignPak = ParseParamValueIfNotSpecified(Command, SignPak, "signpak", String.Empty); this.SignedPak = !String.IsNullOrEmpty(this.SignPak) || GetParamValueIfNotSpecified(Command, SignedPak, this.SignedPak, "signedpak"); this.Pak = this.SignedPak || GetParamValueIfNotSpecified(Command, Pak, this.Pak, "pak"); this.SkipPak = GetParamValueIfNotSpecified(Command, SkipPak, this.SkipPak, "skippak"); if (this.SkipPak) { this.Pak = true; } this.NoXGE = GetParamValueIfNotSpecified(Command, NoXGE, this.NoXGE, "noxge"); this.CookOnTheFly = GetParamValueIfNotSpecified(Command, CookOnTheFly, this.CookOnTheFly, "cookonthefly"); if (this.CookOnTheFly && this.SkipCook) { this.Cook = false; } this.CookOnTheFlyStreaming = GetParamValueIfNotSpecified(Command, CookOnTheFlyStreaming, this.CookOnTheFlyStreaming, "cookontheflystreaming"); this.UnversionedCookedContent = GetParamValueIfNotSpecified(Command, UnversionedCookedContent, this.UnversionedCookedContent, "UnversionedCookedContent"); this.Compressed = GetParamValueIfNotSpecified(Command, Compressed, this.Compressed, "compressed"); this.UseDebugParamForEditorExe = GetParamValueIfNotSpecified(Command, UseDebugParamForEditorExe, this.UseDebugParamForEditorExe, "UseDebugParamForEditorExe"); this.IterativeCooking = GetParamValueIfNotSpecified(Command, IterativeCooking, this.IterativeCooking, new string[] { "iterativecooking", "iterate" } ); this.SkipCookOnTheFly = GetParamValueIfNotSpecified(Command, SkipCookOnTheFly, this.SkipCookOnTheFly, "skipcookonthefly"); this.CookAll = GetParamValueIfNotSpecified(Command, CookAll, this.CookAll, "CookAll"); this.CookMapsOnly = GetParamValueIfNotSpecified(Command, CookMapsOnly, this.CookMapsOnly, "CookMapsOnly"); this.FileServer = GetParamValueIfNotSpecified(Command, FileServer, this.FileServer, "fileserver"); this.DedicatedServer = GetParamValueIfNotSpecified(Command, DedicatedServer, this.DedicatedServer, "dedicatedserver", "server"); this.Client = GetParamValueIfNotSpecified(Command, Client, this.Client, "client"); if( this.Client ) { this.DedicatedServer = true; } this.NoClient = GetParamValueIfNotSpecified(Command, NoClient, this.NoClient, "noclient"); this.LogWindow = GetParamValueIfNotSpecified(Command, LogWindow, this.LogWindow, "logwindow"); this.Stage = GetParamValueIfNotSpecified(Command, Stage, this.Stage, "stage"); this.SkipStage = GetParamValueIfNotSpecified(Command, SkipStage, this.SkipStage, "skipstage"); if (this.SkipStage) { this.Stage = true; } this.StageDirectoryParam = ParseParamValueIfNotSpecified(Command, StageDirectoryParam, "stagingdirectory", String.Empty, true); this.StageNonMonolithic = GetParamValueIfNotSpecified(Command, StageNonMonolithic, this.StageNonMonolithic, "StageNonMonolithic"); this.Manifests = GetParamValueIfNotSpecified(Command, Manifests, this.Manifests, "manifests"); this.CreateChunkInstall = GetParamValueIfNotSpecified(Command, CreateChunkInstall, this.CreateChunkInstall, "createchunkinstall"); this.ChunkInstallDirectory = ParseParamValueIfNotSpecified(Command, ChunkInstallDirectory, "chunkinstalldirectory", String.Empty, true); this.ChunkInstallVersionString = ParseParamValueIfNotSpecified(Command, ChunkInstallVersionString, "chunkinstallversion", String.Empty, true); this.Archive = GetParamValueIfNotSpecified(Command, Archive, this.Archive, "archive"); this.ArchiveDirectoryParam = ParseParamValueIfNotSpecified(Command, ArchiveDirectoryParam, "archivedirectory", String.Empty, true); this.ArchiveMetaData = GetParamValueIfNotSpecified(Command, ArchiveMetaData, this.ArchiveMetaData, "archivemetadata"); this.Distribution = GetParamValueIfNotSpecified(Command, Distribution, this.Distribution, "distribution"); this.Prereqs = GetParamValueIfNotSpecified(Command, Prereqs, this.Prereqs, "prereqs"); this.NoBootstrapExe = GetParamValueIfNotSpecified(Command, NoBootstrapExe, this.NoBootstrapExe, "nobootstrapexe"); this.Prebuilt = GetParamValueIfNotSpecified(Command, Prebuilt, this.Prebuilt, "prebuilt"); if (this.Prebuilt) { this.SkipCook = true; /*this.SkipPak = true; this.SkipStage = true; this.Pak = true; this.Stage = true;*/ this.Cook = true; this.Archive = true; this.Deploy = true; this.Run = true; //this.StageDirectoryParam = this.PrebuiltDir; } this.NoDebugInfo = GetParamValueIfNotSpecified(Command, NoDebugInfo, this.NoDebugInfo, "nodebuginfo"); this.NoCleanStage = GetParamValueIfNotSpecified(Command, NoCleanStage, this.NoCleanStage, "nocleanstage"); this.MapToRun = ParseParamValueIfNotSpecified(Command, MapToRun, "map", String.Empty); this.AdditionalServerMapParams = ParseParamValueIfNotSpecified(Command, AdditionalServerMapParams, "AdditionalServerMapParams", String.Empty); this.Foreign = GetParamValueIfNotSpecified(Command, Foreign, this.Foreign, "foreign"); this.ForeignCode = GetParamValueIfNotSpecified(Command, ForeignCode, this.ForeignCode, "foreigncode"); this.StageCommandline = ParseParamValueIfNotSpecified(Command, StageCommandline, "cmdline"); this.BundleName = ParseParamValueIfNotSpecified(Command, BundleName, "bundlename"); this.RunCommandline = ParseParamValueIfNotSpecified(Command, RunCommandline, "addcmdline"); this.Package = GetParamValueIfNotSpecified(Command, Package, this.Package, "package"); this.Deploy = GetParamValueIfNotSpecified(Command, Deploy, this.Deploy, "deploy"); this.IterativeDeploy = GetParamValueIfNotSpecified(Command, IterativeDeploy, this.IterativeDeploy, new string[] {"iterativedeploy", "iterate" } ); this.FastCook = GetParamValueIfNotSpecified(Command, FastCook, this.FastCook, "FastCook"); this.IgnoreCookErrors = GetParamValueIfNotSpecified(Command, IgnoreCookErrors, this.IgnoreCookErrors, "IgnoreCookErrors"); this.Device = ParseParamValueIfNotSpecified(Command, Device, "device", String.Empty).Trim(new char[] { '\"' }); // strip the platform prefix the specified device. if (this.Device.Contains("@")) { this.DeviceName = this.Device.Substring(this.Device.IndexOf("@") + 1); } else { this.DeviceName = this.Device; } this.ServerDevice = ParseParamValueIfNotSpecified(Command, ServerDevice, "serverdevice", this.Device); this.NullRHI = GetParamValueIfNotSpecified(Command, NullRHI, this.NullRHI, "nullrhi"); this.FakeClient = GetParamValueIfNotSpecified(Command, FakeClient, this.FakeClient, "fakeclient"); this.EditorTest = GetParamValueIfNotSpecified(Command, EditorTest, this.EditorTest, "editortest"); this.RunAutomationTest = ParseParamValueIfNotSpecified(Command, RunAutomationTest, "RunAutomationTest"); this.RunAutomationTests = this.RunAutomationTest != "" || GetParamValueIfNotSpecified(Command, RunAutomationTests, this.RunAutomationTests, "RunAutomationTests"); this.SkipServer = GetParamValueIfNotSpecified(Command, SkipServer, this.SkipServer, "skipserver"); this.Rocket = GetParamValueIfNotSpecified(Command, Rocket, this.Rocket || GlobalCommandLine.Rocket, "rocket"); this.UE4Exe = ParseParamValueIfNotSpecified(Command, UE4Exe, "ue4exe", "UE4Editor-Cmd.exe"); this.Unattended = GetParamValueIfNotSpecified(Command, Unattended, this.Unattended, "unattended"); this.DeviceUsername = ParseParamValueIfNotSpecified(Command, DeviceUsername, "deviceuser", String.Empty); this.DevicePassword = ParseParamValueIfNotSpecified(Command, DevicePassword, "devicepass", String.Empty); this.CrashReporter = GetParamValueIfNotSpecified(Command, CrashReporter, this.CrashReporter, "crashreporter"); this.SpecifiedArchitecture = ParseParamValueIfNotSpecified(Command, SpecifiedArchitecture, "specifiedarchitecture", String.Empty); if (ClientConfigsToBuild == null) { if (Command != null) { var ClientConfig = Command.ParseParamValue("clientconfig"); if (ClientConfig != null) { this.ClientConfigsToBuild = new List<UnrealTargetConfiguration>(); var Configs = new ParamList<string>(ClientConfig.Split('+')); foreach (var ConfigName in Configs) { this.ClientConfigsToBuild.Add((UnrealTargetConfiguration)Enum.Parse(typeof(UnrealTargetConfiguration), ConfigName, true)); } } } } else { this.ClientConfigsToBuild = ClientConfigsToBuild; } if (Port == null) { if( Command != null ) { this.Port = new ParamList<string>(); var PortString = Command.ParseParamValue("port"); if (String.IsNullOrEmpty(PortString) == false) { var Ports = new ParamList<string>(PortString.Split('+')); foreach (var P in Ports) { this.Port.Add(P); } } } } else { this.Port = Port; } if (MapsToCook == null) { if (Command != null) { this.MapsToCook = new ParamList<string>(); var MapsString = Command.ParseParamValue("MapsToCook"); if (String.IsNullOrEmpty(MapsString) == false) { var MapNames = new ParamList<string>(MapsString.Split('+')); foreach ( var M in MapNames ) { this.MapsToCook.Add( M ); } } } } else { this.MapsToCook = MapsToCook; } if (String.IsNullOrEmpty(this.MapToRun) == false) { this.MapsToCook.Add(this.MapToRun); } if (ServerConfigsToBuild == null) { if (Command != null) { var ServerConfig = Command.ParseParamValue("serverconfig"); if (ServerConfig != null && ServerConfigsToBuild == null) { this.ServerConfigsToBuild = new List<UnrealTargetConfiguration>(); var Configs = new ParamList<string>(ServerConfig.Split('+')); foreach (var ConfigName in Configs) { this.ServerConfigsToBuild.Add((UnrealTargetConfiguration)Enum.Parse(typeof(UnrealTargetConfiguration), ConfigName, true)); } } } } else { this.ServerConfigsToBuild = ServerConfigsToBuild; } if (NumClients.HasValue) { this.NumClients = NumClients.Value; } else if (Command != null) { this.NumClients = Command.ParseParamInt("numclients"); } if (CrashIndex.HasValue) { this.CrashIndex = CrashIndex.Value; } else if (Command != null) { this.CrashIndex = Command.ParseParamInt("CrashIndex"); } if (RunTimeoutSeconds.HasValue) { this.RunTimeoutSeconds = RunTimeoutSeconds.Value; } else if (Command != null) { this.RunTimeoutSeconds = Command.ParseParamInt("runtimeoutseconds"); } AutodetectSettings(false); ValidateAndLog(); }
/// <summary> /// Main method. /// </summary> /// <param name="CommandLine">Command line</param> public static ExitCode Process(string[] CommandLine) { // Initial check for local or build machine runs BEFORE we parse the command line (We need this value set // in case something throws the exception while parsing the command line) IsBuildMachine = !String.IsNullOrEmpty(Environment.GetEnvironmentVariable("uebp_LOCAL_ROOT")); // Scan the command line for commands to execute. var CommandsToExecute = new List <CommandInfo>(); string OutScriptsForProjectFileName; var AdditionalScriptsFolders = new List <string>(); ParseCommandLine(CommandLine, CommandsToExecute, out OutScriptsForProjectFileName, AdditionalScriptsFolders); // Check for build machine override (force local) IsBuildMachine = GlobalCommandLine.ForceLocal ? false : IsBuildMachine; Log.TraceVerbose("IsBuildMachine={0}", IsBuildMachine); Environment.SetEnvironmentVariable("IsBuildMachine", IsBuildMachine ? "1" : "0"); // should we kill processes on exit ShouldKillProcesses = !GlobalCommandLine.NoKill; Log.TraceVerbose("ShouldKillProcesses={0}", ShouldKillProcesses); if (CommandsToExecute.Count == 0 && GlobalCommandLine.Help) { DisplayHelp(); return(ExitCode.Success); } // Disable AutoSDKs if specified on the command line if (GlobalCommandLine.NoAutoSDK) { UEBuildPlatformSDK.bAllowAutoSDKSwitching = false; } // Setup environment Log.TraceInformation("Setting up command environment."); CommandUtils.InitCommandEnvironment(); // Change CWD to UE4 root. Environment.CurrentDirectory = CommandUtils.CmdEnv.LocalRoot; // Fill in the project info UnrealBuildTool.UProjectInfo.FillProjectInfo(); // Clean rules folders up ProjectUtils.CleanupFolders(); // Compile scripts. ScriptCompiler Compiler = new ScriptCompiler(); using (TelemetryStopwatch ScriptCompileStopwatch = new TelemetryStopwatch("ScriptCompile")) { Compiler.FindAndCompileAllScripts(OutScriptsForProjectFileName, AdditionalScriptsFolders); } if (GlobalCommandLine.CompileOnly) { Log.TraceInformation("Compilation successful, exiting (CompileOnly)"); return(ExitCode.Success); } if (GlobalCommandLine.List) { ListAvailableCommands(Compiler.Commands); return(ExitCode.Success); } if (GlobalCommandLine.Help) { DisplayHelp(CommandsToExecute, Compiler.Commands); return(ExitCode.Success); } // Enable or disable P4 support CommandUtils.InitP4Support(CommandsToExecute, Compiler.Commands); if (CommandUtils.P4Enabled) { Log.TraceInformation("Setting up Perforce environment."); CommandUtils.InitP4Environment(); CommandUtils.InitDefaultP4Connection(); } // Find and execute commands. return(Execute(CommandsToExecute, Compiler.Commands)); }
public override string GetMsBuildExe() { var DotNETToolsFolder = CommandUtils.CombinePaths(CommandUtils.GetEnvVar(EnvVarNames.NETFrameworkDir), CommandUtils.GetEnvVar(EnvVarNames.NETFrameworkVersion)); var MsBuildExe = CommandUtils.CombinePaths(DotNETToolsFolder, "MSBuild.exe"); if (!CommandUtils.FileExists_NoExceptions(MsBuildExe)) { throw new NotSupportedException("MsBuild.exe does not exist."); } return(MsBuildExe); }
/// <summary> /// Entry point for the commandlet /// </summary> public override void ExecuteBuild() { string OutputDir = ParseRequiredStringParam("OutputDir"); List <UnrealTargetPlatform> Platforms = ParsePlatformsParamValue("Platforms"); List <UnrealTargetPlatform> ContentOnlyPlatforms = ParsePlatformsParamValue("ContentOnlyPlatforms"); string AnalyticsTypeOverride = ParseParamValue("AnalyticsTypeOverride"); // Write InstalledBuild.txt to indicate Engine is installed string InstalledBuildFile = CommandUtils.CombinePaths(OutputDir, "Engine/Build/InstalledBuild.txt"); CommandUtils.CreateDirectory(CommandUtils.GetDirectoryName(InstalledBuildFile)); CommandUtils.WriteAllText(InstalledBuildFile, ""); // Write InstalledBuild.txt to indicate Engine is installed string Project = ParseParamValue("Project"); if (Project != null) { string InstalledProjectBuildFile = CommandUtils.CombinePaths(OutputDir, "Engine/Build/InstalledProjectBuild.txt"); CommandUtils.CreateDirectory(CommandUtils.GetDirectoryName(InstalledProjectBuildFile)); CommandUtils.WriteAllText(InstalledProjectBuildFile, new FileReference(Project).MakeRelativeTo(new DirectoryReference(OutputDir))); } string OutputEnginePath = Path.Combine(OutputDir, "Engine"); string OutputBaseEnginePath = Path.Combine(OutputEnginePath, "Config", "BaseEngine.ini"); FileAttributes OutputAttributes = FileAttributes.ReadOnly; List <String> IniLines = new List <String>(); // Should always exist but if not, we don't need extra line if (File.Exists(OutputBaseEnginePath)) { OutputAttributes = File.GetAttributes(OutputBaseEnginePath); IniLines.Add(""); } else { CommandUtils.CreateDirectory(CommandUtils.GetDirectoryName(OutputBaseEnginePath)); CommandUtils.WriteAllText(OutputBaseEnginePath, ""); OutputAttributes = File.GetAttributes(OutputBaseEnginePath) | OutputAttributes; } // Create list of platform configurations installed in a Rocket build List <InstalledPlatformInfo.InstalledPlatformConfiguration> InstalledConfigs = new List <InstalledPlatformInfo.InstalledPlatformConfiguration>(); // Add the editor platform, otherwise we'll never be able to run UAT string EditorArchitecture = PlatformExports.GetDefaultArchitecture(HostPlatform.Current.HostEditorPlatform, null); InstalledConfigs.Add(new InstalledPlatformInfo.InstalledPlatformConfiguration(UnrealTargetConfiguration.Development, HostPlatform.Current.HostEditorPlatform, TargetRules.TargetType.Editor, EditorArchitecture, "", EProjectType.Unknown, false)); InstalledConfigs.Add(new InstalledPlatformInfo.InstalledPlatformConfiguration(UnrealTargetConfiguration.DebugGame, HostPlatform.Current.HostEditorPlatform, TargetRules.TargetType.Editor, EditorArchitecture, "", EProjectType.Unknown, false)); foreach (UnrealTargetPlatform CodeTargetPlatform in Platforms) { string Architecture = PlatformExports.GetDefaultArchitecture(CodeTargetPlatform, null); // Try to parse additional Architectures from the command line string Architectures = ParseParamValue(CodeTargetPlatform.ToString() + "Architectures"); string GPUArchitectures = ParseParamValue(CodeTargetPlatform.ToString() + "GPUArchitectures"); // Build a list of pre-compiled architecture combinations for this platform if any List <string> AllArchNames; if (!String.IsNullOrWhiteSpace(Architectures) && !String.IsNullOrWhiteSpace(GPUArchitectures)) { AllArchNames = (from Arch in Architectures.Split('+') from GPUArch in GPUArchitectures.Split('+') select "-" + Arch + "-" + GPUArch).ToList(); } else if (!String.IsNullOrWhiteSpace(Architectures)) { AllArchNames = Architectures.Split('+').ToList(); } // if there aren't any, use the default else { AllArchNames = new List <string>() { Architecture }; } // Check whether this platform should only be used for content based projects EProjectType ProjectType = ContentOnlyPlatforms.Contains(CodeTargetPlatform) ? EProjectType.Content : EProjectType.Any; // Allow Content only platforms to be shown as options in all projects bool bCanBeDisplayed = ProjectType == EProjectType.Content; foreach (UnrealTargetConfiguration CodeTargetConfiguration in Enum.GetValues(typeof(UnrealTargetConfiguration))) { Dictionary <String, TargetType> Targets = new Dictionary <string, TargetType>() { { "UE4Game", TargetType.Game }, { "UE4Client", TargetType.Client }, { "UE4Server", TargetType.Server } }; foreach (KeyValuePair <string, TargetType> Target in Targets) { string CurrentTargetName = Target.Key; TargetType CurrentTargetType = Target.Value; // Need to check for development receipt as we use that for the Engine code in DebugGame UnrealTargetConfiguration EngineConfiguration = (CodeTargetConfiguration == UnrealTargetConfiguration.DebugGame) ? UnrealTargetConfiguration.Development : CodeTargetConfiguration; // Android has multiple architecture flavors built without receipts, so use the default arch target instead if (CodeTargetPlatform == UnrealTargetPlatform.Android) { FileReference ReceiptFileName = TargetReceipt.GetDefaultPath(new DirectoryReference(OutputEnginePath), CurrentTargetName, CodeTargetPlatform, EngineConfiguration, Architecture); if (FileReference.Exists(ReceiptFileName)) { // Strip the output folder so that this can be used on any machine string RelativeReceiptFileName = ReceiptFileName.MakeRelativeTo(new DirectoryReference(OutputDir)); // Blindly append all of the architecture names if (AllArchNames.Count > 0) { foreach (string Arch in AllArchNames) { InstalledConfigs.Add(new InstalledPlatformInfo.InstalledPlatformConfiguration(CodeTargetConfiguration, CodeTargetPlatform, CurrentTargetType, Arch, RelativeReceiptFileName, ProjectType, bCanBeDisplayed)); } } // if for some reason we didn't specify any flavors, just add the default one. else { InstalledConfigs.Add(new InstalledPlatformInfo.InstalledPlatformConfiguration(CodeTargetConfiguration, CodeTargetPlatform, CurrentTargetType, Architecture, RelativeReceiptFileName, ProjectType, bCanBeDisplayed)); } } } // If we're not Android, check the existence of the target receipts for each architecture specified. else { foreach (string Arch in AllArchNames) { FileReference ReceiptFileName = TargetReceipt.GetDefaultPath(new DirectoryReference(OutputEnginePath), CurrentTargetName, CodeTargetPlatform, EngineConfiguration, Arch); if (FileReference.Exists(ReceiptFileName)) { string RelativeReceiptFileName = ReceiptFileName.MakeRelativeTo(new DirectoryReference(OutputDir)); InstalledConfigs.Add(new InstalledPlatformInfo.InstalledPlatformConfiguration(CodeTargetConfiguration, CodeTargetPlatform, CurrentTargetType, Arch, RelativeReceiptFileName, ProjectType, bCanBeDisplayed)); } } } } } } UnrealBuildTool.InstalledPlatformInfo.WriteConfigFileEntries(InstalledConfigs, ref IniLines); if (!String.IsNullOrEmpty(AnalyticsTypeOverride)) { // Write Custom Analytics type setting IniLines.Add(""); IniLines.Add("[Analytics]"); IniLines.Add(String.Format("UE4TypeOverride=\"{0}\"", AnalyticsTypeOverride)); } // Make sure we can write to the the config file File.SetAttributes(OutputBaseEnginePath, OutputAttributes & ~FileAttributes.ReadOnly); File.AppendAllLines(OutputBaseEnginePath, IniLines); File.SetAttributes(OutputBaseEnginePath, OutputAttributes); }
/// <summary> /// Initializes trace logging. /// </summary> /// <param name="CommandLine">Command line.</param> public static void InitLogging(string[] CommandLine) { // ensure UTF8Output flag is respected, since we are initializing logging early in the program. if (CommandLine.Any(Arg => Arg.Equals("-utf8output", StringComparison.InvariantCultureIgnoreCase))) { Console.OutputEncoding = new System.Text.UTF8Encoding(false, false); } UnrealBuildTool.Log.InitLogging( bLogTimestamps: CommandUtils.ParseParam(CommandLine, "-Timestamps"), InLogLevel: (UnrealBuildTool.LogEventType)Enum.Parse(typeof(UnrealBuildTool.LogEventType), CommandUtils.ParseParamValue(CommandLine, "-Verbose=", "Log")), bLogSeverity: true, bLogProgramNameWithSeverity: false, bLogSources: true, bLogSourcesToConsole: false, bColorConsoleOutput: true, TraceListeners: new TraceListener[] { new UEConsoleTraceListener(), // could return null, but InitLogging handles this gracefully. CreateLogFileListener(out LogFilename), //@todo - this is only used by GUBP nodes. Ideally we don't waste this 20MB if we are not running GUBP. new AutomationMemoryLogListener(), }); }
public override string GetUE4ExePath(string UE4Exe) { return(CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, RelativeBinariesFolder, UE4Exe)); }
/// <summary> /// Gets a short project name (QAGame, Elemental, etc) /// </summary> /// <param name="RawProjectPath">Full project path.</param> /// <param name="bIsUProjectFile">True if a uproject.</param> /// <returns>Short project name</returns> public static string GetShortProjectName(FileReference RawProjectPath) { return(CommandUtils.GetFilenameWithoutAnyExtensions(RawProjectPath.FullName)); }
/// <summary> /// Initializes the environement. /// </summary> protected virtual void InitEnvironment() { SetUATLocation(); LocalRoot = CommandUtils.GetEnvVar(EnvVarNames.LocalRoot); if (String.IsNullOrEmpty(CommandUtils.GetEnvVar(EnvVarNames.EngineSavedFolder))) { SetUATSavedPath(); } if (LocalRoot.EndsWith(":")) { LocalRoot += Path.DirectorySeparatorChar; } EngineSavedFolder = CommandUtils.GetEnvVar(EnvVarNames.EngineSavedFolder); CSVFile = CommandUtils.GetEnvVar(EnvVarNames.CSVFile); LogFolder = CommandUtils.GetEnvVar(EnvVarNames.LogFolder); RobocopyExe = GetSystemExePath("robocopy.exe"); MountExe = GetSystemExePath("mount.exe"); CmdExe = Utils.IsRunningOnMono ? "/bin/sh" : GetSystemExePath("cmd.exe"); MallocNanoZone = "0"; CommandUtils.SetEnvVar(EnvVarNames.MacMallocNanoZone, MallocNanoZone); if (String.IsNullOrEmpty(LogFolder)) { throw new AutomationException("Environment is not set up correctly: LogFolder is not set!"); } if (String.IsNullOrEmpty(LocalRoot)) { throw new AutomationException("Environment is not set up correctly: LocalRoot is not set!"); } if (String.IsNullOrEmpty(EngineSavedFolder)) { throw new AutomationException("Environment is not set up correctly: EngineSavedFolder is not set!"); } // Make sure that the log folder exists var LogFolderInfo = new DirectoryInfo(LogFolder); if (!LogFolderInfo.Exists) { LogFolderInfo.Create(); } // Setup the timestamp string DateTime LocalTime = DateTime.Now; string TimeStamp = LocalTime.Year + "-" + LocalTime.Month.ToString("00") + "-" + LocalTime.Day.ToString("00") + "_" + LocalTime.Hour.ToString("00") + "." + LocalTime.Minute.ToString("00") + "." + LocalTime.Second.ToString("00"); TimestampAsString = TimeStamp; SetupBuildEnvironment(); LogSettings(); }
/// <summary> /// Finds all targets for the project. /// </summary> /// <param name="Properties">Project properties.</param> /// <param name="ExtraSearchPaths">Additional search paths.</param> private static void DetectTargetsForProject(ProjectProperties Properties, List <string> ExtraSearchPaths = null) { Properties.Targets = new Dictionary <TargetRules.TargetType, SingleTargetProperties>(); FileReference TargetsDllFilename; string FullProjectPath = null; var GameFolders = new List <DirectoryReference>(); var RulesFolder = new DirectoryReference(GetRulesAssemblyFolder()); if (Properties.RawProjectPath != null) { CommandUtils.LogVerbose("Looking for targets for project {0}", Properties.RawProjectPath); TargetsDllFilename = FileReference.Combine(RulesFolder, String.Format("UATRules{0}.dll", Properties.RawProjectPath.GetHashCode())); FullProjectPath = CommandUtils.GetDirectoryName(Properties.RawProjectPath.FullName); GameFolders.Add(new DirectoryReference(FullProjectPath)); CommandUtils.LogVerbose("Searching for target rule files in {0}", FullProjectPath); } else { TargetsDllFilename = FileReference.Combine(RulesFolder, String.Format("UATRules{0}.dll", "_BaseEngine_")); } // the UBT code assumes a certain CWD, but artists don't have this CWD. var SourceDir = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine", "Source"); bool DirPushed = false; if (CommandUtils.DirectoryExists_NoExceptions(SourceDir)) { CommandUtils.PushDir(SourceDir); DirPushed = true; } var ExtraSearchDirectories = (ExtraSearchPaths == null)? null : ExtraSearchPaths.Select(x => new DirectoryReference(x)).ToList(); var TargetScripts = RulesCompiler.FindAllRulesSourceFiles(RulesCompiler.RulesFileType.Target, GameFolders: GameFolders, ForeignPlugins: null, AdditionalSearchPaths: ExtraSearchDirectories); if (DirPushed) { CommandUtils.PopDir(); } if (!CommandUtils.IsNullOrEmpty(TargetScripts)) { // We only care about project target script so filter out any scripts not in the project folder, or take them all if we are just doing engine stuff var ProjectTargetScripts = new List <FileReference>(); foreach (var TargetScript in TargetScripts) { if (FullProjectPath == null || TargetScript.IsUnderDirectory(new DirectoryReference(FullProjectPath))) { ProjectTargetScripts.Add(TargetScript); } } TargetScripts = ProjectTargetScripts; } if (!CommandUtils.IsNullOrEmpty(TargetScripts)) { CommandUtils.LogVerbose("Found {0} target rule files:", TargetScripts.Count); foreach (var Filename in TargetScripts) { CommandUtils.LogVerbose(" {0}", Filename); } // Check if the scripts require compilation bool DoNotCompile = false; if (!CommandUtils.IsBuildMachine && !CheckIfScriptAssemblyIsOutOfDate(TargetsDllFilename, TargetScripts)) { Log.TraceVerbose("Targets DLL {0} is up to date.", TargetsDllFilename); DoNotCompile = true; } if (!DoNotCompile && CommandUtils.FileExists_NoExceptions(TargetsDllFilename.FullName)) { if (!CommandUtils.DeleteFile_NoExceptions(TargetsDllFilename.FullName, true)) { DoNotCompile = true; CommandUtils.LogVerbose("Could not delete {0} assuming it is up to date and reusable for a recursive UAT call.", TargetsDllFilename); } } CompileAndLoadTargetsAssembly(Properties, TargetsDllFilename, DoNotCompile, TargetScripts); } }
/// <summary> /// Build a node /// </summary> /// <param name="Job">Information about the current job</param> /// <param name="Graph">The graph to which the node belongs. Used to determine which outputs need to be transferred to temp storage.</param> /// <param name="Node">The node to build</param> /// <param name="Storage">The temp storage backend which stores the shared state</param> /// <param name="bWithBanner">Whether to write a banner before and after this node's log output</param> /// <returns>True if the node built successfully, false otherwise.</returns> bool BuildNode(JobContext Job, Graph Graph, Node Node, TempStorage Storage, bool bWithBanner) { DirectoryReference RootDir = new DirectoryReference(CommandUtils.CmdEnv.LocalRoot); // Create the mapping of tag names to file sets Dictionary <string, HashSet <FileReference> > TagNameToFileSet = new Dictionary <string, HashSet <FileReference> >(); // Read all the input tags for this node, and build a list of referenced input storage blocks HashSet <TempStorageBlock> InputStorageBlocks = new HashSet <TempStorageBlock>(); foreach (NodeOutput Input in Node.Inputs) { TempStorageFileList FileList = Storage.ReadFileList(Input.ProducingNode.Name, Input.TagName); TagNameToFileSet[Input.TagName] = FileList.ToFileSet(RootDir); InputStorageBlocks.UnionWith(FileList.Blocks); } // Read the manifests for all the input storage blocks Dictionary <TempStorageBlock, TempStorageManifest> InputManifests = new Dictionary <TempStorageBlock, TempStorageManifest>(); foreach (TempStorageBlock InputStorageBlock in InputStorageBlocks) { TempStorageManifest Manifest = Storage.Retreive(InputStorageBlock.NodeName, InputStorageBlock.OutputName); InputManifests[InputStorageBlock] = Manifest; } // Read all the input storage blocks, keeping track of which block each file came from Dictionary <FileReference, TempStorageBlock> FileToStorageBlock = new Dictionary <FileReference, TempStorageBlock>(); foreach (KeyValuePair <TempStorageBlock, TempStorageManifest> Pair in InputManifests) { TempStorageBlock InputStorageBlock = Pair.Key; foreach (FileReference File in Pair.Value.Files.Select(x => x.ToFileReference(RootDir))) { TempStorageBlock CurrentStorageBlock; if (FileToStorageBlock.TryGetValue(File, out CurrentStorageBlock)) { LogError("File '{0}' was produced by {1} and {2}", File, InputStorageBlock, CurrentStorageBlock); } FileToStorageBlock[File] = InputStorageBlock; } } // Add placeholder outputs for the current node foreach (NodeOutput Output in Node.Outputs) { TagNameToFileSet.Add(Output.TagName, new HashSet <FileReference>()); } // Execute the node if (bWithBanner) { Console.WriteLine(); CommandUtils.LogInformation("========== Starting: {0} ==========", Node.Name); } if (!Node.Build(Job, TagNameToFileSet)) { return(false); } if (bWithBanner) { CommandUtils.LogInformation("========== Finished: {0} ==========", Node.Name); Console.WriteLine(); } // Check that none of the inputs have been clobbered Dictionary <string, string> ModifiedFiles = new Dictionary <string, string>(StringComparer.InvariantCultureIgnoreCase); foreach (TempStorageFile File in InputManifests.Values.SelectMany(x => x.Files)) { string Message; if (!ModifiedFiles.ContainsKey(File.RelativePath) && !File.Compare(CommandUtils.RootDirectory, out Message)) { ModifiedFiles.Add(File.RelativePath, Message); } } if (ModifiedFiles.Count > 0) { throw new AutomationException("Build {0} from a previous step have been modified:\n{1}", (ModifiedFiles.Count == 1)? "product" : "products", String.Join("\n", ModifiedFiles.Select(x => x.Value))); } // Determine all the output files which are required to be copied to temp storage (because they're referenced by nodes in another agent) HashSet <FileReference> ReferencedOutputFiles = new HashSet <FileReference>(); foreach (Agent Agent in Graph.Agents) { bool bSameAgent = Agent.Nodes.Contains(Node); foreach (Node OtherNode in Agent.Nodes) { if (!bSameAgent || Node.ControllingTrigger != OtherNode.ControllingTrigger) { foreach (NodeOutput Input in OtherNode.Inputs.Where(x => x.ProducingNode == Node)) { ReferencedOutputFiles.UnionWith(TagNameToFileSet[Input.TagName]); } } } } // Find a block name for all new outputs Dictionary <FileReference, string> FileToOutputName = new Dictionary <FileReference, string>(); foreach (NodeOutput Output in Node.Outputs) { HashSet <FileReference> Files = TagNameToFileSet[Output.TagName]; foreach (FileReference File in Files) { if (!FileToStorageBlock.ContainsKey(File) && File.IsUnderDirectory(RootDir)) { if (Output == Node.DefaultOutput) { if (!FileToOutputName.ContainsKey(File)) { FileToOutputName[File] = ""; } } else { string OutputName; if (FileToOutputName.TryGetValue(File, out OutputName) && OutputName.Length > 0) { FileToOutputName[File] = String.Format("{0}+{1}", OutputName, Output.TagName.Substring(1)); } else { FileToOutputName[File] = Output.TagName.Substring(1); } } } } } // Invert the dictionary to make a mapping of storage block to the files each contains Dictionary <string, HashSet <FileReference> > OutputStorageBlockToFiles = new Dictionary <string, HashSet <FileReference> >(); foreach (KeyValuePair <FileReference, string> Pair in FileToOutputName) { HashSet <FileReference> Files; if (!OutputStorageBlockToFiles.TryGetValue(Pair.Value, out Files)) { Files = new HashSet <FileReference>(); OutputStorageBlockToFiles.Add(Pair.Value, Files); } Files.Add(Pair.Key); } // Write all the storage blocks, and update the mapping from file to storage block foreach (KeyValuePair <string, HashSet <FileReference> > Pair in OutputStorageBlockToFiles) { TempStorageBlock OutputBlock = new TempStorageBlock(Node.Name, Pair.Key); foreach (FileReference File in Pair.Value) { FileToStorageBlock.Add(File, OutputBlock); } Storage.Archive(Node.Name, Pair.Key, Pair.Value.ToArray(), Pair.Value.Any(x => ReferencedOutputFiles.Contains(x))); } // Publish all the output tags foreach (NodeOutput Output in Node.Outputs) { HashSet <FileReference> Files = TagNameToFileSet[Output.TagName]; HashSet <TempStorageBlock> StorageBlocks = new HashSet <TempStorageBlock>(); foreach (FileReference File in Files) { TempStorageBlock StorageBlock; if (FileToStorageBlock.TryGetValue(File, out StorageBlock)) { StorageBlocks.Add(StorageBlock); } } Storage.WriteFileList(Node.Name, Output.TagName, Files, StorageBlocks.ToArray()); } // Mark the node as succeeded Storage.MarkAsComplete(Node.Name); return(true); }
/// <summary> /// Runs GenerateDistillFileSets commandlet. /// </summary> /// <param name="ProjectName">Project name.</param> /// <param name="UE4Exe">The name of the UE4 Editor executable to use.</param> /// <param name="Maps">List of maps to cook, can be null in which case -MapIniSection=AllMaps is used.</param> /// <param name="TargetPlatform">Target platform.</param> /// <param name="Parameters">List of additional parameters.</param> public static List <string> GenerateDistillFileSetsCommandlet(FileReference ProjectName, string ManifestFile, string UE4Exe = "UE4Editor-Cmd.exe", string[] Maps = null, string Parameters = "") { string MapsToCook = ""; if (!IsNullOrEmpty(Maps)) { MapsToCook = CombineCommandletParams(Maps, " ").Trim(); } var Dir = Path.GetDirectoryName(ManifestFile); var Filename = Path.GetFileName(ManifestFile); if (String.IsNullOrEmpty(Dir) || String.IsNullOrEmpty(Filename)) { throw new AutomationException("GenerateDistillFileSets should have a full path and file for {0}.", ManifestFile); } CreateDirectory_NoExceptions(Dir); if (FileExists_NoExceptions(ManifestFile)) { DeleteFile(ManifestFile); } RunCommandlet(ProjectName, UE4Exe, "GenerateDistillFileSets", String.Format("{0} -OutputFolder={1} -Output={2} {3}", MapsToCook, CommandUtils.MakePathSafeToUseWithCommandLine(Dir), Filename, Parameters)); if (!FileExists_NoExceptions(ManifestFile)) { throw new AutomationException("GenerateDistillFileSets did not produce a manifest for {0}.", ProjectName); } var Lines = new List <string>(ReadAllLines(ManifestFile)); if (Lines.Count < 1) { throw new AutomationException("GenerateDistillFileSets for {0} did not produce any files.", ProjectName); } var Result = new List <string>(); foreach (var ThisFile in Lines) { var TestFile = CombinePaths(ThisFile); if (!FileExists_NoExceptions(TestFile)) { throw new AutomationException("GenerateDistillFileSets produced {0}, but {1} doesn't exist.", ThisFile, TestFile); } // we correct the case here var TestFileInfo = new FileInfo(TestFile); var FinalFile = CombinePaths(TestFileInfo.FullName); if (!FileExists_NoExceptions(FinalFile)) { throw new AutomationException("GenerateDistillFileSets produced {0}, but {1} doesn't exist.", ThisFile, FinalFile); } Result.Add(FinalFile); } return(Result); }
/// <summary> /// Main entry point for the BuildGraph command /// </summary> public override ExitCode Execute() { // Parse the command line parameters string ScriptFileName = ParseParamValue("Script", null); string TargetNames = ParseParamValue("Target", null); string DocumentationFileName = ParseParamValue("Documentation", null); string SchemaFileName = ParseParamValue("Schema", null); string ExportFileName = ParseParamValue("Export", null); string PreprocessedFileName = ParseParamValue("Preprocess", null); string SharedStorageDir = ParseParamValue("SharedStorageDir", null); string SingleNodeName = ParseParamValue("SingleNode", null); string TriggerName = ParseParamValue("Trigger", null); string[] SkipTriggerNames = ParseParamValue("SkipTrigger", "").Split(new char[] { '+', ';' }, StringSplitOptions.RemoveEmptyEntries).ToArray(); bool bSkipTriggers = ParseParam("SkipTriggers"); string TokenSignature = ParseParamValue("TokenSignature", null); bool bSkipTargetsWithoutTokens = ParseParam("SkipTargetsWithoutTokens"); bool bResume = SingleNodeName != null || ParseParam("Resume"); bool bListOnly = ParseParam("ListOnly"); bool bShowDiagnostics = ParseParam("ShowDiagnostics"); bool bWriteToSharedStorage = ParseParam("WriteToSharedStorage") || CommandUtils.IsBuildMachine; bool bPublicTasksOnly = ParseParam("PublicTasksOnly"); string ReportName = ParseParamValue("ReportName", null); GraphPrintOptions PrintOptions = GraphPrintOptions.ShowCommandLineOptions; if (ParseParam("ShowDeps")) { PrintOptions |= GraphPrintOptions.ShowDependencies; } if (ParseParam("ShowNotifications")) { PrintOptions |= GraphPrintOptions.ShowNotifications; } // Parse any specific nodes to clean List <string> CleanNodes = new List <string>(); foreach (string NodeList in ParseParamValues("CleanNode")) { foreach (string NodeName in NodeList.Split('+', ';')) { CleanNodes.Add(NodeName); } } // Set up the standard properties which build scripts might need Dictionary <string, string> DefaultProperties = new Dictionary <string, string>(StringComparer.InvariantCultureIgnoreCase); DefaultProperties["Branch"] = P4Enabled ? P4Env.Branch : "Unknown"; DefaultProperties["EscapedBranch"] = P4Enabled ? CommandUtils.EscapePath(P4Env.Branch) : "Unknown"; DefaultProperties["Change"] = P4Enabled ? P4Env.Changelist.ToString() : "0"; DefaultProperties["CodeChange"] = P4Enabled ? P4Env.CodeChangelist.ToString() : "0"; DefaultProperties["RootDir"] = CommandUtils.RootDirectory.FullName; DefaultProperties["IsBuildMachine"] = IsBuildMachine ? "true" : "false"; DefaultProperties["HostPlatform"] = HostPlatform.Current.HostEditorPlatform.ToString(); DefaultProperties["RestrictedFolderNames"] = String.Join(";", RestrictedFolders.Names); DefaultProperties["RestrictedFolderFilter"] = String.Join(";", RestrictedFolders.Names.Select(x => String.Format(".../{0}/...", x))); // Attempt to read existing Build Version information BuildVersion Version; if (BuildVersion.TryRead(BuildVersion.GetDefaultFileName(), out Version)) { DefaultProperties["EngineMajorVersion"] = Version.MajorVersion.ToString(); DefaultProperties["EngineMinorVersion"] = Version.MinorVersion.ToString(); DefaultProperties["EnginePatchVersion"] = Version.PatchVersion.ToString(); DefaultProperties["EngineCompatibleChange"] = Version.CompatibleChangelist.ToString(); } // Add any additional custom arguments from the command line (of the form -Set:X=Y) Dictionary <string, string> Arguments = new Dictionary <string, string>(StringComparer.InvariantCultureIgnoreCase); foreach (string Param in Params) { const string Prefix = "set:"; if (Param.StartsWith(Prefix, StringComparison.InvariantCultureIgnoreCase)) { int EqualsIdx = Param.IndexOf('='); if (EqualsIdx >= 0) { Arguments[Param.Substring(Prefix.Length, EqualsIdx - Prefix.Length)] = Param.Substring(EqualsIdx + 1); } else { LogWarning("Missing value for '{0}'", Param.Substring(Prefix.Length)); } } } // Find all the tasks from the loaded assemblies Dictionary <string, ScriptTask> NameToTask = new Dictionary <string, ScriptTask>(); if (!FindAvailableTasks(NameToTask, bPublicTasksOnly)) { return(ExitCode.Error_Unknown); } // Generate documentation if (DocumentationFileName != null) { GenerateDocumentation(NameToTask, new FileReference(DocumentationFileName)); return(ExitCode.Success); } // Create a schema for the given tasks ScriptSchema Schema = new ScriptSchema(NameToTask); if (SchemaFileName != null) { FileReference FullSchemaFileName = new FileReference(SchemaFileName); LogInformation("Writing schema to {0}...", FullSchemaFileName.FullName); Schema.Export(FullSchemaFileName); if (ScriptFileName == null) { return(ExitCode.Success); } } // Check there was a script specified if (ScriptFileName == null) { LogError("Missing -Script= parameter for BuildGraph"); return(ExitCode.Error_Unknown); } // Read the script from disk Graph Graph; if (!ScriptReader.TryRead(new FileReference(ScriptFileName), Arguments, DefaultProperties, Schema, out Graph)) { return(ExitCode.Error_Unknown); } // Create the temp storage handler DirectoryReference RootDir = new DirectoryReference(CommandUtils.CmdEnv.LocalRoot); TempStorage Storage = new TempStorage(RootDir, DirectoryReference.Combine(RootDir, "Engine", "Saved", "BuildGraph"), (SharedStorageDir == null)? null : new DirectoryReference(SharedStorageDir), bWriteToSharedStorage); if (!bResume) { Storage.CleanLocal(); } foreach (string CleanNode in CleanNodes) { Storage.CleanLocalNode(CleanNode); } // Convert the supplied target references into nodes HashSet <Node> TargetNodes = new HashSet <Node>(); if (TargetNames == null) { if (!bListOnly) { LogError("Missing -Target= parameter for BuildGraph"); return(ExitCode.Error_Unknown); } TargetNodes.UnionWith(Graph.Agents.SelectMany(x => x.Nodes)); } else { foreach (string TargetName in TargetNames.Split(new char[] { '+', ';' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim())) { Node[] Nodes; if (!Graph.TryResolveReference(TargetName, out Nodes)) { LogError("Target '{0}' is not in graph", TargetName); return(ExitCode.Error_Unknown); } TargetNodes.UnionWith(Nodes); } } // Try to acquire tokens for all the target nodes we want to build if (TokenSignature != null) { // Find all the lock files HashSet <FileReference> RequiredTokens = new HashSet <FileReference>(TargetNodes.SelectMany(x => x.RequiredTokens)); // List out all the required tokens if (SingleNodeName == null) { CommandUtils.LogInformation("Required tokens:"); foreach (Node Node in TargetNodes) { foreach (FileReference RequiredToken in Node.RequiredTokens) { CommandUtils.LogInformation(" '{0}' requires {1}", Node, RequiredToken); } } } // Try to create all the lock files List <FileReference> CreatedTokens = new List <FileReference>(); if (!bListOnly) { CreatedTokens.AddRange(RequiredTokens.Where(x => WriteTokenFile(x, TokenSignature))); } // Find all the tokens that we don't have Dictionary <FileReference, string> MissingTokens = new Dictionary <FileReference, string>(); foreach (FileReference RequiredToken in RequiredTokens) { string CurrentOwner = ReadTokenFile(RequiredToken); if (CurrentOwner != null && CurrentOwner != TokenSignature) { MissingTokens.Add(RequiredToken, CurrentOwner); } } // If we want to skip all the nodes with missing locks, adjust the target nodes to account for it if (MissingTokens.Count > 0) { if (bSkipTargetsWithoutTokens) { // Find all the nodes we're going to skip HashSet <Node> SkipNodes = new HashSet <Node>(); foreach (IGrouping <string, FileReference> MissingTokensForBuild in MissingTokens.GroupBy(x => x.Value, x => x.Key)) { LogInformation("Skipping the following nodes due to {0}:", MissingTokensForBuild.Key); foreach (FileReference MissingToken in MissingTokensForBuild) { foreach (Node SkipNode in TargetNodes.Where(x => x.RequiredTokens.Contains(MissingToken) && SkipNodes.Add(x))) { LogInformation(" {0}", SkipNode); } } } // Write a list of everything left over if (SkipNodes.Count > 0) { TargetNodes.ExceptWith(SkipNodes); LogInformation("Remaining target nodes:"); foreach (Node TargetNode in TargetNodes) { LogInformation(" {0}", TargetNode); } if (TargetNodes.Count == 0) { LogInformation(" None."); } } } else { foreach (KeyValuePair <FileReference, string> Pair in MissingTokens) { List <Node> SkipNodes = TargetNodes.Where(x => x.RequiredTokens.Contains(Pair.Key)).ToList(); LogError("Cannot run {0} due to previous build: {1}", String.Join(", ", SkipNodes), Pair.Value); } foreach (FileReference CreatedToken in CreatedTokens) { FileReference.Delete(CreatedToken); } return(ExitCode.Error_Unknown); } } } // Cull the graph to include only those nodes Graph.Select(TargetNodes); // Collapse any triggers in the graph which are marked to be skipped HashSet <ManualTrigger> SkipTriggers = new HashSet <ManualTrigger>(); if (bSkipTriggers) { SkipTriggers.UnionWith(Graph.NameToTrigger.Values); } else { foreach (string SkipTriggerName in SkipTriggerNames) { ManualTrigger SkipTrigger; if (!Graph.NameToTrigger.TryGetValue(TriggerName, out SkipTrigger)) { LogError("Couldn't find trigger '{0}'", TriggerName); return(ExitCode.Error_Unknown); } SkipTriggers.Add(SkipTrigger); } } Graph.SkipTriggers(SkipTriggers); // If a report for the whole build was requested, insert it into the graph if (ReportName != null) { Report NewReport = new Report(ReportName); NewReport.Nodes.UnionWith(Graph.Agents.SelectMany(x => x.Nodes)); Graph.NameToReport.Add(ReportName, NewReport); } // Write out the preprocessed script if (PreprocessedFileName != null) { FileReference PreprocessedFileLocation = new FileReference(PreprocessedFileName); LogInformation("Writing {0}...", PreprocessedFileLocation); Graph.Write(PreprocessedFileLocation, (SchemaFileName != null)? new FileReference(SchemaFileName) : null); return(ExitCode.Success); } // Find the triggers which we are explicitly running. ManualTrigger Trigger = null; if (TriggerName != null && !Graph.NameToTrigger.TryGetValue(TriggerName, out Trigger)) { LogError("Couldn't find trigger '{0}'", TriggerName); return(ExitCode.Error_Unknown); } // If we're just building a single node, find it Node SingleNode = null; if (SingleNodeName != null && !Graph.NameToNode.TryGetValue(SingleNodeName, out SingleNode)) { LogError("Node '{0}' is not in the trimmed graph", SingleNodeName); return(ExitCode.Error_Unknown); } // If we just want to show the contents of the graph, do so and exit. if (bListOnly) { HashSet <Node> CompletedNodes = FindCompletedNodes(Graph, Storage); Graph.Print(CompletedNodes, PrintOptions); } // Print out all the diagnostic messages which still apply, unless we're running a step as part of a build system or just listing the contents of the file. if (SingleNode == null && (!bListOnly || bShowDiagnostics)) { IEnumerable <GraphDiagnostic> Diagnostics = Graph.Diagnostics.Where(x => x.EnclosingTrigger == Trigger); foreach (GraphDiagnostic Diagnostic in Diagnostics) { if (Diagnostic.EventType == LogEventType.Console) { CommandUtils.LogInformation(Diagnostic.Message); } else if (Diagnostic.EventType == LogEventType.Warning) { CommandUtils.LogWarning(Diagnostic.Message); } else { CommandUtils.LogError(Diagnostic.Message); } } if (Diagnostics.Any(x => x.EventType == LogEventType.Error)) { return(ExitCode.Error_Unknown); } } // Export the graph to a file if (ExportFileName != null) { HashSet <Node> CompletedNodes = FindCompletedNodes(Graph, Storage); Graph.Print(CompletedNodes, PrintOptions); Graph.Export(new FileReference(ExportFileName), Trigger, CompletedNodes); return(ExitCode.Success); } // Execute the command if (!bListOnly) { if (SingleNode != null) { if (!BuildNode(new JobContext(this), Graph, SingleNode, Storage, bWithBanner: true)) { return(ExitCode.Error_Unknown); } } else { if (!BuildAllNodes(new JobContext(this), Graph, Storage)) { return(ExitCode.Error_Unknown); } } } return(ExitCode.Success); }
/// <summary> /// Runs Cook commandlet. /// </summary> /// <param name="ProjectName">Project name.</param> /// <param name="UE4Exe">The name of the UE4 Editor executable to use.</param> /// <param name="Maps">List of maps to cook, can be null in which case -MapIniSection=AllMaps is used.</param> /// <param name="Dirs">List of directories to cook, can be null</param> /// <param name="InternationalizationPreset">The name of a prebuilt set of internationalization data to be included.</param> /// <param name="CulturesToCook">List of culture names whose localized assets should be cooked, can be null (implying defaults should be used).</param> /// <param name="TargetPlatform">Target platform.</param> /// <param name="Parameters">List of additional parameters.</param> public static void CookCommandlet(FileReference ProjectName, string UE4Exe = "UE4Editor-Cmd.exe", string[] Maps = null, string[] Dirs = null, string InternationalizationPreset = "", string[] CulturesToCook = null, string TargetPlatform = "WindowsNoEditor", string Parameters = "-Unversioned") { string CommandletArguments = ""; if (IsNullOrEmpty(Maps)) { // MapsToCook = "-MapIniSection=AllMaps"; } else { string MapsToCookArg = "-Map=" + CombineCommandletParams(Maps).Trim(); CommandletArguments += (CommandletArguments.Length > 0 ? " " : "") + MapsToCookArg; } if (!IsNullOrEmpty(Dirs)) { foreach (string Dir in Dirs) { CommandletArguments += (CommandletArguments.Length > 0 ? " " : "") + String.Format("-CookDir={0}", CommandUtils.MakePathSafeToUseWithCommandLine(Dir)); } } if (!String.IsNullOrEmpty(InternationalizationPreset)) { CommandletArguments += (CommandletArguments.Length > 0 ? " " : "") + InternationalizationPreset; } if (!IsNullOrEmpty(CulturesToCook)) { string CulturesToCookArg = "-CookCultures=" + CombineCommandletParams(CulturesToCook).Trim(); CommandletArguments += (CommandletArguments.Length > 0 ? " " : "") + CulturesToCookArg; } RunCommandlet(ProjectName, UE4Exe, "Cook", String.Format("{0} -TargetPlatform={1} {2}", CommandletArguments, TargetPlatform, Parameters)); }
/// <summary> /// Print the contents of the graph /// </summary> /// <param name="CompletedNodes">Set of nodes which are already complete</param> /// <param name="PrintOptions">Options for how to print the graph</param> public void Print(HashSet <Node> CompletedNodes, GraphPrintOptions PrintOptions) { // Print the options if ((PrintOptions & GraphPrintOptions.ShowCommandLineOptions) != 0) { // Get the list of messages List <string> Messages = new List <string>(); foreach (GraphOption Option in Options) { StringBuilder Message = new StringBuilder(); Message.AppendFormat("-set:{0}=... {1}", Option.Name, Option.Description); if (!String.IsNullOrEmpty(Option.DefaultValue)) { Message.AppendFormat(" (Default: {0})", Option.DefaultValue); } Messages.Add(Message.ToString()); } // Format them to the log if (Messages.Count > 0) { CommandUtils.Log(""); CommandUtils.Log("Options:"); CommandUtils.Log(""); foreach (string Line in CommandUtils.FormatParams(Messages, 4, 24)) { CommandUtils.Log(Line); } } } // Get a list of all the triggers, including the null global one List <ManualTrigger> AllTriggers = new List <ManualTrigger>(); AllTriggers.Add(null); AllTriggers.AddRange(NameToTrigger.Values.OrderBy(x => x.QualifiedName)); // Output all the triggers in order CommandUtils.Log(""); CommandUtils.Log("Graph:"); foreach (ManualTrigger Trigger in AllTriggers) { // Filter everything by this trigger Dictionary <Agent, Node[]> FilteredAgentToNodes = new Dictionary <Agent, Node[]>(); foreach (Agent Agent in Agents) { Node[] Nodes = Agent.Nodes.Where(x => x.ControllingTrigger == Trigger).ToArray(); if (Nodes.Length > 0) { FilteredAgentToNodes[Agent] = Nodes; } } // Skip this trigger if there's nothing to display if (FilteredAgentToNodes.Count == 0) { continue; } // Print the trigger name CommandUtils.Log(" Trigger: {0}", (Trigger == null)? "None" : Trigger.QualifiedName); if (Trigger != null && PrintOptions.HasFlag(GraphPrintOptions.ShowNotifications)) { foreach (string User in Trigger.NotifyUsers) { CommandUtils.Log(" notify> {0}", User); } } // Output all the agents for this trigger foreach (Agent Agent in Agents) { Node[] Nodes; if (FilteredAgentToNodes.TryGetValue(Agent, out Nodes)) { CommandUtils.Log(" Agent: {0} ({1})", Agent.Name, String.Join(";", Agent.PossibleTypes)); foreach (Node Node in Nodes) { CommandUtils.Log(" Node: {0}{1}", Node.Name, CompletedNodes.Contains(Node)? " (completed)" : ""); if (PrintOptions.HasFlag(GraphPrintOptions.ShowDependencies)) { HashSet <Node> InputDependencies = new HashSet <Node>(Node.GetDirectInputDependencies()); foreach (Node InputDependency in InputDependencies) { CommandUtils.Log(" input> {0}", InputDependency.Name); } HashSet <Node> OrderDependencies = new HashSet <Node>(Node.GetDirectOrderDependencies()); foreach (Node OrderDependency in OrderDependencies.Except(InputDependencies)) { CommandUtils.Log(" after> {0}", OrderDependency.Name); } } if (PrintOptions.HasFlag(GraphPrintOptions.ShowNotifications)) { string Label = Node.bNotifyOnWarnings? "warnings" : "errors"; foreach (string User in Node.NotifyUsers) { CommandUtils.Log(" {0}> {1}", Label, User); } foreach (string Submitter in Node.NotifySubmitters) { CommandUtils.Log(" {0}> submitters to {1}", Label, Submitter); } } } } } } CommandUtils.Log(""); // Print out all the aggregates string[] AggregateNames = AggregateNameToNodes.Keys.OrderBy(x => x).ToArray(); if (AggregateNames.Length > 0) { CommandUtils.Log("Aggregates:"); foreach (string AggregateName in AggregateNames) { CommandUtils.Log(" {0}", AggregateName); } CommandUtils.Log(""); } }
public override void SetupOptionsForRun(ref string AppName, ref CommandUtils.ERunOptions Options, ref string CommandLine) { }
/// <summary> /// Parses command line parameter. /// </summary> /// <param name="ParamIndex">Parameter index</param> /// <param name="CommandLine">Command line</param> /// <param name="CurrentCommand">Recently parsed command</param> /// <param name="OutScriptsForProjectFileName">The only project to build scripts for</param> /// <param name="OutAdditionalScriptsFolders">Additional script locations</param> /// <returns>True if the parameter has been successfully parsed.</returns> private static void ParseParam(string CurrentParam, CommandInfo CurrentCommand, ref string OutScriptsForProjectFileName, List <string> OutAdditionalScriptsFolders) { bool bGlobalParam = false; foreach (var RegisteredParam in GlobalCommandLine.RegisteredArgs) { if (String.Compare(CurrentParam, RegisteredParam.Key, StringComparison.InvariantCultureIgnoreCase) == 0) { // Register and exit, we're done here. RegisteredParam.Value.Set(); bGlobalParam = true; break; } } // The parameter was not found in the list of global parameters, continue looking... if (CurrentParam.StartsWith("-ScriptsForProject=", StringComparison.InvariantCultureIgnoreCase)) { if (OutScriptsForProjectFileName != null) { throw new AutomationException("The -ProjectScripts argument may only be specified once"); } var ProjectFileName = CurrentParam.Substring(CurrentParam.IndexOf('=') + 1).Replace("\"", ""); if (!File.Exists(ProjectFileName)) { throw new AutomationException("Project '{0}' does not exist", ProjectFileName); } OutScriptsForProjectFileName = Path.GetFullPath(ProjectFileName); } else if (CurrentParam.StartsWith("-ScriptDir=", StringComparison.InvariantCultureIgnoreCase)) { var ScriptDir = CurrentParam.Substring(CurrentParam.IndexOf('=') + 1); if (Directory.Exists(ScriptDir)) { OutAdditionalScriptsFolders.Add(ScriptDir); Log.TraceVerbose("Found additional script dir: {0}", ScriptDir); } else { throw new AutomationException("Specified ScriptDir doesn't exist: {0}", ScriptDir); } } else if (CurrentParam.StartsWith("-")) { if (CurrentCommand != null) { CurrentCommand.Arguments.Add(CurrentParam.Substring(1)); } else if (!bGlobalParam) { throw new AutomationException("Unknown parameter {0} in the command line that does not belong to any command.", CurrentParam); } } else if (CurrentParam.Contains("=")) { // Environment variable int ValueStartIndex = CurrentParam.IndexOf('=') + 1; string EnvVarName = CurrentParam.Substring(0, ValueStartIndex - 1); if (String.IsNullOrEmpty(EnvVarName)) { throw new AutomationException("Unable to parse environment variable that has no name. Error when parsing command line param {0}", CurrentParam); } string EnvVarValue = CurrentParam.Substring(ValueStartIndex); CommandUtils.SetEnvVar(EnvVarName, EnvVarValue); } }
/// <summary> /// Gets a parameter value from the command line if it hasn't been specified in the constructor. /// If the command line is not available, default value will be used. /// </summary> /// <param name="Command">Command to parse the command line for. Can be null.</param> /// <param name="SpecifiedValue">Value specified in the constructor (or not)</param> /// <param name="ParamName">Command line parameter name to parse.</param> /// <param name="Default">Default value</param> /// <returns>Parameter value.</returns> string ParseParamValueIfNotSpecified(CommandUtils Command, string SpecifiedValue, string ParamName, string Default = "") { if (SpecifiedValue != null) { return SpecifiedValue; } else if (Command != null) { return Command.ParseParamValue(ParamName, Default); } else { return Default; } }
/// <summary> /// Main method. /// </summary> /// <param name="Arguments">Command line</param> public static ExitCode Process(string[] Arguments, StartupTraceListener StartupListener) { // Initial check for local or build machine runs BEFORE we parse the command line (We need this value set // in case something throws the exception while parsing the command line) IsBuildMachine = !String.IsNullOrEmpty(Environment.GetEnvironmentVariable("uebp_LOCAL_ROOT")) || Arguments.Any(x => x.Equals("-BuildMachine", StringComparison.InvariantCultureIgnoreCase)); // Scan the command line for commands to execute. var CommandsToExecute = new List <CommandInfo>(); string OutScriptsForProjectFileName; var AdditionalScriptsFolders = new List <string>(); ParseCommandLine(Arguments, CommandsToExecute, out OutScriptsForProjectFileName, AdditionalScriptsFolders); // Get the path to the telemetry file, if present string TelemetryFile = CommandUtils.ParseParamValue(Arguments, "-Telemetry"); Log.TraceVerbose("IsBuildMachine={0}", IsBuildMachine); Environment.SetEnvironmentVariable("IsBuildMachine", IsBuildMachine ? "1" : "0"); // should we kill processes on exit ShouldKillProcesses = !GlobalCommandLine.NoKill; Log.TraceVerbose("ShouldKillProcesses={0}", ShouldKillProcesses); if (CommandsToExecute.Count == 0 && GlobalCommandLine.Help) { DisplayHelp(); return(ExitCode.Success); } // Disable AutoSDKs if specified on the command line if (GlobalCommandLine.NoAutoSDK) { PlatformExports.PreventAutoSDKSwitching(); } // Setup environment Log.TraceLog("Setting up command environment."); CommandUtils.InitCommandEnvironment(); // Determine if the engine is installed bIsEngineInstalled = GlobalCommandLine.Installed; string InstalledBuildFile = Path.Combine(CommandUtils.CmdEnv.LocalRoot, "Engine", "Build", "InstalledBuild.txt"); bIsEngineInstalled |= File.Exists(InstalledBuildFile); if (bIsEngineInstalled.Value) { bIsEngineInstalled = !GlobalCommandLine.NotInstalledEngine; } else { bIsEngineInstalled = GlobalCommandLine.InstalledEngine; } // Create the log file, and flush the startup listener to it TraceListener LogTraceListener = LogUtils.AddLogFileListener(CommandUtils.CmdEnv.LogFolder, CommandUtils.CmdEnv.FinalLogFolder); StartupListener.CopyTo(LogTraceListener); Trace.Listeners.Remove(StartupListener); // Initialize UBT if (!UnrealBuildTool.PlatformExports.Initialize(bIsEngineInstalled.Value)) { Log.TraceInformation("Failed to initialize UBT"); return(ExitCode.Error_Unknown); } // Fill in the project info UnrealBuildTool.UProjectInfo.FillProjectInfo(); // Clean rules folders up ProjectUtils.CleanupFolders(); // Compile scripts. ScriptCompiler Compiler = new ScriptCompiler(); using (TelemetryStopwatch ScriptCompileStopwatch = new TelemetryStopwatch("ScriptCompile")) { Compiler.FindAndCompileAllScripts(OutScriptsForProjectFileName, AdditionalScriptsFolders); } if (GlobalCommandLine.CompileOnly) { Log.TraceInformation("Compilation successful, exiting (CompileOnly)"); return(ExitCode.Success); } if (GlobalCommandLine.List) { ListAvailableCommands(Compiler.Commands); return(ExitCode.Success); } if (GlobalCommandLine.Help) { DisplayHelp(CommandsToExecute, Compiler.Commands); return(ExitCode.Success); } // Enable or disable P4 support CommandUtils.InitP4Support(CommandsToExecute, Compiler.Commands); if (CommandUtils.P4Enabled) { Log.TraceLog("Setting up Perforce environment."); CommandUtils.InitP4Environment(); CommandUtils.InitDefaultP4Connection(); } // Find and execute commands. ExitCode Result = Execute(CommandsToExecute, Compiler.Commands); if (TelemetryFile != null) { Directory.CreateDirectory(Path.GetDirectoryName(TelemetryFile)); CommandUtils.Telemetry.Write(TelemetryFile); } return(Result); }
/// <summary> /// Sets up platforms /// </summary> /// <param name="DependentPlatformMap">Set with a mapping from source->destination if specified on command line</param> /// <param name="Command">The command line to parse</param> /// <param name="OverrideTargetPlatforms">If passed use this always</param> /// <param name="DefaultTargetPlatforms">Use this if nothing is passed on command line</param> /// <param name="AllowPlatformParams">Allow raw -platform options</param> /// <param name="PlatformParamNames">Possible -parameters to check for</param> /// <returns>List of platforms parsed from the command line</returns> private List<UnrealTargetPlatform> SetupTargetPlatforms(ref Dictionary<UnrealTargetPlatform,UnrealTargetPlatform> DependentPlatformMap, CommandUtils Command, List<UnrealTargetPlatform> OverrideTargetPlatforms, List<UnrealTargetPlatform> DefaultTargetPlatforms, bool AllowPlatformParams, params string[] PlatformParamNames) { List<UnrealTargetPlatform> TargetPlatforms = null; if (CommandUtils.IsNullOrEmpty(OverrideTargetPlatforms)) { if (Command != null) { // Parse the command line, we support the following params: // -'PlatformParamNames[n]'=Platform_1+Platform_2+...+Platform_k // or (if AllowPlatformParams is true) // -Platform_1 -Platform_2 ... -Platform_k string CmdLinePlatform = null; foreach (var ParamName in PlatformParamNames) { CmdLinePlatform = Command.ParseParamValue(ParamName); if (!String.IsNullOrEmpty(CmdLinePlatform)) { break; } } if (!String.IsNullOrEmpty(CmdLinePlatform)) { // Get all platforms from the param value: Platform_1+Platform_2+...+Platform_k TargetPlatforms = new List<UnrealTargetPlatform>(); var Platforms = new List<string>(CmdLinePlatform.Split('+')); foreach (var PlatformName in Platforms) { // Look for dependent platforms, Source_1.Dependent_1+Source_2.Dependent_2+Standalone_3 var SubPlatforms = new List<string>(PlatformName.Split('.')); foreach (var SubPlatformName in SubPlatforms) { UnrealTargetPlatform NewPlatform = (UnrealTargetPlatform)Enum.Parse(typeof(UnrealTargetPlatform), SubPlatformName, true); TargetPlatforms.Add(NewPlatform); if (SubPlatformName != SubPlatforms[0]) { // We're a dependent platform so add ourselves to the map, pointing to the first element in the list DependentPlatformMap.Add(NewPlatform, (UnrealTargetPlatform)Enum.Parse(typeof(UnrealTargetPlatform), SubPlatforms[0], true)); } } } } else if (AllowPlatformParams) { // Look up platform names in the command line: -Platform_1 -Platform_2 ... -Platform_k TargetPlatforms = new List<UnrealTargetPlatform>(); foreach (var Plat in CommandUtils.KnownTargetPlatforms) { if (Command.ParseParam(Plat.ToString())) { TargetPlatforms.Add(Plat); } } } } } else { TargetPlatforms = OverrideTargetPlatforms; } if (CommandUtils.IsNullOrEmpty(TargetPlatforms)) { // Revert to single default platform - the current platform we're running TargetPlatforms = DefaultTargetPlatforms; } return TargetPlatforms; }
/// <summary> /// Display AutomationTool.exe help. /// </summary> private static void DisplayHelp() { CommandUtils.LogHelp(typeof(Automation)); }
/// <summary> /// Sets up platforms /// </summary> /// <param name="DependentPlatformMap">Set with a mapping from source->destination if specified on command line</param> /// <param name="Command">The command line to parse</param> /// <param name="OverrideTargetPlatforms">If passed use this always</param> /// <param name="DefaultTargetPlatforms">Use this if nothing is passed on command line</param> /// <param name="AllowPlatformParams">Allow raw -platform options</param> /// <param name="PlatformParamNames">Possible -parameters to check for</param> /// <returns>List of platforms parsed from the command line</returns> private List<TargetPlatformDescriptor> SetupTargetPlatforms(ref Dictionary<TargetPlatformDescriptor, TargetPlatformDescriptor> DependentPlatformMap, CommandUtils Command, List<TargetPlatformDescriptor> OverrideTargetPlatforms, List<TargetPlatformDescriptor> DefaultTargetPlatforms, bool AllowPlatformParams, params string[] PlatformParamNames) { List<TargetPlatformDescriptor> TargetPlatforms = null; if (CommandUtils.IsNullOrEmpty(OverrideTargetPlatforms)) { if (Command != null) { // Parse the command line, we support the following params: // -'PlatformParamNames[n]'=Platform_1+Platform_2+...+Platform_k // or (if AllowPlatformParams is true) // -Platform_1 -Platform_2 ... -Platform_k string CmdLinePlatform = null; foreach (var ParamName in PlatformParamNames) { CmdLinePlatform = Command.ParseParamValue(ParamName); if (!String.IsNullOrEmpty(CmdLinePlatform)) { break; } } List<string> CookFlavors = null; { string CmdLineCookFlavor = Command.ParseParamValue("cookflavor"); if (!String.IsNullOrEmpty(CmdLineCookFlavor)) { CookFlavors = new List<string>(CmdLineCookFlavor.Split('+')); } } if (!String.IsNullOrEmpty(CmdLinePlatform)) { // Get all platforms from the param value: Platform_1+Platform_2+...+Platform_k TargetPlatforms = new List<TargetPlatformDescriptor>(); var PlatformNames = new List<string>(CmdLinePlatform.Split('+')); foreach (var PlatformName in PlatformNames) { // Look for dependent platforms, Source_1.Dependent_1+Source_2.Dependent_2+Standalone_3 var SubPlatformNames = new List<string>(PlatformName.Split('.')); foreach (var SubPlatformName in SubPlatformNames) { UnrealTargetPlatform NewPlatformType = (UnrealTargetPlatform)Enum.Parse(typeof(UnrealTargetPlatform), SubPlatformName, true); // generate all valid platform descriptions for this platform type + cook flavors List<TargetPlatformDescriptor> PlatformDescriptors = Platform.GetValidTargetPlatforms(NewPlatformType, CookFlavors); TargetPlatforms.AddRange(PlatformDescriptors); if (SubPlatformName != SubPlatformNames[0]) { // This is not supported with cook flavors if (!CommandUtils.IsNullOrEmpty(CookFlavors)) { throw new AutomationException("Cook flavors are not supported for dependent platforms!"); } // We're a dependent platform so add ourselves to the map, pointing to the first element in the list UnrealTargetPlatform FirstPlatformType = (UnrealTargetPlatform)Enum.Parse(typeof(UnrealTargetPlatform), SubPlatformNames[0], true); DependentPlatformMap.Add(new TargetPlatformDescriptor(NewPlatformType), new TargetPlatformDescriptor(FirstPlatformType)); } } } } else if (AllowPlatformParams) { // Look up platform names in the command line: -Platform_1 -Platform_2 ... -Platform_k TargetPlatforms = new List<TargetPlatformDescriptor>(); foreach (UnrealTargetPlatform PlatType in Enum.GetValues(typeof(UnrealTargetPlatform))) { if (PlatType != UnrealTargetPlatform.Unknown) { if (Command.ParseParam(PlatType.ToString())) { List<TargetPlatformDescriptor> PlatformDescriptors = Platform.GetValidTargetPlatforms(PlatType, CookFlavors); TargetPlatforms.AddRange(PlatformDescriptors); } } } } } } else { TargetPlatforms = OverrideTargetPlatforms; } if (CommandUtils.IsNullOrEmpty(TargetPlatforms)) { // Revert to single default platform - the current platform we're running TargetPlatforms = DefaultTargetPlatforms; } return TargetPlatforms; }
/// <summary> /// Runs UBT with the specified commandline. Automatically creates a logfile. When /// no LogName is specified, the executable name is used as logfile base name. /// </summary> /// <param name="Env">Environment to use.</param> /// <param name="CommandLine">Commandline to pass on to UBT.</param> /// <param name="LogName">Optional logfile name.</param> public static void RunUBT(CommandEnvironment Env, string UBTExecutable, string CommandLine) { if (!FileExists(UBTExecutable)) { throw new AutomationException("Unable to find UBT executable: " + UBTExecutable); } if (GlobalCommandLine.VS2015) { CommandLine += " -2015"; } if (!IsBuildMachine && UnrealBuildTool.BuildHostPlatform.Current.Platform == UnrealBuildTool.UnrealTargetPlatform.Mac) { CommandLine += " -nocreatestub"; } CommandLine += " -NoHotReload"; if (bJunkDeleted || GlobalCommandLine.IgnoreJunk) { // UBT has already deleted junk files, make sure it doesn't do it again CommandLine += " -ignorejunk"; } else { // UBT will delete junk on first run bJunkDeleted = true; } string BaseLogName = String.Format("UBT-{0}", String.Join("-", SharedUtils.ParseCommandLine(CommandLine).Where(x => !x.Contains('/') && !x.Contains('\\') && !x.StartsWith("-")))); string LogName; for (int Attempt = 1;; Attempt++) { LogName = String.Format("{0}.txt", (Attempt == 1)? BaseLogName : String.Format("{0}_{1}", BaseLogName, Attempt)); FileReference LogLocation = FileReference.Combine(new DirectoryReference(Env.LogFolder), LogName); if (!FileReference.Exists(LogLocation)) { CommandLine += String.Format(" -log=\"{0}\"", LogLocation); break; } if (Attempt >= 50) { throw new AutomationException("Unable to find name for UBT log file after {0} attempts", Attempt); } } IProcessResult Result = Run(UBTExecutable, CommandLine, Options: ERunOptions.AllowSpew | ERunOptions.NoStdOutCapture); if (Result.ExitCode != 0) { throw new AutomationException((ExitCode)Result.ExitCode, "UnrealBuildTool failed. See log for more details. ({0})", CommandUtils.CombinePaths(Env.FinalLogFolder, LogName)); } }
/// <summary> /// Constructor. Be sure to use this.ParamName to set the actual property name as parameter names and property names /// overlap here. /// If a parameter value is not set, it will be parsed from the command line; if the command is null, the default value will be used. /// </summary> public ProjectParams( FileReference RawProjectPath, CommandUtils Command = null, string Device = null, string MapToRun = null, string AdditionalServerMapParams = null, ParamList<string> Port = null, string RunCommandline = null, string StageCommandline = null, string BundleName = null, string StageDirectoryParam = null, string UE4Exe = null, string SignPak = null, List<UnrealTargetConfiguration> ClientConfigsToBuild = null, List<UnrealTargetConfiguration> ServerConfigsToBuild = null, ParamList<string> MapsToCook = null, ParamList<string> DirectoriesToCook = null, string InternationalizationPreset = null, ParamList<string> CulturesToCook = null, ParamList<string> ClientCookedTargets = null, ParamList<string> EditorTargets = null, ParamList<string> ServerCookedTargets = null, List<TargetPlatformDescriptor> ClientTargetPlatforms = null, Dictionary<TargetPlatformDescriptor, TargetPlatformDescriptor> ClientDependentPlatformMap = null, List<TargetPlatformDescriptor> ServerTargetPlatforms = null, Dictionary<TargetPlatformDescriptor, TargetPlatformDescriptor> ServerDependentPlatformMap = null, bool? Build = null, bool? Cook = null, bool? Run = null, bool? SkipServer = null, bool? Clean = null, bool? Compressed = null, bool? UseDebugParamForEditorExe = null, bool? IterativeCooking = null, bool? CookAll = null, bool? CookPartialGC = null, bool? CookMapsOnly = null, bool? CookOnTheFly = null, bool? CookOnTheFlyStreaming = null, bool? UnversionedCookedContent = null, bool? EncryptIniFiles = null, bool? SkipCookingEditorContent = null, int? NumCookersToSpawn = null, string AdditionalCookerOptions = null, string BasedOnReleaseVersion = null, string CreateReleaseVersion = null, string CreateReleaseVersionBasePath = null, string BasedOnReleaseVersionBasePath = null, bool? GeneratePatch = null, string DLCName = null, string DiffCookedContentPath = null, bool? DLCIncludeEngineContent = null, bool? NewCook = null, bool? OldCook = null, bool? CrashReporter = null, bool? DedicatedServer = null, bool? Client = null, bool? Deploy = null, bool? FileServer = null, bool? Foreign = null, bool? ForeignCode = null, bool? LogWindow = null, bool? NoCleanStage = null, bool? NoClient = null, bool? NoDebugInfo = null, bool? NoXGE = null, bool? Package = null, bool? Pak = null, bool? Prereqs = null, string AppLocalDirectory = null, bool? NoBootstrapExe = null, bool? SignedPak = null, bool? NullRHI = null, bool? FakeClient = null, bool? EditorTest = null, bool? RunAutomationTests = null, string RunAutomationTest = null, int? CrashIndex = null, bool? SkipCook = null, bool? SkipCookOnTheFly = null, bool? SkipPak = null, bool? SkipStage = null, bool? Stage = null, bool? Manifests = null, bool? CreateChunkInstall = null, bool? Unattended = null, int? NumClients = null, bool? Archive = null, string ArchiveDirectoryParam = null, bool? ArchiveMetaData = null, bool? CreateAppBundle = null, ParamList<string> ProgramTargets = null, bool? Distribution = null, bool? Prebuilt = null, int? RunTimeoutSeconds = null, string SpecifiedArchitecture = null, bool? IterativeDeploy = null, bool? FastCook = null, bool? IgnoreCookErrors = null, bool? RunAssetNativization = null, bool? CodeSign = null, bool? TreatNonShippingBinariesAsDebugFiles = null, string Provision = null, string Certificate = null, ParamList<string> InMapsToRebuildLightMaps = null, ParamList<string> TitleID = null ) { // //// Use this.Name with properties and fields! // this.RawProjectPath = RawProjectPath; if (DirectoriesToCook != null) { this.DirectoriesToCook = DirectoriesToCook; } this.InternationalizationPreset = ParseParamValueIfNotSpecified(Command, InternationalizationPreset, "i18npreset"); // If not specified in parameters, check commandline. if (CulturesToCook == null) { if (Command != null) { var CookCulturesString = Command.ParseParamValue("CookCultures"); if (CookCulturesString != null) { this.CulturesToCook = new ParamList<string>(CookCulturesString.Split(',')); } } } else { this.CulturesToCook = CulturesToCook; } if (ClientCookedTargets != null) { this.ClientCookedTargets = ClientCookedTargets; } if (ServerCookedTargets != null) { this.ServerCookedTargets = ServerCookedTargets; } if (EditorTargets != null) { this.EditorTargets = EditorTargets; } if (ProgramTargets != null) { this.ProgramTargets = ProgramTargets; } // Parse command line params for client platforms "-TargetPlatform=Win64+Mac", "-Platform=Win64+Mac" and also "-Win64", "-Mac" etc. if (ClientDependentPlatformMap != null) { this.ClientDependentPlatformMap = ClientDependentPlatformMap; } List<TargetPlatformDescriptor> DefaultTargetPlatforms = new ParamList<TargetPlatformDescriptor>(new TargetPlatformDescriptor(HostPlatform.Current.HostEditorPlatform)); this.ClientTargetPlatforms = SetupTargetPlatforms(ref this.ClientDependentPlatformMap, Command, ClientTargetPlatforms, DefaultTargetPlatforms, true, "TargetPlatform", "Platform"); // Parse command line params for server platforms "-ServerTargetPlatform=Win64+Mac", "-ServerPlatform=Win64+Mac". "-Win64" etc is not allowed here if (ServerDependentPlatformMap != null) { this.ServerDependentPlatformMap = ServerDependentPlatformMap; } this.ServerTargetPlatforms = SetupTargetPlatforms(ref this.ServerDependentPlatformMap, Command, ServerTargetPlatforms, this.ClientTargetPlatforms, false, "ServerTargetPlatform", "ServerPlatform"); this.Build = GetParamValueIfNotSpecified(Command, Build, this.Build, "build"); this.Run = GetParamValueIfNotSpecified(Command, Run, this.Run, "run"); this.Cook = GetParamValueIfNotSpecified(Command, Cook, this.Cook, "cook"); this.NewCook = GetParamValueIfNotSpecified(Command, NewCook, this.NewCook, "NewCook"); this.OldCook = GetParamValueIfNotSpecified(Command, OldCook, this.OldCook, "OldCook"); this.CreateReleaseVersionBasePath = ParseParamValueIfNotSpecified(Command, CreateReleaseVersionBasePath, "createreleaseversionroot", String.Empty); this.BasedOnReleaseVersionBasePath = ParseParamValueIfNotSpecified(Command, BasedOnReleaseVersionBasePath, "basedonreleaseversionroot", String.Empty); this.CreateReleaseVersion = ParseParamValueIfNotSpecified(Command, CreateReleaseVersion, "createreleaseversion", String.Empty); this.BasedOnReleaseVersion = ParseParamValueIfNotSpecified(Command, BasedOnReleaseVersion, "basedonreleaseversion", String.Empty); this.GeneratePatch = GetParamValueIfNotSpecified(Command, GeneratePatch, this.GeneratePatch, "GeneratePatch"); this.AdditionalCookerOptions = ParseParamValueIfNotSpecified(Command, AdditionalCookerOptions, "AdditionalCookerOptions", String.Empty); this.DLCName = ParseParamValueIfNotSpecified(Command, DLCName, "DLCName", String.Empty); this.DiffCookedContentPath = ParseParamValueIfNotSpecified(Command, DiffCookedContentPath, "DiffCookedContentPath", String.Empty); this.DLCIncludeEngineContent = GetParamValueIfNotSpecified(Command, DLCIncludeEngineContent, this.DLCIncludeEngineContent, "DLCIncludeEngineContent"); this.SkipCook = GetParamValueIfNotSpecified(Command, SkipCook, this.SkipCook, "skipcook"); if (this.SkipCook) { this.Cook = true; } this.Clean = GetOptionalParamValueIfNotSpecified(Command, Clean, this.Clean, "clean", null); this.SignPak = ParseParamValueIfNotSpecified(Command, SignPak, "signpak", String.Empty); this.SignedPak = !String.IsNullOrEmpty(this.SignPak) || GetParamValueIfNotSpecified(Command, SignedPak, this.SignedPak, "signedpak"); if (string.IsNullOrEmpty(this.SignPak)) { this.SignPak = Path.Combine(RawProjectPath.Directory.FullName, @"Build\NoRedist\Keys.txt"); if (!File.Exists(this.SignPak)) { this.SignPak = null; } } this.Pak = GetParamValueIfNotSpecified(Command, Pak, this.Pak, "pak"); this.SkipPak = GetParamValueIfNotSpecified(Command, SkipPak, this.SkipPak, "skippak"); if (this.SkipPak) { this.Pak = true; } this.NoXGE = GetParamValueIfNotSpecified(Command, NoXGE, this.NoXGE, "noxge"); this.CookOnTheFly = GetParamValueIfNotSpecified(Command, CookOnTheFly, this.CookOnTheFly, "cookonthefly"); if (this.CookOnTheFly && this.SkipCook) { this.Cook = false; } this.CookOnTheFlyStreaming = GetParamValueIfNotSpecified(Command, CookOnTheFlyStreaming, this.CookOnTheFlyStreaming, "cookontheflystreaming"); this.UnversionedCookedContent = GetParamValueIfNotSpecified(Command, UnversionedCookedContent, this.UnversionedCookedContent, "UnversionedCookedContent"); this.EncryptIniFiles = GetParamValueIfNotSpecified(Command, EncryptIniFiles, this.EncryptIniFiles, "EncryptIniFiles"); this.SkipCookingEditorContent = GetParamValueIfNotSpecified(Command, SkipCookingEditorContent, this.SkipCookingEditorContent, "SkipCookingEditorContent"); if (NumCookersToSpawn.HasValue) { this.NumCookersToSpawn = NumCookersToSpawn.Value; } else if (Command != null) { this.NumCookersToSpawn = Command.ParseParamInt("NumCookersToSpawn"); } this.Compressed = GetParamValueIfNotSpecified(Command, Compressed, this.Compressed, "compressed"); this.UseDebugParamForEditorExe = GetParamValueIfNotSpecified(Command, UseDebugParamForEditorExe, this.UseDebugParamForEditorExe, "UseDebugParamForEditorExe"); this.IterativeCooking = GetParamValueIfNotSpecified(Command, IterativeCooking, this.IterativeCooking, new string[] { "iterativecooking", "iterate" } ); this.SkipCookOnTheFly = GetParamValueIfNotSpecified(Command, SkipCookOnTheFly, this.SkipCookOnTheFly, "skipcookonthefly"); this.CookAll = GetParamValueIfNotSpecified(Command, CookAll, this.CookAll, "CookAll"); this.CookPartialGC = GetParamValueIfNotSpecified(Command, CookPartialGC, this.CookPartialGC, "CookPartialGC"); this.CookMapsOnly = GetParamValueIfNotSpecified(Command, CookMapsOnly, this.CookMapsOnly, "CookMapsOnly"); this.FileServer = GetParamValueIfNotSpecified(Command, FileServer, this.FileServer, "fileserver"); this.DedicatedServer = GetParamValueIfNotSpecified(Command, DedicatedServer, this.DedicatedServer, "dedicatedserver", "server"); this.Client = GetParamValueIfNotSpecified(Command, Client, this.Client, "client"); /*if( this.Client ) { this.DedicatedServer = true; }*/ this.NoClient = GetParamValueIfNotSpecified(Command, NoClient, this.NoClient, "noclient"); this.LogWindow = GetParamValueIfNotSpecified(Command, LogWindow, this.LogWindow, "logwindow"); this.Stage = GetParamValueIfNotSpecified(Command, Stage, this.Stage, "stage"); this.SkipStage = GetParamValueIfNotSpecified(Command, SkipStage, this.SkipStage, "skipstage"); if (this.SkipStage) { this.Stage = true; } this.StageDirectoryParam = ParseParamValueIfNotSpecified(Command, StageDirectoryParam, "stagingdirectory", String.Empty, true); this.bCodeSign = GetParamValueIfNotSpecified(Command, CodeSign, CommandUtils.IsBuildMachine, "CodeSign"); this.bTreatNonShippingBinariesAsDebugFiles = GetParamValueIfNotSpecified(Command, TreatNonShippingBinariesAsDebugFiles, false, "TreatNonShippingBinariesAsDebugFiles"); this.Manifests = GetParamValueIfNotSpecified(Command, Manifests, this.Manifests, "manifests"); this.CreateChunkInstall = GetParamValueIfNotSpecified(Command, CreateChunkInstall, this.CreateChunkInstall, "createchunkinstall"); this.ChunkInstallDirectory = ParseParamValueIfNotSpecified(Command, ChunkInstallDirectory, "chunkinstalldirectory", String.Empty, true); this.ChunkInstallVersionString = ParseParamValueIfNotSpecified(Command, ChunkInstallVersionString, "chunkinstallversion", String.Empty, true); this.Archive = GetParamValueIfNotSpecified(Command, Archive, this.Archive, "archive"); this.ArchiveDirectoryParam = ParseParamValueIfNotSpecified(Command, ArchiveDirectoryParam, "archivedirectory", String.Empty, true); this.ArchiveMetaData = GetParamValueIfNotSpecified(Command, ArchiveMetaData, this.ArchiveMetaData, "archivemetadata"); this.CreateAppBundle = GetParamValueIfNotSpecified(Command, CreateAppBundle, true, "createappbundle"); this.Distribution = GetParamValueIfNotSpecified(Command, Distribution, this.Distribution, "distribution"); this.Prereqs = GetParamValueIfNotSpecified(Command, Prereqs, this.Prereqs, "prereqs"); this.AppLocalDirectory = ParseParamValueIfNotSpecified(Command, AppLocalDirectory, "applocaldirectory", String.Empty, true); this.NoBootstrapExe = GetParamValueIfNotSpecified(Command, NoBootstrapExe, this.NoBootstrapExe, "nobootstrapexe"); this.Prebuilt = GetParamValueIfNotSpecified(Command, Prebuilt, this.Prebuilt, "prebuilt"); if (this.Prebuilt) { this.SkipCook = true; /*this.SkipPak = true; this.SkipStage = true; this.Pak = true; this.Stage = true;*/ this.Cook = true; this.Archive = true; this.Deploy = true; this.Run = true; //this.StageDirectoryParam = this.PrebuiltDir; } this.NoDebugInfo = GetParamValueIfNotSpecified(Command, NoDebugInfo, this.NoDebugInfo, "nodebuginfo"); this.NoCleanStage = GetParamValueIfNotSpecified(Command, NoCleanStage, this.NoCleanStage, "nocleanstage"); this.MapToRun = ParseParamValueIfNotSpecified(Command, MapToRun, "map", String.Empty); this.AdditionalServerMapParams = ParseParamValueIfNotSpecified(Command, AdditionalServerMapParams, "AdditionalServerMapParams", String.Empty); this.Foreign = GetParamValueIfNotSpecified(Command, Foreign, this.Foreign, "foreign"); this.ForeignCode = GetParamValueIfNotSpecified(Command, ForeignCode, this.ForeignCode, "foreigncode"); this.StageCommandline = ParseParamValueIfNotSpecified(Command, StageCommandline, "cmdline"); this.BundleName = ParseParamValueIfNotSpecified(Command, BundleName, "bundlename"); this.RunCommandline = ParseParamValueIfNotSpecified(Command, RunCommandline, "addcmdline"); this.RunCommandline = this.RunCommandline.Replace('\'', '\"'); // replace any single quotes with double quotes this.ServerCommandline = ParseParamValueIfNotSpecified(Command, ServerCommandline, "servercmdline"); this.ServerCommandline = this.ServerCommandline.Replace('\'', '\"'); // replace any single quotes with double quotes this.Package = GetParamValueIfNotSpecified(Command, Package, this.Package, "package"); this.Deploy = GetParamValueIfNotSpecified(Command, Deploy, this.Deploy, "deploy"); this.IterativeDeploy = GetParamValueIfNotSpecified(Command, IterativeDeploy, this.IterativeDeploy, new string[] {"iterativedeploy", "iterate" } ); this.FastCook = GetParamValueIfNotSpecified(Command, FastCook, this.FastCook, "FastCook"); this.IgnoreCookErrors = GetParamValueIfNotSpecified(Command, IgnoreCookErrors, this.IgnoreCookErrors, "IgnoreCookErrors"); this.RunAssetNativization = GetParamValueIfNotSpecified(Command, RunAssetNativization, this.RunAssetNativization, "nativizeAssets"); string DeviceString = ParseParamValueIfNotSpecified(Command, Device, "device", String.Empty).Trim(new char[] { '\"' }); if(DeviceString == "") { this.Devices = new ParamList<string>(""); this.DeviceNames = new ParamList<string>(""); } else { this.Devices = new ParamList<string>(DeviceString.Split('+')); this.DeviceNames = new ParamList<string>(); foreach (var d in this.Devices) { // strip the platform prefix the specified device. if (d.Contains("@")) { this.DeviceNames.Add(d.Substring(d.IndexOf("@") + 1)); } else { this.DeviceNames.Add(d); } } } this.Provision = ParseParamValueIfNotSpecified(Command, Provision, "provision", String.Empty, true); this.Certificate = ParseParamValueIfNotSpecified(Command, Certificate, "certificate", String.Empty, true); this.ServerDevice = ParseParamValueIfNotSpecified(Command, ServerDevice, "serverdevice", this.Devices.Count > 0 ? this.Devices[0] : ""); this.NullRHI = GetParamValueIfNotSpecified(Command, NullRHI, this.NullRHI, "nullrhi"); this.FakeClient = GetParamValueIfNotSpecified(Command, FakeClient, this.FakeClient, "fakeclient"); this.EditorTest = GetParamValueIfNotSpecified(Command, EditorTest, this.EditorTest, "editortest"); this.RunAutomationTest = ParseParamValueIfNotSpecified(Command, RunAutomationTest, "RunAutomationTest"); this.RunAutomationTests = this.RunAutomationTest != "" || GetParamValueIfNotSpecified(Command, RunAutomationTests, this.RunAutomationTests, "RunAutomationTests"); this.SkipServer = GetParamValueIfNotSpecified(Command, SkipServer, this.SkipServer, "skipserver"); this.UE4Exe = ParseParamValueIfNotSpecified(Command, UE4Exe, "ue4exe", "UE4Editor-Cmd.exe"); this.Unattended = GetParamValueIfNotSpecified(Command, Unattended, this.Unattended, "unattended"); this.DeviceUsername = ParseParamValueIfNotSpecified(Command, DeviceUsername, "deviceuser", String.Empty); this.DevicePassword = ParseParamValueIfNotSpecified(Command, DevicePassword, "devicepass", String.Empty); this.CrashReporter = GetParamValueIfNotSpecified(Command, CrashReporter, this.CrashReporter, "crashreporter"); this.SpecifiedArchitecture = ParseParamValueIfNotSpecified(Command, SpecifiedArchitecture, "specifiedarchitecture", String.Empty); if (ClientConfigsToBuild == null) { if (Command != null) { var ClientConfig = Command.ParseParamValue("clientconfig"); if (ClientConfig == null) ClientConfig = Command.ParseParamValue("config"); if (ClientConfig != null) { this.ClientConfigsToBuild = new List<UnrealTargetConfiguration>(); var Configs = new ParamList<string>(ClientConfig.Split('+')); foreach (var ConfigName in Configs) { this.ClientConfigsToBuild.Add((UnrealTargetConfiguration)Enum.Parse(typeof(UnrealTargetConfiguration), ConfigName, true)); } } } } else { this.ClientConfigsToBuild = ClientConfigsToBuild; } if (Port == null) { if( Command != null ) { this.Port = new ParamList<string>(); var PortString = Command.ParseParamValue("port"); if (String.IsNullOrEmpty(PortString) == false) { var Ports = new ParamList<string>(PortString.Split('+')); foreach (var P in Ports) { this.Port.Add(P); } } } } else { this.Port = Port; } if (MapsToCook == null) { if (Command != null) { this.MapsToCook = new ParamList<string>(); var MapsString = Command.ParseParamValue("MapsToCook"); if (String.IsNullOrEmpty(MapsString) == false) { var MapNames = new ParamList<string>(MapsString.Split('+')); foreach ( var M in MapNames ) { this.MapsToCook.Add( M ); } } } } else { this.MapsToCook = MapsToCook; } if (String.IsNullOrEmpty(this.MapToRun) == false) { this.MapsToCook.Add(this.MapToRun); } if (InMapsToRebuildLightMaps == null) { if (Command != null) { this.MapsToRebuildLightMaps = new ParamList<string>(); var MapsString = Command.ParseParamValue("MapsToRebuildLightMaps"); if (String.IsNullOrEmpty(MapsString) == false) { var MapNames = new ParamList<string>(MapsString.Split('+')); foreach (var M in MapNames) { this.MapsToRebuildLightMaps.Add(M); } } } } else { this.MapsToRebuildLightMaps = InMapsToRebuildLightMaps; } if (TitleID == null) { if (Command != null) { this.TitleID = new ParamList<string>(); var TitleString = Command.ParseParamValue("TitleID"); if (String.IsNullOrEmpty(TitleString) == false) { var TitleIDs = new ParamList<string>(TitleString.Split('+')); foreach (var T in TitleIDs) { this.TitleID.Add(T); } } } } else { this.TitleID = TitleID; } if (ServerConfigsToBuild == null) { if (Command != null) { var ServerConfig = Command.ParseParamValue("serverconfig"); if (ServerConfig == null) ServerConfig = Command.ParseParamValue("config"); if (ServerConfig != null) { this.ServerConfigsToBuild = new List<UnrealTargetConfiguration>(); var Configs = new ParamList<string>(ServerConfig.Split('+')); foreach (var ConfigName in Configs) { this.ServerConfigsToBuild.Add((UnrealTargetConfiguration)Enum.Parse(typeof(UnrealTargetConfiguration), ConfigName, true)); } } } } else { this.ServerConfigsToBuild = ServerConfigsToBuild; } if (NumClients.HasValue) { this.NumClients = NumClients.Value; } else if (Command != null) { this.NumClients = Command.ParseParamInt("numclients"); } if (CrashIndex.HasValue) { this.CrashIndex = CrashIndex.Value; } else if (Command != null) { this.CrashIndex = Command.ParseParamInt("CrashIndex"); } if (RunTimeoutSeconds.HasValue) { this.RunTimeoutSeconds = RunTimeoutSeconds.Value; } else if (Command != null) { this.RunTimeoutSeconds = Command.ParseParamInt("runtimeoutseconds"); } AutodetectSettings(false); ValidateAndLog(); }
/// <summary> /// Builds a UBT Commandline. /// </summary> /// <param name="Project">Unreal project to build (optional)</param> /// <param name="Target">Target to build.</param> /// <param name="Platform">Platform to build for.</param> /// <param name="Config">Configuration to build.</param> /// <param name="AdditionalArgs">Additional arguments to pass on to UBT.</param> public static string UBTCommandline(FileReference Project, string Target, UnrealTargetPlatform Platform, UnrealTargetConfiguration Config, string AdditionalArgs = "") { string CmdLine; if (Project == null) { CmdLine = String.Format("{0} {1} {2} {3}", Target, Platform, Config, AdditionalArgs); } else { CmdLine = String.Format("{0} {1} {2} -Project={3} {4}", Target, Platform, Config, CommandUtils.MakePathSafeToUseWithCommandLine(Project.FullName), AdditionalArgs); } return(CmdLine); }
/// <summary> /// Gets a parameter value from the command line if it hasn't been specified in the constructor. /// If the command line is not available, default value will be used. /// </summary> /// <param name="Command">Command to parse the command line for. Can be null.</param> /// <param name="SpecifiedValue">Value specified in the constructor (or not)</param> /// <param name="ParamName">Command line parameter name to parse.</param> /// <param name="Default">Default value</param> /// <param name="bTrimQuotes">If set, the leading and trailing quotes will be removed, e.g. instead of "/home/User Name" it will return /home/User Name</param> /// <returns>Parameter value.</returns> string ParseParamValueIfNotSpecified(CommandUtils Command, string SpecifiedValue, string ParamName, string Default = "", bool bTrimQuotes = false) { string Result = Default; if (SpecifiedValue != null) { Result = SpecifiedValue; } else if (Command != null) { Result = Command.ParseParamValue(ParamName, Default); } return bTrimQuotes ? Result.Trim( new char[]{'\"'} ) : Result; }
/// <summary> /// Sets up platforms /// </summary> /// <param name="Command"></param> /// <param name="OverrideTargetPlatforms"></param> /// <param name="AllowPlatformParams"></param> /// <param name="PlatformParamNames"></param> /// <returns>List of platforms parsed from the command line</returns> private List<UnrealTargetPlatform> SetupTargetPlatforms(CommandUtils Command, List<UnrealTargetPlatform> OverrideTargetPlatforms, List<UnrealTargetPlatform> DefaultTargetPlatforms, bool AllowPlatformParams, params string[] PlatformParamNames) { List<UnrealTargetPlatform> TargetPlatforms = null; if (CommandUtils.IsNullOrEmpty(OverrideTargetPlatforms)) { if (Command != null) { // Parse the command line, we support the following params: // -'PlatformParamNames[n]'=Platform_1+Platform_2+...+Platform_k // or (if AllowPlatformParams is true) // -Platform_1 -Platform_2 ... -Platform_k string CmdLinePlatform = null; foreach (var ParamName in PlatformParamNames) { CmdLinePlatform = Command.ParseParamValue(ParamName); if (!String.IsNullOrEmpty(CmdLinePlatform)) { break; } } if (!String.IsNullOrEmpty(CmdLinePlatform)) { // Get all platforms from the param value: Platform_1+Platform_2+...+Platform_k TargetPlatforms = new List<UnrealTargetPlatform>(); var Platforms = new List<string>(CmdLinePlatform.Split('+')); foreach (var PlatformName in Platforms) { TargetPlatforms.Add((UnrealTargetPlatform)Enum.Parse(typeof(UnrealTargetPlatform), PlatformName, true)); } } else if (AllowPlatformParams) { // Look up platform names in the command line: -Platform_1 -Platform_2 ... -Platform_k TargetPlatforms = new List<UnrealTargetPlatform>(); foreach (var Plat in CommandUtils.KnownTargetPlatforms) { if (Command.ParseParam(Plat.ToString())) { TargetPlatforms.Add(Plat); } } } } } else { TargetPlatforms = OverrideTargetPlatforms; } if (CommandUtils.IsNullOrEmpty(TargetPlatforms)) { // Revert to single default platform: Win64 TargetPlatforms = DefaultTargetPlatforms; } return TargetPlatforms; }