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