From f52b2f0b9690f79aca7d61bb84b9ae744d588d36 Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Wed, 9 Oct 2024 11:57:16 +0100 Subject: [PATCH] Install dotnet tools locally in the Nuget Packages In commit 7a398b01 we added two new tools for compressing textures, `crunch` and `basisu`. The problem there is that the management of the `.config/dotnet-tool.json` file by the users was becoming an issue. We needed a more automatic way to install the required tooling. The problem is using the standard `dotnet tool install` calls requires a `.config/dotnet-tool.json` file to be present in either the current directory or a directory that is in the path ABOVE the current one. You would use the `--create-manifest-if-needed` flag to create the manifest, but that will still leave the users having to manage and upgrade the .json file every time we do a release. So lets get the pipeline to install the tooling itself. The `dotnet tool install` command has an additional argument`--tool-path` this allows us to say where we want the tool installed. Once that has happened we get a native binary launcher in `--tool-path` which allows us to launch the app directly without using the `dotnet` executable. So what this allows us to do is install the tooling locally in the directory that the content pipeline is installed. This will usually be the global `.nuget/package` directory. We need to keep an eye on the `DOTNET_ROOT` environment variable when installing the tooling, just in case a user (or CI) wants to use a custom dotnet install. Also added support for overriding which MGCB to use in the editor by looking for a `MGCBCommand` environment variable. This should be the full path to either the `mgcb` exe or the `mgcb.dll` that the user wants to use. This will allow users to change to a custom content compiler without having to change the editor. The one downside is users will no longer be able to run `dotnet mgcb` directly in their project directory unless they install the tooling manually. The Editor also needs to download the `mgcb` tool. We place this in the `ApplicationData` folder rather than in the local assembly folder because we cannot guarantee that folder is writable. So in this instance a location specific to the current user seemed like the best approach. The long term plan is to bundle all these tools into a single native library which can be called directly by the content pipeline. --- .github/workflows/main.yml | 6 -- .vscode/launch.json | 2 +- .../ExternalTool.cs | 50 ++++++++++++++++- ...MonoGame.Framework.Content.Pipeline.csproj | 2 - .../Utilities/BasisUHelpers.cs | 2 +- .../Utilities/CrunchHelpers.cs | 2 +- .../.config/dotnet-tools.json | 6 -- .../.config/dotnet-tools.json | 6 -- .../.config/dotnet-tools.json | 6 -- .../.config/dotnet-tools.json | 6 -- .../.config/dotnet-tools.json | 6 -- .../Common/PipelineController.cs | 55 ++++++++++++------- .../Common/Util.cs | 38 +++++++++++++ .../MonoGame.Content.Builder.Task.props | 4 ++ .../MonoGame.Content.Builder.Task.targets | 18 ++++-- .../BuildContentPipelineTask.cs | 6 -- build/BuildToolsTasks/BuildMGCBEditorTask.cs | 15 +++-- build/BuildToolsTasks/BuildMGCBTask.cs | 10 ++++ build/DeployTasks/UploadArtifactsTask.cs | 47 ++++++++++++++++ 19 files changed, 207 insertions(+), 80 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b61ea766dfe..d9908ae9301 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -105,7 +105,6 @@ jobs: - name: Test run: dotnet test Tools/MonoGame.Tools.Tests/MonoGame.Tools.Tests.csproj --blame-hang-timeout 5m -c Release --filter="TestCategory!=Audio" env: - DOTNET_ROOT: ${{github.workspace}}/dotnet64 MGFXC_WINE_PATH: /Users/runner/.winemonogame CI: true if: runner.os == 'macOS' @@ -231,11 +230,6 @@ jobs: path: tests-windowsdx if: runner.os == 'Windows' - - name: Install Tools - run: | - dotnet tool install --create-manifest-if-needed mgcb-basisu - dotnet tool install --create-manifest-if-needed mgcb-crunch - - name: Run Tools Tests run: dotnet test tests-tools/MonoGame.Tools.Tests.dll --blame-hang-timeout 1m --filter="TestCategory!=Effects" env: diff --git a/.vscode/launch.json b/.vscode/launch.json index bf6c0271172..cd99a61f5a0 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -20,7 +20,7 @@ "type": "coreclr", "request": "launch", "preLaunchTask": "mgcb-editor-mac", - "program": "${workspaceFolder}/Artifacts/MonoGame.Content.Builder.Editor/Mac/Debug/MGCB Editor.app/Contents/MacOS/mgcb-editor-mac", + "program": "${workspaceFolder}/Artifacts/MonoGame.Content.Builder.Editor/Mac/Debug/mgcb-editor-mac.app/Contents/MacOS/mgcb-editor-mac", "args": [], "cwd": "${workspaceFolder}/Artifacts/MonoGame.Content.Builder.Editor/Mac/Debug", "console": "internalConsole", diff --git a/MonoGame.Framework.Content.Pipeline/ExternalTool.cs b/MonoGame.Framework.Content.Pipeline/ExternalTool.cs index c1ceb7b4d2c..f872aa80818 100644 --- a/MonoGame.Framework.Content.Pipeline/ExternalTool.cs +++ b/MonoGame.Framework.Content.Pipeline/ExternalTool.cs @@ -5,6 +5,8 @@ using System; using System.Diagnostics; using System.IO; +using System.Net; +using System.Reflection; using System.Threading; using MonoGame.Framework.Utilities; @@ -17,6 +19,11 @@ namespace Microsoft.Xna.Framework.Content.Pipeline /// internal class ExternalTool { + public static string Crunch = "mgcb-crunch"; + private static string CrunchVersion = "1.0.4.2"; + public static string BasisU = "mgcb-basisu"; + private static string BasisUVersion = "1.16.4.2"; + public static int Run(string command, string arguments) { string stdout, stderr; @@ -27,13 +34,47 @@ public static int Run(string command, string arguments) return result; } + public static void RestoreDotnetTool(string command, string toolName, string toolVersion, string path) + { + Directory.CreateDirectory(path); + var exe = CurrentPlatform.OS == OS.Windows ? "dotnet.exe" : "dotnet"; + var dotnetRoot = Environment.GetEnvironmentVariable("DOTNET_ROOT"); + if (!string.IsNullOrEmpty(dotnetRoot)) + { + exe = Path.Combine(dotnetRoot, exe); + } + if (Run(exe, $"tool {command} {toolName} --version {toolVersion} --tool-path .", out string _, out string _, workingDirectory: path) != 0) + { + // install the latest + Run(exe, $"tool {command} {toolName} --tool-path .", out _, out _, workingDirectory: path); + } + } + + public static void RestoreDotnetTools() + { + var version = Assembly.GetExecutingAssembly().GetName().Version.ToString(); + string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory); + if (CurrentPlatform.OS == OS.Linux) + path= Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "linux"); + if (CurrentPlatform.OS == OS.MacOSX) + path= Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "osx"); + var versionFile = Path.Combine(path, $"tools_version.txt"); + if (File.Exists(versionFile) && File.ReadAllText (versionFile) == version) + return; + RestoreDotnetTool("install", Crunch, CrunchVersion, path); + RestoreDotnetTool("install", BasisU, BasisUVersion, path); + File.WriteAllText(versionFile, version); + } + /// /// Run a dotnet tool. The tool should be installed in a .config/dotnet-tools.json file somewhere in the project lineage. /// public static int RunDotnetTool(string toolName, string args, out string stdOut, out string stdErr, string stdIn=null, string workingDirectory=null) { - var finalizedArgs = toolName + " " + args; - return ExternalTool.Run("dotnet", finalizedArgs, out stdOut, out stdErr, stdIn, workingDirectory); + RestoreDotnetTools(); + var exe = FindCommand (toolName); + var finalizedArgs = args; + return ExternalTool.Run(exe, finalizedArgs, out stdOut, out stdErr, stdIn, workingDirectory); } public static int Run(string command, string arguments, out string stdout, out string stderr, string stdin = null, string workingDirectory=null) @@ -68,6 +109,11 @@ public static int Run(string command, string arguments, out string stdout, out s if (!string.IsNullOrEmpty(workingDirectory)) processInfo.WorkingDirectory = workingDirectory; + var dotnetRoot = Environment.GetEnvironmentVariable ("DOTNET_ROOT"); + if (!string.IsNullOrEmpty(dotnetRoot)) { + processInfo.EnvironmentVariables["DOTNET_ROOT"] = dotnetRoot; + } + EnsureExecutable(fullPath); using (var process = new Process()) diff --git a/MonoGame.Framework.Content.Pipeline/MonoGame.Framework.Content.Pipeline.csproj b/MonoGame.Framework.Content.Pipeline/MonoGame.Framework.Content.Pipeline.csproj index 9da881f5e69..7859d7e06c5 100644 --- a/MonoGame.Framework.Content.Pipeline/MonoGame.Framework.Content.Pipeline.csproj +++ b/MonoGame.Framework.Content.Pipeline/MonoGame.Framework.Content.Pipeline.csproj @@ -76,8 +76,6 @@ - - diff --git a/MonoGame.Framework.Content.Pipeline/Utilities/BasisUHelpers.cs b/MonoGame.Framework.Content.Pipeline/Utilities/BasisUHelpers.cs index f16fbb40388..29b0bf976ae 100644 --- a/MonoGame.Framework.Content.Pipeline/Utilities/BasisUHelpers.cs +++ b/MonoGame.Framework.Content.Pipeline/Utilities/BasisUHelpers.cs @@ -206,7 +206,7 @@ internal static class BasisU /// The exit code for the basisu process. public static int Run(string args, out string stdOut, out string stdErr, string stdIn=null, string workingDirectory=null) { - return ExternalTool.RunDotnetTool("mgcb-basisu", args, out stdOut, out stdErr, stdIn, workingDirectory); + return ExternalTool.RunDotnetTool(ExternalTool.BasisU, args, out stdOut, out stdErr, stdIn, workingDirectory); } /// diff --git a/MonoGame.Framework.Content.Pipeline/Utilities/CrunchHelpers.cs b/MonoGame.Framework.Content.Pipeline/Utilities/CrunchHelpers.cs index 8ef1ae3f97a..ffdb259e810 100644 --- a/MonoGame.Framework.Content.Pipeline/Utilities/CrunchHelpers.cs +++ b/MonoGame.Framework.Content.Pipeline/Utilities/CrunchHelpers.cs @@ -137,7 +137,7 @@ internal static class Crunch /// The exit code for the basisu process. private static int Run(string args, out string stdOut, out string stdErr) { - return ExternalTool.RunDotnetTool("mgcb-crunch", args, out stdOut, out stdErr); + return ExternalTool.RunDotnetTool(ExternalTool.Crunch, args, out stdOut, out stdErr); } /// diff --git a/Templates/MonoGame.Templates.CSharp/content/MonoGame.Application.Android.CSharp/.config/dotnet-tools.json b/Templates/MonoGame.Templates.CSharp/content/MonoGame.Application.Android.CSharp/.config/dotnet-tools.json index a966e81a617..099bf0db52e 100644 --- a/Templates/MonoGame.Templates.CSharp/content/MonoGame.Application.Android.CSharp/.config/dotnet-tools.json +++ b/Templates/MonoGame.Templates.CSharp/content/MonoGame.Application.Android.CSharp/.config/dotnet-tools.json @@ -2,12 +2,6 @@ "version": 1, "isRoot": true, "tools": { - "dotnet-mgcb": { - "version": "3.8.2.1-develop", - "commands": [ - "mgcb" - ] - }, "dotnet-mgcb-editor": { "version": "3.8.2.1-develop", "commands": [ diff --git a/Templates/MonoGame.Templates.CSharp/content/MonoGame.Application.DesktopGL.CSharp/.config/dotnet-tools.json b/Templates/MonoGame.Templates.CSharp/content/MonoGame.Application.DesktopGL.CSharp/.config/dotnet-tools.json index a966e81a617..099bf0db52e 100644 --- a/Templates/MonoGame.Templates.CSharp/content/MonoGame.Application.DesktopGL.CSharp/.config/dotnet-tools.json +++ b/Templates/MonoGame.Templates.CSharp/content/MonoGame.Application.DesktopGL.CSharp/.config/dotnet-tools.json @@ -2,12 +2,6 @@ "version": 1, "isRoot": true, "tools": { - "dotnet-mgcb": { - "version": "3.8.2.1-develop", - "commands": [ - "mgcb" - ] - }, "dotnet-mgcb-editor": { "version": "3.8.2.1-develop", "commands": [ diff --git a/Templates/MonoGame.Templates.CSharp/content/MonoGame.Application.WindowsDX.CSharp/.config/dotnet-tools.json b/Templates/MonoGame.Templates.CSharp/content/MonoGame.Application.WindowsDX.CSharp/.config/dotnet-tools.json index a966e81a617..099bf0db52e 100644 --- a/Templates/MonoGame.Templates.CSharp/content/MonoGame.Application.WindowsDX.CSharp/.config/dotnet-tools.json +++ b/Templates/MonoGame.Templates.CSharp/content/MonoGame.Application.WindowsDX.CSharp/.config/dotnet-tools.json @@ -2,12 +2,6 @@ "version": 1, "isRoot": true, "tools": { - "dotnet-mgcb": { - "version": "3.8.2.1-develop", - "commands": [ - "mgcb" - ] - }, "dotnet-mgcb-editor": { "version": "3.8.2.1-develop", "commands": [ diff --git a/Templates/MonoGame.Templates.CSharp/content/MonoGame.Application.iOS.CSharp/.config/dotnet-tools.json b/Templates/MonoGame.Templates.CSharp/content/MonoGame.Application.iOS.CSharp/.config/dotnet-tools.json index a966e81a617..099bf0db52e 100644 --- a/Templates/MonoGame.Templates.CSharp/content/MonoGame.Application.iOS.CSharp/.config/dotnet-tools.json +++ b/Templates/MonoGame.Templates.CSharp/content/MonoGame.Application.iOS.CSharp/.config/dotnet-tools.json @@ -2,12 +2,6 @@ "version": 1, "isRoot": true, "tools": { - "dotnet-mgcb": { - "version": "3.8.2.1-develop", - "commands": [ - "mgcb" - ] - }, "dotnet-mgcb-editor": { "version": "3.8.2.1-develop", "commands": [ diff --git a/Templates/MonoGame.Templates.CSharp/content/MonoGame.Library.CSharp/.config/dotnet-tools.json b/Templates/MonoGame.Templates.CSharp/content/MonoGame.Library.CSharp/.config/dotnet-tools.json index a966e81a617..099bf0db52e 100644 --- a/Templates/MonoGame.Templates.CSharp/content/MonoGame.Library.CSharp/.config/dotnet-tools.json +++ b/Templates/MonoGame.Templates.CSharp/content/MonoGame.Library.CSharp/.config/dotnet-tools.json @@ -2,12 +2,6 @@ "version": 1, "isRoot": true, "tools": { - "dotnet-mgcb": { - "version": "3.8.2.1-develop", - "commands": [ - "mgcb" - ] - }, "dotnet-mgcb-editor": { "version": "3.8.2.1-develop", "commands": [ diff --git a/Tools/MonoGame.Content.Builder.Editor/Common/PipelineController.cs b/Tools/MonoGame.Content.Builder.Editor/Common/PipelineController.cs index 8f5dbb2764e..e5e58858e7f 100644 --- a/Tools/MonoGame.Content.Builder.Editor/Common/PipelineController.cs +++ b/Tools/MonoGame.Content.Builder.Editor/Common/PipelineController.cs @@ -35,12 +35,17 @@ public partial class PipelineController : IController private static readonly string [] _mgcbSearchPaths = new [] { #if DEBUG +#if MAC + Path.Combine(Path.GetDirectoryName(System.AppContext.BaseDirectory) ?? "", "../../../MonoGame.Content.Builder/Debug/mgcb.dll"), + Path.Combine(Path.GetDirectoryName(System.AppContext.BaseDirectory) ?? "", "../../../../../MonoGame.Content.Builder/Debug/mgcb.dll"), +#else Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? "", "../../../MonoGame.Content.Builder/Debug/mgcb.dll"), Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? "", "../../../../../../MonoGame.Content.Builder/Debug/mgcb.dll"), +#endif #else #if MAC Path.Combine(Path.GetDirectoryName(System.AppContext.BaseDirectory) ?? "", "../../../MonoGame.Content.Builder/Release/mgcb.dll"), - Path.Combine(Path.GetDirectoryName(System.AppContext.BaseDirectory) ?? "", "../../../../../../MonoGame.Content.Builder/Release/mgcb.dll"), + Path.Combine(Path.GetDirectoryName(System.AppContext.BaseDirectory) ?? "", "../../../../../MonoGame.Content.Builder/Release/mgcb.dll"), #else Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? "", "../../../MonoGame.Content.Builder/Release/mgcb.dll"), Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? "", "../../../../../../MonoGame.Content.Builder/Release/mgcb.dll"), @@ -127,6 +132,7 @@ private PipelineController(IView view) LoadTemplates(templatesPath); #endif + RestoreMGCB(); UpdateMenu(); view.UpdateRecentList(PipelineSettings.Default.ProjectHistory); @@ -574,6 +580,22 @@ public void Clean() UpdateMenu(); } + private void RestoreMGCB() + { + var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + var version = Assembly.GetExecutingAssembly().GetName().Version.ToString(); + var workingDirectory = Path.Combine(appDataPath, "mgcb-dotnet-tool", version); + if (Directory.Exists(workingDirectory)) + return; + Directory.CreateDirectory(workingDirectory); + var dotnet = Global.Unix ? "dotnet" : "dotnet.exe"; + if (Util.Run(dotnet, $"tool install dotnet-mgcb --version {version} --tool-path .", workingDirectory) != 0) + { + // install the latest + Util.Run(dotnet, $"tool install dotnet-mgcb --tool-path .", workingDirectory); + } + } + private void DoBuild(string commands) { Encoding encoding; @@ -585,9 +607,11 @@ private void DoBuild(string commands) encoding = Encoding.UTF8; } - var mgcbCommand = "mgcb"; + + var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + var version = Assembly.GetExecutingAssembly().GetName().Version.ToString (); + var mgcbCommand = Path.Combine(appDataPath, "mgcb-dotnet-tool", version, "mgcb"); var currentDir = Environment.CurrentDirectory; - foreach (var path in _mgcbSearchPaths) { var fullPath = Path.Combine(currentDir, path); @@ -598,26 +622,17 @@ private void DoBuild(string commands) break; } } + // allow the users to override the path with an environment variable + // the same as the MSBuild property in the .targets + var mgcbUserPath = Environment.GetEnvironmentVariable("MGCBCommand"); + if (!string.IsNullOrEmpty(mgcbUserPath) && File.Exists(mgcbUserPath)) + { + mgcbCommand = mgcbUserPath; + } try { - // Prepare the process. - _buildProcess = new Process - { - StartInfo = new ProcessStartInfo - { - FileName = Global.Unix ? "dotnet" : "dotnet.exe", - Arguments = $"{mgcbCommand} {commands}", - WorkingDirectory = Path.GetDirectoryName(_project.OriginalPath), - CreateNoWindow = true, - WindowStyle = ProcessWindowStyle.Hidden, - UseShellExecute = false, - RedirectStandardOutput = true, - StandardOutputEncoding = encoding - } - }; - _buildProcess.OutputDataReceived += (sender, args) => View.OutputAppend(args.Data); - + _buildProcess = Util.CreateProcess(mgcbCommand, commands, Path.GetDirectoryName (_project.OriginalPath), encoding, (s) => View.OutputAppend (s)); // Fire off the process. Console.WriteLine(_buildProcess.StartInfo.FileName + " " + _buildProcess.StartInfo.Arguments); Environment.CurrentDirectory = _buildProcess.StartInfo.WorkingDirectory; diff --git a/Tools/MonoGame.Content.Builder.Editor/Common/Util.cs b/Tools/MonoGame.Content.Builder.Editor/Common/Util.cs index 8684e46ad08..3053572ed3f 100644 --- a/Tools/MonoGame.Content.Builder.Editor/Common/Util.cs +++ b/Tools/MonoGame.Content.Builder.Editor/Common/Util.cs @@ -1,6 +1,8 @@ using System; +using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; +using System.Text; namespace MonoGame.Tools.Pipeline { @@ -46,5 +48,41 @@ public static string GetRelativePath(string filespec, string folder) return result; } + + public static int Run(string command, string arguments, string workingDirectory) + { + var process = CreateProcess(command, arguments, workingDirectory, Encoding.UTF8, (s) => Console.WriteLine(s)); + process.Start(); + process.BeginOutputReadLine(); + process.WaitForExit(); + return process.ExitCode; + } + + public static Process CreateProcess(string command, string arguments, string workingDirectory, Encoding encoding, Action output) + { + var exe = command; + var args = arguments; + if (command.EndsWith (".dll")) { + // we are referencing the dll directly. We need to call dotnet to host. + exe = Global.Unix ? "dotnet" : "dotnet.exe"; + args = $"{command} {arguments}"; + } + var _buildProcess = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = exe, + Arguments = args, + WorkingDirectory = workingDirectory, + CreateNoWindow = true, + WindowStyle = ProcessWindowStyle.Hidden, + UseShellExecute = false, + RedirectStandardOutput = true, + StandardOutputEncoding = encoding + } + }; + _buildProcess.OutputDataReceived += (sender, args) => output(args.Data); + return _buildProcess; + } } } diff --git a/Tools/MonoGame.Content.Builder.Task/MonoGame.Content.Builder.Task.props b/Tools/MonoGame.Content.Builder.Task/MonoGame.Content.Builder.Task.props index d3e96526443..59166b6509b 100644 --- a/Tools/MonoGame.Content.Builder.Task/MonoGame.Content.Builder.Task.props +++ b/Tools/MonoGame.Content.Builder.Task/MonoGame.Content.Builder.Task.props @@ -3,7 +3,11 @@ dotnet true + + true + $(MSBuildThisFileDirectory)dotnet-tools/ mgcb + 3.8.1.1-develop diff --git a/Tools/MonoGame.Content.Builder.Task/MonoGame.Content.Builder.Task.targets b/Tools/MonoGame.Content.Builder.Task/MonoGame.Content.Builder.Task.targets index 4c2ab79c492..fb1cdc4766b 100644 --- a/Tools/MonoGame.Content.Builder.Task/MonoGame.Content.Builder.Task.targets +++ b/Tools/MonoGame.Content.Builder.Task/MonoGame.Content.Builder.Task.targets @@ -84,6 +84,12 @@ + + + + + + - + - - - + + <_Command Condition="Exists ('$(MGCBToolDirectory)\$(MGCBCommand)')">"$(MGCBToolDirectory)\$(MGCBCommand)" + + <_Command Condition=" '$(_Command)' == '' ">"$(DotnetCommand)" "$(MGCBCommand)" + diff --git a/build/BuildToolsTasks/BuildContentPipelineTask.cs b/build/BuildToolsTasks/BuildContentPipelineTask.cs index fed3f828928..2f6018bd76e 100644 --- a/build/BuildToolsTasks/BuildContentPipelineTask.cs +++ b/build/BuildToolsTasks/BuildContentPipelineTask.cs @@ -9,11 +9,5 @@ public override void Run(BuildContext context) { var builderPath = context.GetProjectPath(ProjectType.ContentPipeline); context.DotNetPack(builderPath, context.DotNetPackSettings); - - // ensure that the local development has the required dotnet tools. - // this won't actually include the tool manifest in a final build, - // but it will setup a local developer's project - context.DotNetTool(builderPath, "tool install --create-manifest-if-needed mgcb-basisu"); - context.DotNetTool(builderPath, "tool install --create-manifest-if-needed mgcb-crunch"); } } diff --git a/build/BuildToolsTasks/BuildMGCBEditorTask.cs b/build/BuildToolsTasks/BuildMGCBEditorTask.cs index c499dcb168f..8ded808d6d3 100644 --- a/build/BuildToolsTasks/BuildMGCBEditorTask.cs +++ b/build/BuildToolsTasks/BuildMGCBEditorTask.cs @@ -8,12 +8,15 @@ public sealed class BuildMGCBEditorTask : FrostingTask { public override void Run(BuildContext context) { - context.ReplaceRegexInFiles( - @"CFBundleShortVersionString<\/key>\s*([^\s]*)<\/string>", - "Tools/MonoGame.Content.Builder.Editor/Info.plist", - $"CFBundleShortVersionString\n\t{context.Version}", - RegexOptions.Singleline - ); + if (context.BuildSystem().IsRunningOnGitHubActions) + { + context.ReplaceRegexInFiles( + "Tools/MonoGame.Content.Builder.Editor/Info.plist", + @"CFBundleShortVersionString<\/key>\s*([^\s]*)<\/string>", + $"CFBundleShortVersionString\n\t{context.Version}", + RegexOptions.Singleline + ); + } var platform = context.Environment.Platform.Family switch { diff --git a/build/BuildToolsTasks/BuildMGCBTask.cs b/build/BuildToolsTasks/BuildMGCBTask.cs index c2276d601fc..b334796e65e 100644 --- a/build/BuildToolsTasks/BuildMGCBTask.cs +++ b/build/BuildToolsTasks/BuildMGCBTask.cs @@ -1,3 +1,4 @@ +using System.Text.RegularExpressions; namespace BuildScripts; @@ -7,6 +8,15 @@ public sealed class BuildMGCBTask : FrostingTask { public override void Run(BuildContext context) { + if (context.BuildSystem().IsRunningOnGitHubActions) + { + context.ReplaceRegexInFiles( + "Tools/MonoGame.Content.Builder.Task/MonoGame.Content.Builder.Task.props", + @"([^\s]*)<\/MonoGameVersion>", + $"{context.Version}", + RegexOptions.Singleline + ); + } context.DotNetPack(context.GetProjectPath(ProjectType.Tools, "MonoGame.Content.Builder"), context.DotNetPackSettings); context.DotNetPack(context.GetProjectPath(ProjectType.Tools, "MonoGame.Content.Builder.Task"), context.DotNetPackSettings); } diff --git a/build/DeployTasks/UploadArtifactsTask.cs b/build/DeployTasks/UploadArtifactsTask.cs index 61abf7eceef..c50723d0290 100644 --- a/build/DeployTasks/UploadArtifactsTask.cs +++ b/build/DeployTasks/UploadArtifactsTask.cs @@ -15,10 +15,57 @@ public override async Task RunAsync(BuildContext context) _ => "linux" }; + // Clean up build tools if installed + // otherwise we get permission issues after extraction + // because the zip removes all the permissions. + // Plus in windows hidden files (like the .store directory) + // are ignored. This causes `dotnet tool` to error. + var path = System.IO.Path.Combine(context.BuildOutput, "Tests", "Tools", "Release", "dotnet-tools"); + if (System.IO.Directory.Exists(path)) { + context.Log.Information ($"Deleting: {path}"); + System.IO.Directory.Delete (path, recursive: true); + } + if (context.IsRunningOnMacOs()) + { + path = System.IO.Path.Combine(context.BuildOutput, "Tests", "Tools", "Release", "osx"); + DeleteToolStore(context, path); + } + if (context.IsRunningOnLinux()) + { + path = System.IO.Path.Combine(context.BuildOutput, "Tests", "Tools", "Release", "linux"); + DeleteToolStore(context, path); + } + if (context.IsRunningOnWindows()) + { + path = System.IO.Path.Combine(context.BuildOutput, "Tests", "Tools", "Release"); + DeleteToolStore(context, path); + } + + await context.GitHubActions().Commands.UploadArtifact(new DirectoryPath(context.NuGetsDirectory.FullPath), $"nuget-{os}"); await context.GitHubActions().Commands.UploadArtifact(new DirectoryPath(System.IO.Path.Combine(context.BuildOutput, "Tests", "Tools", "Release")), $"tests-tools-{os}"); await context.GitHubActions().Commands.UploadArtifact(new DirectoryPath(System.IO.Path.Combine(context.BuildOutput, "Tests", "DesktopGL", "Release")), $"tests-desktopgl-{os}"); if (context.IsRunningOnWindows()) await context.GitHubActions().Commands.UploadArtifact(new DirectoryPath(System.IO.Path.Combine(context.BuildOutput, "Tests", "WindowsDX", "Release")), $"tests-windowsdx-{os}"); } + + void DeleteToolStore(BuildContext context, string path) + { + if (System.IO.Directory.Exists(path)) { + var store = System.IO.Path.Combine (path, ".store"); + if (System.IO.Directory.Exists(store)) { + context.Log.Information($"Deleting: {store}"); + System.IO.Directory.Delete(store, recursive: true); + foreach (var file in System.IO.Directory.GetFiles(path, "mgcb-*", System.IO.SearchOption.TopDirectoryOnly)) { + context.Log.Information($"Deleting: {file}"); + System.IO.File.Delete(file); + } + foreach (var file in System.IO.Directory.GetFiles(path, "tools_version.txt", System.IO.SearchOption.TopDirectoryOnly)) { + context.Log.Information($"Deleting: {file}"); + System.IO.File.Delete(file); + } + + } + } + } }