Browse Source

Merge pull request #72061 from paulloz/csharp/better-logs-management

C#: MSBuild logs and panel enhancements
Rémi Verschelde 2 years ago
parent
commit
8be4feec04

+ 1 - 2
modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs

@@ -22,8 +22,7 @@ namespace GodotTools.Build
         // TODO Use List once we have proper serialization
         public Godot.Collections.Array CustomProperties { get; private set; } = new();
 
-        public string LogsDirPath =>
-            Path.Combine(GodotSharpDirs.BuildLogsDirs, $"{Solution.Md5Text()}_{Configuration}");
+        public string LogsDirPath => GodotSharpDirs.LogsDirPathFor(Solution, Configuration);
 
         public override bool Equals(object? obj)
         {

+ 52 - 8
modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs

@@ -7,6 +7,7 @@ using System.IO;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using Godot;
 using GodotTools.BuildLogger;
 using GodotTools.Utils;
 
@@ -22,9 +23,11 @@ namespace GodotTools.Build
             if (dotnetPath == null)
                 throw new FileNotFoundException("Cannot find the dotnet executable.");
 
+            var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
+
             var startInfo = new ProcessStartInfo(dotnetPath);
 
-            BuildArguments(buildInfo, startInfo.ArgumentList);
+            BuildArguments(buildInfo, startInfo.ArgumentList, editorSettings);
 
             string launchMessage = startInfo.GetCommandLineDisplay(new StringBuilder("Running: ")).ToString();
             stdOutHandler?.Invoke(launchMessage);
@@ -35,6 +38,8 @@ namespace GodotTools.Build
             startInfo.RedirectStandardError = true;
             startInfo.UseShellExecute = false;
             startInfo.CreateNoWindow = true;
+            startInfo.EnvironmentVariables["DOTNET_CLI_UI_LANGUAGE"]
+                = ((string)editorSettings.GetSetting("interface/editor/editor_language")).Replace('_', '-');
 
             // Needed when running from Developer Command Prompt for VS
             RemovePlatformVariable(startInfo.EnvironmentVariables);
@@ -83,9 +88,11 @@ namespace GodotTools.Build
             if (dotnetPath == null)
                 throw new FileNotFoundException("Cannot find the dotnet executable.");
 
+            var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
+
             var startInfo = new ProcessStartInfo(dotnetPath);
 
-            BuildPublishArguments(buildInfo, startInfo.ArgumentList);
+            BuildPublishArguments(buildInfo, startInfo.ArgumentList, editorSettings);
 
             string launchMessage = startInfo.GetCommandLineDisplay(new StringBuilder("Running: ")).ToString();
             stdOutHandler?.Invoke(launchMessage);
@@ -95,6 +102,8 @@ namespace GodotTools.Build
             startInfo.RedirectStandardOutput = true;
             startInfo.RedirectStandardError = true;
             startInfo.UseShellExecute = false;
+            startInfo.EnvironmentVariables["DOTNET_CLI_UI_LANGUAGE"]
+                = ((string)editorSettings.GetSetting("interface/editor/editor_language")).Replace('_', '-');
 
             // Needed when running from Developer Command Prompt for VS
             RemovePlatformVariable(startInfo.EnvironmentVariables);
@@ -124,7 +133,8 @@ namespace GodotTools.Build
             }
         }
 
-        private static void BuildArguments(BuildInfo buildInfo, Collection<string> arguments)
+        private static void BuildArguments(BuildInfo buildInfo, Collection<string> arguments,
+            EditorSettings editorSettings)
         {
             // `dotnet clean` / `dotnet build` commands
             arguments.Add(buildInfo.OnlyClean ? "clean" : "build");
@@ -150,12 +160,14 @@ namespace GodotTools.Build
             arguments.Add(buildInfo.Configuration);
 
             // Verbosity
-            arguments.Add("-v");
-            arguments.Add("normal");
+            AddVerbosityArguments(buildInfo, arguments, editorSettings);
 
             // Logger
             AddLoggerArgument(buildInfo, arguments);
 
+            // Binary log
+            AddBinaryLogArgument(buildInfo, arguments, editorSettings);
+
             // Custom properties
             foreach (var customProperty in buildInfo.CustomProperties)
             {
@@ -163,7 +175,8 @@ namespace GodotTools.Build
             }
         }
 
-        private static void BuildPublishArguments(BuildInfo buildInfo, Collection<string> arguments)
+        private static void BuildPublishArguments(BuildInfo buildInfo, Collection<string> arguments,
+            EditorSettings editorSettings)
         {
             arguments.Add("publish"); // `dotnet publish` command
 
@@ -193,12 +206,14 @@ namespace GodotTools.Build
             arguments.Add("true");
 
             // Verbosity
-            arguments.Add("-v");
-            arguments.Add("normal");
+            AddVerbosityArguments(buildInfo, arguments, editorSettings);
 
             // Logger
             AddLoggerArgument(buildInfo, arguments);
 
+            // Binary log
+            AddBinaryLogArgument(buildInfo, arguments, editorSettings);
+
             // Custom properties
             foreach (var customProperty in buildInfo.CustomProperties)
             {
@@ -213,6 +228,25 @@ namespace GodotTools.Build
             }
         }
 
+        private static void AddVerbosityArguments(BuildInfo buildInfo, Collection<string> arguments,
+            EditorSettings editorSettings)
+        {
+            var verbosityLevel =
+                editorSettings.GetSetting(GodotSharpEditor.Settings.VerbosityLevel).As<VerbosityLevelId>();
+            arguments.Add("-v");
+            arguments.Add(verbosityLevel switch
+            {
+                VerbosityLevelId.Quiet => "quiet",
+                VerbosityLevelId.Minimal => "minimal",
+                VerbosityLevelId.Detailed => "detailed",
+                VerbosityLevelId.Diagnostic => "diagnostic",
+                _ => "normal",
+            });
+
+            if ((bool)editorSettings.GetSetting(GodotSharpEditor.Settings.NoConsoleLogging))
+                arguments.Add("-noconlog");
+        }
+
         private static void AddLoggerArgument(BuildInfo buildInfo, Collection<string> arguments)
         {
             string buildLoggerPath = Path.Combine(Internals.GodotSharpDirs.DataEditorToolsDir,
@@ -222,6 +256,16 @@ namespace GodotTools.Build
                 $"-l:{typeof(GodotBuildLogger).FullName},{buildLoggerPath};{buildInfo.LogsDirPath}");
         }
 
+        private static void AddBinaryLogArgument(BuildInfo buildInfo, Collection<string> arguments,
+            EditorSettings editorSettings)
+        {
+            if (!(bool)editorSettings.GetSetting(GodotSharpEditor.Settings.CreateBinaryLog))
+                return;
+
+            arguments.Add($"-bl:{Path.Combine(buildInfo.LogsDirPath, "msbuild.binlog")}");
+            arguments.Add("-ds:False"); // Honestly never understood why -bl also switches -ds on.
+        }
+
         private static void RemovePlatformVariable(StringDictionary environmentVariables)
         {
             // EnvironmentVariables is case sensitive? Seriously?

+ 22 - 0
modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs

@@ -1,4 +1,5 @@
 using System;
+using System.IO;
 using Godot;
 using GodotTools.Internals;
 using static GodotTools.Internals.Globals;
@@ -14,6 +15,7 @@ namespace GodotTools.Build
         private Button _errorsBtn;
         private Button _warningsBtn;
         private Button _viewLogBtn;
+        private Button _openLogsFolderBtn;
 
         private void WarningsToggled(bool pressed)
         {
@@ -93,6 +95,10 @@ namespace GodotTools.Build
 
         private void ViewLogToggled(bool pressed) => BuildOutputView.LogVisible = pressed;
 
+        private void OpenLogsFolderPressed() => OS.ShellOpen(
+            $"file://{GodotSharpDirs.LogsDirPathFor("Debug")}"
+        );
+
         private void BuildMenuOptionPressed(long id)
         {
             switch ((BuildMenuOptions)id)
@@ -171,6 +177,22 @@ namespace GodotTools.Build
             _viewLogBtn.Toggled += ViewLogToggled;
             toolBarHBox.AddChild(_viewLogBtn);
 
+            // Horizontal spacer, push everything to the right.
+            toolBarHBox.AddChild(new Control
+            {
+                SizeFlagsHorizontal = SizeFlags.ExpandFill,
+            });
+
+            _openLogsFolderBtn = new Button
+            {
+                Text = "Show Logs in File Manager".TTR(),
+                Icon = GetThemeIcon("Filesystem", "EditorIcons"),
+                ExpandIcon = false,
+                FocusMode = FocusModeEnum.None,
+            };
+            _openLogsFolderBtn.Pressed += OpenLogsFolderPressed;
+            toolBarHBox.AddChild(_openLogsFolderBtn);
+
             BuildOutputView = new BuildOutputView();
             AddChild(BuildOutputView);
         }

+ 45 - 5
modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs

@@ -22,6 +22,14 @@ namespace GodotTools
 {
     public partial class GodotSharpEditor : EditorPlugin, ISerializationListener
     {
+        public static class Settings
+        {
+            public const string ExternalEditor = "dotnet/editor/external_editor";
+            public const string VerbosityLevel = "dotnet/build/verbosity_level";
+            public const string NoConsoleLogging = "dotnet/build/no_console_logging";
+            public const string CreateBinaryLog = "dotnet/build/create_binary_log";
+        }
+
         private EditorSettings _editorSettings;
 
         private PopupMenu _menuPopup;
@@ -171,7 +179,7 @@ namespace GodotTools
         [UsedImplicitly]
         public Error OpenInExternalEditor(Script script, int line, int col)
         {
-            var editorId = (ExternalEditorId)(int)_editorSettings.GetSetting("mono/editor/external_editor");
+            var editorId = _editorSettings.GetSetting(Settings.ExternalEditor).As<ExternalEditorId>();
 
             switch (editorId)
             {
@@ -323,8 +331,7 @@ namespace GodotTools
         [UsedImplicitly]
         public bool OverridesExternalEditor()
         {
-            return (ExternalEditorId)(int)_editorSettings.GetSetting("mono/editor/external_editor") !=
-                   ExternalEditorId.None;
+            return _editorSettings.GetSetting(Settings.ExternalEditor).As<ExternalEditorId>() != ExternalEditorId.None;
         }
 
         public override bool _Build()
@@ -453,7 +460,10 @@ namespace GodotTools
             _menuPopup.IdPressed += _MenuOptionPressed;
 
             // External editor settings
-            EditorDef("mono/editor/external_editor", Variant.From(ExternalEditorId.None));
+            EditorDef(Settings.ExternalEditor, Variant.From(ExternalEditorId.None));
+            EditorDef(Settings.VerbosityLevel, Variant.From(VerbosityLevelId.Normal));
+            EditorDef(Settings.NoConsoleLogging, false);
+            EditorDef(Settings.CreateBinaryLog, false);
 
             string settingsHintStr = "Disabled";
 
@@ -481,11 +491,23 @@ namespace GodotTools
             _editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary
             {
                 ["type"] = (int)Variant.Type.Int,
-                ["name"] = "mono/editor/external_editor",
+                ["name"] = Settings.ExternalEditor,
                 ["hint"] = (int)PropertyHint.Enum,
                 ["hint_string"] = settingsHintStr
             });
 
+            var verbosityLevels = Enum.GetValues<VerbosityLevelId>().Select(level => $"{Enum.GetName(level)}:{(int)level}");
+            _editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary
+            {
+                ["type"] = (int)Variant.Type.Int,
+                ["name"] = Settings.VerbosityLevel,
+                ["hint"] = (int)PropertyHint.Enum,
+                ["hint_string"] = string.Join(",", verbosityLevels),
+            });
+
+            OnSettingsChanged();
+            _editorSettings.SettingsChanged += OnSettingsChanged;
+
             // Export plugin
             var exportPlugin = new ExportPlugin();
             AddExportPlugin(exportPlugin);
@@ -510,6 +532,24 @@ namespace GodotTools
             AddChild(GodotIdeManager);
         }
 
+        public override void _DisablePlugin()
+        {
+            base._DisablePlugin();
+
+            _editorSettings.SettingsChanged -= OnSettingsChanged;
+        }
+
+        private void OnSettingsChanged()
+        {
+            // We want to force NoConsoleLogging to true when the VerbosityLevel is at Detailed or above.
+            // At that point, there's so much info logged that it doesn't make sense to display it in
+            // the tiny editor window, and it'd make the editor hang or crash anyway.
+            var verbosityLevel = _editorSettings.GetSetting(Settings.VerbosityLevel).As<VerbosityLevelId>();
+            var hideConsoleLog = (bool)_editorSettings.GetSetting(Settings.NoConsoleLogging);
+            if (verbosityLevel >= VerbosityLevelId.Detailed && !hideConsoleLog)
+                _editorSettings.SetSetting(Settings.NoConsoleLogging, Variant.From(true));
+        }
+
         protected override void Dispose(bool disposing)
         {
             if (disposing)

+ 4 - 3
modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs

@@ -21,7 +21,8 @@ namespace GodotTools.Ides
                 return _messagingServer;
 
             _messagingServer?.Dispose();
-            _messagingServer = new MessagingServer(OS.GetExecutablePath(), ProjectSettings.GlobalizePath(GodotSharpDirs.ResMetadataDir), new GodotLogger());
+            _messagingServer = new MessagingServer(OS.GetExecutablePath(),
+                ProjectSettings.GlobalizePath(GodotSharpDirs.ResMetadataDir), new GodotLogger());
 
             _ = _messagingServer.Listen();
 
@@ -76,8 +77,8 @@ namespace GodotTools.Ides
 
         public async Task<EditorPick?> LaunchIdeAsync(int millisecondsTimeout = 10000)
         {
-            var editorId = (ExternalEditorId)(int)GodotSharpEditor.Instance.GetEditorInterface()
-                .GetEditorSettings().GetSetting("mono/editor/external_editor");
+            var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
+            var editorId = editorSettings.GetSetting(GodotSharpEditor.Settings.ExternalEditor).As<ExternalEditorId>();
             string editorIdentity = GetExternalEditorIdentity(editorId);
 
             var runningServer = GetRunningOrNewServer();

+ 2 - 2
modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs

@@ -9,7 +9,7 @@ namespace GodotTools.Ides.Rider
 {
     public static class RiderPathManager
     {
-        public static readonly string EditorPathSettingName = "mono/editor/editor_path_optional";
+        public static readonly string EditorPathSettingName = "dotnet/editor/editor_path_optional";
 
         private static string GetRiderPathFromSettings()
         {
@@ -22,7 +22,7 @@ namespace GodotTools.Ides.Rider
         public static void Initialize()
         {
             var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
-            var editor = (ExternalEditorId)(int)editorSettings.GetSetting("mono/editor/external_editor");
+            var editor = editorSettings.GetSetting(GodotSharpEditor.Settings.ExternalEditor).As<ExternalEditorId>();
             if (editor == ExternalEditorId.Rider)
             {
                 if (!editorSettings.HasSetting(EditorPathSettingName))

+ 6 - 0
modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs

@@ -115,5 +115,11 @@ namespace GodotTools.Internals
                 return _projectCsProjPath;
             }
         }
+
+        public static string LogsDirPathFor(string solution, string configuration)
+            => Path.Combine(BuildLogsDirs, $"{solution.Md5Text()}_{configuration}");
+
+        public static string LogsDirPathFor(string configuration)
+            => LogsDirPathFor(ProjectSlnPath, configuration);
     }
 }

+ 11 - 0
modules/mono/editor/GodotTools/GodotTools/VerbosityLevelId.cs

@@ -0,0 +1,11 @@
+namespace GodotTools
+{
+    public enum VerbosityLevelId : long
+    {
+        Quiet,
+        Minimal,
+        Normal,
+        Detailed,
+        Diagnostic,
+    }
+}