Skip to content

Implement RequiredResourceFile and RequiredResource parameters #592

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

Merged
merged 9 commits into from
Jan 21, 2022
234 changes: 218 additions & 16 deletions src/code/InstallPSResource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@
// Licensed under the MIT License.

using Microsoft.PowerShell.PowerShellGet.UtilClasses;
using Newtonsoft.Json;
using NuGet.Versioning;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Management.Automation;
using Microsoft.PowerShell.Commands;

using Dbg = System.Diagnostics.Debug;

Expand Down Expand Up @@ -113,6 +117,63 @@ class InstallPSResource : PSCmdlet
[ValidateNotNullOrEmpty]
public PSResourceInfo InputObject { get; set; }

/// <summary>
/// Installs resources based on input from a JSON file.
/// </summary>
[Parameter(ParameterSetName = RequiredResourceFileParameterSet)]
[ValidateNotNullOrEmpty]
public String RequiredResourceFile
{
get
{
return _requiredResourceFile;
}
set
{
string resolvedPath = string.Empty;
if (!string.IsNullOrWhiteSpace(value))
{
resolvedPath = SessionState.Path.GetResolvedPSPathFromPSPath(value).First().Path;
}

if (!File.Exists(resolvedPath))
{
var exMessage = String.Format("The RequiredResourceFile does not exist. Please try specifying a path to a valid .json file");
var ex = new ArgumentException(exMessage);
var RequiredResourceFileDoesNotExist = new ErrorRecord(ex, "RequiredResourceFileDoesNotExist", ErrorCategory.ObjectNotFound, null);

ThrowTerminatingError(RequiredResourceFileDoesNotExist);
}

_requiredResourceFile = resolvedPath;
}
}

/// <summary>
/// Installs resources in a hashtable or JSON string format.
/// </summary>
[Parameter(ParameterSetName = RequiredResourceParameterSet)]
public Object RequiredResource // takes either string (json) or hashtable
{
get { return _requiredResourceHash != null ? _requiredResourceHash : (Object)_requiredResourceJson; }

set
{
if (value is String jsonResource)
{
_requiredResourceJson = jsonResource;
}
else if (value is Hashtable hashResource)
{
_requiredResourceHash = hashResource;
}
else
{
throw new ParameterBindingException("Object is not a JSON or Hashtable");
}
}
}

#endregion

#region Members
Expand All @@ -122,6 +183,9 @@ class InstallPSResource : PSCmdlet
private const string RequiredResourceFileParameterSet = "RequiredResourceFileParameterSet";
private const string RequiredResourceParameterSet = "RequiredResourceParameterSet";
List<string> _pathsToInstallPkg;
private string _requiredResourceFile;
private string _requiredResourceJson;
private Hashtable _requiredResourceHash;
VersionRange _versionRange;
InstallHelper _installHelper;

Expand Down Expand Up @@ -161,8 +225,11 @@ protected override void ProcessRecord()

ProcessInstallHelper(
pkgNames: Name,
pkgVersion: _versionRange,
pkgPrerelease: Prerelease,
pkgRepository: Repository);
pkgRepository: Repository,
pkgCredential: Credential,
reqResourceParams: null);
break;

case InputObjectParameterSet:
Expand All @@ -177,37 +244,172 @@ protected override void ProcessRecord()

ProcessInstallHelper(
pkgNames: new string[] { InputObject.Name },
pkgVersion: _versionRange,
pkgPrerelease: InputObject.IsPrerelease,
pkgRepository: new string[]{ InputObject.Repository });
pkgRepository: new string[]{ InputObject.Repository },
pkgCredential: Credential,
reqResourceParams: null);
break;

case RequiredResourceFileParameterSet:
ThrowTerminatingError(new ErrorRecord(
new PSNotImplementedException("RequiredResourceFileParameterSet is not yet implemented. Please rerun cmdlet with other parameter set."),
"CommandParameterSetNotImplementedYet",
ErrorCategory.NotImplemented,
this));
/* json file contents should look like:
{
"Pester": {
"allowPrerelease": true,
"version": "[4.4.2,4.7.0]",
"repository": "PSGallery",
"credential": null
}
}
*/

string requiredResourceFileStream = string.Empty;
using (StreamReader sr = new StreamReader(_requiredResourceFile))
{
requiredResourceFileStream = sr.ReadToEnd();
}

Hashtable pkgsInJsonFile = null;
try
{
pkgsInJsonFile = Utils.ConvertJsonToHashtable(this, requiredResourceFileStream);
}
catch (Exception)
{
var exMessage = String.Format("Argument for parameter -RequiredResourceFile is not in proper json format. Make sure argument is either a valid json file.");
var ex = new ArgumentException(exMessage);
var RequiredResourceFileNotInProperJsonFormat = new ErrorRecord(ex, "RequiredResourceFileNotInProperJsonFormat", ErrorCategory.InvalidData, null);

ThrowTerminatingError(RequiredResourceFileNotInProperJsonFormat);
}

RequiredResourceHelper(pkgsInJsonFile);
break;

case RequiredResourceParameterSet:
ThrowTerminatingError(new ErrorRecord(
new PSNotImplementedException("RequiredResourceParameterSet is not yet implemented. Please rerun cmdlet with other parameter set."),
"CommandParameterSetNotImplementedYet",
ErrorCategory.NotImplemented,
this));
if (!string.IsNullOrWhiteSpace(_requiredResourceJson))
{
/* json would look like:
{
"Pester": {
"allowPrerelease": true,
"version": "[4.4.2,4.7.0]",
"repository": "PSGallery",
"credential": null
}
}
*/

Hashtable pkgsHash = null;
try
{
pkgsHash = Utils.ConvertJsonToHashtable(this, _requiredResourceJson);
}
catch (Exception)
{
var exMessage = String.Format("Argument for parameter -RequiredResource is not in proper json format. Make sure argument is either a valid json file.");
var ex = new ArgumentException(exMessage);
var RequiredResourceFileNotInProperJsonFormat = new ErrorRecord(ex, "RequiredResourceFileNotInProperJsonFormat", ErrorCategory.InvalidData, null);

ThrowTerminatingError(RequiredResourceFileNotInProperJsonFormat);
}

RequiredResourceHelper(pkgsHash);
}

if (_requiredResourceHash != null)
{
/* hashtable would look like:
@{
"Configuration" = @{ version = "[4.4.2,4.7.0]" }
"Pester" = @{
version = "[4.4.2,4.7.0]"
repository = PSGallery
credential = $cred
prerelease = $true
}
}
*/

RequiredResourceHelper(_requiredResourceHash);
}
break;

default:
Dbg.Assert(false, "Invalid parameter set");
break;
}
}

#endregion

#region Methods

private void ProcessInstallHelper(string[] pkgNames, bool pkgPrerelease, string[] pkgRepository)
private void RequiredResourceHelper(Hashtable reqResourceHash)
{
var pkgNames = reqResourceHash.Keys;

foreach (string pkgName in pkgNames)
{
var pkgParamInfo = reqResourceHash[pkgName];

// Format should now be a hashtable, whether the original input format was json or hashtable
if (!(pkgParamInfo is Hashtable pkgInstallInfo))
{
return;
}

InstallPkgParams pkgParams = new InstallPkgParams();
var pkgParamNames = pkgInstallInfo.Keys;

PSCredential pkgCredential = Credential;
foreach (string paramName in pkgParamNames)
{
if (string.Equals(paramName, "credential", StringComparison.InvariantCultureIgnoreCase))
{
WriteVerbose("Credential specified for required resource");
pkgCredential = pkgInstallInfo[paramName] as PSCredential;
}

pkgParams.SetProperty(paramName, pkgInstallInfo[paramName] as string, out ErrorRecord IncorrectVersionFormat);

if (IncorrectVersionFormat != null)
{
ThrowTerminatingError(IncorrectVersionFormat);
}
}

if (pkgParams.Scope == ScopeType.AllUsers)
{
_pathsToInstallPkg = Utils.GetAllInstallationPaths(this, pkgParams.Scope);
}

VersionRange pkgVersion;
// If no Version specified, install latest version for the package.
// Otherwise validate Version can be parsed out successfully.
if (pkgInstallInfo["version"] == null || string.IsNullOrWhiteSpace(pkgInstallInfo["version"].ToString()))
{
pkgVersion = VersionRange.All;
}
else if (!Utils.TryParseVersionOrVersionRange(pkgInstallInfo["version"].ToString(), out pkgVersion))
{
var exMessage = "Argument for Version parameter is not in the proper format.";
var ex = new ArgumentException(exMessage);
var IncorrectVersionFormat = new ErrorRecord(ex, "IncorrectVersionFormat", ErrorCategory.InvalidArgument, null);
ThrowTerminatingError(IncorrectVersionFormat);
}

ProcessInstallHelper(
pkgNames: new string[] { pkgName },
pkgVersion: pkgVersion,
pkgPrerelease: pkgParams.Prerelease,
pkgRepository: new string[] { pkgParams.Repository },
pkgCredential: pkgCredential,
reqResourceParams: pkgParams);
}
}

private void ProcessInstallHelper(string[] pkgNames, VersionRange pkgVersion, bool pkgPrerelease, string[] pkgRepository, PSCredential pkgCredential, InstallPkgParams reqResourceParams)
{
var inputNameToInstall = Utils.ProcessNameWildcards(pkgNames, out string[] errorMsgs, out bool nameContainsWildcard);
if (nameContainsWildcard)
Expand Down Expand Up @@ -244,7 +446,7 @@ private void ProcessInstallHelper(string[] pkgNames, bool pkgPrerelease, string[

var installedPkgs = _installHelper.InstallPackages(
names: pkgNames,
versionRange: _versionRange,
versionRange: pkgVersion,
prerelease: pkgPrerelease,
repository: pkgRepository,
acceptLicense: AcceptLicense,
Expand All @@ -253,7 +455,7 @@ private void ProcessInstallHelper(string[] pkgNames, bool pkgPrerelease, string[
force: false,
trustRepository: TrustRepository,
noClobber: NoClobber,
credential: Credential,
credential: pkgCredential,
asNupkg: false,
includeXML: true,
skipDependencyCheck: SkipDependencyCheck,
Expand Down
Loading