// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using EpicGames.Core; using UnrealBuildBase; using Microsoft.Extensions.Logging; namespace AutomationTool { /// /// Base class for buildcommands. /// public abstract class BuildCommand : CommandUtils { /// /// Command line parameters for this command (empty by non-null by default) /// private string[] CommandLineParams = new string[0]; public string[] Params { get { return CommandLineParams; } set { CommandLineParams = value; } } /// /// Parses the command's Params list for a parameter and returns whether it is defined or not. /// /// Param to check for. /// True if param was found, false otherwise. public bool ParseParam(string Param) { return ParseParam(Params, Param); } /// /// Parses the command's Params list for a parameter and reads its value. /// Ex. ParseParamValue(Args, "map=") /// /// Param to read its value. /// Returns the value or Default if the parameter was not found. public string ParseParamValue(string Param, string Default = null, string ObsoleteParam = null) { string ParamValue = ParseParamValue(Params, Param, null); if (ObsoleteParam != null) { string ObsoleteParamValue = ParseParamValue(Params, ObsoleteParam, null); if (ObsoleteParamValue != null) { if (ParamValue == null) { Logger.LogWarning("Param name \"{ObsoleteParam}\" is deprecated, use \"{Param}\" instead.", ObsoleteParam, Param); } else { Logger.LogWarning("Deprecated param name \"{ObsoleteParam}\" was ignored because \"{Param}\" was set.", ObsoleteParam, Param); } } } return ParamValue ?? Default; } /// /// Parses an argument. /// /// /// public string ParseOptionalStringParam(string Param) { return ParseParamValue(Param, null); } /// /// Parses an argument. Throws an exception if the parameter is not specified. /// /// Name of the argument /// Value of the argument public string ParseRequiredStringParam(string Param) { string Value = ParseOptionalStringParam(Param); if(Value == null) { throw new AutomationException("Missing -{0}=... parameter", Param); } return Value; } /// /// Parses an file reference argument. /// /// Name of the argument /// Value of the argument public FileReference ParseOptionalFileReferenceParam(string Param) { string StringValue = ParseParamValue(Param); if(StringValue == null) { return null; } else { return new FileReference(StringValue); } } /// /// Parses an file reference argument. Throws an exception if the parameter is not specified. /// /// Name of the argument /// Value of the argument public FileReference ParseRequiredFileReferenceParam(string Param) { FileReference Value = ParseOptionalFileReferenceParam(Param); if(Value == null) { throw new AutomationException("Missing -{0}=... parameter", Param); } return Value; } /// /// Parses a directory reference argument. /// /// Name of the argument /// Value of the argument public DirectoryReference ParseOptionalDirectoryReferenceParam(string Param) { string StringValue = ParseOptionalStringParam(Param); if(StringValue == null) { return null; } else { return new DirectoryReference(StringValue); } } /// /// Parses a directory reference argument. Throws an exception if the parameter is not specified. /// /// Name of the argument /// Value of the argument public DirectoryReference ParseRequiredDirectoryReferenceParam(string Param) { DirectoryReference Value = ParseOptionalDirectoryReferenceParam(Param); if(Value == null) { throw new AutomationException("Missing -{0}=... parameter", Param); } return Value; } /// /// Parses an argument as an enum. /// /// Name of the parameter to read. /// Returns the value that was parsed. public Nullable ParseOptionalEnumParam(string Param) where T : struct { string ValueString = ParseParamValue(Param); if(ValueString == null) { return null; } else { T Value; if(!Enum.TryParse(ValueString, out Value)) { throw new AutomationException("'{0}' is not a valid value for {1}", ValueString, typeof(T).Name); } return Value; } } /// /// Parses an argument as an enum. Throws an exception if the parameter is not specified. /// /// Name of the parameter to read. /// Returns the value that was parsed. public T ParseRequiredEnumParamEnum(string Param) where T : struct { Nullable Value = ParseOptionalEnumParam(Param); if(!Value.HasValue) { throw new AutomationException("Missing -{0}=... parameter", Param); } return Value.Value; } /// /// Parses the argument list for any number of parameters. /// /// Argument list. /// Param to read its value. /// Returns an array of values for this parameter (or an empty array if one was not found. public string[] ParseParamValues(string Param) { return ParseParamValues(Params, Param); } /// /// Parses the command's Params list for a parameter and reads its value. /// Ex. ParseParamValue(Args, "map=") /// /// Param to read its value. /// Returns the value or Default if the parameter was not found. public bool ParseParamBool(string Param, bool Default = false) { string boolValue = ParseParamValue(Params, Param, Default.ToString()); return bool.Parse(boolValue); } /// /// Parses the command's Params list for a parameter and reads its value. /// Ex. ParseParamValue(Args, "map=") /// /// Param to read its value. /// Returns the value or Default if the parameter was not found. public int ParseParamInt(string Param, int Default = 0) { string num = ParseParamValue(Params, Param, Default.ToString()); return int.Parse(num); } /// /// Parses the command's Params list for a parameter and reads its value. /// Ex. ParseParamValue(Args, "map=") /// /// Param to read its value. /// Returns the value or Default if the parameter was not found. public int? ParseParamNullableInt(string Param) { string Value = ParseParamValue(Params, Param, null); if(Value == null) { return null; } else { return int.Parse(Value); } } public FileReference ParseProjectParam() { FileReference ProjectFullPath = null; var bForeign = ParseParam("foreign"); var bForeignCode = ParseParam("foreigncode"); if (bForeign) { var DestSample = ParseParamValue("DestSample", "CopiedHoverShip"); var Dest = ParseParamValue("ForeignDest", CombinePaths(@"C:\testue\foreign\", DestSample + "_ _Dir")); ProjectFullPath = new FileReference(CombinePaths(Dest, DestSample + ".uproject")); } else if (bForeignCode) { var DestSample = ParseParamValue("DestSample", "PlatformerGame"); var Dest = ParseParamValue("ForeignDest", CombinePaths(@"C:\testue\foreign\", DestSample + "_ _Dir")); ProjectFullPath = new FileReference(CombinePaths(Dest, DestSample + ".uproject")); } else { var OriginalProjectName = ParseParamValue("project", ""); if (string.IsNullOrEmpty(OriginalProjectName)) { return null; } var ProjectName = OriginalProjectName; ProjectName = ProjectName.Trim(new char[] { '\"' }); if (ProjectName.IndexOfAny(new char[] { '\\', '/' }) < 0) { ProjectName = CombinePaths(CmdEnv.LocalRoot, ProjectName, ProjectName + ".uproject"); } else if (!FileExists_NoExceptions(ProjectName)) { ProjectName = CombinePaths(CmdEnv.LocalRoot, ProjectName); } if (FileExists_NoExceptions(ProjectName)) { ProjectFullPath = new FileReference(ProjectName); } else { var Branch = new BranchInfo(); var GameProj = Branch.FindGame(OriginalProjectName); if (GameProj != null) { ProjectFullPath = GameProj.FilePath; } if (ProjectFullPath == null || !FileExists_NoExceptions(ProjectFullPath.FullName)) { throw new AutomationException("Could not find a project file {0}.", ProjectName); } } } return ProjectFullPath; } /// /// Checks that all of the required params are present, throws an exception if not /// /// public void CheckParamsArePresent(params string[] Args) { List MissingParams = new List(); foreach (string Arg in Args) { if (ParseParamValue(Arg, null) == null) { MissingParams.Add(Arg); } } if (MissingParams.Count > 0) { throw new AutomationException("Params {0} are missing but required. Required params are {1}", string.Join(",", MissingParams), string.Join(",", Args)); } } /// /// Build command entry point. Throws AutomationExceptions on failure. /// public virtual void ExecuteBuild() { throw new AutomationException("Either Execute() or ExecuteBuild() should be implemented for {0}", GetType().Name); } /// /// Command entry point. /// public virtual ExitCode Execute() { ExecuteBuild(); return ExitCode.Success; } /// /// Async command entry point. /// public virtual Task ExecuteAsync() { return Task.FromResult(Execute()); } /// /// Executes a new command as a child of another command. /// /// /// public static ExitCode Execute(BuildCommand ParentCommand) where T : BuildCommand, new() { T Command = new T(); if (ParentCommand != null) { Command.Params = ParentCommand.Params; } return Command.Execute(); } } }