259 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			259 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|  | using System.Xml.Linq; | |||
|  | using CommandLine; | |||
|  | using Newtonsoft.Json; | |||
|  | using UnrealSharpBuildTool.Actions; | |||
|  | 
 | |||
|  | namespace UnrealSharpBuildTool; | |||
|  | 
 | |||
|  | public static class Program | |||
|  | { | |||
|  |     public static BuildToolOptions BuildToolOptions = null!; | |||
|  | 
 | |||
|  |     public static int Main(string[] args) | |||
|  |     { | |||
|  |         try | |||
|  |         { | |||
|  |             Console.WriteLine(">>> UnrealSharpBuildTool"); | |||
|  |             Parser parser = new Parser(with => with.HelpWriter = null); | |||
|  |             ParserResult<BuildToolOptions> result = parser.ParseArguments<BuildToolOptions>(args); | |||
|  | 
 | |||
|  |             if (result.Tag == ParserResultType.NotParsed) | |||
|  |             { | |||
|  |                 BuildToolOptions.PrintHelp(result); | |||
|  | 
 | |||
|  |                 string errors = string.Empty; | |||
|  |                 foreach (Error error in result.Errors) | |||
|  |                 { | |||
|  |                     if (error is TokenError tokenError) | |||
|  |                     { | |||
|  |                         errors += $"{tokenError.Tag}: {tokenError.Token} \n"; | |||
|  |                     } | |||
|  |                 } | |||
|  | 
 | |||
|  |                 throw new Exception($"Invalid arguments. Errors: {errors}"); | |||
|  |             } | |||
|  | 
 | |||
|  |             BuildToolOptions = result.Value; | |||
|  |              | |||
|  |             if (!BuildToolAction.InitializeAction()) | |||
|  |             { | |||
|  |                 return 1; | |||
|  |             } | |||
|  | 
 | |||
|  |             Console.WriteLine($"UnrealSharpBuildTool executed {BuildToolOptions.Action.ToString()} action successfully."); | |||
|  |         } | |||
|  |         catch (Exception exception) | |||
|  |         { | |||
|  |             Console.WriteLine("An error occurred: " + exception.Message + Environment.NewLine + exception.StackTrace); | |||
|  |             return 1; | |||
|  |         } | |||
|  | 
 | |||
|  |         return 0; | |||
|  |     } | |||
|  | 
 | |||
|  |     public static string TryGetArgument(string argument) | |||
|  |     { | |||
|  |         return BuildToolOptions.TryGetArgument(argument); | |||
|  |     } | |||
|  | 
 | |||
|  |     public static IEnumerable<string> GetArguments(string argument) | |||
|  |     { | |||
|  |         return BuildToolOptions.GetArguments(argument); | |||
|  |     } | |||
|  | 
 | |||
|  |     public static bool HasArgument(string argument) | |||
|  |     { | |||
|  |         return BuildToolOptions.HasArgument(argument); | |||
|  |     } | |||
|  | 
 | |||
|  |     public static string GetSolutionFile() | |||
|  |     { | |||
|  |         return Path.Combine(GetScriptFolder(), BuildToolOptions.ProjectName + ".sln"); | |||
|  |     } | |||
|  | 
 | |||
|  |     public static string GetUProjectFilePath() | |||
|  |     { | |||
|  |         return Path.Combine(BuildToolOptions.ProjectDirectory, BuildToolOptions.ProjectName + ".uproject"); | |||
|  |     } | |||
|  | 
 | |||
|  |     public static string GetBuildConfiguration() | |||
|  |     { | |||
|  |         string buildConfig = TryGetArgument("BuildConfig"); | |||
|  |         if (string.IsNullOrEmpty(buildConfig)) | |||
|  |         { | |||
|  |             buildConfig = "Debug"; | |||
|  |         } | |||
|  |         return buildConfig; | |||
|  |     } | |||
|  | 
 | |||
|  |     public static BuildConfig GetBuildConfig() | |||
|  |     { | |||
|  |         string buildConfig = GetBuildConfiguration(); | |||
|  |         Enum.TryParse(buildConfig, out BuildConfig config); | |||
|  |         return config; | |||
|  |     } | |||
|  | 
 | |||
|  |     public static string GetBuildConfiguration(BuildConfig buildConfig) | |||
|  |     { | |||
|  |         return buildConfig switch | |||
|  |         { | |||
|  |             BuildConfig.Debug => "Debug", | |||
|  |             BuildConfig.Release => "Release", | |||
|  |             BuildConfig.Publish => "Release", | |||
|  |             _ => "Release" | |||
|  |         }; | |||
|  |     } | |||
|  | 
 | |||
|  |     public static string GetScriptFolder() | |||
|  |     { | |||
|  |         return Path.Combine(BuildToolOptions.ProjectDirectory, "Script"); | |||
|  |     } | |||
|  | 
 | |||
|  |     public static string GetPluginsFolder() | |||
|  |     { | |||
|  |         return Path.Combine(BuildToolOptions.ProjectDirectory, "Plugins"); | |||
|  |     } | |||
|  | 
 | |||
|  |     public static string GetProjectDirectory() | |||
|  |     { | |||
|  |         return BuildToolOptions.ProjectDirectory; | |||
|  |     } | |||
|  | 
 | |||
|  |     public static string FixPath(string path) | |||
|  |     { | |||
|  |         if (OperatingSystem.IsWindows()) | |||
|  |         { | |||
|  |             return path.Replace('/', '\\'); | |||
|  |         } | |||
|  | 
 | |||
|  |         return path; | |||
|  |     } | |||
|  | 
 | |||
|  |     public static string GetProjectNameAsManaged() | |||
|  |     { | |||
|  |         return "Managed" + BuildToolOptions.ProjectName; | |||
|  |     } | |||
|  | 
 | |||
|  |     public static string GetOutputPath(string rootDir = "") | |||
|  |     { | |||
|  |         if (string.IsNullOrEmpty(rootDir)) | |||
|  |         { | |||
|  |             rootDir = BuildToolOptions.ProjectDirectory; | |||
|  |         } | |||
|  | 
 | |||
|  |         return Path.Combine(rootDir, "Binaries", "Managed"); | |||
|  |     } | |||
|  | 
 | |||
|  |     public static string GetWeaver() | |||
|  |     { | |||
|  |         return Path.Combine(GetManagedBinariesDirectory(), "UnrealSharpWeaver.dll"); | |||
|  |     } | |||
|  | 
 | |||
|  |     public static string GetManagedBinariesDirectory() | |||
|  |     { | |||
|  |         return Path.Combine(BuildToolOptions.PluginDirectory, "Binaries", "Managed"); | |||
|  |     } | |||
|  | 
 | |||
|  |     public static string GetVersion() | |||
|  |     { | |||
|  |         Version currentVersion = Environment.Version; | |||
|  |         string currentVersionStr = $"{currentVersion.Major}.{currentVersion.Minor}"; | |||
|  |         return "net" + currentVersionStr; | |||
|  |     } | |||
|  | 
 | |||
|  |     public static void CreateOrUpdateLaunchSettings(string launchSettingsPath) | |||
|  |     { | |||
|  |         Root root = new Root(); | |||
|  | 
 | |||
|  |         string executablePath = string.Empty; | |||
|  |         if (OperatingSystem.IsWindows()) | |||
|  |         { | |||
|  |             executablePath = Path.Combine(BuildToolOptions.EngineDirectory, "Binaries", "Win64", "UnrealEditor.exe"); | |||
|  |         } | |||
|  |         else if (OperatingSystem.IsMacOS()) | |||
|  |         { | |||
|  |             executablePath = Path.Combine(BuildToolOptions.EngineDirectory, "Binaries", "Mac", "UnrealEditor"); | |||
|  |         } | |||
|  |         string commandLineArgs = FixPath(GetUProjectFilePath()); | |||
|  | 
 | |||
|  |         // Create a new profile if it doesn't exist | |||
|  |         if (root.Profiles == null) | |||
|  |         { | |||
|  |             root.Profiles = new Profiles(); | |||
|  |         } | |||
|  | 
 | |||
|  |         root.Profiles.ProfileName = new Profile | |||
|  |         { | |||
|  |             CommandName = "Executable", | |||
|  |             ExecutablePath = executablePath, | |||
|  |             CommandLineArgs = $"\"{commandLineArgs}\"", | |||
|  |         }; | |||
|  | 
 | |||
|  |         string newJsonString = JsonConvert.SerializeObject(root, Formatting.Indented); | |||
|  |         StreamWriter writer = File.CreateText(launchSettingsPath); | |||
|  |         writer.Write(newJsonString); | |||
|  |         writer.Close(); | |||
|  |     } | |||
|  | 
 | |||
|  |     public static List<FileInfo> GetAllProjectFiles(DirectoryInfo folder) | |||
|  |     { | |||
|  |         return folder.GetDirectories("Script") | |||
|  |                 .SelectMany(GetProjectsInDirectory) | |||
|  |                 .Concat(folder.GetDirectories("Plugins") | |||
|  |                         .SelectMany(x => x.EnumerateFiles("*.uplugin", SearchOption.AllDirectories)) | |||
|  |                         .Select(x => x.Directory) | |||
|  |                         .Select(x => x!.GetDirectories("Script").FirstOrDefault()) | |||
|  |                         .Where(x => x is not null) | |||
|  |                         .SelectMany(GetProjectsInDirectory!)) | |||
|  |                 .ToList(); | |||
|  |     } | |||
|  | 
 | |||
|  |     public static Dictionary<string, List<FileInfo>> GetProjectFilesByDirectory(DirectoryInfo folder) | |||
|  |     { | |||
|  |         Dictionary<string, List<FileInfo>> result = new Dictionary<string, List<FileInfo>>(); | |||
|  |         DirectoryInfo? scriptsFolder = folder.GetDirectories("Script").FirstOrDefault(); | |||
|  |          | |||
|  |         if (scriptsFolder is not null) | |||
|  |         { | |||
|  |             result.Add(GetOutputPathForDirectory(scriptsFolder), GetProjectsInDirectory(scriptsFolder).ToList()); | |||
|  |         } | |||
|  | 
 | |||
|  |         foreach (DirectoryInfo? pluginFolder in folder.GetDirectories("Plugins") | |||
|  |                          .SelectMany(x => x.EnumerateFiles("*.uplugin", SearchOption.AllDirectories)) | |||
|  |                          .Select(x => x.Directory) | |||
|  |                          .Select(x => x!.GetDirectories("Script").FirstOrDefault()) | |||
|  |                          .Where(x => x is not null)) | |||
|  |         { | |||
|  |             result.Add(GetOutputPathForDirectory(pluginFolder!), GetProjectsInDirectory(pluginFolder!).ToList()); | |||
|  |         } | |||
|  | 
 | |||
|  |         return result; | |||
|  |     } | |||
|  | 
 | |||
|  |     private static string GetOutputPathForDirectory(DirectoryInfo directory) | |||
|  |     { | |||
|  |         return Path.Combine(directory.Parent!.FullName, "Binaries", "Managed"); | |||
|  |     } | |||
|  | 
 | |||
|  |     private static IEnumerable<FileInfo> GetProjectsInDirectory(DirectoryInfo folder) | |||
|  |     { | |||
|  |         var csprojFiles = folder.EnumerateFiles("*.csproj", SearchOption.AllDirectories); | |||
|  |         var fsprojFiles = folder.EnumerateFiles("*.fsproj", SearchOption.AllDirectories); | |||
|  |         return csprojFiles.Concat(fsprojFiles).Where(IsWeavableProject); | |||
|  |     } | |||
|  | 
 | |||
|  |     private static bool IsWeavableProject(FileInfo projectFile) | |||
|  |     { | |||
|  |         // We need to be able to filter out certain non-production projects. | |||
|  |         // The main target of this is source generators and analyzers which users | |||
|  |         // may want to leverage as part of their solution and can't be weaved because | |||
|  |         // they have to use netstandard2.0. | |||
|  |         XDocument doc = XDocument.Load(projectFile.FullName); | |||
|  |         return !doc.Descendants() | |||
|  |             .Where(element => element.Name.LocalName == "PropertyGroup") | |||
|  |             .SelectMany(element => element.Elements()) | |||
|  |             .Any(element => element.Name.LocalName == "ExcludeFromWeaver" && | |||
|  |                             element.Value.Equals("true", StringComparison.OrdinalIgnoreCase)); | |||
|  |     } | |||
|  | } |