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

C#: MSBuild logs and panel enhancements
This commit is contained in:
Rémi Verschelde 2023-02-07 19:37:43 +01:00
commit 8be4feec04
No known key found for this signature in database
GPG Key ID: C3336907360768E1
8 changed files with 143 additions and 20 deletions

View File

@ -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)
{

View File

@ -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?

View File

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

View File

@ -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)

View File

@ -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();

View File

@ -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))

View File

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

View File

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