From ba2d230d4c9585af3e65cd80cc1974988474ab51 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Tue, 30 Jun 2026 13:56:54 -0700 Subject: [PATCH 01/12] Implement unimplemented concurrency methods for all server classes --- src/code/ContainerRegistryServerAPICalls.cs | 53 ++++- src/code/FindHelper.cs | 88 +++------ src/code/InstallHelper.cs | 4 +- src/code/LocalServerApiCalls.cs | 65 ++++++- src/code/NuGetServerAPICalls.cs | 53 ++++- src/code/V3ServerAPICalls.cs | 205 +++++++++++++++++++- 6 files changed, 388 insertions(+), 80 deletions(-) diff --git a/src/code/ContainerRegistryServerAPICalls.cs b/src/code/ContainerRegistryServerAPICalls.cs index b7af3b98d..1b011c884 100644 --- a/src/code/ContainerRegistryServerAPICalls.cs +++ b/src/code/ContainerRegistryServerAPICalls.cs @@ -82,14 +82,40 @@ public ContainerRegistryServerAPICalls(PSRepositoryInfo repository, PSCmdlet cmd #region Overridden Methods + /// + /// Async find method which allows for searching for single name with specific version. + /// Name: no wildcard support + /// Version: no wildcard support + /// This is the concurrent (parallel) counterpart of FindVersion(). + /// public override Task FindVersionAsync(string packageName, string version, ResourceType type, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - throw new NotImplementedException("FindVersionAsync is not implemented for ContainerRegistryServerAPICalls."); + debugMsgs.Enqueue("In ContainerRegistryServerAPICalls::FindVersionAsync()"); + FindResults findResponse = FindVersion(packageName, version, type, out ErrorRecord errRecord); + if (errRecord != null) + { + errorMsgs.Enqueue(errRecord); + } + + return Task.FromResult(findResponse); } + /// + /// Async find method which allows for searching for single name with version range. + /// Name: no wildcard support + /// Version: supports wildcards + /// This is the concurrent (parallel) counterpart of FindVersionGlobbing(). + /// public override Task FindVersionGlobbingAsync(string packageName, VersionRange versionRange, bool includePrerelease, ResourceType type, bool getOnlyLatest, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - throw new NotImplementedException("FindVersionGlobbingAsync is not implemented for ContainerRegistryServerAPICalls."); + debugMsgs.Enqueue("In ContainerRegistryServerAPICalls::FindVersionGlobbingAsync()"); + FindResults findResponse = FindVersionGlobbing(packageName, versionRange, includePrerelease, type, getOnlyLatest, out ErrorRecord errRecord); + if (errRecord != null) + { + errorMsgs.Enqueue(errRecord); + } + + return Task.FromResult(findResponse); } /// @@ -158,9 +184,21 @@ public override FindResults FindName(string packageName, bool includePrerelease, } + /// + /// Async find method which allows for searching for single name and returns latest version. + /// Name: no wildcard support + /// This is the concurrent (parallel) counterpart of FindName(). + /// public override Task FindNameAsync(string packageName, bool includePrerelease, ResourceType type, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - throw new NotImplementedException("FindNameAsync is not implemented for ContainerRegistryServerAPICalls."); + debugMsgs.Enqueue("In ContainerRegistryServerAPICalls::FindNameAsync()"); + FindResults findResponse = FindName(packageName, includePrerelease, type, out ErrorRecord errRecord); + if (errRecord != null) + { + errorMsgs.Enqueue(errRecord); + } + + return Task.FromResult(findResponse); } /// @@ -329,7 +367,14 @@ public override Stream InstallPackage(string packageName, string packageVersion, /// public override Task InstallPackageAsync(string packageName, string packageVersion, bool includePrerelease, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - throw new NotImplementedException("FindNameAsync is not implemented for ContainerRegistryServerAPICalls."); + debugMsgs.Enqueue("In ContainerRegistryServerAPICalls::InstallPackageAsync()"); + Stream results = InstallPackage(packageName, packageVersion, includePrerelease, out ErrorRecord errRecord); + if (errRecord != null) + { + errorMsgs.Enqueue(errRecord); + } + + return Task.FromResult(results); } /// diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs index 1a074b67e..fb5c9a28d 100644 --- a/src/code/FindHelper.cs +++ b/src/code/FindHelper.cs @@ -912,17 +912,12 @@ private IEnumerable SearchByNames(ServerApiCall currentServer, R ConcurrentDictionary> cachedNetworkCalls = new ConcurrentDictionary>(); Task response = null; - if (currentServer.Repository.ApiVersion == PSRepositoryInfo.APIVersion.V2) { - string key = $"{pkgName}|{_nugetVersion.ToNormalizedString()}|{_type}"; - response = cachedNetworkCalls.GetOrAdd(key, _ => currentServer.FindVersionAsync(pkgName, _nugetVersion.ToNormalizedString(), _type, errorMsgs, warningMsgs, debugMsgs, verboseMsgs)); - - responses = response.GetAwaiter().GetResult(); + string key = $"{pkgName}|{_nugetVersion.ToNormalizedString()}|{_type}"; + response = cachedNetworkCalls.GetOrAdd(key, _ => currentServer.FindVersionAsync(pkgName, _nugetVersion.ToNormalizedString(), _type, errorMsgs, warningMsgs, debugMsgs, verboseMsgs)); + + responses = response.GetAwaiter().GetResult(); - Utils.WriteOutConcurrentQueue(_cmdletPassedIn, errorMsgs, warningMsgs, debugMsgs, verboseMsgs); - } - else { - responses = currentServer.FindVersion(pkgName, _nugetVersion.ToNormalizedString(), _type, out errRecord); - } + Utils.WriteOutConcurrentQueue(_cmdletPassedIn, errorMsgs, warningMsgs, debugMsgs, verboseMsgs); } else { @@ -996,15 +991,10 @@ private IEnumerable SearchByNames(ServerApiCall currentServer, R { ConcurrentDictionary> cachedNetworkCalls = new ConcurrentDictionary>(); Task response = null; - if (currentServer.Repository.ApiVersion == PSRepositoryInfo.APIVersion.V2) { - string key = $"{pkgName}|{_versionRange.ToString()}|{_type}"; - response = cachedNetworkCalls.GetOrAdd(key, _ => currentServer.FindVersionGlobbingAsync(pkgName, _versionRange, _prerelease, _type, getOnlyLatest: false, errorMsgs, warningMsgs, debugMsgs, verboseMsgs)); - - responses = response.GetAwaiter().GetResult(); - } - else { - responses = currentServer.FindVersionGlobbing(pkgName, _versionRange, _prerelease, _type, getOnlyLatest: false, out errRecord); - } + string key = $"{pkgName}|{_versionRange.ToString()}|{_type}"; + response = cachedNetworkCalls.GetOrAdd(key, _ => currentServer.FindVersionGlobbingAsync(pkgName, _versionRange, _prerelease, _type, getOnlyLatest: false, errorMsgs, warningMsgs, debugMsgs, verboseMsgs)); + + responses = response.GetAwaiter().GetResult(); } else { @@ -1189,7 +1179,7 @@ internal void FindDependencyPackagesHelper(ServerApiCall currentServer, Response //const int PARALLEL_THRESHOLD = 5; // TODO: Trottle limit from user, defaults to 5; int processorCount = Environment.ProcessorCount; int maxDegreeOfParallelism = processorCount * 4; - if (currentServer.Repository.ApiVersion == PSRepositoryInfo.APIVersion.V2 && currentPkg.Dependencies.Length > processorCount) + if (currentPkg.Dependencies.Length > processorCount) { Parallel.ForEach(currentPkg.Dependencies, new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism }, dep => { @@ -1293,20 +1283,13 @@ private PSResourceInfo FindDependencyWithSpecificVersion( Task response = null; debugMsgs.Enqueue("In FindHelper::FindDependencyWithSpecificVersion()"); - if (currentServer.Repository.ApiVersion == PSRepositoryInfo.APIVersion.V2) - { - // See if the network call we're making is already cached, if not, call FindNameAsync() and cache results - string key = $"{dep.Name}|{dep.VersionRange.MaxVersion.ToString()}|{_type}"; - debugMsgs.Enqueue("Checking if network call is cached."); - response = _cachedNetworkCalls.GetOrAdd(key, _ => currentServer.FindVersionAsync(dep.Name, dep.VersionRange.MaxVersion.ToString(), _type, errorMsgs, warningMsgs, debugMsgs, verboseMsgs)); - - responses = response.GetAwaiter().GetResult(); - } - else - { - responses = currentServer.FindVersion(dep.Name, dep.VersionRange.MaxVersion.ToString(), _type, out errRecord); - } - + + // See if the network call we're making is already cached, if not, call FindNameAsync() and cache results + string key = $"{dep.Name}|{dep.VersionRange.MaxVersion.ToString()}|{_type}"; + debugMsgs.Enqueue("Checking if network call is cached."); + response = _cachedNetworkCalls.GetOrAdd(key, _ => currentServer.FindVersionAsync(dep.Name, dep.VersionRange.MaxVersion.ToString(), _type, errorMsgs, warningMsgs, debugMsgs, verboseMsgs)); + + responses = response.GetAwaiter().GetResult(); // Error handling and Convert to PSResource object if (errRecord != null) @@ -1369,19 +1352,12 @@ private PSResourceInfo FindDependencyWithLowerBound( Task response = null; debugMsgs.Enqueue("In FindHelper::FindDependencyWithLowerBound()"); - if (currentServer.Repository.ApiVersion == PSRepositoryInfo.APIVersion.V2) - { - // See if the network call we're making is already cached, if not, call FindNameAsync() and cache results - string key = $"{dep.Name}|*|{_type}"; - debugMsgs.Enqueue("Checking if network call is cached."); - response = _cachedNetworkCalls.GetOrAdd(key, _ => currentServer.FindNameAsync(dep.Name, includePrerelease: true, _type, errorMsgs, warningMsgs, debugMsgs, verboseMsgs)); - - responses = response.GetAwaiter().GetResult(); - } - else - { - responses = currentServer.FindName(dep.Name, includePrerelease: true, _type, out errRecord); - } + // See if the network call we're making is already cached, if not, call FindNameAsync() and cache results + string key = $"{dep.Name}|*|{_type}"; + debugMsgs.Enqueue("Checking if network call is cached."); + response = _cachedNetworkCalls.GetOrAdd(key, _ => currentServer.FindNameAsync(dep.Name, includePrerelease: true, _type, errorMsgs, warningMsgs, debugMsgs, verboseMsgs)); + + responses = response.GetAwaiter().GetResult(); // Error handling and Convert to PSResource object if (errRecord != null) @@ -1445,21 +1421,13 @@ private PSResourceInfo FindDependencyWithUpperBound( ConcurrentDictionary> cachedNetworkCalls = new ConcurrentDictionary>(); debugMsgs.Enqueue("In FindHelper::FindDependencyWithUpperBound()"); + // See if the network call we're making is already caced, if not, call FindNameAsync() and cache results + string key = $"{dep.Name}|{dep.VersionRange.MaxVersion.ToString()}|{_type}"; + debugMsgs.Enqueue("Checking if network call is cached."); + response = cachedNetworkCalls.GetOrAdd(key, _ => currentServer.FindVersionGlobbingAsync(dep.Name, dep.VersionRange, includePrerelease: true, ResourceType.None, getOnlyLatest: true, errorMsgs, warningMsgs, debugMsgs, verboseMsgs)); - if (currentServer.Repository.ApiVersion == PSRepositoryInfo.APIVersion.V2) - { - // See if the network call we're making is already caced, if not, call FindNameAsync() and cache results - string key = $"{dep.Name}|{dep.VersionRange.MaxVersion.ToString()}|{_type}"; - debugMsgs.Enqueue("Checking if network call is cached."); - response = cachedNetworkCalls.GetOrAdd(key, _ => currentServer.FindVersionGlobbingAsync(dep.Name, dep.VersionRange, includePrerelease: true, ResourceType.None, getOnlyLatest: true, errorMsgs, warningMsgs, debugMsgs, verboseMsgs)); - - responses = response.GetAwaiter().GetResult(); + responses = response.GetAwaiter().GetResult(); - } - else - { - responses = currentServer.FindVersionGlobbing(dep.Name, dep.VersionRange, includePrerelease: true, ResourceType.None, getOnlyLatest: true, out errRecord); - } // Error handling and Convert to PSResource object if (errRecord != null) diff --git a/src/code/InstallHelper.cs b/src/code/InstallHelper.cs index c89ef0ee9..e3f95b616 100644 --- a/src/code/InstallHelper.cs +++ b/src/code/InstallHelper.cs @@ -801,7 +801,7 @@ private ConcurrentDictionary BeginPackageInstall( } else { - // Concurrent updates, currently only implemented for v2 server repositories + // Concurrent updates // Find all dependencies if (!skipDependencyCheck) { @@ -853,7 +853,7 @@ private ConcurrentDictionary InstallParentAndDependencyPackag // TODO: figure out a good threshold and parallel count int processorCount = Environment.ProcessorCount; _cmdletPassedIn.WriteDebug($"parentAndDeps.Count is {parentAndDeps.Count}, processor count is: {processorCount}"); - if (currentServer.Repository.ApiVersion == PSRepositoryInfo.APIVersion.V2 && parentAndDeps.Count > processorCount) + if (parentAndDeps.Count > processorCount) { _cmdletPassedIn.WriteDebug($"parentAndDeps.Count is greater than processor count"); // Set the maximum degree of parallelism to 32? (Invoke-Command has default of 32, that's where we got this number from) diff --git a/src/code/LocalServerApiCalls.cs b/src/code/LocalServerApiCalls.cs index a8e505acb..1ebb72dcb 100644 --- a/src/code/LocalServerApiCalls.cs +++ b/src/code/LocalServerApiCalls.cs @@ -41,14 +41,40 @@ public LocalServerAPICalls (PSRepositoryInfo repository, PSCmdlet cmdletPassedIn #region Overridden Methods + /// + /// Async find method which allows for searching for single name with specific version. + /// Name: no wildcard support + /// Version: no wildcard support + /// This is the concurrent (parallel) counterpart of FindVersion(). + /// public override Task FindVersionAsync(string packageName, string version, ResourceType type, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - throw new NotImplementedException(); + debugMsgs.Enqueue("In LocalServerApiCalls::FindVersionAsync()"); + FindResults findResponse = FindVersionHelper(packageName, version, tags: Utils.EmptyStrArray, type, out ErrorRecord errRecord); + if (errRecord != null) + { + errorMsgs.Enqueue(errRecord); + } + + return Task.FromResult(findResponse); } + /// + /// Async find method which allows for searching for single name with version range. + /// Name: no wildcard support + /// Version: supports wildcards + /// This is the concurrent (parallel) counterpart of FindVersionGlobbing(). + /// public override Task FindVersionGlobbingAsync(string packageName, VersionRange versionRange, bool includePrerelease, ResourceType type, bool getOnlyLatest, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - throw new NotImplementedException(); + debugMsgs.Enqueue("In LocalServerApiCalls::FindVersionGlobbingAsync()"); + FindResults findResponse = FindVersionGlobbing(packageName, versionRange, includePrerelease, type, getOnlyLatest, out ErrorRecord errRecord); + if (errRecord != null) + { + errorMsgs.Enqueue(errRecord); + } + + return Task.FromResult(findResponse); } /// /// Find method which allows for searching for all packages from a repository and returns latest version for each. @@ -124,9 +150,21 @@ public override FindResults FindName(string packageName, bool includePrerelease, return FindNameHelper(packageName, Utils.EmptyStrArray, includePrerelease, type, out errRecord); } + /// + /// Async find method which allows for searching for single name and returns latest version. + /// Name: no wildcard support + /// This is the concurrent (parallel) counterpart of FindName(). + /// public override Task FindNameAsync(string packageName, bool includePrerelease, ResourceType type, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - throw new NotImplementedException(); + debugMsgs.Enqueue("In LocalServerApiCalls::FindNameAsync()"); + FindResults findResponse = FindNameHelper(packageName, tags: Utils.EmptyStrArray, includePrerelease, type, out ErrorRecord errRecord); + if (errRecord != null) + { + errorMsgs.Enqueue(errRecord); + } + + return Task.FromResult(findResponse); } /// @@ -278,7 +316,26 @@ public override Stream InstallPackage(string packageName, string packageVersion, /// public override Task InstallPackageAsync(string packageName, string packageVersion, bool includePrerelease, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - throw new NotImplementedException("InstallPackageAsync is not implemented for LocalServerAPICalls."); + debugMsgs.Enqueue("In LocalServerApiCalls::InstallPackageAsync()"); + Stream results = new MemoryStream(); + if (string.IsNullOrEmpty(packageVersion)) + { + errorMsgs.Enqueue(new ErrorRecord( + exception: new ArgumentNullException($"Package version could not be found for {packageName}"), + "PackageVersionNullOrEmptyError", + ErrorCategory.InvalidArgument, + _cmdletPassedIn)); + + return Task.FromResult(results); + } + + results = InstallVersion(packageName, packageVersion, out ErrorRecord errRecord); + if (errRecord != null) + { + errorMsgs.Enqueue(errRecord); + } + + return Task.FromResult(results); } #endregion diff --git a/src/code/NuGetServerAPICalls.cs b/src/code/NuGetServerAPICalls.cs index 1c6bb2828..cc4c68223 100644 --- a/src/code/NuGetServerAPICalls.cs +++ b/src/code/NuGetServerAPICalls.cs @@ -49,14 +49,40 @@ public NuGetServerAPICalls (PSRepositoryInfo repository, PSCmdlet cmdletPassedIn #region Overridden Methods + /// + /// Async find method which allows for searching for single name with specific version. + /// Name: no wildcard support + /// Version: no wildcard support + /// This is the concurrent (parallel) counterpart of FindVersion(). + /// public override Task FindVersionAsync(string packageName, string version, ResourceType type, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - throw new NotImplementedException("FindVersionAsync is not implemented for NuGetServerAPICalls."); + debugMsgs.Enqueue("In NuGetServerAPICalls::FindVersionAsync()"); + FindResults findResponse = FindVersion(packageName, version, type, out ErrorRecord errRecord); + if (errRecord != null) + { + errorMsgs.Enqueue(errRecord); + } + + return Task.FromResult(findResponse); } + /// + /// Async find method which allows for searching for single name with version range. + /// Name: no wildcard support + /// Version: supports wildcards + /// This is the concurrent (parallel) counterpart of FindVersionGlobbing(). + /// public override Task FindVersionGlobbingAsync(string packageName, VersionRange versionRange, bool includePrerelease, ResourceType type, bool getOnlyLatest, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - throw new NotImplementedException("FindVersionGlobbingAsync is not implemented for NuGetServerAPICalls."); + debugMsgs.Enqueue("In NuGetServerAPICalls::FindVersionGlobbingAsync()"); + FindResults findResponse = FindVersionGlobbing(packageName, versionRange, includePrerelease, type, getOnlyLatest, out ErrorRecord errRecord); + if (errRecord != null) + { + errorMsgs.Enqueue(errRecord); + } + + return Task.FromResult(findResponse); } /// /// Find method which allows for searching for all packages from a repository and returns latest version for each. @@ -193,9 +219,21 @@ public override FindResults FindName(string packageName, bool includePrerelease, return new FindResults(stringResponse: new string[]{ response }, hashtableResponse: emptyHashResponses, responseType: FindResponseType); } + /// + /// Async find method which allows for searching for single name and returns latest version. + /// Name: no wildcard support + /// This is the concurrent (parallel) counterpart of FindName(). + /// public override Task FindNameAsync(string packageName, bool includePrerelease, ResourceType type, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - throw new NotImplementedException("FindNameAsync is not implemented for NuGetServerAPICalls."); + debugMsgs.Enqueue("In NuGetServerAPICalls::FindNameAsync()"); + FindResults findResponse = FindName(packageName, includePrerelease, type, out ErrorRecord errRecord); + if (errRecord != null) + { + errorMsgs.Enqueue(errRecord); + } + + return Task.FromResult(findResponse); } /// @@ -471,7 +509,14 @@ public override Stream InstallPackage(string packageName, string packageVersion, /// public override Task InstallPackageAsync(string packageName, string packageVersion, bool includePrerelease, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - throw new NotImplementedException("InstallPackageAsync is not implemented for NuGetServerAPICalls."); + debugMsgs.Enqueue("In NuGetServerAPICalls::InstallPackageAsync()"); + Stream results = InstallPackage(packageName, packageVersion, includePrerelease, out ErrorRecord errRecord); + if (errRecord != null) + { + errorMsgs.Enqueue(errRecord); + } + + return Task.FromResult(results); } /// diff --git a/src/code/V3ServerAPICalls.cs b/src/code/V3ServerAPICalls.cs index a2beb1545..3693646a5 100644 --- a/src/code/V3ServerAPICalls.cs +++ b/src/code/V3ServerAPICalls.cs @@ -89,14 +89,43 @@ public V3ServerAPICalls(PSRepositoryInfo repository, PSCmdlet cmdletPassedIn, Ne #region Overridden Methods + /// + /// Async find method which allows for searching for single name with specific version. + /// Name: no wildcard support + /// Version: no wildcard support + /// Examples: Search "NuGet.Server.Core" "3.0.0-beta" + /// This is the concurrent (parallel) counterpart of FindVersion(). + /// public override Task FindVersionAsync(string packageName, string version, ResourceType type, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - throw new NotImplementedException("FindVersionAsync is not implemented for V3ServerAPICalls."); + debugMsgs.Enqueue("In V3ServerAPICalls::FindVersionAsync()"); + FindResults findResponse = FindVersionHelper(packageName, version, tags: Utils.EmptyStrArray, type, out ErrorRecord errRecord); + if (errRecord != null) + { + errorMsgs.Enqueue(errRecord); + } + + return Task.FromResult(findResponse); } + /// + /// Async find method which allows for searching for single name with version range. + /// Name: no wildcard support + /// Version: supports wildcards + /// Examples: Search "NuGet.Server.Core" "[1.0.0.0, 5.0.0.0]" + /// Search "NuGet.Server.Core" "3.*" + /// This is the concurrent (parallel) counterpart of FindVersionGlobbing(). + /// public override Task FindVersionGlobbingAsync(string packageName, VersionRange versionRange, bool includePrerelease, ResourceType type, bool getOnlyLatest, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - throw new NotImplementedException("FindVersionAsync is not implemented for V3ServerAPICalls."); + debugMsgs.Enqueue("In V3ServerAPICalls::FindVersionGlobbingAsync()"); + FindResults findResponse = FindVersionGlobbing(packageName, versionRange, includePrerelease, type, getOnlyLatest, out ErrorRecord errRecord); + if (errRecord != null) + { + errorMsgs.Enqueue(errRecord); + } + + return Task.FromResult(findResponse); } /// @@ -166,9 +195,22 @@ public override FindResults FindName(string packageName, bool includePrerelease, return FindNameHelper(packageName, tags: Utils.EmptyStrArray, includePrerelease, type, out errRecord); } + /// + /// Async find method which allows for searching for single name and returns latest version. + /// Name: no wildcard support + /// Examples: Search "Newtonsoft.Json" + /// This is the concurrent (parallel) counterpart of FindName(). + /// public override Task FindNameAsync(string packageName, bool includePrerelease, ResourceType type, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - throw new NotImplementedException("FindVersionAsync is not implemented for V3ServerAPICalls."); + debugMsgs.Enqueue("In V3ServerAPICalls::FindNameAsync()"); + FindResults findResponse = FindNameHelper(packageName, tags: Utils.EmptyStrArray, includePrerelease, type, out ErrorRecord errRecord); + if (errRecord != null) + { + errorMsgs.Enqueue(errRecord); + } + + return Task.FromResult(findResponse); } /// @@ -239,6 +281,7 @@ public override FindResults FindNameGlobbingWithTag(string packageName, string[] /// public override FindResults FindVersionGlobbing(string packageName, VersionRange versionRange, bool includePrerelease, ResourceType type, bool getOnlyLatest, out ErrorRecord errRecord) { + // TODO: pass in ConcurrentQueue for debug messages so this is thread-safe when called from FindVersionGlobbingAsync(). _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::FindVersionGlobbing()"); string[] versionedResponses = GetVersionedPackageEntriesFromRegistrationsResource(packageName, catalogEntryProperty, isSearch: true, out errRecord); if (errRecord != null) @@ -267,6 +310,7 @@ public override FindResults FindVersionGlobbing(string packageName, VersionRange if (NuGetVersion.TryParse(pkgVersionElement.ToString(), out NuGetVersion pkgVersion) && versionRange.Satisfies(pkgVersion)) { + // TODO: pass in ConcurrentQueue for debug messages so this is thread-safe when called from FindVersionGlobbingAsync(). ? _cmdletPassedIn.WriteDebug($"Package version parsed as '{pkgVersion}' satisfies the version range"); if (!pkgVersion.IsPrerelease || includePrerelease) { @@ -353,9 +397,34 @@ public override Stream InstallPackage(string packageName, string packageVersion, /// Examples: Install "PowerShellGet" -Version "3.5.0-alpha" /// Install "PowerShellGet" -Version "3.0.0" /// - public override Task InstallPackageAsync(string packageName, string packageVersion, bool includePrerelease, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) + public override async Task InstallPackageAsync(string packageName, string packageVersion, bool includePrerelease, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - throw new NotImplementedException("InstallPackageAsync is not implemented for NuGetServerAPICalls."); + debugMsgs.Enqueue("In V3ServerAPICalls::InstallPackageAsync()"); + Stream results = new MemoryStream(); + if (string.IsNullOrEmpty(packageVersion)) + { + errorMsgs.Enqueue(new ErrorRecord( + exception: new ArgumentNullException($"Package version could not be found for {packageName}"), + "PackageVersionNullOrEmptyError", + ErrorCategory.InvalidArgument, + this)); + + return results; + } + + if (!NuGetVersion.TryParse(packageVersion, out NuGetVersion requiredVersion)) + { + errorMsgs.Enqueue(new ErrorRecord( + new ArgumentException($"Version {packageVersion} to be installed is not a valid NuGet version."), + "InstallVersionFailure", + ErrorCategory.InvalidArgument, + this)); + + return results; + } + + results = await InstallHelperAsync(packageName, requiredVersion, errorMsgs, warningMsgs, debugMsgs, verboseMsgs); + return results; } #endregion @@ -514,6 +583,7 @@ private FindResults FindTagsFromNuGetRepo(string[] tags, bool includePrerelease, /// private FindResults FindNameHelper(string packageName, string[] tags, bool includePrerelease, ResourceType type, out ErrorRecord errRecord) { + // TODO: pass in ConcurrentQueue for debug messages so this is thread-safe when called from FindNameAsync(). ? _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::FindNameHelper()"); string[] versionedResponses = GetVersionedPackageEntriesFromRegistrationsResource(packageName, catalogEntryProperty, isSearch: true, out errRecord); if (errRecord != null) @@ -553,6 +623,7 @@ private FindResults FindNameHelper(string packageName, string[] tags, bool inclu if (NuGetVersion.TryParse(pkgVersionElement.ToString(), out NuGetVersion pkgVersion)) { + // ? _cmdletPassedIn.WriteDebug($"'{packageName}' version parsed as '{pkgVersion}'"); if (!pkgVersion.IsPrerelease || includePrerelease) { @@ -610,6 +681,7 @@ private FindResults FindNameHelper(string packageName, string[] tags, bool inclu /// private FindResults FindVersionHelper(string packageName, string version, string[] tags, ResourceType type, out ErrorRecord errRecord) { + // TODO: pass in ConcurrentQueue for debug messages so this is thread-safe when called from FindVersionAsync(). ? _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::FindVersionHelper()"); if (!NuGetVersion.TryParse(version, out NuGetVersion requiredVersion)) { @@ -621,7 +693,7 @@ private FindResults FindVersionHelper(string packageName, string version, string return new FindResults(stringResponse: Utils.EmptyStrArray, hashtableResponse: emptyHashResponses, responseType: v3FindResponseType); } - _cmdletPassedIn.WriteDebug($"'{packageName}' version parsed as '{requiredVersion}'"); + //_cmdletPassedIn.WriteDebug($"'{packageName}' version parsed as '{requiredVersion}'"); string[] versionedResponses = GetVersionedPackageEntriesFromRegistrationsResource(packageName, catalogEntryProperty, isSearch: true, out errRecord); if (errRecord != null) @@ -830,6 +902,88 @@ private Stream InstallHelper(string packageName, NuGetVersion version, out Error return content.ReadAsStreamAsync().GetAwaiter().GetResult(); } + /// + /// Helper method that is called by InstallPackageAsync() + /// For InstallName() we want latest version installed (so version parameter passed in will be null), for InstallVersion() we want specified, non-null version installed. + /// This is the async counterpart of InstallHelper() used for concurrent (parallel) installation workflows. + /// + private async Task InstallHelperAsync(string packageName, NuGetVersion version, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) + { + debugMsgs.Enqueue("In V3ServerAPICalls::InstallHelperAsync()"); + Stream pkgStream = null; + bool getLatestVersion = true; + if (version != null) + { + getLatestVersion = false; + } + + string[] versionedResponses = GetVersionedPackageEntriesFromRegistrationsResource(packageName, packageContentProperty, isSearch: false, out ErrorRecord errRecord); + if (errRecord != null) + { + errorMsgs.Enqueue(errRecord); + return pkgStream; + } + + if (versionedResponses.Length == 0) + { + errorMsgs.Enqueue(new ErrorRecord( + new Exception($"Package with name '{packageName}' and version '{version}' could not be found in repository '{Repository.Name}'"), + "InstallFailure", + ErrorCategory.InvalidResult, + this)); + + return null; + } + + string pkgContentUrl = String.Empty; + if (getLatestVersion) + { + pkgContentUrl = versionedResponses[0]; + } + else + { + // loop through responses to find one containing required version + foreach (string response in versionedResponses) + { + // Response will be "packageContent" element value that looks like: "{packageBaseAddress}/{packageName}/{normalizedVersion}/{packageName}.{normalizedVersion}.nupkg" + // Ex: https://api.nuget.org/v3-flatcontainer/test_module/1.0.0/test_module.1.0.0.nupkg + if (response.Contains(version.ToNormalizedString())) + { + pkgContentUrl = response; + break; + } + } + } + + if (String.IsNullOrEmpty(pkgContentUrl)) + { + errorMsgs.Enqueue(new ErrorRecord( + new Exception($"Package with name '{packageName}' and version '{version}' could not be found in repository '{Repository.Name}'"), + "InstallFailure", + ErrorCategory.InvalidResult, + this)); + + return null; + } + + var content = await HttpRequestCallForContentAsync(pkgContentUrl, errorMsgs, warningMsgs, debugMsgs, verboseMsgs); + + if (content is null) + { + errorMsgs.Enqueue(new ErrorRecord( + new Exception($"No content was returned by repository '{Repository.Name}'"), + "InstallFailureContentNullv3Async", + ErrorCategory.InvalidResult, + this)); + + return new MemoryStream(); + } + + pkgStream = await content.ReadAsStreamAsync(); + + return pkgStream; + } + /// /// Gets the versioned package entries from the RegistrationsBaseUrl resource /// i.e when the package Name being searched for does not contain wildcard @@ -1060,6 +1214,7 @@ private string FindSearchQueryService(Dictionary resources, out /// private JsonElement[] GetMetadataElementFromIdLinkElement(JsonElement idLinkElement, string packageName, out string upperVersion, out ErrorRecord errRecord) { + // TODO: pass in ConcurrentQueue to write out debug message. Called from the concurrent install metadata chain so cmdlet methods cannot be used here. ? _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::GetMetadataElementFromIdLinkElement()"); upperVersion = String.Empty; JsonElement[] innerItems = new JsonElement[]{}; @@ -1102,6 +1257,7 @@ private JsonElement[] GetMetadataElementFromIdLinkElement(JsonElement idLinkElem } else { + // TODO: pass in ConcurrentQueue to write out debug message. Called from the concurrent install metadata chain so cmdlet methods cannot be used here. ? _cmdletPassedIn.WriteDebug($"Package with name '{packageName}' did not have 'upper' property so package versions may not be in descending order."); } @@ -1228,6 +1384,7 @@ private string[] GetMetadataElementsFromResponse(string response, string propert } else { + // TODO: pass in ConcurrentQueue to write out debug message. Called from the concurrent install metadata chain so cmdlet methods cannot be used here. ? _cmdletPassedIn.WriteDebug($"Metadata for package with name '{packageName}' did not have inner 'items' or '@Id' properties."); } } @@ -1267,6 +1424,7 @@ private string[] GetMetadataElementsFromResponse(string response, string propert } else { + // TODO: pass in ConcurrentQueue to write out debug message. Called from the concurrent install metadata chain so cmdlet methods cannot be used here. ? _cmdletPassedIn.WriteDebug($"Metadata for package with name '{packageName}' was not of value kind type string or object."); } } @@ -1355,6 +1513,7 @@ private string[] GetVersionedResponsesFromRegistrationsResource(string registrat /// private bool IsLatestVersionFirstForSearch(string[] versionedResponses, out ErrorRecord errRecord) { + // TODO: pass in ConcurrentQueue for debug messages so this is thread-safe when reached from the async find methods. ? _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::IsLatestVersionFirstForSearch()"); errRecord = null; bool latestVersionFirst = true; @@ -1675,6 +1834,40 @@ private HttpContent HttpRequestCallForContent(string requestUrlV3, out ErrorReco return content; } + /// + /// Helper method that makes the HTTP request for the V3 server protocol url passed in for install APIs asynchronously. + /// This is the async counterpart of HttpRequestCallForContent() used for concurrent (parallel) installation workflows. + /// + private async Task HttpRequestCallForContentAsync(string requestUrlV3, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) + { + debugMsgs.Enqueue("In V3ServerAPICalls::HttpRequestCallForContentAsync()"); + HttpContent content = null; + try + { + debugMsgs.Enqueue($"Request url is '{requestUrlV3}'"); + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrlV3); + + content = await SendV3RequestForContentAsync(request, _sessionClient); + } + catch (Exception e) + { + errorMsgs.Enqueue(new ErrorRecord( + exception: e, + "HttpRequestCallForContentFailure", + ErrorCategory.InvalidResult, + this)); + + return null; + } + + if (string.IsNullOrEmpty(content?.ToString())) + { + debugMsgs.Enqueue("Response is empty"); + } + + return content; + } + /// /// Helper method called by HttpRequestCall() that makes the HTTP request for string response. /// From fbb940f572eb2b132d2bc196b0cb7ab8620d5e72 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Tue, 30 Jun 2026 14:11:38 -0700 Subject: [PATCH 02/12] build fixes --- src/code/FindHelper.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs index fb5c9a28d..693c00aca 100644 --- a/src/code/FindHelper.cs +++ b/src/code/FindHelper.cs @@ -904,15 +904,13 @@ private IEnumerable SearchByNames(ServerApiCall currentServer, R // Example: Find-PSResource -Name "Az" -Version "3.0.0.0" // Example: Find-PSResource -Name "Az" -Version "3.0.0.0" -Tag "Windows" _cmdletPassedIn.WriteDebug("Exact version and package name are specified"); - + string key = string.Empty; FindResults responses = null; if (_tag.Length == 0) { - - ConcurrentDictionary> cachedNetworkCalls = new ConcurrentDictionary>(); Task response = null; - string key = $"{pkgName}|{_nugetVersion.ToNormalizedString()}|{_type}"; + key = $"{pkgName}|{_nugetVersion.ToNormalizedString()}|{_type}"; response = cachedNetworkCalls.GetOrAdd(key, _ => currentServer.FindVersionAsync(pkgName, _nugetVersion.ToNormalizedString(), _type, errorMsgs, warningMsgs, debugMsgs, verboseMsgs)); responses = response.GetAwaiter().GetResult(); @@ -1318,7 +1316,7 @@ private PSResourceInfo FindDependencyWithSpecificVersion( string pkgVersion = FormatPkgVersionString(depPkg); debugMsgs.Enqueue($"Found dependency '{depPkg.Name}' version '{pkgVersion}'"); - string key = $"{depPkg.Name}{pkgVersion}"; + key = $"{depPkg.Name}{pkgVersion}"; if (!depPkgsFound.ContainsKey(key)) { // Add pkg to collection of packages found then find dependencies @@ -1386,7 +1384,7 @@ private PSResourceInfo FindDependencyWithLowerBound( string pkgVersion = FormatPkgVersionString(depPkg); debugMsgs.Enqueue($"Found dependency '{depPkg.Name}' version '{pkgVersion}'"); - string key = $"{depPkg.Name}{pkgVersion}"; + key = $"{depPkg.Name}{pkgVersion}"; if (!depPkgsFound.ContainsKey(key)) { // Add pkg to collection of packages found then find dependencies @@ -1457,7 +1455,7 @@ private PSResourceInfo FindDependencyWithUpperBound( string pkgVersion = FormatPkgVersionString(depPkg); debugMsgs.Enqueue($"Found dependency '{depPkg.Name}' version '{pkgVersion}'"); - string key = $"{depPkg.Name}{pkgVersion}"; + key = $"{depPkg.Name}{pkgVersion}"; if (!depPkgsFound.ContainsKey(key)) { // Add pkg to collection of packages found then find dependencies From a4730af8fdc5f96f90637b3dbf1c4b36619ec575 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Jul 2026 17:15:37 +0000 Subject: [PATCH 03/12] Fix thread-safety in ContainerRegistryServerAPICalls.InstallPackageAsync InstallPackageAsync was calling the synchronous InstallPackage() which writes to _cmdletPassedIn.WriteDebug, causing cross-thread cmdlet stream writes when used from Parallel.ForEach. - Refactor InstallPackageAsync to not call InstallPackage(); inline the null-version check and enqueue all messages via the provided queues - Add a queue-aware InstallVersion overload that uses ConcurrentQueue parameters instead of _cmdletPassedIn.Write* calls, for use by the async install path - Keep the original InstallVersion(out ErrorRecord) overload intact for the synchronous path --- src/code/ContainerRegistryServerAPICalls.cs | 84 ++++++++++++++++++++- 1 file changed, 81 insertions(+), 3 deletions(-) diff --git a/src/code/ContainerRegistryServerAPICalls.cs b/src/code/ContainerRegistryServerAPICalls.cs index 1b011c884..376c3c053 100644 --- a/src/code/ContainerRegistryServerAPICalls.cs +++ b/src/code/ContainerRegistryServerAPICalls.cs @@ -368,12 +368,20 @@ public override Stream InstallPackage(string packageName, string packageVersion, public override Task InstallPackageAsync(string packageName, string packageVersion, bool includePrerelease, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { debugMsgs.Enqueue("In ContainerRegistryServerAPICalls::InstallPackageAsync()"); - Stream results = InstallPackage(packageName, packageVersion, includePrerelease, out ErrorRecord errRecord); - if (errRecord != null) + Stream results = new MemoryStream(); + if (string.IsNullOrEmpty(packageVersion)) { - errorMsgs.Enqueue(errRecord); + errorMsgs.Enqueue(new ErrorRecord( + exception: new ArgumentNullException($"Package version could not be found for {packageName}"), + "PackageVersionNullOrEmptyError", + ErrorCategory.InvalidArgument, + _cmdletPassedIn)); + + return Task.FromResult(results); } + string packageNameForInstall = PrependMARPrefix(packageName); + results = InstallVersion(packageNameForInstall, packageVersion, errorMsgs, debugMsgs, verboseMsgs); return Task.FromResult(results); } @@ -445,6 +453,76 @@ private Stream InstallVersion( return responseContent.ReadAsStreamAsync().Result; } + /// + /// Installs a package with version specified using concurrent queues for output instead of cmdlet streams. + /// Used by the async install path to avoid cross-thread cmdlet stream writes. + /// + private Stream InstallVersion( + string packageName, + string packageVersion, + ConcurrentQueue errorMsgs, + ConcurrentQueue debugMsgs, + ConcurrentQueue verboseMsgs) + { + debugMsgs.Enqueue("In ContainerRegistryServerAPICalls::InstallVersion()"); + string packageNameLowercase = packageName.ToLower(); + string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + try + { + Directory.CreateDirectory(tempPath); + } + catch (Exception e) + { + errorMsgs.Enqueue(new ErrorRecord( + exception: e, + "InstallVersionTempDirCreationError", + ErrorCategory.InvalidResult, + _cmdletPassedIn)); + + return null; + } + + string containerRegistryAccessToken = GetContainerRegistryAccessToken(needCatalogAccess: false, isPushOperation: false, out ErrorRecord errRecord); + if (errRecord != null) + { + errorMsgs.Enqueue(errRecord); + return null; + } + + verboseMsgs.Enqueue($"Getting manifest for {packageNameLowercase} - {packageVersion}"); + var manifest = GetContainerRegistryRepositoryManifest(packageNameLowercase, packageVersion, containerRegistryAccessToken, out errRecord); + if (errRecord != null) + { + errorMsgs.Enqueue(errRecord); + return null; + } + string digest = GetDigestFromManifest(manifest, out errRecord); + if (errRecord != null) + { + errorMsgs.Enqueue(errRecord); + return null; + } + + verboseMsgs.Enqueue($"Downloading blob for {packageNameLowercase} - {packageVersion}"); + HttpContent responseContent; + try + { + responseContent = GetContainerRegistryBlobAsync(packageNameLowercase, digest, containerRegistryAccessToken).Result; + } + catch (Exception e) + { + errorMsgs.Enqueue(new ErrorRecord( + exception: e, + "InstallVersionGetContainerRegistryBlobAsyncError", + ErrorCategory.InvalidResult, + _cmdletPassedIn)); + + return null; + } + + return responseContent.ReadAsStreamAsync().Result; + } + #endregion #region Authentication and Token Methods From f800970c24f0e00a891ea5c04a2624c4b9caf43e Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Wed, 1 Jul 2026 10:55:24 -0700 Subject: [PATCH 04/12] Fix copilot commit for container registry --- src/code/ContainerRegistryServerAPICalls.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/code/ContainerRegistryServerAPICalls.cs b/src/code/ContainerRegistryServerAPICalls.cs index 376c3c053..cd22c1c5d 100644 --- a/src/code/ContainerRegistryServerAPICalls.cs +++ b/src/code/ContainerRegistryServerAPICalls.cs @@ -343,7 +343,6 @@ public override Stream InstallPackage(string packageName, string packageVersion, Stream results = new MemoryStream(); if (string.IsNullOrEmpty(packageVersion)) { - errRecord = new ErrorRecord( exception: new ArgumentNullException($"Package version could not be found for {packageName}"), "PackageVersionNullOrEmptyError", ErrorCategory.InvalidArgument, @@ -381,7 +380,7 @@ public override Task InstallPackageAsync(string packageName, string pack } string packageNameForInstall = PrependMARPrefix(packageName); - results = InstallVersion(packageNameForInstall, packageVersion, errorMsgs, debugMsgs, verboseMsgs); + results = InstallVersionAsync(packageNameForInstall, packageVersion, errorMsgs, debugMsgs, verboseMsgs); return Task.FromResult(results); } @@ -457,14 +456,14 @@ private Stream InstallVersion( /// Installs a package with version specified using concurrent queues for output instead of cmdlet streams. /// Used by the async install path to avoid cross-thread cmdlet stream writes. /// - private Stream InstallVersion( + private Stream InstallVersionAsync( string packageName, string packageVersion, ConcurrentQueue errorMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - debugMsgs.Enqueue("In ContainerRegistryServerAPICalls::InstallVersion()"); + debugMsgs.Enqueue("In ContainerRegistryServerAPICalls::InstallVersionAsync()"); string packageNameLowercase = packageName.ToLower(); string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); try From 6ab7367f660b33782e1ebabcbed9d06117ad322a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Jul 2026 18:01:27 +0000 Subject: [PATCH 05/12] Avoid cmdlet stream writes in NuGet FindVersionAsync path --- src/code/NuGetServerAPICalls.cs | 62 ++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/src/code/NuGetServerAPICalls.cs b/src/code/NuGetServerAPICalls.cs index cc4c68223..d8c6b5ffe 100644 --- a/src/code/NuGetServerAPICalls.cs +++ b/src/code/NuGetServerAPICalls.cs @@ -58,7 +58,18 @@ public NuGetServerAPICalls (PSRepositoryInfo repository, PSCmdlet cmdletPassedIn public override Task FindVersionAsync(string packageName, string version, ResourceType type, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { debugMsgs.Enqueue("In NuGetServerAPICalls::FindVersionAsync()"); - FindResults findResponse = FindVersion(packageName, version, type, out ErrorRecord errRecord); + var queryBuilder = new NuGetV2QueryBuilder(new Dictionary{ + { "id", $"'{packageName}'" }, + }); + var filterBuilder = queryBuilder.FilterBuilder; + + // We need to explicitly add 'Id eq ' whenever $filter is used, otherwise arbitrary results are returned. + filterBuilder.AddCriterion($"Id eq '{packageName}'"); + filterBuilder.AddCriterion($"NormalizedVersion eq '{packageName}'"); + + var requestUrl = $"{Repository.Uri}/FindPackagesById()?{queryBuilder.BuildQueryString()}"; + string response = HttpRequestCallAsync(requestUrl, debugMsgs, out ErrorRecord errRecord); + FindResults findResponse = new FindResults(stringResponse: new string[] { response }, hashtableResponse: emptyHashResponses, responseType: FindResponseType); if (errRecord != null) { errorMsgs.Enqueue(errRecord); @@ -617,6 +628,55 @@ private HttpContent HttpRequestCallForContent(string requestUrl, out ErrorRecord return content; } + /// + /// Helper method that makes the HTTP request for the NuGet server protocol url passed in for async find APIs. + /// This helper writes diagnostics to the provided debug queue and avoids cmdlet stream writes. + /// + private string HttpRequestCallAsync(string requestUrl, ConcurrentQueue debugMsgs, out ErrorRecord errRecord) + { + debugMsgs.Enqueue("In NuGetServerAPICalls::HttpRequestCallAsync()"); + errRecord = null; + string response = string.Empty; + + try + { + debugMsgs.Enqueue($"Request url is: '{requestUrl}'"); + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl); + response = SendRequestAsync(request, _sessionClient).GetAwaiter().GetResult(); + } + catch (HttpRequestException e) + { + errRecord = new ErrorRecord( + exception: e, + "HttpRequestFallFailure", + ErrorCategory.ConnectionError, + this); + } + catch (ArgumentNullException e) + { + errRecord = new ErrorRecord( + exception: e, + "HttpRequestFallFailure", + ErrorCategory.ConnectionError, + this); + } + catch (InvalidOperationException e) + { + errRecord = new ErrorRecord( + exception: e, + "HttpRequestFallFailure", + ErrorCategory.ConnectionError, + this); + } + + if (string.IsNullOrEmpty(response)) + { + debugMsgs.Enqueue("Response is empty"); + } + + return response; + } + #endregion #region Private Methods From dbd1689eec89fe96cd08651ae48da755d49f8563 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Jul 2026 18:13:00 +0000 Subject: [PATCH 06/12] Fix V3 async helper logging to use debug queues --- src/code/V3ServerAPICalls.cs | 61 +++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/src/code/V3ServerAPICalls.cs b/src/code/V3ServerAPICalls.cs index 3693646a5..9df736d7e 100644 --- a/src/code/V3ServerAPICalls.cs +++ b/src/code/V3ServerAPICalls.cs @@ -99,7 +99,7 @@ public V3ServerAPICalls(PSRepositoryInfo repository, PSCmdlet cmdletPassedIn, Ne public override Task FindVersionAsync(string packageName, string version, ResourceType type, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { debugMsgs.Enqueue("In V3ServerAPICalls::FindVersionAsync()"); - FindResults findResponse = FindVersionHelper(packageName, version, tags: Utils.EmptyStrArray, type, out ErrorRecord errRecord); + FindResults findResponse = FindVersionHelper(packageName, version, tags: Utils.EmptyStrArray, type, out ErrorRecord errRecord, debugMsgs); if (errRecord != null) { errorMsgs.Enqueue(errRecord); @@ -119,7 +119,7 @@ public override Task FindVersionAsync(string packageName, string ve public override Task FindVersionGlobbingAsync(string packageName, VersionRange versionRange, bool includePrerelease, ResourceType type, bool getOnlyLatest, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { debugMsgs.Enqueue("In V3ServerAPICalls::FindVersionGlobbingAsync()"); - FindResults findResponse = FindVersionGlobbing(packageName, versionRange, includePrerelease, type, getOnlyLatest, out ErrorRecord errRecord); + FindResults findResponse = FindVersionGlobbingHelper(packageName, versionRange, includePrerelease, type, getOnlyLatest, out ErrorRecord errRecord, debugMsgs); if (errRecord != null) { errorMsgs.Enqueue(errRecord); @@ -204,7 +204,7 @@ public override FindResults FindName(string packageName, bool includePrerelease, public override Task FindNameAsync(string packageName, bool includePrerelease, ResourceType type, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { debugMsgs.Enqueue("In V3ServerAPICalls::FindNameAsync()"); - FindResults findResponse = FindNameHelper(packageName, tags: Utils.EmptyStrArray, includePrerelease, type, out ErrorRecord errRecord); + FindResults findResponse = FindNameHelper(packageName, tags: Utils.EmptyStrArray, includePrerelease, type, out ErrorRecord errRecord, debugMsgs); if (errRecord != null) { errorMsgs.Enqueue(errRecord); @@ -281,9 +281,13 @@ public override FindResults FindNameGlobbingWithTag(string packageName, string[] /// public override FindResults FindVersionGlobbing(string packageName, VersionRange versionRange, bool includePrerelease, ResourceType type, bool getOnlyLatest, out ErrorRecord errRecord) { - // TODO: pass in ConcurrentQueue for debug messages so this is thread-safe when called from FindVersionGlobbingAsync(). - _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::FindVersionGlobbing()"); - string[] versionedResponses = GetVersionedPackageEntriesFromRegistrationsResource(packageName, catalogEntryProperty, isSearch: true, out errRecord); + return FindVersionGlobbingHelper(packageName, versionRange, includePrerelease, type, getOnlyLatest, out errRecord); + } + + private FindResults FindVersionGlobbingHelper(string packageName, VersionRange versionRange, bool includePrerelease, ResourceType type, bool getOnlyLatest, out ErrorRecord errRecord, ConcurrentQueue debugMsgs = null) + { + WriteDebug("In V3ServerAPICalls::FindVersionGlobbing()", debugMsgs); + string[] versionedResponses = GetVersionedPackageEntriesFromRegistrationsResource(packageName, catalogEntryProperty, isSearch: true, out errRecord, debugMsgs); if (errRecord != null) { return new FindResults(stringResponse: Utils.EmptyStrArray, hashtableResponse: emptyHashResponses, responseType: v3FindResponseType); @@ -310,8 +314,7 @@ public override FindResults FindVersionGlobbing(string packageName, VersionRange if (NuGetVersion.TryParse(pkgVersionElement.ToString(), out NuGetVersion pkgVersion) && versionRange.Satisfies(pkgVersion)) { - // TODO: pass in ConcurrentQueue for debug messages so this is thread-safe when called from FindVersionGlobbingAsync(). ? - _cmdletPassedIn.WriteDebug($"Package version parsed as '{pkgVersion}' satisfies the version range"); + WriteDebug($"Package version parsed as '{pkgVersion}' satisfies the version range", debugMsgs); if (!pkgVersion.IsPrerelease || includePrerelease) { satisfyingVersions.Add(response); @@ -581,11 +584,10 @@ private FindResults FindTagsFromNuGetRepo(string[] tags, bool includePrerelease, /// /// Helper method called by FindName() and FindNameWithTag() /// - private FindResults FindNameHelper(string packageName, string[] tags, bool includePrerelease, ResourceType type, out ErrorRecord errRecord) + private FindResults FindNameHelper(string packageName, string[] tags, bool includePrerelease, ResourceType type, out ErrorRecord errRecord, ConcurrentQueue debugMsgs = null) { - // TODO: pass in ConcurrentQueue for debug messages so this is thread-safe when called from FindNameAsync(). ? - _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::FindNameHelper()"); - string[] versionedResponses = GetVersionedPackageEntriesFromRegistrationsResource(packageName, catalogEntryProperty, isSearch: true, out errRecord); + WriteDebug("In V3ServerAPICalls::FindNameHelper()", debugMsgs); + string[] versionedResponses = GetVersionedPackageEntriesFromRegistrationsResource(packageName, catalogEntryProperty, isSearch: true, out errRecord, debugMsgs); if (errRecord != null) { return new FindResults(stringResponse: Utils.EmptyStrArray, hashtableResponse: emptyHashResponses, responseType: v3FindResponseType); @@ -623,8 +625,7 @@ private FindResults FindNameHelper(string packageName, string[] tags, bool inclu if (NuGetVersion.TryParse(pkgVersionElement.ToString(), out NuGetVersion pkgVersion)) { - // ? - _cmdletPassedIn.WriteDebug($"'{packageName}' version parsed as '{pkgVersion}'"); + WriteDebug($"'{packageName}' version parsed as '{pkgVersion}'", debugMsgs); if (!pkgVersion.IsPrerelease || includePrerelease) { // Versions are always in descending order i.e 5.0.0, 3.0.0, 1.0.0 so grabbing the first match suffices @@ -679,10 +680,9 @@ private FindResults FindNameHelper(string packageName, string[] tags, bool inclu /// /// Helper method called by FindVersion() and FindVersionWithTag() /// - private FindResults FindVersionHelper(string packageName, string version, string[] tags, ResourceType type, out ErrorRecord errRecord) + private FindResults FindVersionHelper(string packageName, string version, string[] tags, ResourceType type, out ErrorRecord errRecord, ConcurrentQueue debugMsgs = null) { - // TODO: pass in ConcurrentQueue for debug messages so this is thread-safe when called from FindVersionAsync(). ? - _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::FindVersionHelper()"); + WriteDebug("In V3ServerAPICalls::FindVersionHelper()", debugMsgs); if (!NuGetVersion.TryParse(version, out NuGetVersion requiredVersion)) { errRecord = new ErrorRecord( @@ -695,7 +695,7 @@ private FindResults FindVersionHelper(string packageName, string version, string } //_cmdletPassedIn.WriteDebug($"'{packageName}' version parsed as '{requiredVersion}'"); - string[] versionedResponses = GetVersionedPackageEntriesFromRegistrationsResource(packageName, catalogEntryProperty, isSearch: true, out errRecord); + string[] versionedResponses = GetVersionedPackageEntriesFromRegistrationsResource(packageName, catalogEntryProperty, isSearch: true, out errRecord, debugMsgs); if (errRecord != null) { return new FindResults(stringResponse: Utils.EmptyStrArray, hashtableResponse: emptyHashResponses, responseType: v3FindResponseType); @@ -989,7 +989,7 @@ private async Task InstallHelperAsync(string packageName, NuGetVersion v /// i.e when the package Name being searched for does not contain wildcard /// This is called by FindNameHelper(), FindVersionHelper(), FindVersionGlobbing(), InstallHelper() /// - private string[] GetVersionedPackageEntriesFromRegistrationsResource(string packageName, string propertyName, bool isSearch, out ErrorRecord errRecord) + private string[] GetVersionedPackageEntriesFromRegistrationsResource(string packageName, string propertyName, bool isSearch, out ErrorRecord errRecord, ConcurrentQueue debugMsgs = null) { // TODO: pass in ConcurrentQueue to write out debug message. //_cmdletPassedIn.WriteDebug("In V3ServerAPICalls::GetVersionedPackageEntriesFromRegistrationsResource()"); @@ -1006,7 +1006,7 @@ private string[] GetVersionedPackageEntriesFromRegistrationsResource(string pack return responses; } - responses = GetVersionedResponsesFromRegistrationsResource(registrationsBaseUrl, packageName, propertyName, isSearch, out errRecord); + responses = GetVersionedResponsesFromRegistrationsResource(registrationsBaseUrl, packageName, propertyName, isSearch, out errRecord, debugMsgs); if (errRecord != null) { return Utils.EmptyStrArray; @@ -1452,7 +1452,7 @@ private string[] GetMetadataElementsFromResponse(string response, string propert /// The "packageContent" property is used for download, and the value is a URI for the .nupkg file. /// /// - private string[] GetVersionedResponsesFromRegistrationsResource(string registrationsBaseUrl, string packageName, string property, bool isSearch, out ErrorRecord errRecord) + private string[] GetVersionedResponsesFromRegistrationsResource(string registrationsBaseUrl, string packageName, string property, bool isSearch, out ErrorRecord errRecord, ConcurrentQueue debugMsgs = null) { // TODO: pass in ConcurrentQueue to write out debug message. //_cmdletPassedIn.WriteDebug("In V3ServerAPICalls::GetVersionedResponsesFromRegistrationsResource()"); @@ -1490,7 +1490,7 @@ private string[] GetVersionedResponsesFromRegistrationsResource(string registrat if (isSearch) { - if (!IsLatestVersionFirstForSearch(versionedResponseArr, out errRecord)) + if (!IsLatestVersionFirstForSearch(versionedResponseArr, out errRecord, debugMsgs)) { Array.Reverse(versionedResponseArr); } @@ -1511,10 +1511,9 @@ private string[] GetVersionedResponsesFromRegistrationsResource(string registrat /// ADO feeds usually return version entries in descending order, but Nuget.org repository returns them in ascending order. /// Package versions will reflect prerelease preference, but upper version and lower version would not so we don't use them for comparison. /// - private bool IsLatestVersionFirstForSearch(string[] versionedResponses, out ErrorRecord errRecord) + private bool IsLatestVersionFirstForSearch(string[] versionedResponses, out ErrorRecord errRecord, ConcurrentQueue debugMsgs = null) { - // TODO: pass in ConcurrentQueue for debug messages so this is thread-safe when reached from the async find methods. ? - _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::IsLatestVersionFirstForSearch()"); + WriteDebug("In V3ServerAPICalls::IsLatestVersionFirstForSearch()", debugMsgs); errRecord = null; bool latestVersionFirst = true; int versionResponsesCount = versionedResponses.Length; @@ -1606,6 +1605,18 @@ private bool IsLatestVersionFirstForSearch(string[] versionedResponses, out Erro return latestVersionFirst; } + private void WriteDebug(string message, ConcurrentQueue debugMsgs = null) + { + if (debugMsgs == null) + { + _cmdletPassedIn.WriteDebug(message); + } + else + { + debugMsgs.Enqueue(message); + } + } + /// /// Returns true if the nupkg URI entries for each package version are arranged in descending order with respect to the package's version. /// ADO feeds usually return version entries in descending order, but Nuget.org repository returns them in ascending order. From efb000d090039941dc343a493aabf685af192922 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Wed, 1 Jul 2026 11:24:52 -0700 Subject: [PATCH 07/12] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/code/FindHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs index 693c00aca..0410af585 100644 --- a/src/code/FindHelper.cs +++ b/src/code/FindHelper.cs @@ -1419,7 +1419,7 @@ private PSResourceInfo FindDependencyWithUpperBound( ConcurrentDictionary> cachedNetworkCalls = new ConcurrentDictionary>(); debugMsgs.Enqueue("In FindHelper::FindDependencyWithUpperBound()"); - // See if the network call we're making is already caced, if not, call FindNameAsync() and cache results + // See if the network call we're making is already cached, if not, call FindNameAsync() and cache results string key = $"{dep.Name}|{dep.VersionRange.MaxVersion.ToString()}|{_type}"; debugMsgs.Enqueue("Checking if network call is cached."); response = cachedNetworkCalls.GetOrAdd(key, _ => currentServer.FindVersionGlobbingAsync(dep.Name, dep.VersionRange, includePrerelease: true, ResourceType.None, getOnlyLatest: true, errorMsgs, warningMsgs, debugMsgs, verboseMsgs)); From 0e9c684f2d7d46ce3bfc9f754e791a6b1ae6221a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Jul 2026 18:28:13 +0000 Subject: [PATCH 08/12] Fix specific-version async dependency error handling path --- src/code/FindHelper.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs index 0410af585..f46b843b6 100644 --- a/src/code/FindHelper.cs +++ b/src/code/FindHelper.cs @@ -1282,12 +1282,10 @@ private PSResourceInfo FindDependencyWithSpecificVersion( debugMsgs.Enqueue("In FindHelper::FindDependencyWithSpecificVersion()"); - // See if the network call we're making is already cached, if not, call FindNameAsync() and cache results + // Call FindVersionAsync() for dependency with specific version. string key = $"{dep.Name}|{dep.VersionRange.MaxVersion.ToString()}|{_type}"; - debugMsgs.Enqueue("Checking if network call is cached."); - response = _cachedNetworkCalls.GetOrAdd(key, _ => currentServer.FindVersionAsync(dep.Name, dep.VersionRange.MaxVersion.ToString(), _type, errorMsgs, warningMsgs, debugMsgs, verboseMsgs)); - - responses = response.GetAwaiter().GetResult(); + responses = currentServer.FindVersionAsync(dep.Name, dep.VersionRange.MaxVersion.ToString(), _type, errorMsgs, warningMsgs, debugMsgs, verboseMsgs).GetAwaiter().GetResult(); + errorMsgs.TryPeek(out errRecord); // Error handling and Convert to PSResource object if (errRecord != null) From e3c1af50c786662e0a7ef62c3860a4edf9f35c90 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Jul 2026 18:32:20 +0000 Subject: [PATCH 09/12] Scope async dependency queue handling to current operation --- src/code/FindHelper.cs | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs index f46b843b6..0e4c53865 100644 --- a/src/code/FindHelper.cs +++ b/src/code/FindHelper.cs @@ -1278,14 +1278,41 @@ private PSResourceInfo FindDependencyWithSpecificVersion( PSResourceInfo depPkg = null; ErrorRecord errRecord = null; FindResults responses = null; - Task response = null; debugMsgs.Enqueue("In FindHelper::FindDependencyWithSpecificVersion()"); - + ConcurrentQueue operationErrorMsgs = new ConcurrentQueue(); + ConcurrentQueue operationWarningMsgs = new ConcurrentQueue(); + ConcurrentQueue operationDebugMsgs = new ConcurrentQueue(); + ConcurrentQueue operationVerboseMsgs = new ConcurrentQueue(); + // Call FindVersionAsync() for dependency with specific version. string key = $"{dep.Name}|{dep.VersionRange.MaxVersion.ToString()}|{_type}"; - responses = currentServer.FindVersionAsync(dep.Name, dep.VersionRange.MaxVersion.ToString(), _type, errorMsgs, warningMsgs, debugMsgs, verboseMsgs).GetAwaiter().GetResult(); - errorMsgs.TryPeek(out errRecord); + responses = currentServer.FindVersionAsync(dep.Name, dep.VersionRange.MaxVersion.ToString(), _type, operationErrorMsgs, operationWarningMsgs, operationDebugMsgs, operationVerboseMsgs).GetAwaiter().GetResult(); + + while (operationErrorMsgs.TryDequeue(out ErrorRecord queuedError)) + { + if (errRecord == null) + { + errRecord = queuedError; + } + + errorMsgs.Enqueue(queuedError); + } + + while (operationWarningMsgs.TryDequeue(out string queuedWarning)) + { + warningMsgs.Enqueue(queuedWarning); + } + + while (operationDebugMsgs.TryDequeue(out string queuedDebug)) + { + debugMsgs.Enqueue(queuedDebug); + } + + while (operationVerboseMsgs.TryDequeue(out string queuedVerbose)) + { + verboseMsgs.Enqueue(queuedVerbose); + } // Error handling and Convert to PSResource object if (errRecord != null) From 9b92e77a6ec610b222e488f3946a3a6b7ec3a574 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Jul 2026 18:38:00 +0000 Subject: [PATCH 10/12] Fix version-range async path: reset errRecord and flush concurrent queues --- src/code/FindHelper.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs index 0e4c53865..3d149ab02 100644 --- a/src/code/FindHelper.cs +++ b/src/code/FindHelper.cs @@ -984,6 +984,7 @@ private IEnumerable SearchByNames(ServerApiCall currentServer, R // Example: Find-PSResource -Name "Az" -Version "[1.0.0.0, 3.0.0.0]" _cmdletPassedIn.WriteDebug("Version range and package name are specified"); + errRecord = null; FindResults responses = null; if (_tag.Length == 0) { @@ -993,6 +994,8 @@ private IEnumerable SearchByNames(ServerApiCall currentServer, R response = cachedNetworkCalls.GetOrAdd(key, _ => currentServer.FindVersionGlobbingAsync(pkgName, _versionRange, _prerelease, _type, getOnlyLatest: false, errorMsgs, warningMsgs, debugMsgs, verboseMsgs)); responses = response.GetAwaiter().GetResult(); + + Utils.WriteOutConcurrentQueue(_cmdletPassedIn, errorMsgs, warningMsgs, debugMsgs, verboseMsgs); } else { From 900db222e7dba80c8ed6e6383f4dab11de9d6f24 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Wed, 1 Jul 2026 13:31:22 -0700 Subject: [PATCH 11/12] build fixes --- src/code/ContainerRegistryServerAPICalls.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/code/ContainerRegistryServerAPICalls.cs b/src/code/ContainerRegistryServerAPICalls.cs index cd22c1c5d..cd8c4c8be 100644 --- a/src/code/ContainerRegistryServerAPICalls.cs +++ b/src/code/ContainerRegistryServerAPICalls.cs @@ -343,6 +343,7 @@ public override Stream InstallPackage(string packageName, string packageVersion, Stream results = new MemoryStream(); if (string.IsNullOrEmpty(packageVersion)) { + errRecord = new ErrorRecord( exception: new ArgumentNullException($"Package version could not be found for {packageName}"), "PackageVersionNullOrEmptyError", ErrorCategory.InvalidArgument, From 4cdbea84189a71965fb1c8b293ef78e3fcbda55c Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Mon, 20 Jul 2026 21:05:45 -0700 Subject: [PATCH 12/12] Incorporate code review changes - complete TODOs and remove unneeded key creation --- src/code/FindHelper.cs | 3 +- src/code/V2ServerAPICalls.cs | 10 +- src/code/V3ServerAPICalls.cs | 263 +++++++++++++++++++---------------- 3 files changed, 147 insertions(+), 129 deletions(-) diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs index 3d149ab02..06a0e9df0 100644 --- a/src/code/FindHelper.cs +++ b/src/code/FindHelper.cs @@ -1289,7 +1289,6 @@ private PSResourceInfo FindDependencyWithSpecificVersion( ConcurrentQueue operationVerboseMsgs = new ConcurrentQueue(); // Call FindVersionAsync() for dependency with specific version. - string key = $"{dep.Name}|{dep.VersionRange.MaxVersion.ToString()}|{_type}"; responses = currentServer.FindVersionAsync(dep.Name, dep.VersionRange.MaxVersion.ToString(), _type, operationErrorMsgs, operationWarningMsgs, operationDebugMsgs, operationVerboseMsgs).GetAwaiter().GetResult(); while (operationErrorMsgs.TryDequeue(out ErrorRecord queuedError)) @@ -1344,7 +1343,7 @@ private PSResourceInfo FindDependencyWithSpecificVersion( string pkgVersion = FormatPkgVersionString(depPkg); debugMsgs.Enqueue($"Found dependency '{depPkg.Name}' version '{pkgVersion}'"); - key = $"{depPkg.Name}{pkgVersion}"; + string key = $"{depPkg.Name}{pkgVersion}"; if (!depPkgsFound.ContainsKey(key)) { // Add pkg to collection of packages found then find dependencies diff --git a/src/code/V2ServerAPICalls.cs b/src/code/V2ServerAPICalls.cs index 6f2c5c3e1..963ed5ed7 100644 --- a/src/code/V2ServerAPICalls.cs +++ b/src/code/V2ServerAPICalls.cs @@ -1074,7 +1074,6 @@ private string HttpRequestCall(string requestUrlV2, out ErrorRecord errRecord) /// private async Task HttpRequestCallAsync(string requestUrlV2, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - // TODO: Async methods cannot have out ref, so currently handling errorRecords as thrown exceptions. debugMsgs.Enqueue("In V2ServerAPICalls::HttpRequestCallAsync()"); string response = string.Empty; @@ -1131,7 +1130,6 @@ private async Task HttpRequestCallAsync(string requestUrlV2, ConcurrentQ /// private async Task HttpRequestCallForContentAsync(string requestUrlV2, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - // TODO: Async methods cannot have out ref, so need to handle errorRecords a different way. debugMsgs.Enqueue("In V2ServerAPICalls::HttpRequestCallForContentAsync()"); HttpContent content = null; @@ -1744,13 +1742,7 @@ public override async Task FindVersionGlobbingAsync(string packageN debugMsgs.Enqueue($"Count is '{count}'"); // skip 100 skip += 100; - // TODO: this should be an async method - var tmpResponse = FindVersionGlobbing(packageName, versionRange, includePrerelease, type, skip, getOnlyLatest, out ErrorRecord errRecord); - if (errRecord != null) - { - Utils.EnqueueIfNotNull(errorMsgs, errRecord); - return new FindResults(stringResponse: Utils.EmptyStrArray, hashtableResponse: emptyHashResponses, responseType: v2FindResponseType); - } + var tmpResponse = await FindVersionGlobbingAsync(packageName, versionRange, includePrerelease, type, skip, getOnlyLatest, errorMsgs, warningMsgs, debugMsgs, verboseMsgs); responses.Add(tmpResponse); count--; } diff --git a/src/code/V3ServerAPICalls.cs b/src/code/V3ServerAPICalls.cs index 9df736d7e..234fc513a 100644 --- a/src/code/V3ServerAPICalls.cs +++ b/src/code/V3ServerAPICalls.cs @@ -99,7 +99,7 @@ public V3ServerAPICalls(PSRepositoryInfo repository, PSCmdlet cmdletPassedIn, Ne public override Task FindVersionAsync(string packageName, string version, ResourceType type, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { debugMsgs.Enqueue("In V3ServerAPICalls::FindVersionAsync()"); - FindResults findResponse = FindVersionHelper(packageName, version, tags: Utils.EmptyStrArray, type, out ErrorRecord errRecord, debugMsgs); + FindResults findResponse = FindVersionHelper(packageName, version, tags: Utils.EmptyStrArray, type, out ErrorRecord errRecord, errorMsgs, debugMsgs, verboseMsgs); if (errRecord != null) { errorMsgs.Enqueue(errRecord); @@ -119,7 +119,7 @@ public override Task FindVersionAsync(string packageName, string ve public override Task FindVersionGlobbingAsync(string packageName, VersionRange versionRange, bool includePrerelease, ResourceType type, bool getOnlyLatest, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { debugMsgs.Enqueue("In V3ServerAPICalls::FindVersionGlobbingAsync()"); - FindResults findResponse = FindVersionGlobbingHelper(packageName, versionRange, includePrerelease, type, getOnlyLatest, out ErrorRecord errRecord, debugMsgs); + FindResults findResponse = FindVersionGlobbingHelper(packageName, versionRange, includePrerelease, type, getOnlyLatest, out ErrorRecord errRecord, errorMsgs, debugMsgs, verboseMsgs); if (errRecord != null) { errorMsgs.Enqueue(errRecord); @@ -151,9 +151,15 @@ public override FindResults FindAll(bool includePrerelease, ResourceType type, o public override FindResults FindTags(string[] tags, bool includePrerelease, ResourceType type, out ErrorRecord errRecord) { _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::FindTags()"); + ConcurrentQueue errorMsgs = new ConcurrentQueue(); + ConcurrentQueue warningMsgs = new ConcurrentQueue(); + ConcurrentQueue debugMsgs = new ConcurrentQueue(); + ConcurrentQueue verboseMsgs = new ConcurrentQueue(); if (_isNuGetRepo || _isJFrogRepo) { - return FindTagsFromNuGetRepo(tags, includePrerelease, out errRecord); + FindResults findResults = FindTagsFromNuGetRepo(tags, includePrerelease, out errRecord, errorMsgs, debugMsgs, verboseMsgs); + Utils.WriteOutConcurrentQueue(_cmdletPassedIn, errorMsgs, warningMsgs, debugMsgs, verboseMsgs); + return findResults; } else { @@ -163,6 +169,7 @@ public override FindResults FindTags(string[] tags, bool includePrerelease, Reso ErrorCategory.InvalidOperation, this); + Utils.WriteOutConcurrentQueue(_cmdletPassedIn, errorMsgs, warningMsgs, debugMsgs, verboseMsgs); return new FindResults(stringResponse: Utils.EmptyStrArray, hashtableResponse: emptyHashResponses, responseType: v3FindResponseType); } } @@ -192,7 +199,13 @@ public override FindResults FindCommandOrDscResource(string[] tags, bool include public override FindResults FindName(string packageName, bool includePrerelease, ResourceType type, out ErrorRecord errRecord) { _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::FindName()"); - return FindNameHelper(packageName, tags: Utils.EmptyStrArray, includePrerelease, type, out errRecord); + ConcurrentQueue errorMsgs = new ConcurrentQueue(); + ConcurrentQueue warningMsgs = new ConcurrentQueue(); + ConcurrentQueue debugMsgs = new ConcurrentQueue(); + ConcurrentQueue verboseMsgs = new ConcurrentQueue(); + FindResults findResults = FindNameHelper(packageName, tags: Utils.EmptyStrArray, includePrerelease, type, out errRecord, errorMsgs, debugMsgs, verboseMsgs); + Utils.WriteOutConcurrentQueue(_cmdletPassedIn, errorMsgs, warningMsgs, debugMsgs, verboseMsgs); + return findResults; } /// @@ -204,7 +217,7 @@ public override FindResults FindName(string packageName, bool includePrerelease, public override Task FindNameAsync(string packageName, bool includePrerelease, ResourceType type, ConcurrentQueue errorMsgs, ConcurrentQueue warningMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { debugMsgs.Enqueue("In V3ServerAPICalls::FindNameAsync()"); - FindResults findResponse = FindNameHelper(packageName, tags: Utils.EmptyStrArray, includePrerelease, type, out ErrorRecord errRecord, debugMsgs); + FindResults findResponse = FindNameHelper(packageName, tags: Utils.EmptyStrArray, includePrerelease, type, out ErrorRecord errRecord, errorMsgs, debugMsgs, verboseMsgs); if (errRecord != null) { errorMsgs.Enqueue(errRecord); @@ -222,7 +235,13 @@ public override Task FindNameAsync(string packageName, bool include public override FindResults FindNameWithTag(string packageName, string[] tags, bool includePrerelease, ResourceType type, out ErrorRecord errRecord) { _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::FindNameWithTag()"); - return FindNameHelper(packageName, tags, includePrerelease, type, out errRecord); + ConcurrentQueue errorMsgs = new ConcurrentQueue(); + ConcurrentQueue warningMsgs = new ConcurrentQueue(); + ConcurrentQueue debugMsgs = new ConcurrentQueue(); + ConcurrentQueue verboseMsgs = new ConcurrentQueue(); + FindResults findResults = FindNameHelper(packageName, tags, includePrerelease, type, out errRecord, errorMsgs, debugMsgs, verboseMsgs); + Utils.WriteOutConcurrentQueue(_cmdletPassedIn, errorMsgs, warningMsgs, debugMsgs, verboseMsgs); + return findResults; } /// @@ -232,9 +251,15 @@ public override FindResults FindNameWithTag(string packageName, string[] tags, b public override FindResults FindNameGlobbing(string packageName, bool includePrerelease, ResourceType type, out ErrorRecord errRecord) { _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::FindNameGlobbing()"); + ConcurrentQueue errorMsgs = new ConcurrentQueue(); + ConcurrentQueue warningMsgs = new ConcurrentQueue(); + ConcurrentQueue debugMsgs = new ConcurrentQueue(); + ConcurrentQueue verboseMsgs = new ConcurrentQueue(); if (_isNuGetRepo || _isJFrogRepo || _isGHPkgsRepo || _isMyGetRepo) { - return FindNameGlobbingFromNuGetRepo(packageName, tags: Utils.EmptyStrArray, includePrerelease, out errRecord); + FindResults findResults = FindNameGlobbingFromNuGetRepo(packageName, tags: Utils.EmptyStrArray, includePrerelease, out errRecord, errorMsgs, debugMsgs, verboseMsgs); + Utils.WriteOutConcurrentQueue(_cmdletPassedIn, errorMsgs, warningMsgs, debugMsgs, verboseMsgs); + return findResults; } else { @@ -244,6 +269,7 @@ public override FindResults FindNameGlobbing(string packageName, bool includePre ErrorCategory.InvalidOperation, this); + Utils.WriteOutConcurrentQueue(_cmdletPassedIn, errorMsgs, warningMsgs, debugMsgs, verboseMsgs); return new FindResults(stringResponse: Utils.EmptyStrArray, hashtableResponse: emptyHashResponses, responseType: v3FindResponseType); } } @@ -255,9 +281,15 @@ public override FindResults FindNameGlobbing(string packageName, bool includePre public override FindResults FindNameGlobbingWithTag(string packageName, string[] tags, bool includePrerelease, ResourceType type, out ErrorRecord errRecord) { _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::FindNameGlobbingWithTag()"); + ConcurrentQueue errorMsgs = new ConcurrentQueue(); + ConcurrentQueue warningMsgs = new ConcurrentQueue(); + ConcurrentQueue debugMsgs = new ConcurrentQueue(); + ConcurrentQueue verboseMsgs = new ConcurrentQueue(); if (_isNuGetRepo || _isJFrogRepo || _isGHPkgsRepo || _isMyGetRepo) { - return FindNameGlobbingFromNuGetRepo(packageName, tags, includePrerelease, out errRecord); + FindResults findResults = FindNameGlobbingFromNuGetRepo(packageName, tags, includePrerelease, out errRecord, errorMsgs, debugMsgs, verboseMsgs); + Utils.WriteOutConcurrentQueue(_cmdletPassedIn, errorMsgs, warningMsgs, debugMsgs, verboseMsgs); + return findResults; } else { @@ -267,6 +299,7 @@ public override FindResults FindNameGlobbingWithTag(string packageName, string[] ErrorCategory.InvalidOperation, this); + Utils.WriteOutConcurrentQueue(_cmdletPassedIn, errorMsgs, warningMsgs, debugMsgs, verboseMsgs); return new FindResults(stringResponse: Utils.EmptyStrArray, hashtableResponse: emptyHashResponses, responseType: v3FindResponseType); } } @@ -281,13 +314,19 @@ public override FindResults FindNameGlobbingWithTag(string packageName, string[] /// public override FindResults FindVersionGlobbing(string packageName, VersionRange versionRange, bool includePrerelease, ResourceType type, bool getOnlyLatest, out ErrorRecord errRecord) { - return FindVersionGlobbingHelper(packageName, versionRange, includePrerelease, type, getOnlyLatest, out errRecord); + ConcurrentQueue errorMsgs = new ConcurrentQueue(); + ConcurrentQueue warningMsgs = new ConcurrentQueue(); + ConcurrentQueue debugMsgs = new ConcurrentQueue(); + ConcurrentQueue verboseMsgs = new ConcurrentQueue(); + FindResults findResults = FindVersionGlobbingHelper(packageName, versionRange, includePrerelease, type, getOnlyLatest, out errRecord, errorMsgs, debugMsgs, verboseMsgs); + Utils.WriteOutConcurrentQueue(_cmdletPassedIn, errorMsgs, warningMsgs, debugMsgs, verboseMsgs); + return findResults; } - private FindResults FindVersionGlobbingHelper(string packageName, VersionRange versionRange, bool includePrerelease, ResourceType type, bool getOnlyLatest, out ErrorRecord errRecord, ConcurrentQueue debugMsgs = null) + private FindResults FindVersionGlobbingHelper(string packageName, VersionRange versionRange, bool includePrerelease, ResourceType type, bool getOnlyLatest, out ErrorRecord errRecord, ConcurrentQueue errorMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - WriteDebug("In V3ServerAPICalls::FindVersionGlobbing()", debugMsgs); - string[] versionedResponses = GetVersionedPackageEntriesFromRegistrationsResource(packageName, catalogEntryProperty, isSearch: true, out errRecord, debugMsgs); + debugMsgs.Enqueue("In V3ServerAPICalls::FindVersionGlobbing()"); + string[] versionedResponses = GetVersionedPackageEntriesFromRegistrationsResource(packageName, catalogEntryProperty, isSearch: true, out errRecord, errorMsgs, debugMsgs, verboseMsgs); if (errRecord != null) { return new FindResults(stringResponse: Utils.EmptyStrArray, hashtableResponse: emptyHashResponses, responseType: v3FindResponseType); @@ -314,7 +353,7 @@ private FindResults FindVersionGlobbingHelper(string packageName, VersionRange v if (NuGetVersion.TryParse(pkgVersionElement.ToString(), out NuGetVersion pkgVersion) && versionRange.Satisfies(pkgVersion)) { - WriteDebug($"Package version parsed as '{pkgVersion}' satisfies the version range", debugMsgs); + debugMsgs.Enqueue($"Package version parsed as '{pkgVersion}' satisfies the version range"); if (!pkgVersion.IsPrerelease || includePrerelease) { satisfyingVersions.Add(response); @@ -347,7 +386,13 @@ private FindResults FindVersionGlobbingHelper(string packageName, VersionRange v public override FindResults FindVersion(string packageName, string version, ResourceType type, out ErrorRecord errRecord) { _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::FindVersion()"); - return FindVersionHelper(packageName, version, tags: Utils.EmptyStrArray, type, out errRecord); + ConcurrentQueue errorMsgs = new ConcurrentQueue(); + ConcurrentQueue warningMsgs = new ConcurrentQueue(); + ConcurrentQueue debugMsgs = new ConcurrentQueue(); + ConcurrentQueue verboseMsgs = new ConcurrentQueue(); + FindResults findResults = FindVersionHelper(packageName, version, tags: Utils.EmptyStrArray, type, out errRecord, errorMsgs, debugMsgs, verboseMsgs); + Utils.WriteOutConcurrentQueue(_cmdletPassedIn, errorMsgs, warningMsgs, debugMsgs, verboseMsgs); + return findResults; } /// @@ -360,7 +405,13 @@ public override FindResults FindVersion(string packageName, string version, Reso public override FindResults FindVersionWithTag(string packageName, string version, string[] tags, ResourceType type, out ErrorRecord errRecord) { _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::FindVersionWithTag()"); - return FindVersionHelper(packageName, version, tags: tags, type, out errRecord); + ConcurrentQueue errorMsgs = new ConcurrentQueue(); + ConcurrentQueue warningMsgs = new ConcurrentQueue(); + ConcurrentQueue debugMsgs = new ConcurrentQueue(); + ConcurrentQueue verboseMsgs = new ConcurrentQueue(); + FindResults findResults = FindVersionHelper(packageName, version, tags: tags, type, out errRecord, errorMsgs, debugMsgs, verboseMsgs); + Utils.WriteOutConcurrentQueue(_cmdletPassedIn, errorMsgs, warningMsgs, debugMsgs, verboseMsgs); + return findResults; } /** INSTALL APIS **/ @@ -375,8 +426,11 @@ public override FindResults FindVersionWithTag(string packageName, string versio /// public override Stream InstallPackage(string packageName, string packageVersion, bool includePrerelease, out ErrorRecord errRecord) { - // TODO: pass in ConcurrentQueue to write out debug message. - //_cmdletPassedIn.WriteDebug("In V3ServerAPICalls::InstallPackage()"); + ConcurrentQueue errorMsgs = new ConcurrentQueue(); + ConcurrentQueue warningMsgs = new ConcurrentQueue(); + ConcurrentQueue debugMsgs = new ConcurrentQueue(); + ConcurrentQueue verboseMsgs = new ConcurrentQueue(); + debugMsgs.Enqueue("In V3ServerAPICalls::InstallPackage()"); Stream results = new MemoryStream(); if (string.IsNullOrEmpty(packageVersion)) { @@ -386,10 +440,13 @@ public override Stream InstallPackage(string packageName, string packageVersion, ErrorCategory.InvalidArgument, _cmdletPassedIn); + Utils.WriteOutConcurrentQueue(_cmdletPassedIn, errorMsgs, warningMsgs, debugMsgs, verboseMsgs); return results; } - return InstallVersion(packageName, packageVersion, out errRecord); + Stream installResults = InstallVersion(packageName, packageVersion, out errRecord, errorMsgs, debugMsgs, verboseMsgs); + Utils.WriteOutConcurrentQueue(_cmdletPassedIn, errorMsgs, warningMsgs, debugMsgs, verboseMsgs); + return installResults; } /// @@ -437,9 +494,9 @@ public override async Task InstallPackageAsync(string packageName, strin /// /// Helper method called by FindNameGlobbing() and FindNameGlobbingWithTag() for special case where repository is NuGet.org repository. /// - private FindResults FindNameGlobbingFromNuGetRepo(string packageName, string[] tags, bool includePrerelease, out ErrorRecord errRecord) + private FindResults FindNameGlobbingFromNuGetRepo(string packageName, string[] tags, bool includePrerelease, out ErrorRecord errRecord, ConcurrentQueue errorMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::FindNameGlobbingFromNuGetRepo()"); + debugMsgs.Enqueue("In V3ServerAPICalls::FindNameGlobbingFromNuGetRepo()"); var names = packageName.Split(new char[] { '*' }, StringSplitOptions.RemoveEmptyEntries); string querySearchTerm; @@ -475,7 +532,7 @@ private FindResults FindNameGlobbingFromNuGetRepo(string packageName, string[] t return new FindResults(stringResponse: Utils.EmptyStrArray, hashtableResponse: emptyHashResponses, responseType: v3FindResponseType); } - var matchingPkgEntries = GetVersionedPackageEntriesFromSearchQueryResource(querySearchTerm, includePrerelease, out errRecord); + var matchingPkgEntries = GetVersionedPackageEntriesFromSearchQueryResource(querySearchTerm, includePrerelease, out errRecord, errorMsgs, debugMsgs, verboseMsgs); if (errRecord != null) { return new FindResults(stringResponse: Utils.EmptyStrArray, hashtableResponse: emptyHashResponses, responseType: v3FindResponseType); @@ -549,13 +606,13 @@ private FindResults FindNameGlobbingFromNuGetRepo(string packageName, string[] t /// /// Helper method called by FindTags() for special case where repository is NuGet.org repository. /// - private FindResults FindTagsFromNuGetRepo(string[] tags, bool includePrerelease, out ErrorRecord errRecord) + private FindResults FindTagsFromNuGetRepo(string[] tags, bool includePrerelease, out ErrorRecord errRecord, ConcurrentQueue errorMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::FindTagsFromNuGetRepo()"); + debugMsgs.Enqueue("In V3ServerAPICalls::FindTagsFromNuGetRepo()"); string tagsQueryTerm = $"tags:{String.Join(" ", tags)}"; // Get responses for all packages that contain the required tags // example query: - var tagPkgEntries = GetVersionedPackageEntriesFromSearchQueryResource(tagsQueryTerm, includePrerelease, out errRecord); + var tagPkgEntries = GetVersionedPackageEntriesFromSearchQueryResource(tagsQueryTerm, includePrerelease, out errRecord, errorMsgs, debugMsgs, verboseMsgs); if (errRecord != null) { return new FindResults(stringResponse: Utils.EmptyStrArray, hashtableResponse: emptyHashResponses, responseType: v3FindResponseType); @@ -584,10 +641,10 @@ private FindResults FindTagsFromNuGetRepo(string[] tags, bool includePrerelease, /// /// Helper method called by FindName() and FindNameWithTag() /// - private FindResults FindNameHelper(string packageName, string[] tags, bool includePrerelease, ResourceType type, out ErrorRecord errRecord, ConcurrentQueue debugMsgs = null) + private FindResults FindNameHelper(string packageName, string[] tags, bool includePrerelease, ResourceType type, out ErrorRecord errRecord, ConcurrentQueue errorMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - WriteDebug("In V3ServerAPICalls::FindNameHelper()", debugMsgs); - string[] versionedResponses = GetVersionedPackageEntriesFromRegistrationsResource(packageName, catalogEntryProperty, isSearch: true, out errRecord, debugMsgs); + debugMsgs.Enqueue("In V3ServerAPICalls::FindNameHelper()"); + string[] versionedResponses = GetVersionedPackageEntriesFromRegistrationsResource(packageName, catalogEntryProperty, isSearch: true, out errRecord, errorMsgs, debugMsgs, verboseMsgs); if (errRecord != null) { return new FindResults(stringResponse: Utils.EmptyStrArray, hashtableResponse: emptyHashResponses, responseType: v3FindResponseType); @@ -625,7 +682,7 @@ private FindResults FindNameHelper(string packageName, string[] tags, bool inclu if (NuGetVersion.TryParse(pkgVersionElement.ToString(), out NuGetVersion pkgVersion)) { - WriteDebug($"'{packageName}' version parsed as '{pkgVersion}'", debugMsgs); + debugMsgs.Enqueue($"'{packageName}' version parsed as '{pkgVersion}'"); if (!pkgVersion.IsPrerelease || includePrerelease) { // Versions are always in descending order i.e 5.0.0, 3.0.0, 1.0.0 so grabbing the first match suffices @@ -680,9 +737,9 @@ private FindResults FindNameHelper(string packageName, string[] tags, bool inclu /// /// Helper method called by FindVersion() and FindVersionWithTag() /// - private FindResults FindVersionHelper(string packageName, string version, string[] tags, ResourceType type, out ErrorRecord errRecord, ConcurrentQueue debugMsgs = null) + private FindResults FindVersionHelper(string packageName, string version, string[] tags, ResourceType type, out ErrorRecord errRecord, ConcurrentQueue errorMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - WriteDebug("In V3ServerAPICalls::FindVersionHelper()", debugMsgs); + debugMsgs.Enqueue("In V3ServerAPICalls::FindVersionHelper()"); if (!NuGetVersion.TryParse(version, out NuGetVersion requiredVersion)) { errRecord = new ErrorRecord( @@ -695,7 +752,7 @@ private FindResults FindVersionHelper(string packageName, string version, string } //_cmdletPassedIn.WriteDebug($"'{packageName}' version parsed as '{requiredVersion}'"); - string[] versionedResponses = GetVersionedPackageEntriesFromRegistrationsResource(packageName, catalogEntryProperty, isSearch: true, out errRecord, debugMsgs); + string[] versionedResponses = GetVersionedPackageEntriesFromRegistrationsResource(packageName, catalogEntryProperty, isSearch: true, out errRecord, errorMsgs, debugMsgs, verboseMsgs); if (errRecord != null) { return new FindResults(stringResponse: Utils.EmptyStrArray, hashtableResponse: emptyHashResponses, responseType: v3FindResponseType); @@ -788,10 +845,10 @@ private FindResults FindVersionHelper(string packageName, string version, string /// Name: no wildcard support. /// Examples: Install "Newtonsoft.json" /// - private Stream InstallName(string packageName, out ErrorRecord errRecord) + private Stream InstallName(string packageName, out ErrorRecord errRecord, ConcurrentQueue errorMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::InstallName()"); - return InstallHelper(packageName, version: null, out errRecord); + debugMsgs.Enqueue("In V3ServerAPICalls::InstallName()"); + return InstallHelper(packageName, version: null, out errRecord, errorMsgs, debugMsgs, verboseMsgs); } /// @@ -801,10 +858,9 @@ private Stream InstallName(string packageName, out ErrorRecord errRecord) /// Examples: Install "Newtonsoft.json" -Version "1.0.0.0" /// Install "Newtonsoft.json" -Version "2.5.0-beta" /// - private Stream InstallVersion(string packageName, string version, out ErrorRecord errRecord) + private Stream InstallVersion(string packageName, string version, out ErrorRecord errRecord, ConcurrentQueue errorMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - // TODO: pass in ConcurrentQueue to write out debug message. - _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::InstallVersion()"); + debugMsgs.Enqueue("In V3ServerAPICalls::InstallVersion()"); if (!NuGetVersion.TryParse(version, out NuGetVersion requiredVersion)) { errRecord = new ErrorRecord( @@ -816,17 +872,16 @@ private Stream InstallVersion(string packageName, string version, out ErrorRecor return null; } - return InstallHelper(packageName, requiredVersion, out errRecord); + return InstallHelper(packageName, requiredVersion, out errRecord, errorMsgs, debugMsgs, verboseMsgs); } /// /// Helper method that is called by InstallName() and InstallVersion() /// For InstallName() we want latest version installed (so version parameter passed in will be null), for InstallVersion() we want specified, non-null version installed. /// - private Stream InstallHelper(string packageName, NuGetVersion version, out ErrorRecord errRecord) + private Stream InstallHelper(string packageName, NuGetVersion version, out ErrorRecord errRecord, ConcurrentQueue errorMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - // TODO: pass in ConcurrentQueue to write out debug message. - //_cmdletPassedIn.WriteDebug("In V3ServerAPICalls::InstallHelper()"); + debugMsgs.Enqueue("In V3ServerAPICalls::InstallHelper()"); Stream pkgStream = null; bool getLatestVersion = true; if (version != null) @@ -834,7 +889,7 @@ private Stream InstallHelper(string packageName, NuGetVersion version, out Error getLatestVersion = false; } - string[] versionedResponses = GetVersionedPackageEntriesFromRegistrationsResource(packageName, packageContentProperty, isSearch: false, out errRecord); + string[] versionedResponses = GetVersionedPackageEntriesFromRegistrationsResource(packageName, packageContentProperty, isSearch: false, out errRecord, errorMsgs, debugMsgs, verboseMsgs); if (errRecord != null) { return pkgStream; @@ -882,7 +937,7 @@ private Stream InstallHelper(string packageName, NuGetVersion version, out Error return null; } - var content = HttpRequestCallForContent(pkgContentUrl, out errRecord); + var content = HttpRequestCallForContent(pkgContentUrl, out errRecord, errorMsgs, debugMsgs, verboseMsgs); if (errRecord != null) { return null; @@ -917,7 +972,7 @@ private async Task InstallHelperAsync(string packageName, NuGetVersion v getLatestVersion = false; } - string[] versionedResponses = GetVersionedPackageEntriesFromRegistrationsResource(packageName, packageContentProperty, isSearch: false, out ErrorRecord errRecord); + string[] versionedResponses = GetVersionedPackageEntriesFromRegistrationsResource(packageName, packageContentProperty, isSearch: false, out ErrorRecord errRecord, errorMsgs, debugMsgs, verboseMsgs); if (errRecord != null) { errorMsgs.Enqueue(errRecord); @@ -989,24 +1044,23 @@ private async Task InstallHelperAsync(string packageName, NuGetVersion v /// i.e when the package Name being searched for does not contain wildcard /// This is called by FindNameHelper(), FindVersionHelper(), FindVersionGlobbing(), InstallHelper() /// - private string[] GetVersionedPackageEntriesFromRegistrationsResource(string packageName, string propertyName, bool isSearch, out ErrorRecord errRecord, ConcurrentQueue debugMsgs = null) + private string[] GetVersionedPackageEntriesFromRegistrationsResource(string packageName, string propertyName, bool isSearch, out ErrorRecord errRecord, ConcurrentQueue errorMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - // TODO: pass in ConcurrentQueue to write out debug message. - //_cmdletPassedIn.WriteDebug("In V3ServerAPICalls::GetVersionedPackageEntriesFromRegistrationsResource()"); + debugMsgs.Enqueue("In V3ServerAPICalls::GetVersionedPackageEntriesFromRegistrationsResource()"); string[] responses = Utils.EmptyStrArray; - Dictionary resources = GetResourcesFromServiceIndex(out errRecord); + Dictionary resources = GetResourcesFromServiceIndex(out errRecord, errorMsgs, debugMsgs, verboseMsgs); if (errRecord != null) { return responses; } - string registrationsBaseUrl = FindRegistrationsBaseUrl(resources, out errRecord); + string registrationsBaseUrl = FindRegistrationsBaseUrl(resources, out errRecord, errorMsgs, debugMsgs, verboseMsgs); if (errRecord != null) { return responses; } - responses = GetVersionedResponsesFromRegistrationsResource(registrationsBaseUrl, packageName, propertyName, isSearch, out errRecord, debugMsgs); + responses = GetVersionedResponsesFromRegistrationsResource(registrationsBaseUrl, packageName, propertyName, isSearch, out errRecord, errorMsgs, debugMsgs, verboseMsgs); if (errRecord != null) { return Utils.EmptyStrArray; @@ -1020,11 +1074,11 @@ private string[] GetVersionedPackageEntriesFromRegistrationsResource(string pack /// i.e when the package Name being searched for contains wildcards or a Tag query search is performed /// This is called by FindNameGlobbingFromNuGetRepo() and FindTagsFromNuGetRepo() /// - private List GetVersionedPackageEntriesFromSearchQueryResource(string queryTerm, bool includePrerelease, out ErrorRecord errRecord) + private List GetVersionedPackageEntriesFromSearchQueryResource(string queryTerm, bool includePrerelease, out ErrorRecord errRecord, ConcurrentQueue errorMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::GetVersionedPackageEntriesFromSearchQueryResource()"); + debugMsgs.Enqueue("In V3ServerAPICalls::GetVersionedPackageEntriesFromSearchQueryResource()"); List pkgEntries = new(); - Dictionary resources = GetResourcesFromServiceIndex(out errRecord); + Dictionary resources = GetResourcesFromServiceIndex(out errRecord, errorMsgs, debugMsgs, verboseMsgs); if (errRecord != null) { return pkgEntries; @@ -1041,7 +1095,7 @@ private List GetVersionedPackageEntriesFromSearchQueryResource(stri string query = $"{searchQueryServiceUrl}?q={queryTerm}&prerelease={includePrerelease}&semVerLevel=2.0.0&skip={skip}&take=100"; // Get responses for all packages that contain the required tags - pkgEntries.AddRange(GetJsonElementArr(query, dataName, out int initialCount, out errRecord).ToList()); + pkgEntries.AddRange(GetJsonElementArr(query, dataName, out int initialCount, out errRecord, errorMsgs, debugMsgs, verboseMsgs).ToList()); // check count (ie "totalHits") 425 ==> count/100 ~~> 4 calls ~~> + 1 = 5 calls int count = initialCount / 100 + 1; @@ -1050,7 +1104,7 @@ private List GetVersionedPackageEntriesFromSearchQueryResource(stri { skip += 100; query = $"{searchQueryServiceUrl}?q={queryTerm}&prerelease={includePrerelease}&semVerLevel=2.0.0&skip={skip}&take=100"; - pkgEntries.AddRange(GetJsonElementArr(query, dataName, out int unneededCount, out errRecord).ToList()); + pkgEntries.AddRange(GetJsonElementArr(query, dataName, out int unneededCount, out errRecord, errorMsgs, debugMsgs, verboseMsgs).ToList()); count--; } @@ -1061,12 +1115,11 @@ private List GetVersionedPackageEntriesFromSearchQueryResource(stri /// Finds all resources present in the repository's service index. /// For example: https://api.nuget.org/v3/index.json /// - private Dictionary GetResourcesFromServiceIndex(out ErrorRecord errRecord) + private Dictionary GetResourcesFromServiceIndex(out ErrorRecord errRecord, ConcurrentQueue errorMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - // TODO: pass in ConcurrentQueue to write out debug message. - //_cmdletPassedIn.WriteDebug("In V3ServerAPICalls::GetResourcesFromServiceIndex()"); + debugMsgs.Enqueue("In V3ServerAPICalls::GetResourcesFromServiceIndex()"); Dictionary resources = new Dictionary(); - JsonElement[] resourcesArray = GetJsonElementArr($"{Repository.Uri}", resourcesName, out int totalHits, out errRecord); + JsonElement[] resourcesArray = GetJsonElementArr($"{Repository.Uri}", resourcesName, out int totalHits, out errRecord, errorMsgs, debugMsgs, verboseMsgs); if (errRecord != null) { return resources; @@ -1122,10 +1175,9 @@ private Dictionary GetResourcesFromServiceIndex(out ErrorRecord /// Gets the resource of type "RegistrationBaseUrl" from the repository's resources. /// A repository can have multiple resources of type "RegistrationsBaseUrl" so it finds the best match according to the guideline comment in the method. /// - private string FindRegistrationsBaseUrl(Dictionary resources, out ErrorRecord errRecord) + private string FindRegistrationsBaseUrl(Dictionary resources, out ErrorRecord errRecord, ConcurrentQueue errorMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - // TODO: pass in ConcurrentQueue to write out debug message. - //_cmdletPassedIn.WriteDebug("In V3ServerAPICalls::FindRegistrationsBaseUrl()"); + debugMsgs.Enqueue("In V3ServerAPICalls::FindRegistrationsBaseUrl()"); errRecord = null; string registrationsBaseUrl = String.Empty; @@ -1212,16 +1264,15 @@ private string FindSearchQueryService(Dictionary resources, out /// For some packages (that we know of: JFrog repo and some packages on NuGet.org), the metadata is located under outer "items" element > "@id" element > inner "items" element /// This requires a different search. /// - private JsonElement[] GetMetadataElementFromIdLinkElement(JsonElement idLinkElement, string packageName, out string upperVersion, out ErrorRecord errRecord) + private JsonElement[] GetMetadataElementFromIdLinkElement(JsonElement idLinkElement, string packageName, out string upperVersion, out ErrorRecord errRecord, ConcurrentQueue errorMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - // TODO: pass in ConcurrentQueue to write out debug message. Called from the concurrent install metadata chain so cmdlet methods cannot be used here. ? - _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::GetMetadataElementFromIdLinkElement()"); + debugMsgs.Enqueue("In V3ServerAPICalls::GetMetadataElementFromIdLinkElement()"); upperVersion = String.Empty; JsonElement[] innerItems = new JsonElement[]{}; List innerItemsList = new List(); string metadataUri = idLinkElement.ToString(); - string response = HttpRequestCall(metadataUri, out errRecord); + string response = HttpRequestCall(metadataUri, out errRecord, errorMsgs, debugMsgs, verboseMsgs); if (errRecord != null) { if (errRecord.Exception is ResourceNotFoundException) { @@ -1257,8 +1308,7 @@ private JsonElement[] GetMetadataElementFromIdLinkElement(JsonElement idLinkElem } else { - // TODO: pass in ConcurrentQueue to write out debug message. Called from the concurrent install metadata chain so cmdlet methods cannot be used here. ? - _cmdletPassedIn.WriteDebug($"Package with name '{packageName}' did not have 'upper' property so package versions may not be in descending order."); + debugMsgs.Enqueue($"Package with name '{packageName}' did not have 'upper' property so package versions may not be in descending order."); } foreach(JsonElement entry in innerItemsElement.EnumerateArray()) @@ -1283,10 +1333,9 @@ private JsonElement[] GetMetadataElementFromIdLinkElement(JsonElement idLinkElem /// /// For most packages returned from V3 server protocol responses, the metadata is located under outer "items" element > inner "items" element. /// - private JsonElement[] GetMetadataElementFromItemsElement(JsonElement itemsElement, string packageName, out ErrorRecord errRecord) + private JsonElement[] GetMetadataElementFromItemsElement(JsonElement itemsElement, string packageName, out ErrorRecord errRecord, ConcurrentQueue errorMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - // TODO: pass in ConcurrentQueue to write out debug message. - //_cmdletPassedIn.WriteDebug("In V3ServerAPICalls::GetMetadataElementFromItemsElement()"); + debugMsgs.Enqueue("In V3ServerAPICalls::GetMetadataElementFromItemsElement()"); errRecord = null; List innerItemsList = new List(); @@ -1316,10 +1365,9 @@ private JsonElement[] GetMetadataElementFromItemsElement(JsonElement itemsElemen /// under outer "items" element > inner "items" element (for which we call helper method GetMetadataElementFromItemsElement()), OR /// under outer "items" element > "@Id" element > inner "items" element (for which we call helper method GetMetadataElementFromIdLinkElement) /// - private string[] GetMetadataElementsFromResponse(string response, string property, string packageName, out string upperVersion, out ErrorRecord errRecord) + private string[] GetMetadataElementsFromResponse(string response, string property, string packageName, out string upperVersion, out ErrorRecord errRecord, ConcurrentQueue errorMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - // TODO: pass in ConcurrentQueue to write out debug message. - //_cmdletPassedIn.WriteDebug("In V3ServerAPICalls::GetMetadataElementsFromResponse()"); + debugMsgs.Enqueue("In V3ServerAPICalls::GetMetadataElementsFromResponse()"); errRecord = null; upperVersion = String.Empty; List versionedPkgResponses = new List(); @@ -1353,7 +1401,7 @@ private string[] GetMetadataElementsFromResponse(string response, string propert if (currentItem.TryGetProperty(itemsName, out JsonElement currentInnerItemsElement)) { // Scenarios: NuGet.org majority responses - JsonElement[] innerItemsFromItemsElement = GetMetadataElementFromItemsElement(currentInnerItemsElement, packageName, out errRecord); + JsonElement[] innerItemsFromItemsElement = GetMetadataElementFromItemsElement(currentInnerItemsElement, packageName, out errRecord, errorMsgs, debugMsgs, verboseMsgs); if (errRecord != null) { continue; @@ -1365,8 +1413,7 @@ private string[] GetMetadataElementsFromResponse(string response, string propert } else { - // TODO: pass in ConcurrentQueue to write out debug message. - // _cmdletPassedIn.WriteDebug($"Package with name '{packageName}' did not have 'upper' property so package versions may not be in descending order."); + debugMsgs.Enqueue($"Package with name '{packageName}' did not have 'upper' property so package versions may not be in descending order."); } innerItemsElements.AddRange(innerItemsFromItemsElement); @@ -1374,7 +1421,7 @@ private string[] GetMetadataElementsFromResponse(string response, string propert else if (currentItem.TryGetProperty(idLinkName, out JsonElement idLinkElement)) { // Scenarios: JFrog responses, some NuGet.org responses - JsonElement[] innerItemsFromIdElement = GetMetadataElementFromIdLinkElement(idLinkElement, packageName, out upperVersion, out errRecord); + JsonElement[] innerItemsFromIdElement = GetMetadataElementFromIdLinkElement(idLinkElement, packageName, out upperVersion, out errRecord, errorMsgs, debugMsgs, verboseMsgs); if (errRecord != null) { continue; @@ -1384,8 +1431,7 @@ private string[] GetMetadataElementsFromResponse(string response, string propert } else { - // TODO: pass in ConcurrentQueue to write out debug message. Called from the concurrent install metadata chain so cmdlet methods cannot be used here. ? - _cmdletPassedIn.WriteDebug($"Metadata for package with name '{packageName}' did not have inner 'items' or '@Id' properties."); + debugMsgs.Enqueue($"Metadata for package with name '{packageName}' did not have inner 'items' or '@Id' properties."); } } @@ -1424,8 +1470,7 @@ private string[] GetMetadataElementsFromResponse(string response, string propert } else { - // TODO: pass in ConcurrentQueue to write out debug message. Called from the concurrent install metadata chain so cmdlet methods cannot be used here. ? - _cmdletPassedIn.WriteDebug($"Metadata for package with name '{packageName}' was not of value kind type string or object."); + debugMsgs.Enqueue($"Metadata for package with name '{packageName}' was not of value kind type string or object."); } } } @@ -1452,14 +1497,13 @@ private string[] GetMetadataElementsFromResponse(string response, string propert /// The "packageContent" property is used for download, and the value is a URI for the .nupkg file. /// /// - private string[] GetVersionedResponsesFromRegistrationsResource(string registrationsBaseUrl, string packageName, string property, bool isSearch, out ErrorRecord errRecord, ConcurrentQueue debugMsgs = null) + private string[] GetVersionedResponsesFromRegistrationsResource(string registrationsBaseUrl, string packageName, string property, bool isSearch, out ErrorRecord errRecord, ConcurrentQueue errorMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - // TODO: pass in ConcurrentQueue to write out debug message. - //_cmdletPassedIn.WriteDebug("In V3ServerAPICalls::GetVersionedResponsesFromRegistrationsResource()"); + debugMsgs.Enqueue("In V3ServerAPICalls::GetVersionedResponsesFromRegistrationsResource()"); List versionedResponses = new List(); var requestPkgMapping = registrationsBaseUrl.EndsWith("/") ? $"{registrationsBaseUrl}{packageName.ToLower()}/index.json" : $"{registrationsBaseUrl}/{packageName.ToLower()}/index.json"; - string pkgMappingResponse = HttpRequestCall(requestPkgMapping, out errRecord); + string pkgMappingResponse = HttpRequestCall(requestPkgMapping, out errRecord, errorMsgs, debugMsgs, verboseMsgs); if (errRecord != null) { if (errRecord.Exception is ResourceNotFoundException) @@ -1475,7 +1519,7 @@ private string[] GetVersionedResponsesFromRegistrationsResource(string registrat } string upperVersion = String.Empty; - string[] versionedResponseArr = GetMetadataElementsFromResponse(pkgMappingResponse, property, packageName, out upperVersion, out errRecord); + string[] versionedResponseArr = GetMetadataElementsFromResponse(pkgMappingResponse, property, packageName, out upperVersion, out errRecord, errorMsgs, debugMsgs, verboseMsgs); if (errRecord != null) { return Utils.EmptyStrArray; @@ -1490,14 +1534,14 @@ private string[] GetVersionedResponsesFromRegistrationsResource(string registrat if (isSearch) { - if (!IsLatestVersionFirstForSearch(versionedResponseArr, out errRecord, debugMsgs)) + if (!IsLatestVersionFirstForSearch(versionedResponseArr, out errRecord, errorMsgs, debugMsgs, verboseMsgs)) { Array.Reverse(versionedResponseArr); } } else { - if (!IsLatestVersionFirstForInstall(versionedResponseArr, upperVersion, out errRecord)) + if (!IsLatestVersionFirstForInstall(versionedResponseArr, upperVersion, out errRecord, errorMsgs, debugMsgs, verboseMsgs)) { Array.Reverse(versionedResponseArr); } @@ -1511,9 +1555,9 @@ private string[] GetVersionedResponsesFromRegistrationsResource(string registrat /// ADO feeds usually return version entries in descending order, but Nuget.org repository returns them in ascending order. /// Package versions will reflect prerelease preference, but upper version and lower version would not so we don't use them for comparison. /// - private bool IsLatestVersionFirstForSearch(string[] versionedResponses, out ErrorRecord errRecord, ConcurrentQueue debugMsgs = null) + private bool IsLatestVersionFirstForSearch(string[] versionedResponses, out ErrorRecord errRecord, ConcurrentQueue errorMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - WriteDebug("In V3ServerAPICalls::IsLatestVersionFirstForSearch()", debugMsgs); + debugMsgs.Enqueue("In V3ServerAPICalls::IsLatestVersionFirstForSearch()"); errRecord = null; bool latestVersionFirst = true; int versionResponsesCount = versionedResponses.Length; @@ -1605,27 +1649,14 @@ private bool IsLatestVersionFirstForSearch(string[] versionedResponses, out Erro return latestVersionFirst; } - private void WriteDebug(string message, ConcurrentQueue debugMsgs = null) - { - if (debugMsgs == null) - { - _cmdletPassedIn.WriteDebug(message); - } - else - { - debugMsgs.Enqueue(message); - } - } - /// /// Returns true if the nupkg URI entries for each package version are arranged in descending order with respect to the package's version. /// ADO feeds usually return version entries in descending order, but Nuget.org repository returns them in ascending order. /// Entries do not reflect prerelease preference so all versions (including prerelease) are being considered here, so upper version (including prerelease) can be used for comparison. /// - private bool IsLatestVersionFirstForInstall(string[] versionedResponses, string upperVersion, out ErrorRecord errRecord) + private bool IsLatestVersionFirstForInstall(string[] versionedResponses, string upperVersion, out ErrorRecord errRecord, ConcurrentQueue errorMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - // TODO: pass in ConcurrentQueue to write out debug message. - //_cmdletPassedIn.WriteDebug("In V3ServerAPICalls::IsLatestVersionFirstForInstall()"); + debugMsgs.Enqueue("In V3ServerAPICalls::IsLatestVersionFirstForInstall()"); errRecord = null; bool latestVersionFirst = true; @@ -1701,14 +1732,14 @@ private bool IsRequiredTagSatisfied(JsonElement tagsElement, string[] tags, out /// /// Helper method that parses response for given property and returns result for that property as a JsonElement array. /// - private JsonElement[] GetJsonElementArr(string request, string propertyName, out int totalHits, out ErrorRecord errRecord) + private JsonElement[] GetJsonElementArr(string request, string propertyName, out int totalHits, out ErrorRecord errRecord, ConcurrentQueue errorMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { List responseEntries = new List(); JsonElement[] entries = new JsonElement[0]; totalHits = 0; try { - string response = HttpRequestCall(request, out errRecord); + string response = HttpRequestCall(request, out errRecord, errorMsgs, debugMsgs, verboseMsgs); if (errRecord != null) { return new JsonElement[]{}; @@ -1759,17 +1790,15 @@ private JsonElement[] GetJsonElementArr(string request, string propertyName, out /// /// Helper method that makes the HTTP request for the V3 server protocol url passed in for find APIs. /// - private string HttpRequestCall(string requestUrlV3, out ErrorRecord errRecord) + private string HttpRequestCall(string requestUrlV3, out ErrorRecord errRecord, ConcurrentQueue errorMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - // TODO: pass in ConcurrentQueue to write out debug message. - //_cmdletPassedIn.WriteDebug("In V3ServerAPICalls::HttpRequestCall()"); + debugMsgs.Enqueue("In V3ServerAPICalls::HttpRequestCall()"); errRecord = null; string response = string.Empty; try { - // TODO: pass in ConcurrentQueue to write out debug message. - //_cmdletPassedIn.WriteDebug($"Request url is '{requestUrlV3}'"); + debugMsgs.Enqueue($"Request url is '{requestUrlV3}'"); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrlV3); response = SendV3RequestAsync(request, _sessionClient).GetAwaiter().GetResult(); @@ -1813,10 +1842,9 @@ private string HttpRequestCall(string requestUrlV3, out ErrorRecord errRecord) /// /// Helper method that makes the HTTP request for the V3 server protocol url passed in for install APIs. /// - private HttpContent HttpRequestCallForContent(string requestUrlV3, out ErrorRecord errRecord) + private HttpContent HttpRequestCallForContent(string requestUrlV3, out ErrorRecord errRecord, ConcurrentQueue errorMsgs, ConcurrentQueue debugMsgs, ConcurrentQueue verboseMsgs) { - // TODO: pass in ConcurrentQueue to write out debug message. - //_cmdletPassedIn.WriteDebug("In V3ServerAPICalls::HttpRequestCallForContent()"); + debugMsgs.Enqueue("In V3ServerAPICalls::HttpRequestCallForContent()"); errRecord = null; HttpContent content = null; try @@ -1838,8 +1866,7 @@ private HttpContent HttpRequestCallForContent(string requestUrlV3, out ErrorReco if (string.IsNullOrEmpty(content?.ToString())) { - // TODO: pass in ConcurrentQueue to write out debug message. - //_cmdletPassedIn.WriteDebug("Response is empty"); + debugMsgs.Enqueue("Response is empty"); } return content;