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));
 | |
|     }
 | |
| }
 |