diff --git a/Microsoft.DotNet.UpgradeAssistant.sln b/Microsoft.DotNet.UpgradeAssistant.sln
index 53dd67794..5cd467835 100644
--- a/Microsoft.DotNet.UpgradeAssistant.sln
+++ b/Microsoft.DotNet.UpgradeAssistant.sln
@@ -172,6 +172,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.UpgradeAss
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.UpgradeAssistant.Steps.Source.Tests", "tests\extensions\default\Microsoft.DotNet.UpgradeAssistant.Steps.Source.Tests\Microsoft.DotNet.UpgradeAssistant.Steps.Source.Tests.csproj", "{134CE4A1-E9A4-49C0-A998-7C531E6207CE}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nuget", "nuget", "{021F1610-F2D0-4F00-81C7-AD7397DA296C}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet", "src\extensions\nuget\Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet\Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.csproj", "{E18A3CB0-BFDB-4672-AD53-7EAAF26C52AB}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nuget", "nuget", "{824AFFC6-40A2-4AD6-8010-B939841CA16E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests", "tests\extensions\nuget\Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests\Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests.csproj", "{58633641-85F3-4F8E-AC18-0EFACC36D142}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -758,6 +766,30 @@ Global
{134CE4A1-E9A4-49C0-A998-7C531E6207CE}.Release|x64.Build.0 = Release|Any CPU
{134CE4A1-E9A4-49C0-A998-7C531E6207CE}.Release|x86.ActiveCfg = Release|Any CPU
{134CE4A1-E9A4-49C0-A998-7C531E6207CE}.Release|x86.Build.0 = Release|Any CPU
+ {E18A3CB0-BFDB-4672-AD53-7EAAF26C52AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E18A3CB0-BFDB-4672-AD53-7EAAF26C52AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E18A3CB0-BFDB-4672-AD53-7EAAF26C52AB}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {E18A3CB0-BFDB-4672-AD53-7EAAF26C52AB}.Debug|x64.Build.0 = Debug|Any CPU
+ {E18A3CB0-BFDB-4672-AD53-7EAAF26C52AB}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E18A3CB0-BFDB-4672-AD53-7EAAF26C52AB}.Debug|x86.Build.0 = Debug|Any CPU
+ {E18A3CB0-BFDB-4672-AD53-7EAAF26C52AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E18A3CB0-BFDB-4672-AD53-7EAAF26C52AB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E18A3CB0-BFDB-4672-AD53-7EAAF26C52AB}.Release|x64.ActiveCfg = Release|Any CPU
+ {E18A3CB0-BFDB-4672-AD53-7EAAF26C52AB}.Release|x64.Build.0 = Release|Any CPU
+ {E18A3CB0-BFDB-4672-AD53-7EAAF26C52AB}.Release|x86.ActiveCfg = Release|Any CPU
+ {E18A3CB0-BFDB-4672-AD53-7EAAF26C52AB}.Release|x86.Build.0 = Release|Any CPU
+ {58633641-85F3-4F8E-AC18-0EFACC36D142}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {58633641-85F3-4F8E-AC18-0EFACC36D142}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {58633641-85F3-4F8E-AC18-0EFACC36D142}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {58633641-85F3-4F8E-AC18-0EFACC36D142}.Debug|x64.Build.0 = Debug|Any CPU
+ {58633641-85F3-4F8E-AC18-0EFACC36D142}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {58633641-85F3-4F8E-AC18-0EFACC36D142}.Debug|x86.Build.0 = Debug|Any CPU
+ {58633641-85F3-4F8E-AC18-0EFACC36D142}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {58633641-85F3-4F8E-AC18-0EFACC36D142}.Release|Any CPU.Build.0 = Release|Any CPU
+ {58633641-85F3-4F8E-AC18-0EFACC36D142}.Release|x64.ActiveCfg = Release|Any CPU
+ {58633641-85F3-4F8E-AC18-0EFACC36D142}.Release|x64.Build.0 = Release|Any CPU
+ {58633641-85F3-4F8E-AC18-0EFACC36D142}.Release|x86.ActiveCfg = Release|Any CPU
+ {58633641-85F3-4F8E-AC18-0EFACC36D142}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -831,6 +863,10 @@ Global
{7304F25F-0F4D-450F-A529-3C7AFE9D98CA} = {82BC0AAB-94CA-4D5B-BF95-F7329D1150CB}
{CEDAAB8D-613C-4A3F-8114-7D6B480F1EE3} = {7304F25F-0F4D-450F-A529-3C7AFE9D98CA}
{134CE4A1-E9A4-49C0-A998-7C531E6207CE} = {4E12F429-CEC0-4080-B0FE-39F9B8B9AE4C}
+ {021F1610-F2D0-4F00-81C7-AD7397DA296C} = {AA22EE67-3BBE-49A2-8868-531FE68FE162}
+ {E18A3CB0-BFDB-4672-AD53-7EAAF26C52AB} = {021F1610-F2D0-4F00-81C7-AD7397DA296C}
+ {824AFFC6-40A2-4AD6-8010-B939841CA16E} = {82BC0AAB-94CA-4D5B-BF95-F7329D1150CB}
+ {58633641-85F3-4F8E-AC18-0EFACC36D142} = {824AFFC6-40A2-4AD6-8010-B939841CA16E}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D02F665B-C14D-43C2-955C-9338A23836E0}
diff --git a/docs/images/dependency-validation.png b/docs/images/dependency-validation.png
index c5b39e3cb..7880b709c 100644
Binary files a/docs/images/dependency-validation.png and b/docs/images/dependency-validation.png differ
diff --git a/eng/DependencyValidation/DependencyValidation.modelproj b/eng/DependencyValidation/DependencyValidation.modelproj
index 71461f316..7d24d629c 100644
--- a/eng/DependencyValidation/DependencyValidation.modelproj
+++ b/eng/DependencyValidation/DependencyValidation.modelproj
@@ -134,6 +134,10 @@
Microsoft.DotNet.UpgradeAssistant.Extensions.Maui
{a122dd5b-4b80-4558-8db2-8e9ebff12a1a}
+
+ Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet
+ {e18a3cb0-bfdb-4672-ad53-7eaaf26c52ab}
+
Microsoft.DotNet.UpgradeAssistant.Extensions.VisualBasic
{608e7ce5-5674-49eb-8728-719a468fc62e}
diff --git a/eng/DependencyValidation/UpgradeAssistant.layerdiagram b/eng/DependencyValidation/UpgradeAssistant.layerdiagram
index 996839f84..428d4845a 100644
--- a/eng/DependencyValidation/UpgradeAssistant.layerdiagram
+++ b/eng/DependencyValidation/UpgradeAssistant.layerdiagram
@@ -205,6 +205,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/eng/DependencyValidation/UpgradeAssistant.layerdiagram.layout b/eng/DependencyValidation/UpgradeAssistant.layerdiagram.layout
index 1e93f95a5..68340c930 100644
--- a/eng/DependencyValidation/UpgradeAssistant.layerdiagram.layout
+++ b/eng/DependencyValidation/UpgradeAssistant.layerdiagram.layout
@@ -50,9 +50,12 @@
+
+
+
-
+
@@ -79,7 +82,7 @@
-
+
@@ -103,7 +106,7 @@
-
+
@@ -124,7 +127,7 @@
-
+
diff --git a/src/cli/Microsoft.DotNet.UpgradeAssistant.Cli/Microsoft.DotNet.UpgradeAssistant.Cli.csproj b/src/cli/Microsoft.DotNet.UpgradeAssistant.Cli/Microsoft.DotNet.UpgradeAssistant.Cli.csproj
index 3655bbf31..d75dffe64 100644
--- a/src/cli/Microsoft.DotNet.UpgradeAssistant.Cli/Microsoft.DotNet.UpgradeAssistant.Cli.csproj
+++ b/src/cli/Microsoft.DotNet.UpgradeAssistant.Cli/Microsoft.DotNet.UpgradeAssistant.Cli.csproj
@@ -108,6 +108,9 @@
windows
+
+ nuget
+
diff --git a/src/cli/Microsoft.DotNet.UpgradeAssistant.Cli/UpgradeAssistantHostExtensions.cs b/src/cli/Microsoft.DotNet.UpgradeAssistant.Cli/UpgradeAssistantHostExtensions.cs
index f38104832..f73f6832d 100644
--- a/src/cli/Microsoft.DotNet.UpgradeAssistant.Cli/UpgradeAssistantHostExtensions.cs
+++ b/src/cli/Microsoft.DotNet.UpgradeAssistant.Cli/UpgradeAssistantHostExtensions.cs
@@ -101,14 +101,6 @@ public static IHostBuilder UseUpgradeAssistant(this IHostBuilder host, IUp
}
});
- services.AddNuGet(optionss =>
- {
- if (upgradeOptions.Project?.FullName is string fullname)
- {
- optionss.PackageSourcePath = Path.GetDirectoryName(fullname);
- }
- });
-
services.AddUserInput();
services.AddAnalysis();
diff --git a/src/cli/Microsoft.DotNet.UpgradeAssistant.Cli/appsettings.json b/src/cli/Microsoft.DotNet.UpgradeAssistant.Cli/appsettings.json
index 7679c31ae..5578f6ae0 100644
--- a/src/cli/Microsoft.DotNet.UpgradeAssistant.Cli/appsettings.json
+++ b/src/cli/Microsoft.DotNet.UpgradeAssistant.Cli/appsettings.json
@@ -15,6 +15,10 @@
"Extensions": {
"Source": "https://upgradeassistant.blob.core.windows.net/extensions/index.json",
+ "required": [
+ "nuget"
+ ],
+
"Default": [
"default",
"vb",
diff --git a/src/common/Microsoft.DotNet.UpgradeAssistant.Abstractions/IProjectFile.cs b/src/common/Microsoft.DotNet.UpgradeAssistant.Abstractions/IProjectFile.cs
index 7d0f93371..9747527b2 100644
--- a/src/common/Microsoft.DotNet.UpgradeAssistant.Abstractions/IProjectFile.cs
+++ b/src/common/Microsoft.DotNet.UpgradeAssistant.Abstractions/IProjectFile.cs
@@ -15,6 +15,8 @@ public interface IProjectFile
string FilePath { get; }
+ IEnumerable PackageReferences { get; }
+
void AddFrameworkReferences(IEnumerable frameworkReferences);
void RemoveFrameworkReferences(IEnumerable frameworkReferences);
diff --git a/src/common/Microsoft.DotNet.UpgradeAssistant.Abstractions/ITargetFrameworkCollection.cs b/src/common/Microsoft.DotNet.UpgradeAssistant.Abstractions/ITargetFrameworkCollection.cs
new file mode 100644
index 000000000..f7da49a0a
--- /dev/null
+++ b/src/common/Microsoft.DotNet.UpgradeAssistant.Abstractions/ITargetFrameworkCollection.cs
@@ -0,0 +1,12 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+
+namespace Microsoft.DotNet.UpgradeAssistant
+{
+ public interface ITargetFrameworkCollection : IReadOnlyCollection
+ {
+ void SetTargetFramework(TargetFrameworkMoniker tfm);
+ }
+}
diff --git a/src/components/Microsoft.DotNet.UpgradeAssistant.Extensions/ExtensionAssemblyLoadContext.cs b/src/components/Microsoft.DotNet.UpgradeAssistant.Extensions/ExtensionAssemblyLoadContext.cs
index afe39ef6c..f4d92e27d 100644
--- a/src/components/Microsoft.DotNet.UpgradeAssistant.Extensions/ExtensionAssemblyLoadContext.cs
+++ b/src/components/Microsoft.DotNet.UpgradeAssistant.Extensions/ExtensionAssemblyLoadContext.cs
@@ -64,7 +64,9 @@ private void Load(ExtensionInstance extension, string[] assemblies)
protected override Assembly? Load(AssemblyName assemblyName)
{
// If available in the default, we want to ensure that is used.
- var inDefault = Default.Assemblies.FirstOrDefault(a => string.Equals(a.GetName().Name, assemblyName.Name, StringComparison.Ordinal));
+ var inDefault = Default.Assemblies
+ .Where(a => !a.GetName().Name!.Contains("NuGet", StringComparison.OrdinalIgnoreCase))
+ .FirstOrDefault(a => string.Equals(a.GetName().Name, assemblyName.Name, StringComparison.Ordinal));
if (inDefault is Assembly existing)
{
diff --git a/src/components/Microsoft.DotNet.UpgradeAssistant.Extensions/ExtensionOptions.cs b/src/components/Microsoft.DotNet.UpgradeAssistant.Extensions/ExtensionOptions.cs
index d57362085..84a8e5458 100644
--- a/src/components/Microsoft.DotNet.UpgradeAssistant.Extensions/ExtensionOptions.cs
+++ b/src/components/Microsoft.DotNet.UpgradeAssistant.Extensions/ExtensionOptions.cs
@@ -14,6 +14,8 @@ public class ExtensionOptions
public ICollection DefaultExtensions { get; } = new List();
+ public ICollection RequiredExtensions { get; } = new List();
+
public ICollection ExtensionPaths { get; } = new List();
public IEnumerable AdditionalOptions { get; set; } = Enumerable.Empty();
diff --git a/src/components/Microsoft.DotNet.UpgradeAssistant.Extensions/ExtensionProvider.cs b/src/components/Microsoft.DotNet.UpgradeAssistant.Extensions/ExtensionProvider.cs
index c2555dcfb..c16f7391f 100644
--- a/src/components/Microsoft.DotNet.UpgradeAssistant.Extensions/ExtensionProvider.cs
+++ b/src/components/Microsoft.DotNet.UpgradeAssistant.Extensions/ExtensionProvider.cs
@@ -46,11 +46,19 @@ public ExtensionProvider(
_extensions = new Lazy>(() =>
{
+ var list = new List();
+
var opts = options.Value;
+ foreach (var path in opts.RequiredExtensions)
+ {
+ LoadPath(path, isDefault: true);
+ }
+
+ // Required extensions must load, otherwise they may be turned off
if (!opts.LoadExtensions)
{
- return Enumerable.Empty();
+ return list;
}
var list = new List();
diff --git a/src/components/Microsoft.DotNet.UpgradeAssistant.Extensions/ExtensionProviderExtensions.cs b/src/components/Microsoft.DotNet.UpgradeAssistant.Extensions/ExtensionProviderExtensions.cs
index f8db82160..a7924c4a2 100644
--- a/src/components/Microsoft.DotNet.UpgradeAssistant.Extensions/ExtensionProviderExtensions.cs
+++ b/src/components/Microsoft.DotNet.UpgradeAssistant.Extensions/ExtensionProviderExtensions.cs
@@ -87,16 +87,22 @@ public static OptionsBuilder AddDefaultExtensions(this Options
return builder.Configure(options =>
{
const string ExtensionDirectory = "extensions";
-
var settings = configuration.GetSection("Extensions").Get();
- var defaultExtensions = settings.Default
- .Select(n => Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, ExtensionDirectory, n)));
options.DefaultSource = settings.Source;
- foreach (var path in defaultExtensions)
+ AddExtensions(options.DefaultExtensions, settings.Default);
+ AddExtensions(options.RequiredExtensions, settings.Required);
+
+ static void AddExtensions(ICollection collection, string[] names)
{
- options.DefaultExtensions.Add(path);
+ var extensionFullPaths = names
+ .Select(n => Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, ExtensionDirectory, n)));
+
+ foreach (var path in extensionFullPaths)
+ {
+ collection.Add(path);
+ }
}
});
}
@@ -106,6 +112,8 @@ private class ExtensionSettings
public string Source { get; set; } = string.Empty;
public string[] Default { get; set; } = Array.Empty();
+
+ public string[] Required { get; set; } = Array.Empty();
}
public static IServiceCollection AddExtensionOption(this IServiceCollection services, TOption option)
diff --git a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/Factories.cs b/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/Factories.cs
new file mode 100644
index 000000000..e599770b6
--- /dev/null
+++ b/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/Factories.cs
@@ -0,0 +1,25 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+
+namespace Microsoft.DotNet.UpgradeAssistant.MSBuild
+{
+ internal class Factories
+ {
+ private readonly Func _nugetReferenceFactory;
+ private readonly Func _tfmCollectionFactory;
+
+ public Factories(
+ Func nugetReferenceFactory,
+ Func tfmCollectionFactory)
+ {
+ _nugetReferenceFactory = nugetReferenceFactory;
+ _tfmCollectionFactory = tfmCollectionFactory;
+ }
+
+ public INuGetReferences CreateNuGetReferences(IUpgradeContext context, IProject project) => _nugetReferenceFactory(context, project);
+
+ public ITargetFrameworkCollection CreateTfmCollection(IProjectFile project) => _tfmCollectionFactory(project);
+ }
+}
diff --git a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/MSBuildProject.File.cs b/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/MSBuildProject.File.cs
index 12217a737..de10a64a5 100644
--- a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/MSBuildProject.File.cs
+++ b/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/MSBuildProject.File.cs
@@ -44,7 +44,7 @@ public ProjectRootElement ProjectRoot
public ICollection Sdk => new SdkCollection(ProjectRoot);
- public void SetTFM(TargetFrameworkMoniker tfm) => new TargetFrameworkMonikerCollection(this, _comparer).SetTargetFramework(tfm);
+ public void SetTFM(TargetFrameworkMoniker tfm) => _factories.CreateTfmCollection(this).SetTargetFramework(tfm);
public void AddPackages(IEnumerable references)
{
@@ -61,7 +61,7 @@ public void AddPackages(IEnumerable references)
public void RemovePackages(IEnumerable references)
{
- foreach (var reference in PackageReferences)
+ foreach (var reference in NuGetReferences.PackageReferences)
{
if (references.Contains(reference))
{
@@ -184,7 +184,7 @@ public void RemoveProperty(string propertyName)
{
Project.RemoveProperty(property);
}
- }
+ }
private static string GetPathRelativeToProject(string path, string projectDir) =>
Path.IsPathFullyQualified(path)
diff --git a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/MSBuildProject.NuGetPackages.cs b/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/MSBuildProject.NuGetPackages.cs
index d457a4b33..848f942c0 100644
--- a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/MSBuildProject.NuGetPackages.cs
+++ b/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/MSBuildProject.NuGetPackages.cs
@@ -1,200 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
using System.Collections.Generic;
-using System.IO;
using System.Linq;
-using System.Runtime.CompilerServices;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.CodeAnalysis;
-using Microsoft.Extensions.Logging;
-using NuGet.Frameworks;
-using NuGet.Packaging.Core;
-using NuGet.ProjectModel;
namespace Microsoft.DotNet.UpgradeAssistant.MSBuild
{
- internal partial class MSBuildProject : INuGetReferences
+ internal partial class MSBuildProject
{
- public INuGetReferences NuGetReferences => this;
+ public INuGetReferences NuGetReferences => _factories.CreateNuGetReferences(Context, this);
- public NugetPackageFormat PackageReferenceFormat
- {
- get
- {
- if (GetPackagesConfigPath() is not null)
- {
- return NugetPackageFormat.PackageConfig;
- }
- else if (ProjectRoot.GetAllPackageReferences().ToList() is IEnumerable list && list.Any())
- {
- return NugetPackageFormat.PackageReference;
- }
- else
- {
- return NugetPackageFormat.None;
- }
- }
- }
-
- private string? GetPackagesConfigPath() => FindFiles("packages.config", ProjectItemType.Content).FirstOrDefault();
-
- public IEnumerable PackageReferences
- {
- get
- {
- var packagesConfig = GetPackagesConfigPath();
-
- if (packagesConfig is null)
- {
- var packages = ProjectRoot.GetAllPackageReferences();
-
- return packages.Select(p => p.AsNuGetReference());
- }
- else
- {
- return PackageConfig.GetPackages(packagesConfig);
- }
- }
- }
-
- public IAsyncEnumerable GetTransitivePackageReferencesAsync(TargetFrameworkMoniker tfm, CancellationToken token)
- => PackageReferenceFormat switch
- {
- NugetPackageFormat.PackageConfig => PackageReferences.ToAsyncEnumerable(),
- NugetPackageFormat.PackageReference => GetAllPackageReferenceDependenciesAsync(tfm, token).Select(l => new NuGetReference(l.Name, l.Version.ToNormalizedString())),
- _ => AsyncEnumerable.Empty()
- };
-
- public async ValueTask IsTransitivelyAvailableAsync(string packageName, CancellationToken token)
- => PackageReferences.Any(p => p.Name.Equals(packageName, StringComparison.OrdinalIgnoreCase))
- || (PackageReferenceFormat == NugetPackageFormat.PackageReference && await TargetFrameworks.ToAsyncEnumerable().AnyAwaitAsync(tfm => ContainsPackageDependencyAsync(tfm, d => string.Equals(packageName, d.Id, StringComparison.OrdinalIgnoreCase), token), cancellationToken: token).ConfigureAwait(false));
-
- public async ValueTask IsTransitiveDependencyAsync(NuGetReference nugetReference, CancellationToken token)
- => PackageReferenceFormat == NugetPackageFormat.PackageReference && await TargetFrameworks.ToAsyncEnumerable().AnyAwaitAsync(tfm => ContainsPackageDependencyAsync(tfm, d => ReferenceSatisfiesDependency(d, nugetReference, true), token), token).ConfigureAwait(false);
-
- private static bool ReferenceSatisfiesDependency(PackageDependency dependency, NuGetReference packageReference, bool minVersionMatchOnly)
- {
- // If the dependency's name doesn't match the reference's name, return false
- if (!dependency.Id.Equals(packageReference.Name, StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
-
- if (!packageReference.TryGetNuGetVersion(out var packageVersion))
- {
- throw new InvalidOperationException("Package references from a lock file should always have a specific version");
- }
-
- // Return false if the reference's version falls outside of the dependency range
- var versionRange = dependency.VersionRange;
- if (versionRange.HasLowerBound && packageVersion < versionRange.MinVersion)
- {
- return false;
- }
-
- if (versionRange.HasUpperBound && packageVersion > versionRange.MaxVersion)
- {
- return false;
- }
-
- // In some cases (looking for transitive dependencies), it's interesting to only match packages that are the minimum version
- if (minVersionMatchOnly && versionRange.HasLowerBound && packageVersion != versionRange.MinVersion)
- {
- return false;
- }
-
- // Otherwise, return true
- return true;
- }
-
- private ValueTask ContainsPackageDependencyAsync(TargetFrameworkMoniker tfm, Func filter, CancellationToken token)
- => GetAllPackageReferenceDependenciesAsync(tfm, token).AnyAsync(l => l.Dependencies.Any(d => filter(d)), token);
-
- private async IAsyncEnumerable GetAllPackageReferenceDependenciesAsync(TargetFrameworkMoniker tfm, [EnumeratorCancellation] CancellationToken token)
- {
- if (!IsRestored)
- {
- throw new InvalidOperationException("Project should have already been restored. Please file an issue at https://github.com/dotnet/upgrade-assistant");
- }
-
- if (PackageReferenceFormat != NugetPackageFormat.PackageReference)
- {
- throw new InvalidOperationException("PackageReference restore for transitive dependencies should only happen for PackageReference package reference format");
- }
-
- var parsedTfm = NuGetFramework.Parse(tfm.Name);
- var target = GetLockFileTarget(parsedTfm);
-
- if (target is null)
- {
- // Break if there are no packages in the project. Otherwise, we end up performing restores too often.
- if (!PackageReferences.Any())
- {
- _logger.LogDebug("Skipping restore as no package references exist in project file {Path}", FileInfo.FullName);
- yield break;
- }
-
- _logger.LogDebug("Attempting a restore to retrieve missing lock file data {Path}", FileInfo.FullName);
-
- await _restorer.RestorePackagesAsync(Context, this, token).ConfigureAwait(false);
-
- // If the LockFilePath is defined but does not exist, there are no libraries
- if (!File.Exists(LockFilePath))
- {
- yield break;
- }
-
- target = GetLockFileTarget(parsedTfm);
- }
-
- if (target is null)
- {
- _logger.LogError("NuGet target in project.assets.json is still unavailable after restore. Please verify that the project has been restored.");
- throw new UpgradeException("Restore has not restored the expected TFMs. Please review any warnings from dotnet-restore.");
- }
-
- foreach (var library in target.Libraries)
- {
- yield return library;
- }
-
- LockFileTarget? GetLockFileTarget(NuGetFramework parsedTfm)
- {
- var lockFile = LockFileUtilities.GetLockFile(LockFilePath, NuGet.Common.NullLogger.Instance);
-
- if (lockFile?.Targets is null)
- {
- return null;
- }
-
- return lockFile.Targets
- .FirstOrDefault(t => t.TargetFramework.DotNetFrameworkName.Equals(parsedTfm.DotNetFrameworkName, StringComparison.Ordinal));
- }
- }
-
- private bool IsRestored => LockFilePath is not null;
-
- private string? LockFilePath
- {
- get
- {
- var lockFilePath = Path.Combine(GetPropertyValue("MSBuildProjectExtensionsPath"), "project.assets.json");
-
- if (string.IsNullOrEmpty(lockFilePath))
- {
- return null;
- }
-
- if (!Path.IsPathFullyQualified(lockFilePath))
- {
- lockFilePath = Path.Combine(FileInfo.DirectoryName ?? string.Empty, lockFilePath);
- }
-
- return lockFilePath;
- }
- }
+ public IEnumerable PackageReferences => ProjectRoot.GetAllPackageReferences().Select(p => p.AsNuGetReference());
}
}
diff --git a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/MSBuildProject.cs b/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/MSBuildProject.cs
index 9639a5bff..1e5b2220b 100644
--- a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/MSBuildProject.cs
+++ b/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/MSBuildProject.cs
@@ -20,7 +20,7 @@ internal partial class MSBuildProject : IProject
private readonly ILogger _logger;
private readonly IEnumerable _componentIdentifiers;
private readonly IPackageRestorer _restorer;
- private readonly ITargetFrameworkMonikerComparer _comparer;
+ private readonly Factories _factories;
public MSBuildWorkspaceUpgradeContext Context { get; }
@@ -29,6 +29,7 @@ internal partial class MSBuildProject : IProject
public MSBuildProject(
MSBuildWorkspaceUpgradeContext context,
IEnumerable componentIdentifiers,
+ Factories factories,
IPackageRestorer restorer,
ITargetFrameworkMonikerComparer comparer,
FileInfo file,
@@ -37,9 +38,9 @@ public MSBuildProject(
FileInfo = file ?? throw new ArgumentNullException(nameof(file));
Context = context ?? throw new ArgumentNullException(nameof(context));
+ _factories = factories ?? throw new ArgumentNullException(nameof(factories));
_componentIdentifiers = componentIdentifiers ?? throw new ArgumentNullException(nameof(componentIdentifiers));
_restorer = restorer ?? throw new ArgumentNullException(nameof(restorer));
- _comparer = comparer ?? throw new ArgumentNullException(nameof(comparer));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
@@ -141,7 +142,7 @@ public IEnumerable FindFiles(ProjectItemMatcher matcher, ProjectItemType
public IEnumerable References =>
ProjectRoot.GetAllReferences().Select(r => r.AsReference()).ToList();
- public IReadOnlyCollection TargetFrameworks => new TargetFrameworkMonikerCollection(this, _comparer);
+ public IReadOnlyCollection TargetFrameworks => _factories.CreateTfmCollection(this);
public IEnumerable ProjectTypes => GetPropertyValue("ProjectTypeGuids").Split(';');
diff --git a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/MSBuildWorkspaceUpgradeContext.cs b/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/MSBuildWorkspaceUpgradeContext.cs
index 56af463b3..1534cf076 100644
--- a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/MSBuildWorkspaceUpgradeContext.cs
+++ b/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/MSBuildWorkspaceUpgradeContext.cs
@@ -23,6 +23,7 @@ internal sealed class MSBuildWorkspaceUpgradeContext : IUpgradeContext, IDisposa
private readonly ILogger _logger;
private readonly Dictionary _projectCache;
private readonly IOptions _options;
+ private readonly Factories _factories;
private List? _entryPointPaths;
private FileInfo? _projectPath;
@@ -58,6 +59,7 @@ public MSBuildWorkspaceUpgradeContext(
IOptions options,
Func infoGenerator,
IPackageRestorer restorer,
+ Factories factories,
ITargetFrameworkMonikerComparer comparer,
IEnumerable componentIdentifiers,
ILogger logger)
@@ -67,6 +69,7 @@ public MSBuildWorkspaceUpgradeContext(
throw new ArgumentNullException(nameof(infoGenerator));
}
+ _factories = factories ?? throw new ArgumentNullException(nameof(factories));
_projectCache = new Dictionary(StringComparer.OrdinalIgnoreCase);
_options = options ?? throw new ArgumentNullException(nameof(options));
_restorer = restorer ?? throw new ArgumentNullException(nameof(restorer));
@@ -96,7 +99,7 @@ public IProject GetOrAddProject(FileInfo path)
return cached;
}
- var project = new MSBuildProject(this, _componentIdentifiers, _restorer, _comparer, path, _logger);
+ var project = new MSBuildProject(this, _componentIdentifiers, _factories, _restorer, _comparer, path, _logger);
_projectCache.Add(path.FullName, project);
diff --git a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/UpgraderMsBuildExtensions.cs b/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/UpgraderMsBuildExtensions.cs
index 3dedd9737..56415f534 100644
--- a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/UpgraderMsBuildExtensions.cs
+++ b/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/UpgraderMsBuildExtensions.cs
@@ -8,7 +8,6 @@
using Microsoft.DotNet.UpgradeAssistant.MSBuild;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
-using NuGet.Configuration;
namespace Microsoft.DotNet.UpgradeAssistant
{
@@ -22,6 +21,8 @@ public static void AddMsBuild(this IServiceCollection services, Action();
+
services.AddTransient, VisualStudioFinder>();
services.AddTransient, MSBuildWorkspaceOptionsConfigure>();
services.AddTransient();
@@ -35,24 +36,6 @@ public static void AddMsBuild(this IServiceCollection services, Action>(sp => () => sp.GetRequiredService());
}
- public static void AddNuGet(this IServiceCollection services, Action configure)
- {
- services.AddSingleton();
- services.AddTransient(ctx => ctx.GetRequiredService());
- services.AddTransient(ctx => ctx.GetRequiredService());
- services.AddSingleton();
- services.AddTransient();
- services.AddSingleton();
- services.AddSingleton();
- services.AddOptions()
- .Configure(configure)
- .Configure(options =>
- {
- var settings = Settings.LoadDefaultSettings(null);
- options.CachePath = SettingsUtility.GetGlobalPackagesFolder(settings);
- });
- }
-
// TEMPORARY WORKAROUND
// https://github.com/dotnet/roslyn/issues/36781
// Adding documents to a project can result in extra "" items
diff --git a/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/ExtensionManifest.json b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/ExtensionManifest.json
new file mode 100644
index 000000000..5deb1af86
--- /dev/null
+++ b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/ExtensionManifest.json
@@ -0,0 +1,7 @@
+{
+ "ExtensionName": "NuGet",
+
+ "ExtensionServiceProviders": [
+ "Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.dll"
+ ]
+}
\ No newline at end of file
diff --git a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/INuGetPackageSourceFactory.cs b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/INuGetPackageSourceFactory.cs
similarity index 84%
rename from src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/INuGetPackageSourceFactory.cs
rename to src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/INuGetPackageSourceFactory.cs
index 9df369754..5937f1a72 100644
--- a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/INuGetPackageSourceFactory.cs
+++ b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/INuGetPackageSourceFactory.cs
@@ -4,7 +4,7 @@
using System.Collections.Generic;
using NuGet.Configuration;
-namespace Microsoft.DotNet.UpgradeAssistant.MSBuild
+namespace Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet
{
public interface INuGetPackageSourceFactory
{
diff --git a/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.csproj b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.csproj
new file mode 100644
index 000000000..a44e14bb5
--- /dev/null
+++ b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.csproj
@@ -0,0 +1,48 @@
+
+
+
+ net5.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
+
diff --git a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/NuGetCredentialsStartup.cs b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetCredentialsStartup.cs
similarity index 94%
rename from src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/NuGetCredentialsStartup.cs
rename to src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetCredentialsStartup.cs
index 37fad51b3..e846c5a64 100644
--- a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/NuGetCredentialsStartup.cs
+++ b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetCredentialsStartup.cs
@@ -7,7 +7,7 @@
using Microsoft.Extensions.Logging;
using NuGet.Credentials;
-namespace Microsoft.DotNet.UpgradeAssistant.MSBuild
+namespace Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet
{
public class NuGetCredentialsStartup : IUpgradeStartup
{
diff --git a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/NuGetDownloaderOptions.cs b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetDownloaderOptions.cs
similarity index 83%
rename from src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/NuGetDownloaderOptions.cs
rename to src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetDownloaderOptions.cs
index 759189ef3..420d87615 100644
--- a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/NuGetDownloaderOptions.cs
+++ b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetDownloaderOptions.cs
@@ -1,7 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-namespace Microsoft.DotNet.UpgradeAssistant.MSBuild
+namespace Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet
{
public class NuGetDownloaderOptions
{
diff --git a/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetExtensionBuilder.cs b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetExtensionBuilder.cs
new file mode 100644
index 000000000..60324f71d
--- /dev/null
+++ b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetExtensionBuilder.cs
@@ -0,0 +1,34 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.DotNet.UpgradeAssistant.MSBuild;
+using Microsoft.Extensions.DependencyInjection;
+using NuGet.Configuration;
+
+namespace Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet
+{
+ public class NuGetExtensionBuilder : IExtensionServiceProvider
+ {
+ public void AddServices(IExtensionServiceCollection services)
+ => AddNuGet(services.Services);
+
+ private static void AddNuGet(IServiceCollection services)
+ {
+ services.AddTransient();
+ services.AddTransient();
+ services.AddSingleton();
+ services.AddTransient(ctx => ctx.GetRequiredService());
+ services.AddTransient(ctx => ctx.GetRequiredService());
+ services.AddSingleton();
+ services.AddTransient();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddOptions()
+ .Configure(options =>
+ {
+ var settings = Settings.LoadDefaultSettings(null);
+ options.CachePath = SettingsUtility.GetGlobalPackagesFolder(settings);
+ });
+ }
+ }
+}
diff --git a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/NuGetExtensions.cs b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetExtensions.cs
similarity index 96%
rename from src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/NuGetExtensions.cs
rename to src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetExtensions.cs
index 46f0594b2..0094dcfb6 100644
--- a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/NuGetExtensions.cs
+++ b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetExtensions.cs
@@ -4,7 +4,7 @@
using System.Diagnostics.CodeAnalysis;
using NuGet.Versioning;
-namespace Microsoft.DotNet.UpgradeAssistant.MSBuild
+namespace Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet
{
public static class NuGetExtensions
{
diff --git a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/NuGetLogger.cs b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetLogger.cs
similarity index 97%
rename from src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/NuGetLogger.cs
rename to src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetLogger.cs
index e8928ac7b..19149a176 100644
--- a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/NuGetLogger.cs
+++ b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetLogger.cs
@@ -8,7 +8,7 @@
using ILogger = NuGet.Common.ILogger;
using LogLevel = NuGet.Common.LogLevel;
-namespace Microsoft.DotNet.UpgradeAssistant.MSBuild
+namespace Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet
{
public class NuGetLogger : ILogger
{
diff --git a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/NuGetPackageSourceFactory.cs b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetPackageSourceFactory.cs
similarity index 95%
rename from src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/NuGetPackageSourceFactory.cs
rename to src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetPackageSourceFactory.cs
index 8d4c15995..cf1699e1a 100644
--- a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/NuGetPackageSourceFactory.cs
+++ b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetPackageSourceFactory.cs
@@ -6,7 +6,7 @@
using Microsoft.Extensions.Logging;
using NuGet.Configuration;
-namespace Microsoft.DotNet.UpgradeAssistant.MSBuild
+namespace Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet
{
public class NuGetPackageSourceFactory : INuGetPackageSourceFactory
{
diff --git a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/NuGetTargetFrameworkMonikerComparer.cs b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetTargetFrameworkMonikerComparer.cs
similarity index 98%
rename from src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/NuGetTargetFrameworkMonikerComparer.cs
rename to src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetTargetFrameworkMonikerComparer.cs
index b95603413..79ac6754f 100644
--- a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/NuGetTargetFrameworkMonikerComparer.cs
+++ b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetTargetFrameworkMonikerComparer.cs
@@ -6,7 +6,7 @@
using Microsoft.Extensions.Logging;
using NuGet.Frameworks;
-namespace Microsoft.DotNet.UpgradeAssistant.MSBuild
+namespace Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet
{
public class NuGetTargetFrameworkMonikerComparer : ITargetFrameworkMonikerComparer
{
diff --git a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/NuGetVersionComparer.cs b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetVersionComparer.cs
similarity index 95%
rename from src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/NuGetVersionComparer.cs
rename to src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetVersionComparer.cs
index 2203be4a9..edb34de33 100644
--- a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/NuGetVersionComparer.cs
+++ b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/NuGetVersionComparer.cs
@@ -3,7 +3,7 @@
using NuGet.Versioning;
-namespace Microsoft.DotNet.UpgradeAssistant.MSBuild
+namespace Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet
{
public class NuGetVersionComparer : IVersionComparer
{
diff --git a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/PackageConfig.cs b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/PackageConfig.cs
similarity index 94%
rename from src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/PackageConfig.cs
rename to src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/PackageConfig.cs
index 04710ac5e..28ac0ee84 100644
--- a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/PackageConfig.cs
+++ b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/PackageConfig.cs
@@ -4,7 +4,7 @@
using System.Collections.Generic;
using System.Xml.Linq;
-namespace Microsoft.DotNet.UpgradeAssistant.MSBuild
+namespace Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet
{
internal static class PackageConfig
{
diff --git a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/PackageLoader.cs b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/PackageLoader.cs
similarity index 99%
rename from src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/PackageLoader.cs
rename to src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/PackageLoader.cs
index 8ab41cf5b..42e319b25 100644
--- a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/PackageLoader.cs
+++ b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/PackageLoader.cs
@@ -11,7 +11,6 @@
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
-using Microsoft.DotNet.UpgradeAssistant.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NuGet.Configuration;
@@ -21,7 +20,7 @@
using NuGet.Protocol.Core.Types;
using NuGet.Versioning;
-namespace Microsoft.DotNet.UpgradeAssistant.MSBuild
+namespace Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet
{
public sealed class PackageLoader : IPackageLoader, IPackageDownloader, IDisposable
{
@@ -30,7 +29,7 @@ public sealed class PackageLoader : IPackageLoader, IPackageDownloader, IDisposa
private readonly SourceCacheContext _cache;
private readonly Lazy> _packageSources;
private readonly ILogger _logger;
- private readonly NuGet.Common.ILogger _nugetLogger;
+ private readonly global::NuGet.Common.ILogger _nugetLogger;
private readonly Dictionary _sourceRepositoryCache;
private readonly NuGetDownloaderOptions _options;
diff --git a/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/ProjectNuGetReferences.cs b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/ProjectNuGetReferences.cs
new file mode 100644
index 000000000..ea5c63173
--- /dev/null
+++ b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/ProjectNuGetReferences.cs
@@ -0,0 +1,213 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.Extensions.Logging;
+using NuGet.Frameworks;
+using NuGet.Packaging.Core;
+using NuGet.ProjectModel;
+
+namespace Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet
+{
+ public class ProjectNuGetReferences : INuGetReferences
+ {
+ private readonly IUpgradeContext _context;
+ private readonly IProject _project;
+ private readonly IPackageRestorer _restorer;
+ private readonly ILogger _logger;
+
+ public ProjectNuGetReferences(
+ IUpgradeContext context,
+ IProject project,
+ IPackageRestorer restorer,
+ ILogger logger)
+ {
+ _context = context ?? throw new ArgumentNullException(nameof(context));
+ _project = project ?? throw new ArgumentNullException(nameof(project));
+ _restorer = restorer ?? throw new ArgumentNullException(nameof(restorer));
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ }
+
+ public NugetPackageFormat PackageReferenceFormat
+ {
+ get
+ {
+ if (GetPackagesConfigPath() is not null)
+ {
+ return NugetPackageFormat.PackageConfig;
+ }
+ else if (_project.GetFile().PackageReferences.Any())
+ {
+ return NugetPackageFormat.PackageReference;
+ }
+ else
+ {
+ return NugetPackageFormat.None;
+ }
+ }
+ }
+
+ private string? GetPackagesConfigPath() => _project.FindFiles("packages.config", ProjectItemType.Content).FirstOrDefault();
+
+ public IEnumerable PackageReferences
+ {
+ get
+ {
+ var packagesConfig = GetPackagesConfigPath();
+
+ if (packagesConfig is null)
+ {
+ return _project.GetFile().PackageReferences;
+ }
+ else
+ {
+ return PackageConfig.GetPackages(packagesConfig);
+ }
+ }
+ }
+
+ public IAsyncEnumerable GetTransitivePackageReferencesAsync(TargetFrameworkMoniker tfm, CancellationToken token)
+ => PackageReferenceFormat switch
+ {
+ NugetPackageFormat.PackageConfig => PackageReferences.ToAsyncEnumerable(),
+ NugetPackageFormat.PackageReference => GetAllPackageReferenceDependenciesAsync(tfm, token).Select(l => new NuGetReference(l.Name, l.Version.ToNormalizedString())),
+ _ => AsyncEnumerable.Empty()
+ };
+
+ public async ValueTask IsTransitivelyAvailableAsync(string packageName, CancellationToken token)
+ => PackageReferences.Any(p => p.Name.Equals(packageName, StringComparison.OrdinalIgnoreCase))
+ || (PackageReferenceFormat == NugetPackageFormat.PackageReference && await _project.TargetFrameworks.ToAsyncEnumerable().AnyAwaitAsync(tfm => ContainsPackageDependencyAsync(tfm, d => string.Equals(packageName, d.Id, StringComparison.OrdinalIgnoreCase), token), cancellationToken: token).ConfigureAwait(false));
+
+ public async ValueTask IsTransitiveDependencyAsync(NuGetReference nugetReference, CancellationToken token)
+ => PackageReferenceFormat == NugetPackageFormat.PackageReference && await _project.TargetFrameworks.ToAsyncEnumerable().AnyAwaitAsync(tfm => ContainsPackageDependencyAsync(tfm, d => ReferenceSatisfiesDependency(d, nugetReference, true), token), token).ConfigureAwait(false);
+
+ private static bool ReferenceSatisfiesDependency(PackageDependency dependency, NuGetReference packageReference, bool minVersionMatchOnly)
+ {
+ // If the dependency's name doesn't match the reference's name, return false
+ if (!dependency.Id.Equals(packageReference.Name, StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+
+ if (!packageReference.TryGetNuGetVersion(out var packageVersion))
+ {
+ throw new InvalidOperationException("Package references from a lock file should always have a specific version");
+ }
+
+ // Return false if the reference's version falls outside of the dependency range
+ var versionRange = dependency.VersionRange;
+ if (versionRange.HasLowerBound && packageVersion < versionRange.MinVersion)
+ {
+ return false;
+ }
+
+ if (versionRange.HasUpperBound && packageVersion > versionRange.MaxVersion)
+ {
+ return false;
+ }
+
+ // In some cases (looking for transitive dependencies), it's interesting to only match packages that are the minimum version
+ if (minVersionMatchOnly && versionRange.HasLowerBound && packageVersion != versionRange.MinVersion)
+ {
+ return false;
+ }
+
+ // Otherwise, return true
+ return true;
+ }
+
+ private ValueTask ContainsPackageDependencyAsync(TargetFrameworkMoniker tfm, Func filter, CancellationToken token)
+ => GetAllPackageReferenceDependenciesAsync(tfm, token).AnyAsync(l => l.Dependencies.Any(d => filter(d)), token);
+
+ private async IAsyncEnumerable GetAllPackageReferenceDependenciesAsync(TargetFrameworkMoniker tfm, [EnumeratorCancellation] CancellationToken token)
+ {
+ if (!IsRestored)
+ {
+ throw new InvalidOperationException("Project should have already been restored. Please file an issue at https://github.com/dotnet/upgrade-assistant");
+ }
+
+ if (PackageReferenceFormat != NugetPackageFormat.PackageReference)
+ {
+ throw new InvalidOperationException("PackageReference restore for transitive dependencies should only happen for PackageReference package reference format");
+ }
+
+ var parsedTfm = NuGetFramework.Parse(tfm.Name);
+ var target = GetLockFileTarget(parsedTfm);
+
+ if (target is null)
+ {
+ // Break if there are no packages in the project. Otherwise, we end up performing restores too often.
+ if (!PackageReferences.Any())
+ {
+ _logger.LogDebug("Skipping restore as no package references exist in project file {Path}", _project.FileInfo.FullName);
+ yield break;
+ }
+
+ _logger.LogDebug("Attempting a restore to retrieve missing lock file data {Path}", _project.FileInfo.FullName);
+
+ await _restorer.RestorePackagesAsync(_context, _project, token).ConfigureAwait(false);
+
+ // If the LockFilePath is defined but does not exist, there are no libraries
+ if (!File.Exists(LockFilePath))
+ {
+ yield break;
+ }
+
+ target = GetLockFileTarget(parsedTfm);
+ }
+
+ if (target is null)
+ {
+ _logger.LogError("NuGet target in project.assets.json is still unavailable after restore. Please verify that the project has been restored.");
+ throw new UpgradeException("Restore has not restored the expected TFMs. Please review any warnings from dotnet-restore.");
+ }
+
+ foreach (var library in target.Libraries)
+ {
+ yield return library;
+ }
+
+ LockFileTarget? GetLockFileTarget(NuGetFramework parsedTfm)
+ {
+ var lockFile = LockFileUtilities.GetLockFile(LockFilePath, global::NuGet.Common.NullLogger.Instance);
+
+ if (lockFile?.Targets is null)
+ {
+ return null;
+ }
+
+ return lockFile.Targets
+ .FirstOrDefault(t => t.TargetFramework.DotNetFrameworkName.Equals(parsedTfm.DotNetFrameworkName, StringComparison.Ordinal));
+ }
+ }
+
+ private bool IsRestored => LockFilePath is not null;
+
+ private string? LockFilePath
+ {
+ get
+ {
+ var lockFilePath = Path.Combine(_project.GetFile().GetPropertyValue("MSBuildProjectExtensionsPath"), "project.assets.json");
+
+ if (string.IsNullOrEmpty(lockFilePath))
+ {
+ return null;
+ }
+
+ if (!Path.IsPathFullyQualified(lockFilePath))
+ {
+ lockFilePath = Path.Combine(_project.FileInfo.DirectoryName ?? string.Empty, lockFilePath);
+ }
+
+ return lockFilePath;
+ }
+ }
+ }
+}
diff --git a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/TargetFrameworkMonikerCollection.cs b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/TargetFrameworkMonikerCollection.cs
similarity index 96%
rename from src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/TargetFrameworkMonikerCollection.cs
rename to src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/TargetFrameworkMonikerCollection.cs
index 32317564c..3c35a0b88 100644
--- a/src/components/Microsoft.DotNet.UpgradeAssistant.MSBuild/TargetFrameworkMonikerCollection.cs
+++ b/src/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet/TargetFrameworkMonikerCollection.cs
@@ -5,9 +5,9 @@
using System.Collections.Generic;
using NuGet.Frameworks;
-namespace Microsoft.DotNet.UpgradeAssistant.MSBuild
+namespace Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet
{
- public class TargetFrameworkMonikerCollection : IReadOnlyCollection
+ public class TargetFrameworkMonikerCollection : IReadOnlyCollection, ITargetFrameworkCollection
{
private const string SdkSingleTargetFramework = "TargetFramework";
private const string SdkMultipleTargetFrameworks = "TargetFrameworks";
diff --git a/tests/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests.csproj b/tests/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests.csproj
new file mode 100644
index 000000000..e5717e1f6
--- /dev/null
+++ b/tests/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests.csproj
@@ -0,0 +1,9 @@
+
+
+ net5.0
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/components/Microsoft.DotNet.UpgradeAssistant.MSBuild.Tests/NuGetExtensionsTests.cs b/tests/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests/NuGetExtensionsTests.cs
similarity index 91%
rename from tests/components/Microsoft.DotNet.UpgradeAssistant.MSBuild.Tests/NuGetExtensionsTests.cs
rename to tests/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests/NuGetExtensionsTests.cs
index 09fe47e92..c350deeae 100644
--- a/tests/components/Microsoft.DotNet.UpgradeAssistant.MSBuild.Tests/NuGetExtensionsTests.cs
+++ b/tests/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests/NuGetExtensionsTests.cs
@@ -4,9 +4,8 @@
using System;
using Xunit;
-namespace Microsoft.DotNet.UpgradeAssistant.MSBuild.Tests
+namespace Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests
{
- [Collection(MSBuildStepTestCollection.Name)]
public class NuGetExtensionsTests
{
[Fact]
diff --git a/tests/components/Microsoft.DotNet.UpgradeAssistant.MSBuild.Tests/NuGetTargetFrameworkMonikerComparerTests.cs b/tests/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests/NuGetTargetFrameworkMonikerComparerTests.cs
similarity index 98%
rename from tests/components/Microsoft.DotNet.UpgradeAssistant.MSBuild.Tests/NuGetTargetFrameworkMonikerComparerTests.cs
rename to tests/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests/NuGetTargetFrameworkMonikerComparerTests.cs
index e89e2c5c8..3c773c22e 100644
--- a/tests/components/Microsoft.DotNet.UpgradeAssistant.MSBuild.Tests/NuGetTargetFrameworkMonikerComparerTests.cs
+++ b/tests/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests/NuGetTargetFrameworkMonikerComparerTests.cs
@@ -7,9 +7,8 @@
using static Microsoft.DotNet.UpgradeAssistant.TargetFrameworkMonikerParser;
-namespace Microsoft.DotNet.UpgradeAssistant.MSBuild.Tests
+namespace Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests
{
- [Collection(MSBuildStepTestCollection.Name)]
public class NuGetTargetFrameworkMonikerComparerTests
{
[InlineData(Net50, NetCoreApp31, true)]
diff --git a/tests/components/Microsoft.DotNet.UpgradeAssistant.MSBuild.Tests/NuGetVersionComparerTests.cs b/tests/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests/NuGetVersionComparerTests.cs
similarity index 92%
rename from tests/components/Microsoft.DotNet.UpgradeAssistant.MSBuild.Tests/NuGetVersionComparerTests.cs
rename to tests/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests/NuGetVersionComparerTests.cs
index 6ddab9d84..226b91978 100644
--- a/tests/components/Microsoft.DotNet.UpgradeAssistant.MSBuild.Tests/NuGetVersionComparerTests.cs
+++ b/tests/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests/NuGetVersionComparerTests.cs
@@ -3,9 +3,8 @@
using Xunit;
-namespace Microsoft.DotNet.UpgradeAssistant.MSBuild.Tests
+namespace Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests
{
- [Collection(MSBuildStepTestCollection.Name)]
public class NuGetVersionComparerTests
{
[InlineData("1.0", "1.0", 0)]
diff --git a/tests/components/Microsoft.DotNet.UpgradeAssistant.MSBuild.Tests/PackageLoaderTests.cs b/tests/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests/PackageLoaderTests.cs
similarity index 99%
rename from tests/components/Microsoft.DotNet.UpgradeAssistant.MSBuild.Tests/PackageLoaderTests.cs
rename to tests/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests/PackageLoaderTests.cs
index c586348a8..16619f125 100644
--- a/tests/components/Microsoft.DotNet.UpgradeAssistant.MSBuild.Tests/PackageLoaderTests.cs
+++ b/tests/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests/PackageLoaderTests.cs
@@ -12,9 +12,8 @@
using NuGet.Protocol.Core.Types;
using Xunit;
-namespace Microsoft.DotNet.UpgradeAssistant.MSBuild.Tests
+namespace Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests
{
- [Collection(MSBuildStepTestCollection.Name)]
public class PackageLoaderTests
{
private readonly Fixture _fixture;
diff --git a/tests/components/Microsoft.DotNet.UpgradeAssistant.MSBuild.Tests/TargetFrameworkMonikerCollectionTests.cs b/tests/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests/TargetFrameworkMonikerCollectionTests.cs
similarity index 98%
rename from tests/components/Microsoft.DotNet.UpgradeAssistant.MSBuild.Tests/TargetFrameworkMonikerCollectionTests.cs
rename to tests/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests/TargetFrameworkMonikerCollectionTests.cs
index d508b0b49..c135a20a1 100644
--- a/tests/components/Microsoft.DotNet.UpgradeAssistant.MSBuild.Tests/TargetFrameworkMonikerCollectionTests.cs
+++ b/tests/extensions/nuget/Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests/TargetFrameworkMonikerCollectionTests.cs
@@ -8,9 +8,8 @@
using static Microsoft.DotNet.UpgradeAssistant.TargetFrameworkMonikerParser;
-namespace Microsoft.DotNet.UpgradeAssistant.MSBuild.Tests
+namespace Microsoft.DotNet.UpgradeAssistant.Extensions.NuGet.Tests
{
- [Collection(MSBuildStepTestCollection.Name)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Assertions", "xUnit2013:Do not use equality check to check for collection size.", Justification = "Need to verify .Count property")]
public class TargetFrameworkMonikerCollectionTests
{