diff --git a/src/code/ContainerRegistryServerAPICalls.cs b/src/code/ContainerRegistryServerAPICalls.cs
index b7af3b98d..cd8c4c8be 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,22 @@ 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 = 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);
+ }
+
+ string packageNameForInstall = PrependMARPrefix(packageName);
+ results = InstallVersionAsync(packageNameForInstall, packageVersion, errorMsgs, debugMsgs, verboseMsgs);
+ return Task.FromResult(results);
}
///
@@ -400,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 InstallVersionAsync(
+ string packageName,
+ string packageVersion,
+ ConcurrentQueue errorMsgs,
+ ConcurrentQueue debugMsgs,
+ ConcurrentQueue verboseMsgs)
+ {
+ debugMsgs.Enqueue("In ContainerRegistryServerAPICalls::InstallVersionAsync()");
+ 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
diff --git a/src/code/FindHelper.cs b/src/code/FindHelper.cs
index 1a074b67e..3d149ab02 100644
--- a/src/code/FindHelper.cs
+++ b/src/code/FindHelper.cs
@@ -904,25 +904,18 @@ 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;
- 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();
+ 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
{
@@ -991,20 +984,18 @@ 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)
{
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();
+
+ Utils.WriteOutConcurrentQueue(_cmdletPassedIn, errorMsgs, warningMsgs, debugMsgs, verboseMsgs);
}
else
{
@@ -1189,7 +1180,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 =>
{
@@ -1290,23 +1281,41 @@ private PSResourceInfo FindDependencyWithSpecificVersion(
PSResourceInfo depPkg = null;
ErrorRecord errRecord = null;
FindResults responses = null;
- Task response = null;
debugMsgs.Enqueue("In FindHelper::FindDependencyWithSpecificVersion()");
- if (currentServer.Repository.ApiVersion == PSRepositoryInfo.APIVersion.V2)
+ 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, operationErrorMsgs, operationWarningMsgs, operationDebugMsgs, operationVerboseMsgs).GetAwaiter().GetResult();
+
+ while (operationErrorMsgs.TryDequeue(out ErrorRecord queuedError))
{
- // 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();
+ if (errRecord == null)
+ {
+ errRecord = queuedError;
+ }
+
+ errorMsgs.Enqueue(queuedError);
}
- else
+
+ while (operationWarningMsgs.TryDequeue(out string queuedWarning))
{
- responses = currentServer.FindVersion(dep.Name, dep.VersionRange.MaxVersion.ToString(), _type, out errRecord);
+ 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)
@@ -1335,7 +1344,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
@@ -1369,19 +1378,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)
@@ -1410,7 +1412,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
@@ -1445,21 +1447,13 @@ private PSResourceInfo FindDependencyWithUpperBound(
ConcurrentDictionary> cachedNetworkCalls = new ConcurrentDictionary>();
debugMsgs.Enqueue("In FindHelper::FindDependencyWithUpperBound()");
+ // 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));
- 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)
@@ -1489,7 +1483,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
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..d8c6b5ffe 100644
--- a/src/code/NuGetServerAPICalls.cs
+++ b/src/code/NuGetServerAPICalls.cs
@@ -49,14 +49,51 @@ 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()");
+ 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);
+ }
+
+ 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 +230,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 +520,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);
}
///
@@ -572,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
diff --git a/src/code/V3ServerAPICalls.cs b/src/code/V3ServerAPICalls.cs
index a2beb1545..9df736d7e 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, debugMsgs);
+ 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 = FindVersionGlobbingHelper(packageName, versionRange, includePrerelease, type, getOnlyLatest, out ErrorRecord errRecord, debugMsgs);
+ 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, debugMsgs);
+ if (errRecord != null)
+ {
+ errorMsgs.Enqueue(errRecord);
+ }
+
+ return Task.FromResult(findResponse);
}
///
@@ -239,8 +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)
{
- _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);
@@ -267,7 +314,7 @@ public override FindResults FindVersionGlobbing(string packageName, VersionRange
if (NuGetVersion.TryParse(pkgVersionElement.ToString(), out NuGetVersion pkgVersion) && versionRange.Satisfies(pkgVersion))
{
- _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);
@@ -353,9 +400,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
@@ -512,10 +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)
{
- _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);
@@ -553,7 +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
@@ -608,9 +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)
{
- _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::FindVersionHelper()");
+ WriteDebug("In V3ServerAPICalls::FindVersionHelper()", debugMsgs);
if (!NuGetVersion.TryParse(version, out NuGetVersion requiredVersion))
{
errRecord = new ErrorRecord(
@@ -621,9 +693,9 @@ 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);
+ string[] versionedResponses = GetVersionedPackageEntriesFromRegistrationsResource(packageName, catalogEntryProperty, isSearch: true, out errRecord, debugMsgs);
if (errRecord != null)
{
return new FindResults(stringResponse: Utils.EmptyStrArray, hashtableResponse: emptyHashResponses, responseType: v3FindResponseType);
@@ -830,12 +902,94 @@ 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
/// 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()");
@@ -852,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;
@@ -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.");
}
}
@@ -1294,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()");
@@ -1332,7 +1490,7 @@ private string[] GetVersionedResponsesFromRegistrationsResource(string registrat
if (isSearch)
{
- if (!IsLatestVersionFirstForSearch(versionedResponseArr, out errRecord))
+ if (!IsLatestVersionFirstForSearch(versionedResponseArr, out errRecord, debugMsgs))
{
Array.Reverse(versionedResponseArr);
}
@@ -1353,9 +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)
{
- _cmdletPassedIn.WriteDebug("In V3ServerAPICalls::IsLatestVersionFirstForSearch()");
+ WriteDebug("In V3ServerAPICalls::IsLatestVersionFirstForSearch()", debugMsgs);
errRecord = null;
bool latestVersionFirst = true;
int versionResponsesCount = versionedResponses.Length;
@@ -1447,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.
@@ -1675,6 +1845,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.
///