// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using System.Diagnostics;
using UnrealBuildTool;
using Tools.DotNETCommon;
namespace AutomationTool
{
///
/// Command to execute info.
///
class CommandInfo
{
public string CommandName;
public List Arguments = new List();
public override string ToString()
{
string Result = CommandName;
Result += "(";
for (int Index = 0; Index < Arguments.Count; ++Index)
{
if (Index > 0)
{
Result += ", ";
}
Result += Arguments[Index];
}
Result += ")";
return Result;
}
}
///
/// Helper class for automatically registering command line params.
///
public class CommandLineArg
{
public delegate void OnSetDelegate();
public string Name;
public OnSetDelegate SetDelegate;
///
/// True of this arg was set in the command line.
///
public bool IsSet { get; private set; }
public CommandLineArg(string InName, OnSetDelegate InSet = null)
{
Name = InName;
SetDelegate = InSet;
GlobalCommandLine.RegisteredArgs.Add(Name, this);
}
public void Set()
{
IsSet = true;
if (SetDelegate != null)
{
SetDelegate();
}
}
public override string ToString()
{
return String.Format("{0}, {1}", Name, IsSet);
}
///
/// Returns true of this arg was set in the command line.
///
public static implicit operator bool(CommandLineArg Arg)
{
return Arg.IsSet;
}
}
///
/// Global command line parameters.
///
public static class GlobalCommandLine
{
///
/// List of all registered command line parameters (global, not command-specific)
///
public static Dictionary RegisteredArgs = new Dictionary(StringComparer.InvariantCultureIgnoreCase);
public static CommandLineArg CompileOnly = new CommandLineArg("-CompileOnly");
public static CommandLineArg Verbose = new CommandLineArg("-Verbose");
public static CommandLineArg TimeStamps = new CommandLineArg("-TimeStamps");
public static CommandLineArg Submit = new CommandLineArg("-Submit");
public static CommandLineArg NoSubmit = new CommandLineArg("-NoSubmit");
public static CommandLineArg NoP4 = new CommandLineArg("-NoP4");
public static CommandLineArg P4 = new CommandLineArg("-P4");
public static CommandLineArg Compile = new CommandLineArg("-Compile");
public static CommandLineArg IgnoreDependencies = new CommandLineArg("-IgnoreDependencies");
///
/// This command is LEGACY because we used to run UAT.exe to compile scripts by default.
/// Now we only compile by default when run via RunUAT.bat, which still understands -nocompile.
/// However, the batch file simply passes on all arguments, so UAT will choke when encountering -nocompile.
/// Keep this CommandLineArg around so that doesn't happen.
///
public static CommandLineArg NoCompileLegacyDontUse = new CommandLineArg("-NoCompile");
public static CommandLineArg NoCompileEditor = new CommandLineArg("-NoCompileEditor");
public static CommandLineArg Help = new CommandLineArg("-Help");
public static CommandLineArg List = new CommandLineArg("-List");
public static CommandLineArg NoKill = new CommandLineArg("-NoKill");
public static CommandLineArg UTF8Output = new CommandLineArg("-UTF8Output");
public static CommandLineArg AllowStdOutLogVerbosity = new CommandLineArg("-AllowStdOutLogVerbosity");
public static CommandLineArg NoAutoSDK = new CommandLineArg("-NoAutoSDK");
///
/// Allows you to use local storage for your root build storage dir (default of P:\Builds (on PC) is changed to Engine\Saved\LocalBuilds). Used for local testing.
///
public static CommandLineArg UseLocalBuildStorage = new CommandLineArg("-UseLocalBuildStorage");
///
/// Force initialize static members by calling this.
///
public static void Init()
{
Log.TraceVerbose("Registered {0} command line parameters.", RegisteredArgs.Count);
}
}
[Help(
@"Executes scripted commands
AutomationTool.exe [-verbose] [-compileonly] [-p4] Command0 [-Arg0 -Arg1 -Arg2 ...] Command1 [-Arg0 -Arg1 ...] Command2 [-Arg0 ...] Commandn ... [EnvVar0=MyValue0 ... EnvVarn=MyValuen]"
)]
[Help("verbose", "Enables verbose logging")]
[Help("nop4", "Disables Perforce functionality (default if not run on a build machine)")]
[Help("p4", "Enables Perforce functionality (default if run on a build machine)")]
[Help("compileonly", "Does not run any commands, only compiles them")]
[Help("compile", "Dynamically compiles all commands (otherwise assumes they are already built)")]
[Help("help", "Displays help")]
[Help("list", "Lists all available commands")]
[Help("submit", "Allows UAT command to submit changes")]
[Help("nosubmit", "Prevents any submit attempts")]
[Help("nokill", "Does not kill any spawned processes on exit")]
[Help("ignorejunk", "Prevents UBT from cleaning junk files")]
[Help("UseLocalBuildStorage", @"Allows you to use local storage for your root build storage dir (default of P:\Builds (on PC) is changed to Engine\Saved\LocalBuilds). Used for local testing.")]
public static class Automation
{
///
/// Parses command line parameter.
///
/// Parameter index
/// Command line
/// Recently parsed command
/// The only project to build scripts for
/// Additional script locations
/// True if the parameter has been successfully parsed.
private static void ParseParam(string CurrentParam, CommandInfo CurrentCommand, ref string OutScriptsForProjectFileName, List 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);
}
}
private static string ParseString(string Key, string Value)
{
if (!String.IsNullOrEmpty(Key))
{
if (Value == "true" || Value == "false")
{
return "-" + Key;
}
else
{
string param = "-" + Key + "=";
if (Value.Contains(" "))
{
param += "\"" + Value + "\"";
}
else
{
param += Value;
}
return param;
}
}
else
{
return Value;
}
}
private static string ParseList(string Key, List