| @ -0,0 +1,52 @@ | ||||
| using System.Collections.ObjectModel; | ||||
|  | ||||
| namespace UnrealSharpBuildTool.Actions; | ||||
|  | ||||
| public class BuildSolution : BuildToolAction | ||||
| { | ||||
|     private readonly BuildConfig _buildConfig; | ||||
|     private readonly string _folder; | ||||
|     private readonly Collection<string>? _extraArguments; | ||||
|  | ||||
|     public BuildSolution(string folder, Collection<string>? extraArguments = null, BuildConfig buildConfig = BuildConfig.Debug) | ||||
|     { | ||||
|         _folder = Program.FixPath(folder); | ||||
|         _buildConfig = buildConfig; | ||||
|         _extraArguments = extraArguments; | ||||
|     } | ||||
|  | ||||
|     public override bool RunAction() | ||||
|     { | ||||
|         if (!Directory.Exists(_folder)) | ||||
|         { | ||||
|             throw new Exception($"Couldn't find the solution file at \"{_folder}\""); | ||||
|         } | ||||
|  | ||||
|         using BuildToolProcess buildSolutionProcess = new BuildToolProcess(); | ||||
|  | ||||
|         if (_buildConfig == BuildConfig.Publish) | ||||
|         { | ||||
|             buildSolutionProcess.StartInfo.ArgumentList.Add("publish"); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             buildSolutionProcess.StartInfo.ArgumentList.Add("build"); | ||||
|         } | ||||
|  | ||||
|         buildSolutionProcess.StartInfo.ArgumentList.Add($"{_folder}"); | ||||
|  | ||||
|         buildSolutionProcess.StartInfo.ArgumentList.Add("--configuration"); | ||||
|         buildSolutionProcess.StartInfo.ArgumentList.Add(Program.GetBuildConfiguration(_buildConfig)); | ||||
|         buildSolutionProcess.StartInfo.WorkingDirectory = _folder; | ||||
|          | ||||
|         if (_extraArguments != null) | ||||
|         { | ||||
|             foreach (var argument in _extraArguments) | ||||
|             { | ||||
|                 buildSolutionProcess.StartInfo.ArgumentList.Add(argument); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return buildSolutionProcess.StartBuildToolProcess(); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,25 @@ | ||||
| namespace UnrealSharpBuildTool.Actions; | ||||
|  | ||||
| public abstract class BuildToolAction | ||||
| { | ||||
|     public static bool InitializeAction() | ||||
|     { | ||||
|         BuildToolAction buildToolAction = Program.BuildToolOptions.Action switch | ||||
|         { | ||||
|             BuildAction.Build => new BuildUserSolution(), | ||||
|             BuildAction.Clean => new CleanSolution(), | ||||
|             BuildAction.GenerateProject => new GenerateProject(), | ||||
|             BuildAction.UpdateProjectDependencies => new UpdateProjectDependencies(), | ||||
|             BuildAction.Rebuild => new RebuildSolution(), | ||||
|             BuildAction.Weave => new WeaveProject(), | ||||
|             BuildAction.PackageProject => new PackageProject(), | ||||
|             BuildAction.GenerateSolution => new GenerateSolution(), | ||||
|             BuildAction.BuildWeave => new BuildWeave(), | ||||
|             _ => throw new Exception($"Can't find build action with name \"{Program.BuildToolOptions.Action}\"") | ||||
|         }; | ||||
|  | ||||
|         return buildToolAction.RunAction(); | ||||
|     } | ||||
|  | ||||
|     public abstract bool RunAction(); | ||||
| } | ||||
| @ -0,0 +1,12 @@ | ||||
| using System.Collections.ObjectModel; | ||||
|  | ||||
| namespace UnrealSharpBuildTool.Actions; | ||||
|  | ||||
| public class BuildUserSolution : BuildSolution | ||||
| { | ||||
|     public BuildUserSolution(Collection<string>? extraArguments = null, BuildConfig buildConfig = BuildConfig.Debug)  | ||||
|         : base(Program.GetScriptFolder(), extraArguments, buildConfig) | ||||
|     { | ||||
|          | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,39 @@ | ||||
| namespace UnrealSharpBuildTool.Actions; | ||||
|  | ||||
| public class BuildWeave : BuildToolAction | ||||
| { | ||||
|     public override bool RunAction() | ||||
|     { | ||||
|         BuildSolution buildSolution = new BuildUserSolution(); | ||||
|         WeaveProject weaveProject = new WeaveProject(); | ||||
|         return buildSolution.RunAction() && weaveProject.RunAction() && AddLaunchSettings(); | ||||
|     } | ||||
|      | ||||
|     bool AddLaunchSettings() | ||||
|     { | ||||
|         List<FileInfo> allProjectFiles = Program.GetAllProjectFiles(new DirectoryInfo(Program.GetProjectDirectory())); | ||||
|  | ||||
|         foreach (FileInfo projectFile in allProjectFiles) | ||||
|         { | ||||
|             if (projectFile.Directory!.Name.EndsWith(".Glue")) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|              | ||||
|             string csProjectPath = Path.Combine(Program.GetScriptFolder(), projectFile.Directory.Name); | ||||
|             string propertiesDirectoryPath = Path.Combine(csProjectPath, "Properties"); | ||||
|             string launchSettingsPath = Path.Combine(propertiesDirectoryPath, "launchSettings.json"); | ||||
|             if (!Directory.Exists(propertiesDirectoryPath)) | ||||
|             { | ||||
|                 Directory.CreateDirectory(propertiesDirectoryPath); | ||||
|             } | ||||
|             if (File.Exists(launchSettingsPath)) | ||||
|             { | ||||
|                 return true; | ||||
|             } | ||||
|             Program.CreateOrUpdateLaunchSettings(launchSettingsPath); | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,18 @@ | ||||
| namespace UnrealSharpBuildTool.Actions; | ||||
|  | ||||
| public class CleanSolution : BuildToolAction | ||||
| { | ||||
|     public override bool RunAction() | ||||
|     { | ||||
|         using BuildToolProcess cleanProcess = new BuildToolProcess(); | ||||
|  | ||||
|         string unrealSharpBinaries = Program.GetOutputPath(); | ||||
|  | ||||
|         if (Directory.Exists(unrealSharpBinaries)) | ||||
|         { | ||||
|             Directory.Delete(unrealSharpBinaries, true); | ||||
|         } | ||||
|  | ||||
|         return cleanProcess.StartBuildToolProcess(); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,342 @@ | ||||
| using System.Xml; | ||||
| using Newtonsoft.Json; | ||||
|  | ||||
| namespace UnrealSharpBuildTool.Actions; | ||||
|  | ||||
| public class GenerateProject : BuildToolAction | ||||
| { | ||||
|     private string _projectPath = string.Empty; | ||||
|     private string _projectFolder = string.Empty; | ||||
|     private string _projectRoot = string.Empty; | ||||
|      | ||||
|     bool ContainsUPluginOrUProjectFile(string folder) | ||||
|     { | ||||
|         string[] files = Directory.GetFiles(folder, "*.*", SearchOption.AllDirectories); | ||||
|          | ||||
|         foreach (string file in files) | ||||
|         { | ||||
|             if (file.EndsWith(".uplugin", StringComparison.OrdinalIgnoreCase) || file.EndsWith(".uproject", StringComparison.OrdinalIgnoreCase)) | ||||
|             { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     public override bool RunAction() | ||||
|     { | ||||
|         string folder = Program.TryGetArgument("NewProjectFolder"); | ||||
|         _projectRoot = Program.TryGetArgument("ProjectRoot"); | ||||
|          | ||||
|         if (!ContainsUPluginOrUProjectFile(_projectRoot)) | ||||
|         { | ||||
|             throw new InvalidOperationException("Project folder must contain a .uplugin or .uproject file."); | ||||
|         } | ||||
|          | ||||
|         if (folder == _projectRoot) | ||||
|         { | ||||
|             folder = Path.Combine(folder, "Script"); | ||||
|         } | ||||
|  | ||||
|         string projectName = Program.TryGetArgument("NewProjectName"); | ||||
|         string csProjFileName = $"{projectName}.csproj"; | ||||
|  | ||||
|         if (!Directory.Exists(folder)) | ||||
|         { | ||||
|             Directory.CreateDirectory(folder); | ||||
|         } | ||||
|  | ||||
|         _projectFolder = Path.Combine(folder, projectName); | ||||
|         _projectPath = Path.Combine(_projectFolder, csProjFileName); | ||||
|  | ||||
|         string version = Program.GetVersion(); | ||||
|         using BuildToolProcess generateProjectProcess = new BuildToolProcess(); | ||||
|  | ||||
|         // Create a class library. | ||||
|         generateProjectProcess.StartInfo.ArgumentList.Add("new"); | ||||
|         generateProjectProcess.StartInfo.ArgumentList.Add("classlib"); | ||||
|  | ||||
|         // Assign project name to the class library. | ||||
|         generateProjectProcess.StartInfo.ArgumentList.Add("-n"); | ||||
|         generateProjectProcess.StartInfo.ArgumentList.Add(projectName); | ||||
|  | ||||
|         // Set the target framework to the current version. | ||||
|         generateProjectProcess.StartInfo.ArgumentList.Add("-f"); | ||||
|         generateProjectProcess.StartInfo.ArgumentList.Add(version); | ||||
|  | ||||
|         generateProjectProcess.StartInfo.WorkingDirectory = folder; | ||||
|  | ||||
|         if (!generateProjectProcess.StartBuildToolProcess()) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         // dotnet new class lib generates a file named Class1, remove it. | ||||
|         string myClassFile = Path.Combine(_projectFolder, "Class1.cs"); | ||||
|         if (File.Exists(myClassFile)) | ||||
|         { | ||||
|             File.Delete(myClassFile); | ||||
|         } | ||||
|  | ||||
|         string slnPath = Program.GetSolutionFile(); | ||||
|         if (!File.Exists(slnPath)) | ||||
|         { | ||||
|             GenerateSolution generateSolution = new GenerateSolution(); | ||||
|             generateSolution.RunAction(); | ||||
|         } | ||||
|  | ||||
|         if (Program.HasArgument("SkipUSharpProjSetup")) | ||||
|         { | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         AddLaunchSettings(); | ||||
|         ModifyCSProjFile(); | ||||
|  | ||||
|         string relativePath = Path.GetRelativePath(Program.GetScriptFolder(), _projectPath); | ||||
|         AddProjectToSln(relativePath); | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     public static void AddProjectToSln(string relativePath) | ||||
|     { | ||||
|         AddProjectToSln([relativePath]); | ||||
|     } | ||||
|  | ||||
|     public static void AddProjectToSln(List<string> relativePaths) | ||||
|     { | ||||
|         foreach (IGrouping<string, string> projects in GroupPathsBySolutionFolder(relativePaths)) | ||||
|         { | ||||
|             using BuildToolProcess addProjectToSln = new BuildToolProcess(); | ||||
|             addProjectToSln.StartInfo.ArgumentList.Add("sln"); | ||||
|             addProjectToSln.StartInfo.ArgumentList.Add("add"); | ||||
|  | ||||
|             foreach (string relativePath in projects) | ||||
|             { | ||||
|                 addProjectToSln.StartInfo.ArgumentList.Add(relativePath); | ||||
|             } | ||||
|  | ||||
|             addProjectToSln.StartInfo.ArgumentList.Add("-s"); | ||||
|             addProjectToSln.StartInfo.ArgumentList.Add(projects.Key); | ||||
|  | ||||
|             addProjectToSln.StartInfo.WorkingDirectory = Program.GetScriptFolder(); | ||||
|             addProjectToSln.StartBuildToolProcess(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static IEnumerable<IGrouping<string, string>> GroupPathsBySolutionFolder(List<string> relativePaths) | ||||
|     { | ||||
|         return relativePaths.GroupBy(GetPathRelativeToProject)!; | ||||
|     } | ||||
|  | ||||
|     private static string GetPathRelativeToProject(string path) | ||||
|     { | ||||
|         var fullPath = Path.GetFullPath(path, Program.GetScriptFolder()); | ||||
|         var relativePath = Path.GetRelativePath(Program.GetProjectDirectory(), fullPath); | ||||
|         var projectDirName = Path.GetDirectoryName(relativePath)!; | ||||
|  | ||||
|         // If we're in the script folder we want these to be in the Script solution folder, otherwise we want these to | ||||
|         // be in the directory for the plugin itself. | ||||
|         var containingDirName = Path.GetDirectoryName(projectDirName)!; | ||||
|         return containingDirName == "Script" ? containingDirName : Path.GetDirectoryName(containingDirName)!; | ||||
|     } | ||||
|  | ||||
|     private void ModifyCSProjFile() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             XmlDocument csprojDocument = new XmlDocument(); | ||||
|             csprojDocument.Load(_projectPath); | ||||
|  | ||||
|             if (csprojDocument.SelectSingleNode("//ItemGroup") is not XmlElement newItemGroup) | ||||
|             { | ||||
|                 newItemGroup = csprojDocument.CreateElement("ItemGroup"); | ||||
|                 csprojDocument.DocumentElement!.AppendChild(newItemGroup); | ||||
|             } | ||||
|  | ||||
|             AppendProperties(csprojDocument); | ||||
|             AppendConstantDefines(csprojDocument); | ||||
|  | ||||
|             AppendReference(csprojDocument, newItemGroup, "UnrealSharp", GetPathToBinaries()); | ||||
|             AppendReference(csprojDocument, newItemGroup, "UnrealSharp.Core", GetPathToBinaries()); | ||||
|  | ||||
|             AppendSourceGeneratorReference(csprojDocument, newItemGroup); | ||||
|  | ||||
|             if (!Program.HasArgument("SkipIncludeProjectGlue")) | ||||
|             { | ||||
|                 AppendGeneratedCode(csprojDocument, newItemGroup); | ||||
|             } | ||||
|  | ||||
|             foreach (string dependency in Program.GetArguments("Dependency")) | ||||
|             { | ||||
|                 AddDependency(csprojDocument, newItemGroup, dependency); | ||||
|             } | ||||
|  | ||||
|             csprojDocument.Save(_projectPath); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             throw new InvalidOperationException($"An error occurred while updating the .csproj file: {ex.Message}", ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void AddProperty(string name, string value, XmlDocument doc, XmlNode propertyGroup) | ||||
|     { | ||||
|         XmlNode? newProperty = propertyGroup.SelectSingleNode(name); | ||||
|  | ||||
|         if (newProperty == null) | ||||
|         { | ||||
|             newProperty = doc.CreateElement(name); | ||||
|             propertyGroup.AppendChild(newProperty); | ||||
|         } | ||||
|  | ||||
|         newProperty.InnerText = value; | ||||
|     } | ||||
|  | ||||
|     private void AppendProperties(XmlDocument doc) | ||||
|     { | ||||
|         XmlNode? propertyGroup = doc.SelectSingleNode("//PropertyGroup"); | ||||
|  | ||||
|         if (propertyGroup == null) | ||||
|         { | ||||
|             propertyGroup = doc.CreateElement("PropertyGroup"); | ||||
|         } | ||||
|  | ||||
|         AddProperty("CopyLocalLockFileAssembliesName", "true", doc, propertyGroup); | ||||
|         AddProperty("AllowUnsafeBlocks", "true", doc, propertyGroup); | ||||
|         AddProperty("EnableDynamicLoading", "true", doc, propertyGroup); | ||||
|     } | ||||
|      | ||||
|     private void AddConstDefine(string value, XmlDocument doc, XmlNode propertyGroup, string? condition = null) | ||||
|     { | ||||
|         var newProperty = doc.CreateElement("DefineConstants"); | ||||
|         propertyGroup.AppendChild(newProperty); | ||||
|         newProperty.InnerText = value; | ||||
|         if (condition is not null) | ||||
|         { | ||||
|             newProperty.SetAttribute("Condition", condition); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     private void AppendConstantDefines(XmlDocument doc) | ||||
|     { | ||||
|         var propertyGroup = doc.CreateElement("PropertyGroup"); | ||||
|  | ||||
|         AddConstDefine("WITH_EDITOR", doc, propertyGroup); | ||||
|         AddConstDefine("$(DefineConstants.Replace('WITH_EDITOR;', '').Replace('WITH_EDITOR', ''))", doc, propertyGroup,  | ||||
|             "'$(DisableWithEditor)' == 'true'"); | ||||
|         AddConstDefine("$(DefineConstants);$(DefineAdditionalConstants)", doc, propertyGroup,  | ||||
|             "'$(DefineAdditionalConstants)' != ''"); | ||||
|     } | ||||
|  | ||||
|     private string GetPathToBinaries() | ||||
|     { | ||||
|         string directoryPath = Path.GetDirectoryName(_projectPath)!; | ||||
|         string unrealSharpPath = GetRelativePathToUnrealSharp(directoryPath); | ||||
|         return Path.Combine(unrealSharpPath, "Binaries", "Managed"); | ||||
|     } | ||||
|  | ||||
|     private void AppendReference(XmlDocument doc, XmlElement itemGroup, string referenceName, string binPath) | ||||
|     { | ||||
|         XmlElement referenceElement = doc.CreateElement("Reference"); | ||||
|         referenceElement.SetAttribute("Include", referenceName); | ||||
|  | ||||
|         XmlElement hintPath = doc.CreateElement("HintPath"); | ||||
|         hintPath.InnerText = Path.Combine(binPath, Program.GetVersion(), referenceName + ".dll"); | ||||
|         referenceElement.AppendChild(hintPath); | ||||
|         itemGroup.AppendChild(referenceElement); | ||||
|     } | ||||
|  | ||||
|     private void AppendSourceGeneratorReference(XmlDocument doc, XmlElement itemGroup) | ||||
|     { | ||||
|         string sourceGeneratorPath = Path.Combine(GetPathToBinaries(), "UnrealSharp.SourceGenerators.dll"); | ||||
|         XmlElement sourceGeneratorReference = doc.CreateElement("Analyzer"); | ||||
|         sourceGeneratorReference.SetAttribute("Include", sourceGeneratorPath); | ||||
|         itemGroup.AppendChild(sourceGeneratorReference); | ||||
|     } | ||||
|  | ||||
|     private void AppendPackageReference(XmlDocument doc, XmlElement itemGroup, string packageName, string packageVersion) | ||||
|     { | ||||
|         XmlElement packageReference = doc.CreateElement("PackageReference"); | ||||
|         packageReference.SetAttribute("Include", packageName); | ||||
|         packageReference.SetAttribute("Version", packageVersion); | ||||
|         itemGroup.AppendChild(packageReference); | ||||
|     } | ||||
|  | ||||
|     private void AppendGeneratedCode(XmlDocument doc, XmlElement itemGroup) | ||||
|     { | ||||
|         string providedGlueName = Program.TryGetArgument("GlueProjectName"); | ||||
|         string scriptFolder = string.IsNullOrEmpty(_projectRoot) ? Program.GetScriptFolder() : Path.Combine(_projectRoot, "Script"); | ||||
|         string generatedGluePath = Path.Combine(scriptFolder, providedGlueName, $"{providedGlueName}.csproj"); | ||||
|         AddDependency(doc, itemGroup, generatedGluePath); | ||||
|     } | ||||
|  | ||||
|     private void AddDependency(XmlDocument doc, XmlElement itemGroup, string dependency) | ||||
|     { | ||||
|         string relativePath = GetRelativePath(_projectFolder, dependency); | ||||
|  | ||||
|         XmlElement generatedCode = doc.CreateElement("ProjectReference"); | ||||
|         generatedCode.SetAttribute("Include", relativePath); | ||||
|         itemGroup.AppendChild(generatedCode); | ||||
|     } | ||||
|  | ||||
|     private string GetRelativePathToUnrealSharp(string basePath) | ||||
|     { | ||||
|         string targetPath = Path.Combine(basePath, Program.BuildToolOptions.PluginDirectory); | ||||
|         return GetRelativePath(basePath, targetPath); | ||||
|     } | ||||
|  | ||||
|     public static string GetRelativePath(string basePath, string targetPath) | ||||
|     { | ||||
|         Uri baseUri = new Uri(basePath.EndsWith(Path.DirectorySeparatorChar.ToString()) | ||||
|                 ? basePath | ||||
|                 : basePath + Path.DirectorySeparatorChar); | ||||
|         Uri targetUri = new Uri(targetPath); | ||||
|         Uri relativeUri = baseUri.MakeRelativeUri(targetUri); | ||||
|         return OperatingSystem.IsWindows() ? Uri.UnescapeDataString(relativeUri.ToString()).Replace('/', '\\') : Uri.UnescapeDataString(relativeUri.ToString()); | ||||
|     } | ||||
|  | ||||
|     void AddLaunchSettings() | ||||
|     { | ||||
|         string csProjectPath = Path.Combine(Program.GetScriptFolder(), _projectFolder); | ||||
|         string propertiesDirectoryPath = Path.Combine(csProjectPath, "Properties"); | ||||
|         string launchSettingsPath = Path.Combine(propertiesDirectoryPath, "launchSettings.json"); | ||||
|  | ||||
|         if (!Directory.Exists(propertiesDirectoryPath)) | ||||
|         { | ||||
|             Directory.CreateDirectory(propertiesDirectoryPath); | ||||
|         } | ||||
|  | ||||
|         if (File.Exists(launchSettingsPath)) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         Program.CreateOrUpdateLaunchSettings(launchSettingsPath); | ||||
|     } | ||||
| } | ||||
|  | ||||
| public class Root | ||||
| { | ||||
|     [JsonProperty("profiles")] | ||||
|     public Profiles Profiles { get; set; } = new Profiles(); | ||||
| } | ||||
| public class Profiles | ||||
| { | ||||
|     [JsonProperty("UnrealSharp")] | ||||
|     public Profile ProfileName { get; set; } = new Profile(); | ||||
| } | ||||
|  | ||||
| public class Profile | ||||
| { | ||||
|     [JsonProperty("commandName")] | ||||
|     public string CommandName { get; set; } = string.Empty; | ||||
|  | ||||
|     [JsonProperty("executablePath")] | ||||
|     public string ExecutablePath { get; set; } = string.Empty; | ||||
|  | ||||
|     [JsonProperty("commandLineArgs")] | ||||
|     public string CommandLineArgs { get; set; } = string.Empty; | ||||
| } | ||||
| @ -0,0 +1,47 @@ | ||||
| namespace UnrealSharpBuildTool.Actions; | ||||
|  | ||||
| public class GenerateSolution : BuildToolAction | ||||
| { | ||||
|     public override bool RunAction() | ||||
|     { | ||||
|         using BuildToolProcess generateSln = new BuildToolProcess(); | ||||
|  | ||||
|         // Create a solution. | ||||
|         generateSln.StartInfo.ArgumentList.Add("new"); | ||||
|         generateSln.StartInfo.ArgumentList.Add("sln"); | ||||
|  | ||||
|         // Assign project name to the solution. | ||||
|         generateSln.StartInfo.ArgumentList.Add("-n"); | ||||
|         generateSln.StartInfo.ArgumentList.Add(Program.GetProjectNameAsManaged()); | ||||
|         generateSln.StartInfo.WorkingDirectory = Program.GetScriptFolder(); | ||||
|  | ||||
|         // Force the creation of the solution. | ||||
|         generateSln.StartInfo.ArgumentList.Add("--force"); | ||||
|         generateSln.StartBuildToolProcess(); | ||||
|  | ||||
|         List<string> existingProjectsList = GetExistingProjects() | ||||
|                 .Select(x => Path.GetRelativePath(Program.GetScriptFolder(), x)) | ||||
|                 .ToList(); | ||||
|  | ||||
|         GenerateProject.AddProjectToSln(existingProjectsList); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     private static IEnumerable<string> GetExistingProjects() | ||||
|     { | ||||
|         var scriptsDirectory = new DirectoryInfo(Program.GetScriptFolder()); | ||||
|         var pluginsDirectory = new DirectoryInfo(Program.GetPluginsFolder()); | ||||
|         return FindCSharpProjects(scriptsDirectory) | ||||
|                 .Concat(pluginsDirectory.EnumerateFiles("*.uplugin", SearchOption.AllDirectories) | ||||
|                         .Select(x => x.Directory) | ||||
|                         .SelectMany(x => x!.EnumerateDirectories("Script")) | ||||
|                         .SelectMany(FindCSharpProjects)) | ||||
|                 .Select(x => x.FullName); | ||||
|     } | ||||
|  | ||||
|     private static IEnumerable<FileInfo> FindCSharpProjects(DirectoryInfo directoryInfo) | ||||
|     { | ||||
|         IEnumerable<FileInfo> files = directoryInfo.EnumerateFiles("*.csproj", SearchOption.AllDirectories); | ||||
|         return files; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,42 @@ | ||||
| using System.Collections.ObjectModel; | ||||
|  | ||||
| namespace UnrealSharpBuildTool.Actions; | ||||
|  | ||||
| public class PackageProject : BuildToolAction | ||||
| { | ||||
|     public override bool RunAction() | ||||
|     { | ||||
|         string archiveDirectoryPath = Program.TryGetArgument("ArchiveDirectory"); | ||||
|          | ||||
|         if (string.IsNullOrEmpty(archiveDirectoryPath)) | ||||
|         { | ||||
|             throw new Exception("ArchiveDirectory argument is required for the Publish action."); | ||||
|         } | ||||
|  | ||||
|         string rootProjectPath = Path.Combine(archiveDirectoryPath, Program.BuildToolOptions.ProjectName); | ||||
|         string binariesPath = Program.GetOutputPath(rootProjectPath); | ||||
|         string bindingsPath = Path.Combine(Program.BuildToolOptions.PluginDirectory, "Managed", "UnrealSharp"); | ||||
|         string bindingsOutputPath = Path.Combine(Program.BuildToolOptions.PluginDirectory, "Intermediate", "Build", "Managed"); | ||||
|          | ||||
|         Collection<string> extraArguments = | ||||
|         [ | ||||
|             "--self-contained", | ||||
|             "--runtime", | ||||
|             "win-x64", | ||||
| 			"-p:DisableWithEditor=true", | ||||
|             $"-p:PublishDir=\"{binariesPath}\"", | ||||
|             $"-p:OutputPath=\"{bindingsOutputPath}\"", | ||||
|         ]; | ||||
|  | ||||
|         BuildSolution buildBindings = new BuildSolution(bindingsPath, extraArguments, BuildConfig.Publish); | ||||
|         buildBindings.RunAction(); | ||||
|          | ||||
|         BuildUserSolution buildUserSolution = new BuildUserSolution(null, BuildConfig.Publish); | ||||
|         buildUserSolution.RunAction(); | ||||
|          | ||||
|         WeaveProject weaveProject = new WeaveProject(binariesPath); | ||||
|         weaveProject.RunAction(); | ||||
|          | ||||
|         return true; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,25 @@ | ||||
| using System.Collections.ObjectModel; | ||||
|  | ||||
| namespace UnrealSharpBuildTool.Actions; | ||||
|  | ||||
| public class RebuildSolution : BuildToolAction | ||||
| { | ||||
|     public override bool RunAction() | ||||
|     { | ||||
|         CleanSolution cleanSolutionProcess = new CleanSolution(); | ||||
|          | ||||
|         if (!cleanSolutionProcess.RunAction()) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         BuildSolution buildSolution = new BuildUserSolution(); | ||||
|          | ||||
|         if (!buildSolution.RunAction()) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,77 @@ | ||||
| using System.Collections.Immutable; | ||||
| using System.Xml; | ||||
|  | ||||
| namespace UnrealSharpBuildTool.Actions; | ||||
|  | ||||
| public class UpdateProjectDependencies : BuildToolAction | ||||
| { | ||||
|     private string _projectPath = string.Empty; | ||||
|     private string _projectFolder = string.Empty; | ||||
|     private ImmutableList<string> _dependencies = ImmutableList<string>.Empty; | ||||
|     private HashSet<string> _existingDependencies = new HashSet<string>(); | ||||
|  | ||||
|     public override bool RunAction() | ||||
|     { | ||||
|         _projectPath = Program.TryGetArgument("ProjectPath"); | ||||
|         _projectFolder = Directory.GetParent(_projectPath)!.FullName; | ||||
|         _dependencies = Program.GetArguments("Dependency").ToImmutableList(); | ||||
|  | ||||
|         Console.WriteLine($"Project Path: {_projectPath}"); | ||||
|         Console.WriteLine($"Project Folder: {_projectFolder}"); | ||||
|  | ||||
|         UpdateProject(); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     private void UpdateProject() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             XmlDocument csprojDocument = new XmlDocument(); | ||||
|             csprojDocument.Load(_projectPath); | ||||
|  | ||||
|             XmlNodeList itemGroups = csprojDocument.SelectNodes("//ItemGroup")!; | ||||
|  | ||||
|             _existingDependencies = itemGroups | ||||
|                     .OfType<XmlElement>() | ||||
|                     .Where(x => x.Name == "ItemGroup") | ||||
|                     .SelectMany(x => x.ChildNodes.OfType<XmlElement>()) | ||||
|                     .Where(x => x.Name == "ProjectReference") | ||||
|                     .Select(x => x.GetAttribute("Include")) | ||||
|                     .ToHashSet(); | ||||
|  | ||||
|             XmlElement? newItemGroup = itemGroups.OfType<XmlElement>().FirstOrDefault(); | ||||
|              | ||||
|             if (newItemGroup is null) | ||||
|             { | ||||
|                 newItemGroup = csprojDocument.CreateElement("ItemGroup"); | ||||
|                 csprojDocument.DocumentElement!.AppendChild(newItemGroup); | ||||
|             } | ||||
|  | ||||
|             foreach (string dependency in _dependencies) | ||||
|             { | ||||
|                 AddDependency(csprojDocument, newItemGroup, dependency); | ||||
|             } | ||||
|  | ||||
|             csprojDocument.Save(_projectPath); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             throw new InvalidOperationException($"An error occurred while updating the .csproj file: {ex.Message}", ex); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void AddDependency(XmlDocument doc, XmlElement itemGroup, string dependency) | ||||
|     { | ||||
|         string relativePath = GenerateProject.GetRelativePath(_projectFolder, dependency); | ||||
|          | ||||
|         if (_existingDependencies.Contains(relativePath)) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         XmlElement generatedCode = doc.CreateElement("ProjectReference"); | ||||
|         generatedCode.SetAttribute("Include", relativePath); | ||||
|         itemGroup.AppendChild(generatedCode); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,64 @@ | ||||
| namespace UnrealSharpBuildTool.Actions; | ||||
|  | ||||
| public class WeaveProject : BuildToolAction | ||||
| { | ||||
|     readonly string _outputDirectory; | ||||
|  | ||||
|     public WeaveProject(string outputDirectory = "") | ||||
|     { | ||||
|         _outputDirectory = string.IsNullOrEmpty(outputDirectory) ? Program.GetOutputPath() : outputDirectory; | ||||
|     } | ||||
|  | ||||
|     public override bool RunAction() | ||||
|     { | ||||
|         string weaverPath = Program.GetWeaver(); | ||||
|  | ||||
|         if (!File.Exists(weaverPath)) | ||||
|         { | ||||
|             throw new Exception("Couldn't find the weaver"); | ||||
|         } | ||||
|  | ||||
|         DirectoryInfo scriptRootDirInfo = new DirectoryInfo(Program.GetProjectDirectory()); | ||||
|         return Weave(scriptRootDirInfo, weaverPath); | ||||
|     } | ||||
|  | ||||
|     private bool Weave(DirectoryInfo scriptFolder, string weaverPath) | ||||
|     { | ||||
|         Dictionary<string, List<FileInfo>> projectFiles = Program.GetProjectFilesByDirectory(scriptFolder); | ||||
|         List<FileInfo> allProjectFiles = projectFiles.Values.SelectMany(x => x).ToList(); | ||||
|          | ||||
|         if (allProjectFiles.Count == 0) | ||||
|         { | ||||
|             Console.WriteLine("No project files found. Skipping weaving..."); | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         using BuildToolProcess weaveProcess = new BuildToolProcess(); | ||||
|         weaveProcess.StartInfo.ArgumentList.Add(weaverPath); | ||||
|         weaveProcess.StartInfo.WorkingDirectory = Directory.GetCurrentDirectory(); | ||||
|  | ||||
|         bool foundValidProject = false; | ||||
|         foreach (FileInfo projectFile in allProjectFiles) | ||||
|         { | ||||
|             weaveProcess.StartInfo.ArgumentList.Add("-p"); | ||||
|             string csProjName = Path.GetFileNameWithoutExtension(projectFile.Name); | ||||
|             string assemblyPath = Path.Combine(projectFile.DirectoryName!, "bin", | ||||
|                 Program.GetBuildConfiguration(), Program.GetVersion(), csProjName + ".dll"); | ||||
|  | ||||
|             weaveProcess.StartInfo.ArgumentList.Add(assemblyPath); | ||||
|             foundValidProject = true; | ||||
|         } | ||||
|  | ||||
|         if (!foundValidProject) | ||||
|         { | ||||
|             Console.WriteLine("No valid project found to weave. Skipping weaving..."); | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         // Add path to the output folder for the weaver. | ||||
|         weaveProcess.StartInfo.ArgumentList.Add("-o"); | ||||
|         weaveProcess.StartInfo.ArgumentList.Add($"{Program.FixPath(_outputDirectory)}"); | ||||
|  | ||||
|         return weaveProcess.StartBuildToolProcess(); | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user