提交 f1ff04b1 编写于 作者: C CyrusNajmabadi 提交者: GitHub

Merge pull request #19226 from CyrusNajmabadi/poisonProject

Do not allow 'add nuget reference' for projects that we fail calling into Nuget for.
...@@ -54,7 +54,7 @@ public async Task TestSearchPackageSingleName() ...@@ -54,7 +54,7 @@ public async Task TestSearchPackageSingleName()
// Make a loose mock for the installer service. We don't care what this test // Make a loose mock for the installer service. We don't care what this test
// calls on it. // calls on it.
var installerServiceMock = new Mock<IPackageInstallerService>(MockBehavior.Loose); var installerServiceMock = new Mock<IPackageInstallerService>(MockBehavior.Loose);
installerServiceMock.SetupGet(i => i.IsEnabled).Returns(true); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny<ProjectId>())).Returns(true);
installerServiceMock.SetupGet(i => i.PackageSources).Returns(NugetPackageSources); installerServiceMock.SetupGet(i => i.PackageSources).Returns(NugetPackageSources);
installerServiceMock.Setup(s => s.TryInstallPackage(It.IsAny<Workspace>(), It.IsAny<DocumentId>(), It.IsAny<string>(), "NuGetPackage", It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<CancellationToken>())) installerServiceMock.Setup(s => s.TryInstallPackage(It.IsAny<Workspace>(), It.IsAny<DocumentId>(), It.IsAny<string>(), "NuGetPackage", It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<CancellationToken>()))
.Returns(true); .Returns(true);
...@@ -83,7 +83,7 @@ public async Task TestSearchPackageMultipleNames() ...@@ -83,7 +83,7 @@ public async Task TestSearchPackageMultipleNames()
// Make a loose mock for the installer service. We don't care what this test // Make a loose mock for the installer service. We don't care what this test
// calls on it. // calls on it.
var installerServiceMock = new Mock<IPackageInstallerService>(MockBehavior.Loose); var installerServiceMock = new Mock<IPackageInstallerService>(MockBehavior.Loose);
installerServiceMock.SetupGet(i => i.IsEnabled).Returns(true); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny<ProjectId>())).Returns(true);
installerServiceMock.SetupGet(i => i.PackageSources).Returns(NugetPackageSources); installerServiceMock.SetupGet(i => i.PackageSources).Returns(NugetPackageSources);
installerServiceMock.Setup(s => s.TryInstallPackage(It.IsAny<Workspace>(), It.IsAny<DocumentId>(), It.IsAny<string>(), "NuGetPackage", It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<CancellationToken>())) installerServiceMock.Setup(s => s.TryInstallPackage(It.IsAny<Workspace>(), It.IsAny<DocumentId>(), It.IsAny<string>(), "NuGetPackage", It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<CancellationToken>()))
.Returns(true); .Returns(true);
...@@ -112,7 +112,7 @@ public async Task TestMissingIfPackageAlreadyInstalled() ...@@ -112,7 +112,7 @@ public async Task TestMissingIfPackageAlreadyInstalled()
// Make a loose mock for the installer service. We don't care what this test // Make a loose mock for the installer service. We don't care what this test
// calls on it. // calls on it.
var installerServiceMock = new Mock<IPackageInstallerService>(MockBehavior.Loose); var installerServiceMock = new Mock<IPackageInstallerService>(MockBehavior.Loose);
installerServiceMock.SetupGet(i => i.IsEnabled).Returns(true); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny<ProjectId>())).Returns(true);
installerServiceMock.SetupGet(i => i.PackageSources).Returns(NugetPackageSources); installerServiceMock.SetupGet(i => i.PackageSources).Returns(NugetPackageSources);
installerServiceMock.Setup(s => s.IsInstalled(It.IsAny<Workspace>(), It.IsAny<ProjectId>(), "NuGetPackage")) installerServiceMock.Setup(s => s.IsInstalled(It.IsAny<Workspace>(), It.IsAny<ProjectId>(), "NuGetPackage"))
.Returns(true); .Returns(true);
...@@ -135,7 +135,7 @@ public async Task TestOptionsOffered() ...@@ -135,7 +135,7 @@ public async Task TestOptionsOffered()
// Make a loose mock for the installer service. We don't care what this test // Make a loose mock for the installer service. We don't care what this test
// calls on it. // calls on it.
var installerServiceMock = new Mock<IPackageInstallerService>(MockBehavior.Loose); var installerServiceMock = new Mock<IPackageInstallerService>(MockBehavior.Loose);
installerServiceMock.SetupGet(i => i.IsEnabled).Returns(true); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny<ProjectId>())).Returns(true);
installerServiceMock.SetupGet(i => i.PackageSources).Returns(NugetPackageSources); installerServiceMock.SetupGet(i => i.PackageSources).Returns(NugetPackageSources);
installerServiceMock.Setup(s => s.GetInstalledVersions("NuGetPackage")) installerServiceMock.Setup(s => s.GetInstalledVersions("NuGetPackage"))
.Returns(ImmutableArray.Create("1.0", "2.0")); .Returns(ImmutableArray.Create("1.0", "2.0"));
...@@ -177,7 +177,7 @@ public async Task TestOptionsOffered() ...@@ -177,7 +177,7 @@ public async Task TestOptionsOffered()
public async Task TestInstallGetsCalledNoVersion() public async Task TestInstallGetsCalledNoVersion()
{ {
var installerServiceMock = new Mock<IPackageInstallerService>(MockBehavior.Loose); var installerServiceMock = new Mock<IPackageInstallerService>(MockBehavior.Loose);
installerServiceMock.SetupGet(i => i.IsEnabled).Returns(true); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny<ProjectId>())).Returns(true);
installerServiceMock.SetupGet(i => i.PackageSources).Returns(NugetPackageSources); installerServiceMock.SetupGet(i => i.PackageSources).Returns(NugetPackageSources);
installerServiceMock.Setup(s => s.TryInstallPackage(It.IsAny<Workspace>(), It.IsAny<DocumentId>(), It.IsAny<string>(), "NuGetPackage", /*versionOpt*/ null, It.IsAny<bool>(), It.IsAny<CancellationToken>())) installerServiceMock.Setup(s => s.TryInstallPackage(It.IsAny<Workspace>(), It.IsAny<DocumentId>(), It.IsAny<string>(), "NuGetPackage", /*versionOpt*/ null, It.IsAny<bool>(), It.IsAny<CancellationToken>()))
.Returns(true); .Returns(true);
...@@ -205,7 +205,7 @@ class C ...@@ -205,7 +205,7 @@ class C
public async Task TestInstallGetsCalledWithVersion() public async Task TestInstallGetsCalledWithVersion()
{ {
var installerServiceMock = new Mock<IPackageInstallerService>(MockBehavior.Loose); var installerServiceMock = new Mock<IPackageInstallerService>(MockBehavior.Loose);
installerServiceMock.SetupGet(i => i.IsEnabled).Returns(true); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny<ProjectId>())).Returns(true);
installerServiceMock.SetupGet(i => i.PackageSources).Returns(NugetPackageSources); installerServiceMock.SetupGet(i => i.PackageSources).Returns(NugetPackageSources);
installerServiceMock.Setup(s => s.GetInstalledVersions("NuGetPackage")) installerServiceMock.Setup(s => s.GetInstalledVersions("NuGetPackage"))
.Returns(ImmutableArray.Create("1.0")); .Returns(ImmutableArray.Create("1.0"));
...@@ -235,7 +235,7 @@ class C ...@@ -235,7 +235,7 @@ class C
public async Task TestFailedInstallRollsBackFile() public async Task TestFailedInstallRollsBackFile()
{ {
var installerServiceMock = new Mock<IPackageInstallerService>(MockBehavior.Loose); var installerServiceMock = new Mock<IPackageInstallerService>(MockBehavior.Loose);
installerServiceMock.SetupGet(i => i.IsEnabled).Returns(true); installerServiceMock.Setup(i => i.IsEnabled(It.IsAny<ProjectId>())).Returns(true);
installerServiceMock.SetupGet(i => i.PackageSources).Returns(NugetPackageSources); installerServiceMock.SetupGet(i => i.PackageSources).Returns(NugetPackageSources);
installerServiceMock.Setup(s => s.GetInstalledVersions("NuGetPackage")) installerServiceMock.Setup(s => s.GetInstalledVersions("NuGetPackage"))
.Returns(ImmutableArray.Create("1.0")); .Returns(ImmutableArray.Create("1.0"));
......
...@@ -44,7 +44,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeActions.AddImp ...@@ -44,7 +44,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeActions.AddImp
' Make a loose mock for the installer service. We don't care what this test ' Make a loose mock for the installer service. We don't care what this test
' calls on it. ' calls on it.
Dim installerServiceMock = New Mock(Of IPackageInstallerService)(MockBehavior.Loose) Dim installerServiceMock = New Mock(Of IPackageInstallerService)(MockBehavior.Loose)
installerServiceMock.SetupGet(Function(i) i.IsEnabled).Returns(True) installerServiceMock.Setup(Function(i) i.IsEnabled(It.IsAny(Of ProjectId))).Returns(True)
installerServiceMock.SetupGet(Function(i) i.PackageSources).Returns(NugetPackageSources) installerServiceMock.SetupGet(Function(i) i.PackageSources).Returns(NugetPackageSources)
installerServiceMock.Setup(Function(s) s.TryInstallPackage(It.IsAny(Of Workspace), It.IsAny(Of DocumentId), It.IsAny(Of String), "NuGetPackage", It.IsAny(Of String), It.IsAny(Of Boolean), It.IsAny(Of CancellationToken))). installerServiceMock.Setup(Function(s) s.TryInstallPackage(It.IsAny(Of Workspace), It.IsAny(Of DocumentId), It.IsAny(Of String), "NuGetPackage", It.IsAny(Of String), It.IsAny(Of Boolean), It.IsAny(Of CancellationToken))).
Returns(True) Returns(True)
...@@ -71,7 +71,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa ...@@ -71,7 +71,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa
' Make a loose mock for the installer service. We don't care what this test ' Make a loose mock for the installer service. We don't care what this test
' calls on it. ' calls on it.
Dim installerServiceMock = New Mock(Of IPackageInstallerService)(MockBehavior.Loose) Dim installerServiceMock = New Mock(Of IPackageInstallerService)(MockBehavior.Loose)
installerServiceMock.SetupGet(Function(i) i.IsEnabled).Returns(True) installerServiceMock.Setup(Function(i) i.IsEnabled(It.IsAny(Of ProjectId))).Returns(True)
installerServiceMock.SetupGet(Function(i) i.PackageSources).Returns(NugetPackageSources) installerServiceMock.SetupGet(Function(i) i.PackageSources).Returns(NugetPackageSources)
installerServiceMock.Setup(Function(s) s.TryInstallPackage(It.IsAny(Of Workspace), It.IsAny(Of DocumentId), It.IsAny(Of String), "NuGetPackage", It.IsAny(Of String), It.IsAny(Of Boolean), It.IsAny(Of CancellationToken))). installerServiceMock.Setup(Function(s) s.TryInstallPackage(It.IsAny(Of Workspace), It.IsAny(Of DocumentId), It.IsAny(Of String), "NuGetPackage", It.IsAny(Of String), It.IsAny(Of Boolean), It.IsAny(Of CancellationToken))).
Returns(True) Returns(True)
...@@ -98,7 +98,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa ...@@ -98,7 +98,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa
' Make a loose mock for the installer service. We don't care what this test ' Make a loose mock for the installer service. We don't care what this test
' calls on it. ' calls on it.
Dim installerServiceMock = New Mock(Of IPackageInstallerService)(MockBehavior.Loose) Dim installerServiceMock = New Mock(Of IPackageInstallerService)(MockBehavior.Loose)
installerServiceMock.SetupGet(Function(i) i.IsEnabled).Returns(True) installerServiceMock.Setup(Function(i) i.IsEnabled(It.IsAny(Of ProjectId))).Returns(True)
installerServiceMock.SetupGet(Function(i) i.PackageSources).Returns(NugetPackageSources) installerServiceMock.SetupGet(Function(i) i.PackageSources).Returns(NugetPackageSources)
installerServiceMock.Setup(Function(s) s.TryInstallPackage(It.IsAny(Of Workspace), It.IsAny(Of DocumentId), It.IsAny(Of String), "NuGetPackage", It.IsAny(Of String), It.IsAny(Of Boolean), It.IsAny(Of CancellationToken))). installerServiceMock.Setup(Function(s) s.TryInstallPackage(It.IsAny(Of Workspace), It.IsAny(Of DocumentId), It.IsAny(Of String), "NuGetPackage", It.IsAny(Of String), It.IsAny(Of Boolean), It.IsAny(Of CancellationToken))).
Returns(False) Returns(False)
...@@ -123,7 +123,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa ...@@ -123,7 +123,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa
' Make a loose mock for the installer service. We don't care what this test ' Make a loose mock for the installer service. We don't care what this test
' calls on it. ' calls on it.
Dim installerServiceMock = New Mock(Of IPackageInstallerService)(MockBehavior.Loose) Dim installerServiceMock = New Mock(Of IPackageInstallerService)(MockBehavior.Loose)
installerServiceMock.SetupGet(Function(i) i.IsEnabled).Returns(True) installerServiceMock.Setup(Function(i) i.IsEnabled(It.IsAny(Of ProjectId))).Returns(True)
installerServiceMock.SetupGet(Function(i) i.PackageSources).Returns(NugetPackageSources) installerServiceMock.SetupGet(Function(i) i.PackageSources).Returns(NugetPackageSources)
installerServiceMock.Setup(Function(s) s.IsInstalled(It.IsAny(Of Workspace)(), It.IsAny(Of ProjectId)(), "NuGetPackage")). installerServiceMock.Setup(Function(s) s.IsInstalled(It.IsAny(Of Workspace)(), It.IsAny(Of ProjectId)(), "NuGetPackage")).
Returns(True) Returns(True)
...@@ -145,7 +145,7 @@ New TestParameters(fixProviderData:=New ProviderData(installerServiceMock.Object ...@@ -145,7 +145,7 @@ New TestParameters(fixProviderData:=New ProviderData(installerServiceMock.Object
' Make a loose mock for the installer service. We don't care what this test ' Make a loose mock for the installer service. We don't care what this test
' calls on it. ' calls on it.
Dim installerServiceMock = New Mock(Of IPackageInstallerService)(MockBehavior.Loose) Dim installerServiceMock = New Mock(Of IPackageInstallerService)(MockBehavior.Loose)
installerServiceMock.SetupGet(Function(i) i.IsEnabled).Returns(True) installerServiceMock.Setup(Function(i) i.IsEnabled(It.IsAny(Of ProjectId))).Returns(True)
installerServiceMock.SetupGet(Function(i) i.PackageSources).Returns(NugetPackageSources) installerServiceMock.SetupGet(Function(i) i.PackageSources).Returns(NugetPackageSources)
installerServiceMock.Setup(Function(s) s.GetInstalledVersions("NuGetPackage")). installerServiceMock.Setup(Function(s) s.GetInstalledVersions("NuGetPackage")).
Returns(ImmutableArray.Create("1.0", "2.0")) Returns(ImmutableArray.Create("1.0", "2.0"))
...@@ -185,7 +185,7 @@ parameters:=New TestParameters(fixProviderData:=data)) ...@@ -185,7 +185,7 @@ parameters:=New TestParameters(fixProviderData:=data))
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddImport)> <Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddImport)>
Public Async Function TestInstallGetsCalledNoVersion() As Task Public Async Function TestInstallGetsCalledNoVersion() As Task
Dim installerServiceMock = New Mock(Of IPackageInstallerService)(MockBehavior.Loose) Dim installerServiceMock = New Mock(Of IPackageInstallerService)(MockBehavior.Loose)
installerServiceMock.SetupGet(Function(i) i.IsEnabled).Returns(True) installerServiceMock.Setup(Function(i) i.IsEnabled(It.IsAny(Of ProjectId))).Returns(True)
installerServiceMock.SetupGet(Function(i) i.PackageSources).Returns(NugetPackageSources) installerServiceMock.SetupGet(Function(i) i.PackageSources).Returns(NugetPackageSources)
installerServiceMock.Setup(Function(s) s.TryInstallPackage(It.IsAny(Of Workspace), It.IsAny(Of DocumentId), It.IsAny(Of String), "NuGetPackage", Nothing, It.IsAny(Of Boolean), It.IsAny(Of CancellationToken))). installerServiceMock.Setup(Function(s) s.TryInstallPackage(It.IsAny(Of Workspace), It.IsAny(Of DocumentId), It.IsAny(Of String), "NuGetPackage", Nothing, It.IsAny(Of Boolean), It.IsAny(Of CancellationToken))).
Returns(True) Returns(True)
...@@ -211,7 +211,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa ...@@ -211,7 +211,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddImport)> <Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddImport)>
Public Async Function TestInstallGetsCalledWithVersion() As Task Public Async Function TestInstallGetsCalledWithVersion() As Task
Dim installerServiceMock = New Mock(Of IPackageInstallerService)(MockBehavior.Loose) Dim installerServiceMock = New Mock(Of IPackageInstallerService)(MockBehavior.Loose)
installerServiceMock.SetupGet(Function(i) i.IsEnabled).Returns(True) installerServiceMock.Setup(Function(i) i.IsEnabled(It.IsAny(Of ProjectId))).Returns(True)
installerServiceMock.SetupGet(Function(i) i.PackageSources).Returns(NugetPackageSources) installerServiceMock.SetupGet(Function(i) i.PackageSources).Returns(NugetPackageSources)
installerServiceMock.Setup(Function(s) s.GetInstalledVersions("NuGetPackage")). installerServiceMock.Setup(Function(s) s.GetInstalledVersions("NuGetPackage")).
Returns(ImmutableArray.Create("1.0")) Returns(ImmutableArray.Create("1.0"))
......
...@@ -84,7 +84,7 @@ private partial class SymbolReferenceFinder ...@@ -84,7 +84,7 @@ private partial class SymbolReferenceFinder
if (symbolSearchService != null && if (symbolSearchService != null &&
installerService != null && installerService != null &&
searchNugetPackages && searchNugetPackages &&
installerService.IsEnabled) installerService.IsEnabled(_document.Project.Id))
{ {
foreach (var packageSource in installerService.PackageSources) foreach (var packageSource in installerService.PackageSources)
{ {
......
...@@ -51,7 +51,7 @@ internal abstract partial class AbstractAddPackageCodeFixProvider : CodeFixProvi ...@@ -51,7 +51,7 @@ internal abstract partial class AbstractAddPackageCodeFixProvider : CodeFixProvi
if (symbolSearchService != null && if (symbolSearchService != null &&
installerService != null && installerService != null &&
searchNugetPackages && searchNugetPackages &&
installerService.IsEnabled) installerService.IsEnabled(document.Project.Id))
{ {
foreach (var packageSource in installerService.PackageSources) foreach (var packageSource in installerService.PackageSources)
{ {
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
namespace Microsoft.VisualStudio.LanguageServices.Packaging
{
internal partial class PackageInstallerService
{
private struct ProjectState
{
public readonly bool IsEnabled;
public readonly Dictionary<string, string> InstalledPackageToVersion;
public ProjectState(bool isEnabled, Dictionary<string, string> installedPackageToVersion)
{
IsEnabled = isEnabled;
InstalledPackageToVersion = installedPackageToVersion;
}
}
}
}
...@@ -56,8 +56,8 @@ internal partial class PackageInstallerService : AbstractDelayStartedService, IP ...@@ -56,8 +56,8 @@ internal partial class PackageInstallerService : AbstractDelayStartedService, IP
private bool _solutionChanged; private bool _solutionChanged;
private HashSet<ProjectId> _changedProjects = new HashSet<ProjectId>(); private HashSet<ProjectId> _changedProjects = new HashSet<ProjectId>();
private readonly ConcurrentDictionary<ProjectId, Dictionary<string, string>> _projectToInstalledPackageAndVersion = private readonly ConcurrentDictionary<ProjectId, ProjectState> _projectToInstalledPackageAndVersion =
new ConcurrentDictionary<ProjectId, Dictionary<string, string>>(); new ConcurrentDictionary<ProjectId, ProjectState>();
[ImportingConstructor] [ImportingConstructor]
public PackageInstallerService( public PackageInstallerService(
...@@ -77,7 +77,23 @@ internal partial class PackageInstallerService : AbstractDelayStartedService, IP ...@@ -77,7 +77,23 @@ internal partial class PackageInstallerService : AbstractDelayStartedService, IP
public event EventHandler PackageSourcesChanged; public event EventHandler PackageSourcesChanged;
public bool IsEnabled => _packageServices != null; private bool IsEnabled => _packageServices != null;
bool IPackageInstallerService.IsEnabled(ProjectId projectId)
{
if (_packageServices == null)
{
return false;
}
if (_projectToInstalledPackageAndVersion.TryGetValue(projectId, out var state))
{
return state.IsEnabled;
}
// If we haven't scanned the project yet, assume that we're available for it.
return true;
}
protected override void EnableService() protected override void EnableService()
{ {
...@@ -270,10 +286,25 @@ private string GetInstalledVersion(string packageName, EnvDTE.Project dteProject ...@@ -270,10 +286,25 @@ private string GetInstalledVersion(string packageName, EnvDTE.Project dteProject
var metadata = installedPackages.FirstOrDefault(m => m.Id == packageName); var metadata = installedPackages.FirstOrDefault(m => m.Id == packageName);
return metadata?.VersionString; return metadata?.VersionString;
} }
catch (ArgumentException e) when (IsKnownNugetIssue(e))
{
// Nuget may throw an ArgumentException when there is something about the project
// they do not like/support.
}
catch (Exception e) when (FatalError.ReportWithoutCrash(e)) catch (Exception e) when (FatalError.ReportWithoutCrash(e))
{ {
return null;
} }
return null;
}
private bool IsKnownNugetIssue(ArgumentException exception)
{
// See https://github.com/NuGet/Home/issues/4706
// Nuget throws on legal projects. We do not want to report this exception
// as it is known (and NFWs are expensive), but we do want to report if we
// run into anything else.
return exception.Message.Contains("is not a valid version string");
} }
private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e) private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e)
...@@ -388,8 +419,9 @@ private ProjectId DequeueNextProject(Solution solution) ...@@ -388,8 +419,9 @@ private ProjectId DequeueNextProject(Solution solution)
private void ProcessProjectChange(Solution solution, ProjectId projectId) private void ProcessProjectChange(Solution solution, ProjectId projectId)
{ {
this.AssertIsForeground(); this.AssertIsForeground();
// Remove anything we have associated with this project. // Remove anything we have associated with this project.
_projectToInstalledPackageAndVersion.TryRemove(projectId, out var installedPackages); _projectToInstalledPackageAndVersion.TryRemove(projectId, out var projectState);
var project = solution.GetProject(projectId); var project = solution.GetProject(projectId);
if (project == null) if (project == null)
...@@ -416,26 +448,35 @@ private void ProcessProjectChange(Solution solution, ProjectId projectId) ...@@ -416,26 +448,35 @@ private void ProcessProjectChange(Solution solution, ProjectId projectId)
return; return;
} }
installedPackages = new Dictionary<string, string>(); var installedPackages = new Dictionary<string, string>();
var isEnabled = false;
// Calling into NuGet. Assume they may fail for any reason. // Calling into NuGet. Assume they may fail for any reason.
try try
{ {
var installedPackageMetadata = _packageServices.GetInstalledPackages(dteProject); var installedPackageMetadata = _packageServices.GetInstalledPackages(dteProject);
installedPackages.AddRange(installedPackageMetadata.Select(m => new KeyValuePair<string, string>(m.Id, m.VersionString))); installedPackages.AddRange(installedPackageMetadata.Select(m => new KeyValuePair<string, string>(m.Id, m.VersionString)));
isEnabled = true;
}
catch (ArgumentException e) when (IsKnownNugetIssue(e))
{
// Nuget may throw an ArgumentException when there is something about the project
// they do not like/support.
} }
catch (Exception e) when (FatalError.ReportWithoutCrash(e)) catch (Exception e) when (FatalError.ReportWithoutCrash(e))
{ {
} }
_projectToInstalledPackageAndVersion.AddOrUpdate(projectId, installedPackages, (_1, _2) => installedPackages); var state = new ProjectState(isEnabled, installedPackages);
_projectToInstalledPackageAndVersion.AddOrUpdate(
projectId, state, (_1, _2) => state);
} }
public bool IsInstalled(Workspace workspace, ProjectId projectId, string packageName) public bool IsInstalled(Workspace workspace, ProjectId projectId, string packageName)
{ {
ThisCanBeCalledOnAnyThread(); ThisCanBeCalledOnAnyThread();
return _projectToInstalledPackageAndVersion.TryGetValue(projectId, out var installedPackages) && return _projectToInstalledPackageAndVersion.TryGetValue(projectId, out var installedPackages) &&
installedPackages.ContainsKey(packageName); installedPackages.InstalledPackageToVersion.ContainsKey(packageName);
} }
public ImmutableArray<string> GetInstalledVersions(string packageName) public ImmutableArray<string> GetInstalledVersions(string packageName)
...@@ -443,10 +484,10 @@ public ImmutableArray<string> GetInstalledVersions(string packageName) ...@@ -443,10 +484,10 @@ public ImmutableArray<string> GetInstalledVersions(string packageName)
ThisCanBeCalledOnAnyThread(); ThisCanBeCalledOnAnyThread();
var installedVersions = new HashSet<string>(); var installedVersions = new HashSet<string>();
foreach (var installedPackages in _projectToInstalledPackageAndVersion.Values) foreach (var state in _projectToInstalledPackageAndVersion.Values)
{ {
string version = null; string version = null;
if (installedPackages?.TryGetValue(packageName, out version) == true && version != null) if (state.InstalledPackageToVersion.TryGetValue(packageName, out version) && version != null)
{ {
installedVersions.Add(version); installedVersions.Add(version);
} }
...@@ -494,16 +535,13 @@ public IEnumerable<Project> GetProjectsWithInstalledPackage(Solution solution, s ...@@ -494,16 +535,13 @@ public IEnumerable<Project> GetProjectsWithInstalledPackage(Solution solution, s
foreach (var kvp in this._projectToInstalledPackageAndVersion) foreach (var kvp in this._projectToInstalledPackageAndVersion)
{ {
var installedPackageAndVersion = kvp.Value; var state = kvp.Value;
if (installedPackageAndVersion != null) if (state.InstalledPackageToVersion.TryGetValue(packageName, out var installedVersion) && installedVersion == version)
{ {
if (installedPackageAndVersion.TryGetValue(packageName, out var installedVersion) && installedVersion == version) var project = solution.GetProject(kvp.Key);
if (project != null)
{ {
var project = solution.GetProject(kvp.Key); result.Add(project);
if (project != null)
{
result.Add(project);
}
} }
} }
} }
...@@ -631,4 +669,4 @@ public void UninstallPackage(EnvDTE.Project project, string packageId, bool remo ...@@ -631,4 +669,4 @@ public void UninstallPackage(EnvDTE.Project project, string packageId, bool remo
=> _packageUninstaller.UninstallPackage(project, packageId, removeDependencies); => _packageUninstaller.UninstallPackage(project, packageId, removeDependencies);
} }
} }
} }
\ No newline at end of file
...@@ -174,6 +174,7 @@ ...@@ -174,6 +174,7 @@
<Compile Include="Implementation\Workspace\VisualStudioTaskSchedulerFactory.cs" /> <Compile Include="Implementation\Workspace\VisualStudioTaskSchedulerFactory.cs" />
<Compile Include="Packaging\Interop\SVsRemoteControlService.cs" /> <Compile Include="Packaging\Interop\SVsRemoteControlService.cs" />
<Compile Include="Packaging\IPackageServicesProxy.cs" /> <Compile Include="Packaging\IPackageServicesProxy.cs" />
<Compile Include="Packaging\PackageInstallerService.ProjectState.cs" />
<Compile Include="Storage\VisualStudioPersistentStorageLocationService.cs" /> <Compile Include="Storage\VisualStudioPersistentStorageLocationService.cs" />
<Compile Include="SymbolSearch\AbstractDelayStartedService.cs" /> <Compile Include="SymbolSearch\AbstractDelayStartedService.cs" />
<Compile Include="Packaging\PackageInstallerServiceFactory.cs" /> <Compile Include="Packaging\PackageInstallerServiceFactory.cs" />
......
...@@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.Packaging ...@@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.Packaging
{ {
internal interface IPackageInstallerService : IWorkspaceService internal interface IPackageInstallerService : IWorkspaceService
{ {
bool IsEnabled { get; } bool IsEnabled(ProjectId projectId);
bool IsInstalled(Workspace workspace, ProjectId projectId, string packageName); bool IsInstalled(Workspace workspace, ProjectId projectId, string packageName);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册