Files
UnrealEngine/Engine/Source/Programs/AutomationTool/Turnkey/TurnkeyCommand.cs
2025-05-18 13:04:45 +08:00

180 lines
4.6 KiB
C#

// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using System.Text;
using EpicGames.Core;
namespace Turnkey
{
class CommandInfo
{
public TurnkeyCommand Command;
public string DisplayString;
public string[] Options; // this is in commandline format, like -opt=val
public CommandInfo(TurnkeyCommand InCommand)
{
Command = InCommand;
DisplayString = InCommand.GetType().Name;
Options = new string[0];
}
public CommandInfo(TurnkeyCommand InCommand, string InDisplayString, string[] InOptions)
{
Command = InCommand;
DisplayString = string.Format("{0} [{1}]", InDisplayString, string.Join(" ", InOptions));
Options = InOptions;
}
}
abstract class TurnkeyCommand
{
protected enum CommandGroup
{
Sdk,
Builds,
Informational,
Settings,
Misc,
}
protected abstract CommandGroup Group { get; }
protected abstract void Execute(string[] CommandOptions);
protected virtual Dictionary<string, string[]> GetExtendedCommandsWithOptions()
{
return null;
}
internal void InternalExecute(string[] CommandOptions)
{
Execute(CommandOptions);
}
// cached commands
private static Dictionary<string, TurnkeyCommand> CachedCommandsByName = new Dictionary<string, TurnkeyCommand>(StringComparer.OrdinalIgnoreCase);
private static List<CommandInfo> CachedCommandsByIndex = new List<CommandInfo>();
private static Dictionary<CommandGroup, List<CommandInfo>> CachedCommandsByGroup = new Dictionary<CommandGroup, List<CommandInfo>>();
static TurnkeyCommand()
{
List<TurnkeyCommand> BaseCommands = new List<TurnkeyCommand>();
// look for all subclasses, and cache by their ProviderToken
foreach (Type AssemType in Assembly.GetExecutingAssembly().GetTypes())
{
if (typeof(TurnkeyCommand).IsAssignableFrom(AssemType) && AssemType != typeof(TurnkeyCommand))
{
TurnkeyCommand Provider = (TurnkeyCommand)Activator.CreateInstance(AssemType);
BaseCommands.Add(Provider);
}
}
BaseCommands.SortBy(x => x.GetType().Name);
foreach (CommandGroup Group in Enum.GetValues(typeof(CommandGroup)))
{
CachedCommandsByGroup[Group] = new List<CommandInfo>();
}
foreach (TurnkeyCommand Command in BaseCommands)
{
CachedCommandsByName[Command.GetType().Name] = Command;
// always add base option
CachedCommandsByGroup[Command.Group].Add(new CommandInfo(Command));
Dictionary<string, string[]> ExtendedCommands = Command.GetExtendedCommandsWithOptions();
if (ExtendedCommands != null)
{
foreach (var Pair in ExtendedCommands)
{
CachedCommandsByGroup[Command.Group].Add(new CommandInfo(Command, Pair.Key, Pair.Value));
}
}
}
// now flatten the lists to match the choices in ChooseCommand
foreach (var Pair in CachedCommandsByGroup)
{
foreach (CommandInfo Command in Pair.Value)
{
CachedCommandsByIndex.Add(Command);
}
}
}
static bool bExitAfterCommand = false;
public static void ExitTurnkeyLoopAfterCommand()
{
bExitAfterCommand = true;
}
public static bool ExecuteCommand(string CommandString=null)
{
TurnkeyCommand Command;
string[] CommandOptions;
if (CommandString == null)
{
int CommandIndex = PromptForCommand();
// zero means to exit
if (CommandIndex == 0)
{
return false;
}
// we know this is okay because PromptForCommand() will validate the input
Command = CachedCommandsByIndex[CommandIndex - 1].Command;
CommandOptions = CachedCommandsByIndex[CommandIndex - 1].Options;
}
else
{
if (!CachedCommandsByName.TryGetValue(CommandString, out Command))
{
TurnkeyUtils.Log("Invalid command");
return false;
}
// no extra options, everything would be on the commandline
CommandOptions = new string[0];
}
try
{
TurnkeyUtils.Log("");
// run the command!
Command.Execute(CommandOptions);
TurnkeyUtils.Log("");
}
catch (System.Exception)
{
throw;
}
// true if we should keep going
return !bExitAfterCommand;
}
private static int PromptForCommand()
{
// build up categorized list
List<string> Options = new List<string>();
foreach (var Pair in CachedCommandsByGroup)
{
CommandGroup Group = Pair.Key;
List<CommandInfo> Commands = Pair.Value;
if (Commands.Count > 0)
{
Options.Add($";{Group}:");
foreach (CommandInfo Command in Commands)
{
Options.Add($" {Command.DisplayString}");
}
}
}
return TurnkeyUtils.ReadInputInt("Enter command", Options, true);
}
}
}