Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement IManagedHotReloadAgent2 and IManagedHotReloadAgent4 for ProjectHotReloadSession #9555

Merged
merged 27 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
81826bd
implement IManagedHotReloadAgent2
LittleLittleCloud Oct 10, 2024
c93988e
return project full path
LittleLittleCloud Oct 11, 2024
fd6a529
update
LittleLittleCloud Oct 14, 2024
4a9c235
update
LittleLittleCloud Oct 14, 2024
1166c77
implement RestartProject
LittleLittleCloud Oct 17, 2024
5b0435e
Merge branch 'u/implementV2' of https://github.com/LittleLittleCloud/…
LittleLittleCloud Oct 17, 2024
0deb4cb
update debug contract version
LittleLittleCloud Oct 17, 2024
1cc524d
update
LittleLittleCloud Oct 17, 2024
a262c58
bump debugger contract version
LittleLittleCloud Oct 18, 2024
682b3af
revert setup/ProjectSystemSetup/ProjectSystemSetup.csproj
LittleLittleCloud Oct 18, 2024
4d35fc8
add ISolutionBuildManager mock to test
LittleLittleCloud Oct 21, 2024
1026620
return _sessionManager._project
LittleLittleCloud Oct 21, 2024
6910c67
update
LittleLittleCloud Oct 30, 2024
7c4f9cf
dispose event listenr when stop project
LittleLittleCloud Oct 30, 2024
86a6bc3
update
LittleLittleCloud Oct 31, 2024
fea82ec
remove restarting seesion from project system side
LittleLittleCloud Nov 1, 2024
dc2f0d5
Merge branch 'main' into u/implementV2
LittleLittleCloud Nov 11, 2024
e622839
clean up
LittleLittleCloud Nov 12, 2024
07809e9
Merge branch 'u/implementV2' of https://github.com/LittleLittleCloud/…
LittleLittleCloud Nov 12, 2024
cad337f
fix comment
LittleLittleCloud Nov 12, 2024
240c2a5
remove unused subscription listener
LittleLittleCloud Nov 13, 2024
135231a
revert change in solution build manager
LittleLittleCloud Nov 13, 2024
c8bbcbc
make HotReloadState back to private again
LittleLittleCloud Nov 13, 2024
299f64e
fix build error
LittleLittleCloud Nov 13, 2024
54b93b9
Update src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSys…
LittleLittleCloud Nov 14, 2024
31c664e
fix comment
LittleLittleCloud Nov 14, 2024
e89e342
Update src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSys…
LittleLittleCloud Nov 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<VSDebuggerVersion>17.13.0-beta.24561.1</VSDebuggerVersion>
</PropertyGroup>

<!--
Expand Down Expand Up @@ -44,6 +45,8 @@
<PackageVersion Include="Microsoft.ServiceHub.Framework" Version="4.7.37" />
<PackageVersion Include="Microsoft.VisualStudio.ComponentModelHost" Version="17.13.13-preview" />
<PackageVersion Include="Microsoft.VisualStudio.Composition" Version="17.12.18" />
<PackageVersion Include="Microsoft.VisualStudio.Debugger.Contracts" Version="$(VSDebuggerVersion)" />
<PackageVersion Include="Microsoft.VisualStudio.Debugger.UI.Interfaces" Version="$(VSDebuggerVersion)" />
<PackageVersion Include="Microsoft.VisualStudio.Data.Core" Version="17.13.38047-preview.1" />
<PackageVersion Include="Microsoft.VisualStudio.Data.Services" Version="17.13.38055-preview.1" />
<PackageVersion Include="Microsoft.VisualStudio.DataDesign.Common" Version="17.13.38055-preview.1" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE.md file in the project root for more information.

using System.Diagnostics;
using Microsoft.VisualStudio.HotReload.Components.DeltaApplier;

namespace Microsoft.VisualStudio.ProjectSystem.VS.HotReload
Expand All @@ -16,4 +17,15 @@ public interface IProjectHotReloadSessionCallback

IDeltaApplier? GetDeltaApplier();
}

internal interface IProjectHotReloadSessionCallback2 : IProjectHotReloadSessionCallback
{
UnconfiguredProject? Project { get; }

Process? Process { get; }

IProjectHotReloadSession? Session { get; }

Task<bool> RestartProjectAsync(bool isRunningUnderDebug, CancellationToken cancellationToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

using Microsoft.VisualStudio.Debugger.Contracts.HotReload;
using Microsoft.VisualStudio.HotReload.Components.DeltaApplier;
using static Microsoft.VisualStudio.ProjectSystem.VS.HotReload.ProjectHotReloadSessionManager;

namespace Microsoft.VisualStudio.ProjectSystem.VS.HotReload
{
internal class ProjectHotReloadSession : IManagedHotReloadAgent, IProjectHotReloadSession, IProjectHotReloadSessionInternal
internal class ProjectHotReloadSession : IManagedHotReloadAgent, IManagedHotReloadAgent2, IManagedHotReloadAgent4, IProjectHotReloadSession, IProjectHotReloadSessionInternal
{
private readonly string _variant;
private readonly string _runtimeVersion;
Expand All @@ -15,6 +16,9 @@ internal class ProjectHotReloadSession : IManagedHotReloadAgent, IProjectHotRelo
private readonly IProjectHotReloadSessionCallback _callback;

private bool _sessionActive;

// This flag is used to identify Debug|NonDebug cases
private bool _isRunningUnderDebugger;
private IDeltaApplier? _deltaApplier;

public ProjectHotReloadSession(
Expand Down Expand Up @@ -99,6 +103,7 @@ public async Task StartSessionAsync(bool runningUnderDebugger, CancellationToken
),
default);
_sessionActive = true;
_isRunningUnderDebugger = runningUnderDebugger;
EnsureDeltaApplierforSession();
}

Expand All @@ -107,7 +112,6 @@ public async Task StopSessionAsync(CancellationToken cancellationToken)
if (_sessionActive)
{
_sessionActive = false;

await _hotReloadAgentManagerClient.Value.AgentTerminatedAsync(this, cancellationToken);
WriteToOutputWindow(
new HotReloadLogMessage(
Expand Down Expand Up @@ -248,10 +252,15 @@ public async ValueTask RestartAsync(CancellationToken cancellationToken)
),
cancellationToken);

await _callback.RestartProjectAsync(cancellationToken);

// TODO: Should we stop the session here? Or does someone else do it?
// TODO: Should we handle rebuilding here? Or do we expect the callback to handle it?
if (_callback is IProjectHotReloadSessionCallback2 callBack2)
{
await callBack2.RestartProjectAsync(_isRunningUnderDebugger, cancellationToken);
}
else
{
await _callback.RestartProjectAsync(cancellationToken);
}
}

public async ValueTask StopAsync(CancellationToken cancellationToken)
Expand Down Expand Up @@ -288,5 +297,25 @@ private void EnsureDeltaApplierforSession()
?? _deltaApplierCreator.Value.CreateManagedDeltaApplier(_runtimeVersion);
}
}

public ValueTask<int?> GetTargetLocalProcessIdAsync(CancellationToken cancellationToken)
{
if (_callback is IProjectHotReloadSessionCallback2 callback2)
{
return new ValueTask<int?>(callback2.Process?.Id);
}

return new ValueTask<int?>();
}

public ValueTask<string?> GetProjectFullPathAsync(CancellationToken cancellationToken)
{
if (_callback is IProjectHotReloadSessionCallback2 callback2)
{
return new ValueTask<string?>(callback2.Project?.FullPath);
}

return new ValueTask<string?>();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE.md file in the project root for more information.

using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Debugger.Contracts.HotReload;
using Microsoft.VisualStudio.HotReload.Components.DeltaApplier;
using Microsoft.VisualStudio.ProjectSystem.Debug;
using Microsoft.VisualStudio.ProjectSystem.Properties;
using Microsoft.VisualStudio.ProjectSystem.VS.Build;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Threading;

namespace Microsoft.VisualStudio.ProjectSystem.VS.HotReload
Expand All @@ -19,6 +23,9 @@ internal class ProjectHotReloadSessionManager : OnceInitializedOnceDisposedAsync
private readonly Lazy<IProjectHotReloadAgent> _projectHotReloadAgent;
private readonly Lazy<IHotReloadDiagnosticOutputService> _hotReloadDiagnosticOutputService;
private readonly Lazy<IProjectHotReloadNotificationService> _projectHotReloadNotificationService;
private readonly IVsService<SVsSolutionBuildManager, IVsSolutionBuildManager2> _vsSolutionBuildManagerService;
private IVsSolutionBuildManager2? _vsSolutionBuildManager2;
private readonly IProjectThreadingService _projectThreadingService;

// Protect the state from concurrent access. For example, our Process.Exited event
// handler may run on one thread while we're still setting up the session on
Expand All @@ -39,15 +46,18 @@ public ProjectHotReloadSessionManager(
IActiveDebugFrameworkServices activeDebugFrameworkServices,
Lazy<IProjectHotReloadAgent> projectHotReloadAgent,
Lazy<IHotReloadDiagnosticOutputService> hotReloadDiagnosticOutputService,
Lazy<IProjectHotReloadNotificationService> projectHotReloadNotificationService)
Lazy<IProjectHotReloadNotificationService> projectHotReloadNotificationService,
IVsService<SVsSolutionBuildManager, IVsSolutionBuildManager2> solutionBuildManagerService)
: base(threadingService.JoinableTaskContext)
{
_project = project;
_projectThreadingService = threadingService;
_projectFaultHandlerService = projectFaultHandlerService;
_activeDebugFrameworkServices = activeDebugFrameworkServices;
_projectHotReloadAgent = projectHotReloadAgent;
_hotReloadDiagnosticOutputService = hotReloadDiagnosticOutputService;
_projectHotReloadNotificationService = projectHotReloadNotificationService;
_vsSolutionBuildManagerService = solutionBuildManagerService;

_semaphore = ReentrantSemaphore.Create(
initialCount: 1,
Expand Down Expand Up @@ -352,10 +362,36 @@ private async Task OnProcessExitedAsync(HotReloadState hotReloadState)
return null;
}

private static Task<bool> RestartProjectAsync(HotReloadState hotReloadState, CancellationToken cancellationToken)
private async Task<bool> RestartProjectAsync(
HotReloadState hotReloadState,
bool isRunningUnderDebug,
CancellationToken cancellationToken)
{
// TODO: Support restarting the project.
return TaskResult.False;
Assumes.NotNull(_project.Services.HostObject);
await _projectThreadingService.SwitchToUIThread();

if (_vsSolutionBuildManager2 is null)
{
_vsSolutionBuildManager2 = await _vsSolutionBuildManagerService.GetValueAsync(cancellationToken);
}

// Step 1: Debug or NonDebug?
uint dbgLaunchFlag = isRunningUnderDebug ? (uint)VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_LAUNCHDEBUG : (uint)VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_LAUNCH;

// Step 2: Build and Launch Debug
var projectVsHierarchy = (IVsHierarchy)_project.Services.HostObject;

var result = _vsSolutionBuildManager2.StartSimpleUpdateProjectConfiguration(
pIVsHierarchyToBuild: projectVsHierarchy,
pIVsHierarchyDependent: null,
pszDependentConfigurationCanonicalName: null,
dwFlags: (uint)VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_BUILD | dbgLaunchFlag,
dwDefQueryResults: (uint)VSSOLNBUILDQUERYRESULTS.VSSBQR_SAVEBEFOREBUILD_QUERY_YES,
fSuppressUI: 0);

ErrorHandler.ThrowOnFailure(result);

return result == HResult.OK;
}

private static Task OnAfterChangesAppliedAsync(HotReloadState hotReloadState, CancellationToken cancellationToken)
Expand Down Expand Up @@ -449,15 +485,16 @@ async Task ApplyHotReloadUpdateInternalAsync()
}
}

private class HotReloadState : IProjectHotReloadSessionCallback
private class HotReloadState : IProjectHotReloadSessionCallback2
{
private readonly ProjectHotReloadSessionManager _sessionManager;

public Process? Process { get; set; }
public IProjectHotReloadSession? Session { get; set; }

// TODO: Support restarting the session.
public bool SupportsRestart => false;
public bool SupportsRestart => true;

public UnconfiguredProject? Project => _sessionManager._project;

public HotReloadState(ProjectHotReloadSessionManager sessionManager)
{
Expand All @@ -481,7 +518,12 @@ public Task<bool> StopProjectAsync(CancellationToken cancellationToken)

public Task<bool> RestartProjectAsync(CancellationToken cancellationToken)
{
return ProjectHotReloadSessionManager.RestartProjectAsync(this, cancellationToken);
return TaskResult.False;
}

public Task<bool> RestartProjectAsync(bool isRunningUnderDebug, CancellationToken cancellationToken)
{
return _sessionManager.RestartProjectAsync(this, isRunningUnderDebug, cancellationToken);
}

public IDeltaApplier? GetDeltaApplier()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE.md file in the project root for more information.

using Microsoft.VisualStudio.ProjectSystem.Debug;
using Microsoft.VisualStudio.ProjectSystem.VS.Build;
using Microsoft.VisualStudio.Shell.Interop;

namespace Microsoft.VisualStudio.ProjectSystem.VS.HotReload
{
Expand Down Expand Up @@ -169,14 +171,17 @@ private static ProjectHotReloadSessionManager CreateHotReloadSessionManager(Conf
.ImplementGetConfiguredProjectForActiveFrameworkAsync(activeConfiguredProject)
.Object;

var iVSSolutionBuildManagerServiceMock = new Mock<IVsService<SVsSolutionBuildManager, IVsSolutionBuildManager2>>();

var manager = new ProjectHotReloadSessionManager(
UnconfiguredProjectFactory.Create(),
IProjectThreadingServiceFactory.Create(),
IProjectFaultHandlerServiceFactory.Create(),
activeDebugFrameworkServices,
new Lazy<IProjectHotReloadAgent>(() => IProjectHotReloadAgentFactory.Create()),
new Lazy<IHotReloadDiagnosticOutputService>(() => IHotReloadDiagnosticOutputServiceFactory.Create(outputServiceCallback)),
new Lazy<IProjectHotReloadNotificationService>(() => IProjectHotReloadNotificationServiceFactory.Create()));
new Lazy<IProjectHotReloadNotificationService>(() => IProjectHotReloadNotificationServiceFactory.Create()),
iVSSolutionBuildManagerServiceMock.Object);

return manager;
}
Expand Down
Loading