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

Download tool packages from NuGet feeds directly, instead of implicitly restoring #33835

Merged
merged 48 commits into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
e04c530
able to download a package via nuget api
JL03-Yue May 26, 2023
6556b54
commit before switch branch
JL03-Yue Jun 15, 2023
983897d
tool package downloader using nuget API for installing global tools
JL03-Yue Jun 27, 2023
8c66b87
update the global install method entry point
JL03-Yue Jun 29, 2023
f322c75
update the global install method entry point
JL03-Yue Jun 29, 2023
496c854
add nuget api to tool update global command
JL03-Yue Jul 10, 2023
587fe7b
remove unused comment
JL03-Yue Jul 29, 2023
4be01a5
combine global and local tool nuget install & update
JL03-Yue Aug 2, 2023
498ceee
clear out comments
JL03-Yue Aug 2, 2023
c533116
resolve the path of runtimeIdentifierGraph.json in ToolPackageDownloader
JL03-Yue Aug 2, 2023
9621b31
adding class interface for ToolPackageDownloader class
JL03-Yue Aug 2, 2023
01320fa
changing createToolPackageStoresAndDownlaoder to return a downloader
JL03-Yue Aug 2, 2023
6893a23
Writing a mock for ToolPackageDownloader; Updated ToolInstallGlobalOr…
JL03-Yue Aug 10, 2023
047b35d
Updated ToolUpdateGlobalOrToolPathCommandTests.cs to use ToolPackageD…
JL03-Yue Aug 10, 2023
ce166b3
Updated ToolUninstallGlobalOrToolPathCommandTests.cs to use toolPacka…
JL03-Yue Aug 10, 2023
d3b4fec
Update the tests in ToolInstallLocalCommandTests, ToolUpdateLocalComm…
JL03-Yue Aug 10, 2023
0c3c9a6
Update the part for local install in ToolPackageDownloaderMock.cs
JL03-Yue Aug 10, 2023
c63bd07
Update the verbosity feature of Downloading tools using Nuget and cha…
JL03-Yue Aug 11, 2023
b707d89
Clean ToolPackageDownloaderMock
JL03-Yue Aug 11, 2023
2267519
Updated the targetFramework to be dynamic; Adding comments for the fo…
JL03-Yue Aug 15, 2023
ee5b27c
Update the local nuget tool download folder
JL03-Yue Aug 16, 2023
2a16464
add package source mapping when loading nuget source
JL03-Yue Aug 23, 2023
38feeee
Remove installer package in ToolPackageInstaller and all its tests; u…
JL03-Yue Aug 24, 2023
2a08e1c
Remove ToolPackageInstaller class
JL03-Yue Aug 26, 2023
c7fe380
Updated local tool path
JL03-Yue Aug 26, 2023
50dcfd5
Updated local tool path to use NUGET_PACKAGES env_var
JL03-Yue Aug 28, 2023
d3493e8
Update the ToolPackageInstallerNugetCacheTests to expect user nuget f…
JL03-Yue Aug 29, 2023
5cc6d7f
Updated PSM only applys to downloading NuGet tools; Updated PSM's err…
JL03-Yue Aug 30, 2023
83eb501
Resolve double ; in ToolPackageDownloader and PSM link
JL03-Yue Aug 30, 2023
4accdad
Merge remote-tracking branch 'upstream/release/8.0.1xx' into 31134-to…
JL03-Yue Aug 31, 2023
0bcd7be
Update LocalizableStrings on PSM for spelling error, links, and comma
JL03-Yue Sep 1, 2023
4d15bc4
Add PSM tests
JL03-Yue Sep 7, 2023
729b4bc
Commenting out ItRunsWithTheSpecificVerbosity
JL03-Yue Sep 7, 2023
e9542bf
Add configureAwait() for async tool method
JL03-Yue Sep 8, 2023
4dcc5aa
Resolve naming conventions, variable scopes, class range
JL03-Yue Sep 13, 2023
893d794
Resolve test failures 1
JL03-Yue Sep 13, 2023
b6a7c2d
Pass in parameters and rename conventions
JL03-Yue Sep 14, 2023
ae2934b
rollback directory unchanged
JL03-Yue Sep 14, 2023
6b5da76
Change verbosityOptions
JL03-Yue Sep 14, 2023
160244a
Resolve versionRange
JL03-Yue Sep 14, 2023
6b9c7c8
Pass targetFramework and add GetBestPackageVersionAsync method
JL03-Yue Sep 15, 2023
4245c83
Update PSM test, update duplicate download error, remove unused code
JL03-Yue Sep 17, 2023
ea5eaa6
fix check duplicate global packages
JL03-Yue Sep 18, 2023
c1e3177
Change verbosity type and add packageSourceMapping tests
JL03-Yue Sep 18, 2023
797ebb4
Add test for when local tool rollback, it should delete the <Package …
JL03-Yue Sep 18, 2023
3b9dddc
update rollback directory test
JL03-Yue Sep 18, 2023
e7568cb
Adding scope to global tool duplicate download check; clean up te; re…
JL03-Yue Sep 18, 2023
38ee802
Include package version in cannot match version error
JL03-Yue Sep 18, 2023
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
10 changes: 8 additions & 2 deletions src/Cli/dotnet/NugetPackageDownloader/INuGetPackageDownloader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using Microsoft.DotNet.ToolPackage;
using Microsoft.Extensions.EnvironmentAbstractions;
using NuGet.Configuration;
using NuGet.Versioning;

namespace Microsoft.DotNet.Cli.NuGetPackageDownloader
Expand All @@ -13,7 +14,8 @@ Task<string> DownloadPackageAsync(PackageId packageId,
NuGetVersion packageVersion = null,
PackageSourceLocation packageSourceLocation = null,
bool includePreview = false,
DirectoryPath? downloadFolder = null);
DirectoryPath? downloadFolder = null,
PackageSourceMapping packageSourceMapping = null);

Task<string> GetPackageUrl(PackageId packageId,
NuGetVersion packageVersion = null,
Expand All @@ -25,5 +27,9 @@ Task<string> GetPackageUrl(PackageId packageId,
Task<NuGetVersion> GetLatestPackageVersion(PackageId packageId,
PackageSourceLocation packageSourceLocation = null,
bool includePreview = false);
}

Task<NuGetVersion> GetBestPackageVersionAsync(PackageId packageId,
VersionRange versionRange,
PackageSourceLocation packageSourceLocation = null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,10 @@
<data name="FailedToValidatePackageSigning" xml:space="preserve">
<value>Failed to validate package signing.</value>
</data>
</root>
<data name="FailedToFindSourceUnderPackageSourceMapping" xml:space="preserve">
<value>Package Source Mapping is enabled, but no source found under the specified package ID: {0}. See the documentation for Package Source Mapping at https://aka.ms/nuget-package-source-mapping for more details.</value>
</data>
<data name="FailedToMapSourceUnderPackageSourceMapping" xml:space="preserve">
<value>Package Source Mapping is enabled, but no source mapped under the specified package ID: {0}. See the documentation for Package Source Mapping at https://aka.ms/nuget-package-source-mapping for more details.</value>
</data>
JL03-Yue marked this conversation as resolved.
Show resolved Hide resolved
</root>
116 changes: 105 additions & 11 deletions src/Cli/dotnet/NugetPackageDownloader/NuGetPackageDownloader.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Threading;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.ToolPackage;
using Microsoft.DotNet.Tools;
Expand Down Expand Up @@ -36,6 +37,7 @@ internal class NuGetPackageDownloader : INuGetPackageDownloader
private readonly IFirstPartyNuGetPackageSigningVerifier _firstPartyNuGetPackageSigningVerifier;
private bool _validationMessagesDisplayed = false;
private IDictionary<PackageSource, SourceRepository> _sourceRepositories;
private readonly bool _isNuGetTool;

private bool _verifySignatures;

Expand All @@ -47,7 +49,8 @@ public NuGetPackageDownloader(
IReporter reporter = null,
RestoreActionConfig restoreActionConfig = null,
Func<IEnumerable<Task>> timer = null,
bool verifySignatures = false)
bool verifySignatures = false,
JL03-Yue marked this conversation as resolved.
Show resolved Hide resolved
bool isNuGetTool = false)
{
_packageInstallDir = packageInstallDir;
_reporter = reporter ?? Reporter.Output;
Expand All @@ -69,18 +72,20 @@ public NuGetPackageDownloader(

DefaultCredentialServiceUtility.SetupDefaultCredentialService(new NuGetConsoleLogger(),
!_restoreActionConfig.Interactive);
_isNuGetTool = isNuGetTool;
}

public async Task<string> DownloadPackageAsync(PackageId packageId,
NuGetVersion packageVersion = null,
PackageSourceLocation packageSourceLocation = null,
bool includePreview = false,
DirectoryPath? downloadFolder = null)
DirectoryPath? downloadFolder = null,
PackageSourceMapping packageSourceMapping = null)
{
CancellationToken cancellationToken = CancellationToken.None;

(var source, var resolvedPackageVersion) = await GetPackageSourceAndVersion(packageId, packageVersion,
packageSourceLocation, includePreview);
packageSourceLocation, includePreview, packageSourceMapping).ConfigureAwait(false);

FindPackageByIdResource resource = null;
SourceRepository repository = GetSourceRepository(source);
Expand Down Expand Up @@ -214,13 +219,14 @@ public async Task<IEnumerable<string>> ExtractPackageAsync(string packagePath, D
private async Task<(PackageSource, NuGetVersion)> GetPackageSourceAndVersion(PackageId packageId,
NuGetVersion packageVersion = null,
PackageSourceLocation packageSourceLocation = null,
bool includePreview = false)
bool includePreview = false,
PackageSourceMapping packageSourceMapping = null)
{
CancellationToken cancellationToken = CancellationToken.None;

IPackageSearchMetadata packageMetadata;

IEnumerable<PackageSource> packagesSources = LoadNuGetSources(packageSourceLocation);
IEnumerable<PackageSource> packagesSources = LoadNuGetSources(packageId, packageSourceLocation, packageSourceMapping);
PackageSource source;

if (packageVersion is null)
Expand Down Expand Up @@ -284,9 +290,9 @@ private static bool PackageIsInAllowList(IEnumerable<string> files)
return true;
}

private IEnumerable<PackageSource> LoadNuGetSources(PackageSourceLocation packageSourceLocation = null)
private IEnumerable<PackageSource> LoadNuGetSources(PackageId packageId, PackageSourceLocation packageSourceLocation = null, PackageSourceMapping packageSourceMapping = null)
{
IEnumerable<PackageSource> defaultSources = new List<PackageSource>();
List<PackageSource> defaultSources = new List<PackageSource>();
string currentDirectory = Directory.GetCurrentDirectory();
ISettings settings;
if (packageSourceLocation?.NugetConfig != null)
Expand All @@ -304,8 +310,25 @@ private IEnumerable<PackageSource> LoadNuGetSources(PackageSourceLocation packag
}

PackageSourceProvider packageSourceProvider = new PackageSourceProvider(settings);
defaultSources = packageSourceProvider.LoadPackageSources().Where(source => source.IsEnabled);
defaultSources = packageSourceProvider.LoadPackageSources().Where(source => source.IsEnabled).ToList();

packageSourceMapping = packageSourceMapping ?? PackageSourceMapping.GetPackageSourceMapping(settings);

// filter package patterns if enabled
if (_isNuGetTool && packageSourceMapping?.IsEnabled == true)
{
IReadOnlyList<string> sources = packageSourceMapping.GetConfiguredPackageSources(packageId.ToString());
JL03-Yue marked this conversation as resolved.
Show resolved Hide resolved

if (sources.Count == 0)
{
throw new NuGetPackageInstallerException(string.Format(LocalizableStrings.FailedToFindSourceUnderPackageSourceMapping, packageId));
}
defaultSources = defaultSources.Where(source => sources.Contains(source.Name)).ToList();
if (defaultSources.Count == 0)
{
throw new NuGetPackageInstallerException(string.Format(LocalizableStrings.FailedToMapSourceUnderPackageSourceMapping, packageId));
}
JL03-Yue marked this conversation as resolved.
Show resolved Hide resolved
}

if (packageSourceLocation?.AdditionalSourceFeed?.Any() ?? false)
{
Expand All @@ -325,7 +348,7 @@ private IEnumerable<PackageSource> LoadNuGetSources(PackageSourceLocation packag
continue;
}

defaultSources = defaultSources.Append(packageSource);
defaultSources.Add(packageSource);
}
}

Expand Down Expand Up @@ -377,7 +400,61 @@ private IEnumerable<PackageSource> LoadNuGetSources(PackageSourceLocation packag
return retrievedSources;
}

private async Task<(PackageSource, IPackageSearchMetadata)> GetLatestVersionInternalAsync(
private async Task<(PackageSource, IPackageSearchMetadata)> GetMatchingVersionInternalAsync(
string packageIdentifier, IEnumerable<PackageSource> packageSources, VersionRange versionRange,
CancellationToken cancellationToken)
{
if (packageSources == null)
{
throw new ArgumentNullException(nameof(packageSources));
}

if (string.IsNullOrWhiteSpace(packageIdentifier))
{
throw new ArgumentException($"{nameof(packageIdentifier)} cannot be null or empty",
nameof(packageIdentifier));
}

(PackageSource source, IEnumerable<IPackageSearchMetadata> foundPackages)[] foundPackagesBySource;

if (_restoreActionConfig.DisableParallel)
{
foundPackagesBySource = packageSources.Select(source => GetPackageMetadataAsync(source,
packageIdentifier,
true, cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()).ToArray();
}
else
{
foundPackagesBySource =
await Task.WhenAll(
packageSources.Select(source => GetPackageMetadataAsync(source, packageIdentifier,
true, cancellationToken)))
.ConfigureAwait(false);
}

IEnumerable<(PackageSource source, IPackageSearchMetadata package)> accumulativeSearchResults =
foundPackagesBySource
.SelectMany(result => result.foundPackages.Select(package => (result.source, package)));

var availableVersions = accumulativeSearchResults.Select(t => t.package.Identity.Version).ToList();
var bestVersion = versionRange.FindBestMatch(availableVersions);
if (bestVersion != null)
{
var bestResult = accumulativeSearchResults.First(t => t.package.Identity.Version == bestVersion);
return bestResult;
}
else
{
throw new NuGetPackageNotFoundException(
string.Format(
LocalizableStrings.IsNotFoundInNuGetFeeds,
JL03-Yue marked this conversation as resolved.
Show resolved Hide resolved
packageIdentifier,
string.Join(", ", packageSources.Select(source => source.Source))));
}

}

private async Task<(PackageSource, IPackageSearchMetadata)> GetLatestVersionInternalAsync(
string packageIdentifier, IEnumerable<PackageSource> packageSources, bool includePreview,
CancellationToken cancellationToken)
{
Expand Down Expand Up @@ -444,6 +521,23 @@ await Task.WhenAll(
return latestVersion;
}

public async Task<NuGetVersion> GetBestPackageVersionAsync(PackageId packageId,
VersionRange versionRange,
PackageSourceLocation packageSourceLocation = null)
{
CancellationToken cancellationToken = CancellationToken.None;
IPackageSearchMetadata packageMetadata;

IEnumerable<PackageSource> packagesSources = LoadNuGetSources(packageId, packageSourceLocation);
PackageSource source;

(source, packageMetadata) = await GetMatchingVersionInternalAsync(packageId.ToString(), packagesSources,
versionRange, cancellationToken).ConfigureAwait(false);

NuGetVersion packageVersion = packageMetadata.Identity.Version;
return packageVersion;
}

private async Task<(PackageSource, IPackageSearchMetadata)> GetPackageMetadataAsync(string packageIdentifier,
NuGetVersion packageVersion, IEnumerable<PackageSource> sources, CancellationToken cancellationToken)
{
Expand Down Expand Up @@ -569,7 +663,7 @@ public async Task<NuGetVersion> GetLatestPackageVersion(PackageId packageId,
{
CancellationToken cancellationToken = CancellationToken.None;
IPackageSearchMetadata packageMetadata;
IEnumerable<PackageSource> packagesSources = LoadNuGetSources(packageSourceLocation);
IEnumerable<PackageSource> packagesSources = LoadNuGetSources(packageId, packageSourceLocation);

(_, packageMetadata) = await GetLatestVersionInternalAsync(packageId.ToString(), packagesSources,
includePreview, cancellationToken).ConfigureAwait(false);
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading