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..778707cda56 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,9 @@ namespace Microsoft.Xna.Framework.Content.Pipeline
///
internal class ExternalTool
{
+ public static string Crunch = "mgcb-crunch";
+ public static string BasisU = "mgcb-basisu";
+
public static int Run(string command, string arguments)
{
string stdout, stderr;
@@ -27,13 +32,45 @@ public static int Run(string command, string arguments)
return result;
}
+ public static void RestoreDotnetTool(string command, string toolName)
+ {
+ 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");
+ if (Directory.Exists (Path.Combine(path, toolName)))
+ return;
+ 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);
+ }
+ var version = Assembly.GetExecutingAssembly().GetName().Version.ToString();
+ if (Run(exe, $"tool {command} {toolName} --version {version} --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()
+ {
+ RestoreDotnetTool("install", Crunch);
+ RestoreDotnetTool("install", BasisU);
+ }
+
///
/// 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 +105,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/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..1308e0052de 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,20 @@ 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);
+ 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 +605,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 +620,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..daa0884a020 100644
--- a/Tools/MonoGame.Content.Builder.Task/MonoGame.Content.Builder.Task.props
+++ b/Tools/MonoGame.Content.Builder.Task/MonoGame.Content.Builder.Task.props
@@ -3,6 +3,7 @@
dotnet
true
+ $(MSBuildThisFileDirectory)dotnet-tools/
mgcb
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..52f05b26a27 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/DeployTasks/UploadArtifactsTask.cs b/build/DeployTasks/UploadArtifactsTask.cs
index 61abf7eceef..e738b20ffce 100644
--- a/build/DeployTasks/UploadArtifactsTask.cs
+++ b/build/DeployTasks/UploadArtifactsTask.cs
@@ -15,10 +15,52 @@ 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);
+ }
+ }
+ }
+ }
}