Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Concurrency Investigations #1652

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
388 changes: 269 additions & 119 deletions src/code/FindHelper.cs

Large diffs are not rendered by default.

215 changes: 175 additions & 40 deletions src/code/InstallHelper.cs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/code/InstallPSResource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ protected override void ProcessRecord()
pkgRepository: Repository,
pkgCredential: Credential,
reqResourceParams: null);

break;

case InputObjectParameterSet:
Expand Down
1 change: 0 additions & 1 deletion src/code/ServerApiCall.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
using System.Text;
using System.Runtime.ExceptionServices;
using System.Management.Automation;
using System;

namespace Microsoft.PowerShell.PSResourceGet.Cmdlets
{
Expand Down
86 changes: 67 additions & 19 deletions src/code/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1223,37 +1223,85 @@ private static bool TryReadPSDataFile(
out Hashtable dataFileInfo,
out Exception error)
{
dataFileInfo = null;
error = null;
try
{
if (filePath is null)
{
throw new PSArgumentNullException(nameof(filePath));
}

string contents = System.IO.File.ReadAllText(filePath);
var scriptBlock = System.Management.Automation.ScriptBlock.Create(contents);

// Ensure that the content script block is safe to convert into a PSDataFile Hashtable.
// This will throw for unsafe content.
scriptBlock.CheckRestrictedLanguage(
allowedCommands: allowedCommands,
allowedVariables: allowedVariables,
allowEnvironmentVariables: allowEnvironmentVariables);

// Convert contents into PSDataFile Hashtable by executing content as script.
object result = scriptBlock.InvokeReturnAsIs();
if (result is PSObject psObject)

// Parallel.ForEach calls into this method.
// Each thread needs its own runspace created to provide a separate environment for operations to run independently.
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
runspace.SessionStateProxy.LanguageMode = PSLanguageMode.ConstrainedLanguage;

// Set the created runspace as the default for the current thread
Runspace.DefaultRunspace = runspace;

using (System.Management.Automation.PowerShell pwsh = System.Management.Automation.PowerShell.Create())
{
result = psObject.BaseObject;
}
pwsh.Runspace = runspace;

dataFileInfo = (Hashtable) result;
error = null;
return true;
var cmd = new Command(
command: contents,
isScript: true,
useLocalScope: true);
cmd.MergeMyResults(
myResult: PipelineResultTypes.Error | PipelineResultTypes.Warning | PipelineResultTypes.Verbose | PipelineResultTypes.Debug | PipelineResultTypes.Information,
toResult: PipelineResultTypes.Output);
pwsh.Commands.AddCommand(cmd);


try
{
// Invoke the pipeline and retrieve the results
var results = pwsh.Invoke();

if (results[0] is PSObject pwshObj)
{
switch (pwshObj.BaseObject)
{
case ErrorRecord err:
//_cmdletPassedIn.WriteError(error);
break;

case WarningRecord warning:
//cmdlet.WriteWarning(warning.Message);
break;

case VerboseRecord verbose:
//cmdlet.WriteVerbose(verbose.Message);
break;

case DebugRecord debug:
//cmdlet.WriteDebug(debug.Message);
break;

case InformationRecord info:
//cmdlet.WriteInformation(info);
break;

case Hashtable result:
dataFileInfo = result;
return true;
}
}
}
catch (Exception ex)
{
error = ex;
}
}
runspace.Close();

return false;
}
catch (Exception ex)
{
dataFileInfo = null;
error = ex;
return false;
}
Expand Down
24 changes: 12 additions & 12 deletions src/code/V2ServerAPICalls.cs
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ public override FindResults FindCommandOrDscResource(string[] tags, bool include
/// </summary>
public override FindResults FindName(string packageName, bool includePrerelease, ResourceType type, out ErrorRecord errRecord)
{
_cmdletPassedIn.WriteDebug("In V2ServerAPICalls::FindName()");
//_cmdletPassedIn.WriteDebug("In V2ServerAPICalls::FindName()");
// Make sure to include quotations around the package name

// This should return the latest stable version or the latest prerelease version (respectively)
Expand Down Expand Up @@ -623,7 +623,7 @@ public override FindResults FindVersionGlobbing(string packageName, VersionRange
/// </summary>
public override FindResults FindVersion(string packageName, string version, ResourceType type, out ErrorRecord errRecord)
{
_cmdletPassedIn.WriteDebug("In V2ServerAPICalls::FindVersion()");
//_cmdletPassedIn.WriteDebug("In V2ServerAPICalls::FindVersion()");
// https://www.powershellgallery.com/api/v2/FindPackagesById()?id='blah'&includePrerelease=false&$filter= NormalizedVersion eq '1.1.0' and substringof('PSModule', Tags) eq true
// Quotations around package name and version do not matter, same metadata gets returned.
// We need to explicitly add 'Id eq <packageName>' whenever $filter is used, otherwise arbitrary results are returned.
Expand Down Expand Up @@ -653,7 +653,7 @@ public override FindResults FindVersion(string packageName, string version, Reso
}

int count = GetCountFromResponse(response, out errRecord);
_cmdletPassedIn.WriteDebug($"Count from response is '{count}'");
//_cmdletPassedIn.WriteDebug($"Count from response is '{count}'");

if (errRecord != null)
{
Expand Down Expand Up @@ -767,13 +767,13 @@ public override Stream InstallPackage(string packageName, string packageVersion,
/// </summary>
private string HttpRequestCall(string requestUrlV2, out ErrorRecord errRecord)
{
_cmdletPassedIn.WriteDebug("In V2ServerAPICalls::HttpRequestCall()");
//_cmdletPassedIn.WriteDebug("In V2ServerAPICalls::HttpRequestCall()");
errRecord = null;
string response = string.Empty;

try
{
_cmdletPassedIn.WriteDebug($"Request url is '{requestUrlV2}'");
// _cmdletPassedIn.WriteDebug($"Request url is '{requestUrlV2}'");
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrlV2);

response = SendV2RequestAsync(request, _sessionClient).GetAwaiter().GetResult();
Expand Down Expand Up @@ -813,7 +813,7 @@ private string HttpRequestCall(string requestUrlV2, out ErrorRecord errRecord)

if (string.IsNullOrEmpty(response))
{
_cmdletPassedIn.WriteDebug("Response is empty");
// _cmdletPassedIn.WriteDebug("Response is empty");
}

return response;
Expand All @@ -824,13 +824,13 @@ private string HttpRequestCall(string requestUrlV2, out ErrorRecord errRecord)
/// </summary>
private HttpContent HttpRequestCallForContent(string requestUrlV2, out ErrorRecord errRecord)
{
_cmdletPassedIn.WriteDebug("In V2ServerAPICalls::HttpRequestCallForContent()");
// _cmdletPassedIn.WriteDebug("In V2ServerAPICalls::HttpRequestCallForContent()");
errRecord = null;
HttpContent content = null;

try
{
_cmdletPassedIn.WriteDebug($"Request url is '{requestUrlV2}'");
//_cmdletPassedIn.WriteDebug($"Request url is '{requestUrlV2}'");
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrlV2);

content = SendV2RequestForContentAsync(request, _sessionClient).GetAwaiter().GetResult();
Expand Down Expand Up @@ -862,7 +862,7 @@ private HttpContent HttpRequestCallForContent(string requestUrlV2, out ErrorReco

if (content == null || string.IsNullOrEmpty(content.ToString()))
{
_cmdletPassedIn.WriteDebug("Response is empty");
//_cmdletPassedIn.WriteDebug("Response is empty");
}

return content;
Expand Down Expand Up @@ -1195,7 +1195,7 @@ private string FindNameGlobbingWithTag(string packageName, string[] tags, Resour
/// </summary>
private string FindVersionGlobbing(string packageName, VersionRange versionRange, bool includePrerelease, ResourceType type, int skip, bool getOnlyLatest, out ErrorRecord errRecord)
{
_cmdletPassedIn.WriteDebug("In V2ServerAPICalls::FindVersionGlobbing()");
//_cmdletPassedIn.WriteDebug("In V2ServerAPICalls::FindVersionGlobbing()");
//https://www.powershellgallery.com/api/v2//FindPackagesById()?id='blah'&includePrerelease=false&$filter= NormalizedVersion gt '1.0.0' and NormalizedVersion lt '2.2.5' and substringof('PSModule', Tags) eq true
//https://www.powershellgallery.com/api/v2//FindPackagesById()?id='PowerShellGet'&includePrerelease=false&$filter= NormalizedVersion gt '1.1.1' and NormalizedVersion lt '2.2.5'
// NormalizedVersion doesn't include trailing zeroes
Expand Down Expand Up @@ -1301,7 +1301,7 @@ private string FindVersionGlobbing(string packageName, VersionRange versionRange
/// </summary>
private Stream InstallVersion(string packageName, string version, out ErrorRecord errRecord)
{
_cmdletPassedIn.WriteDebug("In V2ServerAPICalls::InstallVersion()");
//_cmdletPassedIn.WriteDebug("In V2ServerAPICalls::InstallVersion()");
string requestUrlV2;

if (_isADORepo)
Expand Down Expand Up @@ -1402,7 +1402,7 @@ public int GetCountFromResponse(string httpResponse, out ErrorRecord errRecord)
}
else
{
_cmdletPassedIn.WriteDebug($"Property 'count' and 'd:Id' could not be found in response. This may indicate that the package could not be found");
//_cmdletPassedIn.WriteDebug($"Property 'count' and 'd:Id' could not be found in response. This may indicate that the package could not be found");
}
}
}
Expand Down
Loading