// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Tools.DotNETCommon; namespace BuildAgent { class Program { /// /// Entry point /// /// Command-line arguments /// Exit code static int Main(string[] Args) { try { int Result = GuardedMain(Args); return Result; } catch (FatalErrorException Ex) { Log.WriteException(Ex, null); return Ex.ExitCode; } catch (Exception Ex) { Log.WriteException(Ex, null); return 1; } } /// /// Actual Main function, without exception guards /// /// Command-line arguments /// Exit code static int GuardedMain(string[] Args) { // Find the index of the first command int ModeIndex = 0; while (ModeIndex < Args.Length && Args[ModeIndex].StartsWith("-")) { ModeIndex++; } // Find all the ToolMode types Dictionary ModeNameToType = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (Type Type in Assembly.GetExecutingAssembly().GetTypes()) { ProgramModeAttribute Attribute = Type.GetCustomAttribute(); if (Attribute != null) { ModeNameToType.Add(Attribute.Name, Type); } } // Check if there are any commands specified on the command line. if (ModeIndex == Args.Length) { Log.TraceInformation("BuildAgent"); Log.TraceInformation(""); Log.TraceInformation("Utility for managing automated processes on build machines."); Log.TraceInformation(""); Log.TraceInformation("Usage:"); Log.TraceInformation(" BuildAgent.exe [Command] [-Option1] [-Option2]..."); Log.TraceInformation(""); Log.TraceInformation("Commands:"); PrintCommands(ModeNameToType); Log.TraceInformation(""); Log.TraceInformation("Specify \"Command -Help\" for command-specific help"); return 0; } // Get the command name string ModeName = Args[ModeIndex]; // Get the command type Type ModeType; if (!ModeNameToType.TryGetValue(ModeName, out ModeType)) { Log.TraceError("Unknown command '{0}'.", ModeName); Log.TraceInformation(""); Log.TraceInformation("Available commands"); PrintCommands(ModeNameToType); return 1; } // Update the mode name to use the correct casing, in case we need it for error messages ModeName = ModeType.GetCustomAttribute().Name; // Build an argument list for the command, including all the global arguments as well as arguments until the next command List ArgumentList = new List(); for (int Idx = 0; Idx < Args.Length; Idx++) { if (Idx != ModeIndex) { ArgumentList.Add(Args[Idx]); } } CommandLineArguments ModeArguments = new CommandLineArguments(ArgumentList.ToArray()); // Create the command instance ProgramMode Mode = (ProgramMode)Activator.CreateInstance(ModeType); // If the help flag is specified, print the help info and exit immediately if (ModeArguments.HasOption("-Help")) { HelpUtils.PrintHelp(ModeName, HelpUtils.GetDescription(ModeType), Mode.GetParameters(ModeArguments)); return 1; } // Configure the command try { Mode.Configure(ModeArguments); ModeArguments.CheckAllArgumentsUsed(); } catch (CommandLineArgumentException Ex) { Log.TraceError("{0}: {1}", ModeName, Ex.Message); Log.TraceInformation(""); Log.TraceInformation("Arguments for {0}:", ModeName); HelpUtils.PrintTable(Mode.GetParameters(ModeArguments), 4, 24); return 1; } // Execute all the commands return Mode.Execute(); } /// /// Print a formatted list of all the available commands /// /// Map from command name to type static void PrintCommands(Dictionary ModeNameToType) { List> Commands = new List>(); foreach (KeyValuePair Pair in ModeNameToType.OrderBy(x => x.Key)) { ProgramModeAttribute Attribute = Pair.Value.GetCustomAttribute(); Commands.Add(new KeyValuePair(Attribute.Name, Attribute.Description)); } HelpUtils.PrintTable(Commands, 4, 20); } } }