| File: parent\dotnet\Commands\Tool\Search\ToolSearchCommand.cs | Web Access |
| Project: dotnet-aot.csproj (dotnet-aot) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.CommandLine; using Microsoft.DotNet.Cli.Extensions; using Microsoft.DotNet.Cli.NuGetPackageDownloader; using Microsoft.DotNet.Cli.NugetSearch; using Microsoft.DotNet.Cli.Utils; using NuGet.Configuration; using NuGet.Credentials; namespace Microsoft.DotNet.Cli.Commands.Tool.Search; internal sealed class ToolSearchCommand { private const int MaxConcurrentSourceRequests = 4; private readonly ParseResult _parseResult; private readonly ToolSearchCommandDefinition _definition; private readonly INugetToolSearchApiRequest _nugetToolSearchApiRequest; private readonly string? _currentWorkingDirectory; private readonly Action<bool> _setupCredentialService; private readonly SearchResultPrinter _searchResultPrinter; public ToolSearchCommand( ParseResult result, INugetToolSearchApiRequest? nugetToolSearchApiRequest = null, string? currentWorkingDirectory = null, Action<bool>? setupCredentialService = null) { result.ShowHelpOrErrorIfAppropriate(); _parseResult = result; _definition = (ToolSearchCommandDefinition)result.CommandResult.Command; _nugetToolSearchApiRequest = nugetToolSearchApiRequest ?? new NugetToolSearchApiRequest(); _currentWorkingDirectory = currentWorkingDirectory; _setupCredentialService = setupCredentialService ?? (interactive => DefaultCredentialServiceUtility.SetupDefaultCredentialService(new NuGetConsoleLogger(), !interactive)); _searchResultPrinter = new SearchResultPrinter(Reporter.Output); } public async Task<int> ExecuteAsync(CancellationToken cancellationToken) { var isDetailed = _parseResult.GetValue(_definition.DetailOption); NuGetSourceConfiguration sourceConfiguration = NuGetSourceConfiguration.Load( nugetConfig: _parseResult.GetValue(_definition.ConfigOption)?.FullName, sourceFeedOverrides: _parseResult.GetValue(_definition.SourceOption), additionalSourceFeeds: _parseResult.GetValue(_definition.AddSourceOption), basePath: _currentWorkingDirectory, invalidSource: _searchResultPrinter.PrintInvalidSource); if (sourceConfiguration.PackageSources.Count == 0) { _searchResultPrinter.PrintNoSourcesConfigured(); return 1; } _setupCredentialService(_parseResult.GetValue(_definition.InteractiveOption)); NugetSearchApiParameter nugetSearchApiParameter = GetNugetSearchApiParameter(); using var concurrencyLimiter = new SemaphoreSlim(MaxConcurrentSourceRequests); SourceSearchResult[] results = await Task.WhenAll( sourceConfiguration.PackageSources.Select( source => SearchSourceAsync(source, nugetSearchApiParameter, concurrencyLimiter, cancellationToken))) .ConfigureAwait(false); int successCount = 0; foreach (SourceSearchResult result in results) { if (result.ErrorMessage is null) { _searchResultPrinter.PrintSourceHeading(result.Source); _searchResultPrinter.Print(isDetailed, result.Packages); successCount++; } else { _searchResultPrinter.PrintSourceFailure(result.Source, result.ErrorMessage); } } return successCount > 0 ? 0 : 1; } internal NugetSearchApiParameter GetNugetSearchApiParameter() => new( searchTerm: _parseResult.GetValue(_definition.SearchTermArgument), skip: GetParsedResultAsInt(_definition.SkipOption), take: GetParsedResultAsInt(_definition.TakeOption), prerelease: _parseResult.GetValue(_definition.PrereleaseOption), includeVersions: _parseResult.GetValue(_definition.DetailOption)); private async Task<SourceSearchResult> SearchSourceAsync( PackageSource source, NugetSearchApiParameter searchParameters, SemaphoreSlim concurrencyLimiter, CancellationToken cancellationToken) { await concurrencyLimiter.WaitAsync(cancellationToken).ConfigureAwait(false); try { IReadOnlyCollection<SearchResultPackage> packages = await _nugetToolSearchApiRequest.GetResult(searchParameters, source, cancellationToken).ConfigureAwait(false); return new SourceSearchResult(source, packages, ErrorMessage: null); } catch (NugetSearchApiRequestException e) { return new SourceSearchResult(source, Packages: [], e.Message); } finally { concurrencyLimiter.Release(); } } private int? GetParsedResultAsInt(Option<string> alias) { var valueFromParser = _parseResult.GetValue(alias); if (string.IsNullOrWhiteSpace(valueFromParser)) { return null; } if (int.TryParse(valueFromParser, out int i)) { return i; } else { throw new GracefulException( string.Format( CliStrings.InvalidInputTypeInteger, alias)); } } private sealed record SourceSearchResult( PackageSource Source, IReadOnlyCollection<SearchResultPackage> Packages, string? ErrorMessage); }