From 7f603ddb7ad7e93efcee949cc8f9532e7a580da8 Mon Sep 17 00:00:00 2001 From: Matt Parker <61717342+MattParkerDev@users.noreply.github.com> Date: Sat, 17 Jan 2026 15:03:44 +1000 Subject: [PATCH] cancel msbuild action --- .../Features/Build/BuildService.cs | 20 ++++++++++++++++--- .../Features/Build/BuildPanel.cs | 2 +- src/SharpIDE.Godot/IdeRoot.cs | 5 +++++ src/SharpIDE.Godot/IdeRoot.tscn | 3 ++- .../Components/BuildOutputDisplay.razor | 4 ++-- 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/SharpIDE.Application/Features/Build/BuildService.cs b/src/SharpIDE.Application/Features/Build/BuildService.cs index 6e61ad6..b36cb1e 100644 --- a/src/SharpIDE.Application/Features/Build/BuildService.cs +++ b/src/SharpIDE.Application/Features/Build/BuildService.cs @@ -4,6 +4,7 @@ using Microsoft.Build.Execution; using Microsoft.Build.Framework; using Microsoft.Build.Logging; using Microsoft.Extensions.Logging; +using SharpIDE.Application.Features.Events; using SharpIDE.Application.Features.Logging; namespace SharpIDE.Application.Features.Build; @@ -19,10 +20,14 @@ public class BuildService(ILogger logger) { private readonly ILogger _logger = logger; - public event Func BuildStarted = () => Task.CompletedTask; + public EventWrapper BuildStarted { get; } = new(() => Task.CompletedTask); + public EventWrapper BuildFinished { get; } = new(() => Task.CompletedTask); public ChannelTextWriter BuildTextWriter { get; } = new ChannelTextWriter(); + private CancellationTokenSource? _cancellationTokenSource; public async Task MsBuildAsync(string solutionOrProjectFilePath, BuildType buildType = BuildType.Build, CancellationToken cancellationToken = default) { + if (_cancellationTokenSource is not null) throw new InvalidOperationException("A build is already in progress."); + _cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); using var _ = SharpIdeOtel.Source.StartActivity($"{nameof(BuildService)}.{nameof(MsBuildAsync)}"); var terminalLogger = InternalTerminalLoggerFactory.CreateLogger(BuildTextWriter); @@ -50,13 +55,22 @@ public class BuildService(ILogger logger) hostServices: null, flags: BuildRequestDataFlags.None); - await BuildStarted.Invoke().ConfigureAwait(false); + BuildStarted.InvokeParallelFireAndForget(); var timer = Stopwatch.StartNew(); - var buildResult = await BuildManager.DefaultBuildManager.BuildAsync(buildParameters, buildRequest, cancellationToken).ConfigureAwait(false); + var buildResult = await BuildManager.DefaultBuildManager.BuildAsync(buildParameters, buildRequest, _cancellationTokenSource.Token).ConfigureAwait(false); timer.Stop(); + BuildFinished.InvokeParallelFireAndForget(); + _cancellationTokenSource = null; _logger.LogInformation(buildResult.Exception, "Build result: {BuildResult} in {ElapsedMilliseconds}ms", buildResult.OverallResult, timer.ElapsedMilliseconds); } + public async Task CancelBuildAsync() + { + if (_cancellationTokenSource is null) throw new InvalidOperationException("No build is in progress."); + await _cancellationTokenSource.CancelAsync(); + _cancellationTokenSource = null; + } + private static string[] TargetsToBuild(BuildType buildType) { string[] targetsToBuild = buildType switch diff --git a/src/SharpIDE.Godot/Features/Build/BuildPanel.cs b/src/SharpIDE.Godot/Features/Build/BuildPanel.cs index ba1aca8..56ef6f9 100644 --- a/src/SharpIDE.Godot/Features/Build/BuildPanel.cs +++ b/src/SharpIDE.Godot/Features/Build/BuildPanel.cs @@ -14,7 +14,7 @@ public partial class BuildPanel : Control public override void _Ready() { _terminal = new Terminal(GetNode("%Terminal")); - _buildService.BuildStarted += OnBuildStarted; + _buildService.BuildStarted.Subscribe(OnBuildStarted); } public override void _Process(double delta) diff --git a/src/SharpIDE.Godot/IdeRoot.cs b/src/SharpIDE.Godot/IdeRoot.cs index f194aa4..2bd72df 100644 --- a/src/SharpIDE.Godot/IdeRoot.cs +++ b/src/SharpIDE.Godot/IdeRoot.cs @@ -28,6 +28,7 @@ public partial class IdeRoot : Control private Button _rebuildSlnButton = null!; private Button _cleanSlnButton = null!; private Button _restoreSlnButton = null!; + private TextureButton _cancelMsBuildActionButton = null!; private SearchWindow _searchWindow = null!; private SearchAllFilesWindow _searchAllFilesWindow = null!; private CodeEditorPanel _codeEditorPanel = null!; @@ -71,6 +72,7 @@ public partial class IdeRoot : Control _rebuildSlnButton = GetNode