From c82b4b2b678940b90d33686bb7c4c29ef55c77e5 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Mon, 25 Oct 2021 15:32:43 -0400 Subject: [PATCH 01/14] implement prerelease version search support for Get --- src/code/GetHelper.cs | 1 + src/code/GetInstalledPSResource.cs | 12 ++++++- src/code/UninstallPSResource.cs | 57 ++++++++++++++++++++++++++++-- src/code/Utils.cs | 55 ++++++++++++++++++++++++++++ test/UninstallPSResource.Tests.ps1 | 19 ++++++++++ 5 files changed, 140 insertions(+), 4 deletions(-) diff --git a/src/code/GetHelper.cs b/src/code/GetHelper.cs index 18cd5ab29..014475cbb 100644 --- a/src/code/GetHelper.cs +++ b/src/code/GetHelper.cs @@ -124,6 +124,7 @@ public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, Li } _cmdletPassedIn.WriteVerbose(string.Format("Directory parsed as NuGet version: '{0}'", dirAsNugetVersion)); + _cmdletPassedIn.WriteVerbose("versionRange: " + versionRange + " and dirAsNuGetVersion: " + dirAsNugetVersion); if (versionRange.Satisfies(dirAsNugetVersion)) { // This will be one version or a version range. diff --git a/src/code/GetInstalledPSResource.cs b/src/code/GetInstalledPSResource.cs index dfcd7202b..e4246a8ef 100644 --- a/src/code/GetInstalledPSResource.cs +++ b/src/code/GetInstalledPSResource.cs @@ -22,6 +22,7 @@ public sealed class GetInstalledPSResource : PSCmdlet private VersionRange _versionRange; private List _pathsToSearch; + string[] _prereleaseLabels = new string[]{}; #endregion @@ -59,7 +60,8 @@ protected override void BeginProcessing() { _versionRange = VersionRange.All; } - else if (!Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) + else if (!Utils.TryParseVersionOrVersionRange(version: Utils.GetVersionWithoutPrerelease(Version, out _prereleaseLabels), + versionRange: out _versionRange)) { var exMessage = "Argument for -Version parameter is not in the proper format."; var ex = new ArgumentException(exMessage); @@ -130,8 +132,16 @@ protected override void ProcessRecord() } GetHelper getHelper = new GetHelper(this); + string[] versionRangeParts = _versionRange.ToString().Trim(new char []{'[', ']', '(', ')'}).Split(','); + foreach (PSResourceInfo pkg in getHelper.FilterPkgPaths(namesToSearch, _versionRange, _pathsToSearch)) { + if ((_versionRange != VersionRange.All) && (pkg.Version.ToString().StartsWith(versionRangeParts[0]) && !String.Equals(pkg.PrereleaseLabel, _prereleaseLabels[0], StringComparison.InvariantCultureIgnoreCase)) || + (pkg.Version.ToString().StartsWith(versionRangeParts[1]) && !String.Equals(pkg.PrereleaseLabel, _prereleaseLabels[1], StringComparison.InvariantCultureIgnoreCase))) + { + continue; + } + WriteObject(pkg); } } diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index 36d16a1a0..df80fe06b 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -1,7 +1,8 @@ -using System.Text; +using System.Reflection; // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using System; +using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; @@ -56,6 +57,7 @@ public sealed class UninstallPSResource : PSCmdlet public static readonly string OsPlatform = System.Runtime.InteropServices.RuntimeInformation.OSDescription; VersionRange _versionRange; List _pathsToSearch = new List(); + string _prereleaseLabel = String.Empty; #endregion #region Methods @@ -76,7 +78,8 @@ protected override void ProcessRecord() { _versionRange = VersionRange.All; } - else if (!Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) + else if (!Utils.TryParseVersionOrVersionRange(version: Utils.GetVersionWithoutPrereleaseHelper(Version, out _prereleaseLabel), + versionRange: out _versionRange)) { var exMessage = "Argument for -Version parameter is not in the proper format."; var ex = new ArgumentException(exMessage); @@ -110,7 +113,8 @@ protected override void ProcessRecord() break; case InputObjectParameterSet: - if (!Utils.TryParseVersionOrVersionRange(InputObject.Version.ToString(), out _versionRange)) + if (!Utils.TryParseVersionOrVersionRange(version: Utils.GetVersionWithoutPrereleaseHelper(InputObject.Version.ToString(), out _prereleaseLabel), + versionRange: out _versionRange)) { var exMessage = String.Format("Version '{0}' for resource '{1}' cannot be parsed.", InputObject.Version.ToString(), InputObject.Name); var ex = new ArgumentException(exMessage); @@ -202,6 +206,15 @@ private bool UninstallModuleHelper(string pkgPath, string pkgName, out ErrorReco errRecord = null; var successfullyUninstalledPkg = false; + // if Version provided by user contains prerelease label and installed package contains same prerelease label, then uninstall + if (!String.IsNullOrEmpty(_prereleaseLabel) && !CheckIfPrerelease(isModule: true, + pkgPath: pkgPath, + pkgName: pkgName, + expectedPrereleaseLabel: _prereleaseLabel)) + { + return false; + } + // if -Force is not specified and the pkg is a dependency for another package, // an error will be written and we return false if (!Force && CheckIfDependency(pkgName, out errRecord)) @@ -252,6 +265,15 @@ private bool UninstallScriptHelper(string pkgPath, string pkgName, out ErrorReco errRecord = null; var successfullyUninstalledPkg = false; + // if Version provided by user contains prerelease label and installed package contains same prerelease label, then uninstall + if (!String.IsNullOrEmpty(_prereleaseLabel) && !CheckIfPrerelease(isModule: true, + pkgPath: pkgPath, + pkgName: pkgName, + expectedPrereleaseLabel: _prereleaseLabel)) + { + return false; + } + // delete the appropriate file try { @@ -332,6 +354,35 @@ private bool CheckIfDependency(string pkgName, out ErrorRecord errRecord) } return false; } + + private bool CheckIfPrerelease(bool isModule, string pkgPath, string pkgName, string expectedPrereleaseLabel) + { + // get module manifest path, same for modules and scripts: + // ./Modules/TestModule/0.0.1/TestModule.psd1 + // ./Scripts/TestScript/0.0.1/TestScript.psd1 + string moduleManifestPath = Path.Combine(pkgPath, pkgName + ".psd1"); + + if (!Utils.TryParseModuleManifest(moduleManifestPath, this, out Hashtable parsedMetadataHashtable)) + { + WriteError(new ErrorRecord( + new PSInvalidOperationException("Module manifest could not be parsed for package: " + pkgName), + "ErrorParsingModuleManifest", + ErrorCategory.InvalidData, + this)); + return false; + } + + var parsedPrivateData = parsedMetadataHashtable["PrivateData"] as Hashtable; + var parsedPSData = parsedPrivateData["PSData"] as Hashtable; + string parsedPrereleaseLabel = parsedPSData["prerelease"] as string; + + if (String.Equals(parsedPrereleaseLabel, expectedPrereleaseLabel, StringComparison.InvariantCultureIgnoreCase)) + { + return true; + } + + return false; + } #endregion } } diff --git a/src/code/Utils.cs b/src/code/Utils.cs index aaca16bbc..d265703eb 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -116,6 +116,61 @@ public static string[] ProcessNameWildcards( #region Version methods + public static string GetVersionWithoutPrerelease(string versionString, out string[] prereleaseLabels) + { + List prereleaseLabelList = new List(); + if (versionString.StartsWith("[") || versionString.StartsWith("(")) + { + // TODO: do I need to check end cases? + // this is a version range, i.e: [3.0.0-preview, ] or (2.9.0, 3.0.0-preview) + // not supported, bc you can't install versions with same core version part side by side (3.0.0, 3.0.0-preview) + string[] versionRangeParts = versionString.Substring(1, versionString.Length - 2).Split(','); + // versionRangeParts should be like: ["3.0.0-preview", ""] or ("2.9.0", "3.0.0-preview") + string endString = versionString.Substring(0, 1); // "[" or "(" + List versionOnlyParts = new List(); + foreach(string individualVersion in versionRangeParts) + { + if (!String.IsNullOrEmpty(individualVersion)) + { + versionOnlyParts.Add(GetVersionWithoutPrereleaseHelper(individualVersion, out string prereleaseLabel)); + prereleaseLabelList.Add(prereleaseLabel); + // endString += GetVersionWithoutPrereleaseHelper(individualVersion, out string prereleaseLabel); + // prereleaseLabelList.Add(prereleaseLabel); + } + else + { + prereleaseLabelList.Add(String.Empty); + } + } + + prereleaseLabels = prereleaseLabelList.ToArray(); + return versionString.Substring(0, 1) + String.Join(",", versionOnlyParts) + versionString.Substring(versionString.Length-1); + + // Console.WriteLine + // endString.TrimEnd(','); + // endString += versionString.Substring(versionString.Length -1); + // prereleaseLabels = prereleaseLabelList.ToArray(); + // Console.WriteLine(endString); + // return endString; + } + + // just a specific version + prereleaseLabels = new string[]{""}; + return GetVersionWithoutPrereleaseHelper(versionString, out prereleaseLabels[0]); + } + public static string GetVersionWithoutPrereleaseHelper(string versionString, out string prereleaseLabel) + { + if (versionString.Contains("-")) + { + string[] versionParts = versionString.Split('-'); + prereleaseLabel = versionParts[1]; + return versionParts[0]; + } + + prereleaseLabel = String.Empty; + return versionString; + } + public static string GetNormalizedVersionString( string versionString, string prerelease) diff --git a/test/UninstallPSResource.Tests.ps1 b/test/UninstallPSResource.Tests.ps1 index 8f5f6a9f9..4cbb94b48 100644 --- a/test/UninstallPSResource.Tests.ps1 +++ b/test/UninstallPSResource.Tests.ps1 @@ -137,6 +137,25 @@ Describe 'Test Uninstall-PSResource for Modules' { $pkg.Version | Should -Be "2.5" } + It "Uninstall version with prerelease" { + Install-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Version "1.1.0-preview" -Repository $PSGalleryName + Uninstall-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Version "1.1.0-preview" + $res = Get-InstalledPSResource "Microsoft.PowerShell.SecretManagement" + $prereleaseVersionFound = $false + foreach ($item in $res) { + if ([System.Version]$item.Version -eq "1.1.0" -and $item.PrereleaseLabel -eq "preview") + { + $prereleaseVersionFound = $true + } + } + + $prereleaseVersionFound | Should -Be $true + } + + It "Not Uninstall non-prerelease when similar prerelease version is specified" { + + } + It "Uninstall module using -WhatIf, should not uninstall the module" { $res = Uninstall-PSResource -Name "ContosoServer" -WhatIf From 3bf0a1be9afa11105077ef26aa23e9aa978e2c78 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Mon, 25 Oct 2021 17:43:58 -0400 Subject: [PATCH 02/14] use PSGetModuleInfo.xml for uninstall noy module manifest --- src/code/UninstallPSResource.cs | 80 ++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 30 deletions(-) diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index df80fe06b..e13a56063 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -57,7 +57,7 @@ public sealed class UninstallPSResource : PSCmdlet public static readonly string OsPlatform = System.Runtime.InteropServices.RuntimeInformation.OSDescription; VersionRange _versionRange; List _pathsToSearch = new List(); - string _prereleaseLabel = String.Empty; + string[] _prereleaseLabels = new string[]{}; #endregion #region Methods @@ -78,7 +78,7 @@ protected override void ProcessRecord() { _versionRange = VersionRange.All; } - else if (!Utils.TryParseVersionOrVersionRange(version: Utils.GetVersionWithoutPrereleaseHelper(Version, out _prereleaseLabel), + else if (!Utils.TryParseVersionOrVersionRange(version: Utils.GetVersionWithoutPrerelease(Version, out _prereleaseLabels), versionRange: out _versionRange)) { var exMessage = "Argument for -Version parameter is not in the proper format."; @@ -113,7 +113,7 @@ protected override void ProcessRecord() break; case InputObjectParameterSet: - if (!Utils.TryParseVersionOrVersionRange(version: Utils.GetVersionWithoutPrereleaseHelper(InputObject.Version.ToString(), out _prereleaseLabel), + if (!Utils.TryParseVersionOrVersionRange(version: Utils.GetVersionWithoutPrerelease(InputObject.Version.ToString(), out _prereleaseLabels), versionRange: out _versionRange)) { var exMessage = String.Format("Version '{0}' for resource '{1}' cannot be parsed.", InputObject.Version.ToString(), InputObject.Name); @@ -140,7 +140,6 @@ protected override void ProcessRecord() } } - private bool UninstallPkgHelper() { var successfullyUninstalled = false; @@ -206,11 +205,16 @@ private bool UninstallModuleHelper(string pkgPath, string pkgName, out ErrorReco errRecord = null; var successfullyUninstalledPkg = false; + // TODO: remove // if Version provided by user contains prerelease label and installed package contains same prerelease label, then uninstall - if (!String.IsNullOrEmpty(_prereleaseLabel) && !CheckIfPrerelease(isModule: true, - pkgPath: pkgPath, - pkgName: pkgName, - expectedPrereleaseLabel: _prereleaseLabel)) + // if (!String.IsNullOrEmpty(_prereleaseLabel) && !CheckIfPrerelease(isModule: true, + // pkgPath: pkgPath, + // pkgName: pkgName, + // expectedPrereleaseLabel: _prereleaseLabel)) + // { + // return false; + // } + if (!CheckIfPrerelease(isModule: true, pkgName: pkgName, pkgPath: pkgPath)) { return false; } @@ -265,11 +269,16 @@ private bool UninstallScriptHelper(string pkgPath, string pkgName, out ErrorReco errRecord = null; var successfullyUninstalledPkg = false; + // TODO: remove // if Version provided by user contains prerelease label and installed package contains same prerelease label, then uninstall - if (!String.IsNullOrEmpty(_prereleaseLabel) && !CheckIfPrerelease(isModule: true, - pkgPath: pkgPath, - pkgName: pkgName, - expectedPrereleaseLabel: _prereleaseLabel)) + // if (!String.IsNullOrEmpty(_prereleaseLabel) && !CheckIfPrerelease(isModule: true, + // pkgPath: pkgPath, + // pkgName: pkgName, + // expectedPrereleaseLabel: _prereleaseLabel)) + // { + // return false; + // } + if (!CheckIfPrerelease(isModule: false, pkgName: pkgName, pkgPath: pkgPath)) { return false; } @@ -355,33 +364,44 @@ private bool CheckIfDependency(string pkgName, out ErrorRecord errRecord) return false; } - private bool CheckIfPrerelease(bool isModule, string pkgPath, string pkgName, string expectedPrereleaseLabel) + private bool CheckIfPrerelease(bool isModule, string pkgPath, string pkgName) { - // get module manifest path, same for modules and scripts: - // ./Modules/TestModule/0.0.1/TestModule.psd1 - // ./Scripts/TestScript/0.0.1/TestScript.psd1 - string moduleManifestPath = Path.Combine(pkgPath, pkgName + ".psd1"); - if (!Utils.TryParseModuleManifest(moduleManifestPath, this, out Hashtable parsedMetadataHashtable)) + string PSGetModuleInfoFilePath = isModule ? Path.Combine(pkgPath, "PSGetModuleInfo.xml") : Path.Combine(Path.GetDirectoryName(pkgPath), "InstalledScriptInfos", pkgName + "_InstalledScriptInfo.xml"); + WriteVerbose("pkgPath: " + PSGetModuleInfoFilePath); + if (!PSResourceInfo.TryRead(PSGetModuleInfoFilePath, out PSResourceInfo psGetInfo, out string errorMsg)) { - WriteError(new ErrorRecord( - new PSInvalidOperationException("Module manifest could not be parsed for package: " + pkgName), - "ErrorParsingModuleManifest", - ErrorCategory.InvalidData, - this)); return false; } - var parsedPrivateData = parsedMetadataHashtable["PrivateData"] as Hashtable; - var parsedPSData = parsedPrivateData["PSData"] as Hashtable; - string parsedPrereleaseLabel = parsedPSData["prerelease"] as string; - - if (String.Equals(parsedPrereleaseLabel, expectedPrereleaseLabel, StringComparison.InvariantCultureIgnoreCase)) + string[] versionRangeParts = _versionRange.ToString().Trim(new char []{'[', ']', '(', ')'}).Split(','); + if ((_versionRange != VersionRange.All) && + (psGetInfo.Version.ToString().StartsWith(versionRangeParts[0]) && !String.Equals(psGetInfo.PrereleaseLabel, _prereleaseLabels[0], StringComparison.InvariantCultureIgnoreCase)) || + (psGetInfo.Version.ToString().StartsWith(versionRangeParts[1]) && !String.Equals(psGetInfo.PrereleaseLabel, _prereleaseLabels[1], StringComparison.InvariantCultureIgnoreCase))) { - return true; + return false; } + return true; - return false; + // // get module manifest path, same for modules and scripts: + // // ./Modules/TestModule/0.0.1/TestModule.psd1 + // // ./Scripts/TestScript/0.0.1/TestScript.psd1 + // string moduleManifestPath = Path.Combine(pkgPath, pkgName + ".psd1"); + + // if (!Utils.TryParseModuleManifest(moduleManifestPath, this, out Hashtable parsedMetadataHashtable)) + // { + // WriteError(new ErrorRecord( + // new PSInvalidOperationException("Module manifest could not be parsed for package: " + pkgName), + // "ErrorParsingModuleManifest", + // ErrorCategory.InvalidData, + // this)); + // return false; + // } + + // if (String.Equals(parsedPrereleaseLabel, expectedPrereleaseLabel, StringComparison.InvariantCultureIgnoreCase)) + // { + // return true; + // } } #endregion } From 5429e32097e67ba916401623ab160a7bbf1c0e8c Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Mon, 25 Oct 2021 23:26:08 -0400 Subject: [PATCH 03/14] remove unnecessary verbose statement --- src/code/GetHelper.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/code/GetHelper.cs b/src/code/GetHelper.cs index 014475cbb..18cd5ab29 100644 --- a/src/code/GetHelper.cs +++ b/src/code/GetHelper.cs @@ -124,7 +124,6 @@ public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, Li } _cmdletPassedIn.WriteVerbose(string.Format("Directory parsed as NuGet version: '{0}'", dirAsNugetVersion)); - _cmdletPassedIn.WriteVerbose("versionRange: " + versionRange + " and dirAsNuGetVersion: " + dirAsNugetVersion); if (versionRange.Satisfies(dirAsNugetVersion)) { // This will be one version or a version range. From d823ea4a6383686334f63ce6d931d5c866f348a6 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Mon, 25 Oct 2021 23:28:53 -0400 Subject: [PATCH 04/14] remove commented code --- src/code/UninstallPSResource.cs | 1 - src/code/Utils.cs | 10 ---------- 2 files changed, 11 deletions(-) diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index e13a56063..b39462a80 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -1,4 +1,3 @@ -using System.Reflection; // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using System; diff --git a/src/code/Utils.cs b/src/code/Utils.cs index d265703eb..9d8cc0a4b 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -126,7 +126,6 @@ public static string GetVersionWithoutPrerelease(string versionString, out strin // not supported, bc you can't install versions with same core version part side by side (3.0.0, 3.0.0-preview) string[] versionRangeParts = versionString.Substring(1, versionString.Length - 2).Split(','); // versionRangeParts should be like: ["3.0.0-preview", ""] or ("2.9.0", "3.0.0-preview") - string endString = versionString.Substring(0, 1); // "[" or "(" List versionOnlyParts = new List(); foreach(string individualVersion in versionRangeParts) { @@ -134,8 +133,6 @@ public static string GetVersionWithoutPrerelease(string versionString, out strin { versionOnlyParts.Add(GetVersionWithoutPrereleaseHelper(individualVersion, out string prereleaseLabel)); prereleaseLabelList.Add(prereleaseLabel); - // endString += GetVersionWithoutPrereleaseHelper(individualVersion, out string prereleaseLabel); - // prereleaseLabelList.Add(prereleaseLabel); } else { @@ -145,13 +142,6 @@ public static string GetVersionWithoutPrerelease(string versionString, out strin prereleaseLabels = prereleaseLabelList.ToArray(); return versionString.Substring(0, 1) + String.Join(",", versionOnlyParts) + versionString.Substring(versionString.Length-1); - - // Console.WriteLine - // endString.TrimEnd(','); - // endString += versionString.Substring(versionString.Length -1); - // prereleaseLabels = prereleaseLabelList.ToArray(); - // Console.WriteLine(endString); - // return endString; } // just a specific version From 85c06b180d8cf639b2489fb18af78af8a2b2bab9 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 26 Oct 2021 02:14:16 -0400 Subject: [PATCH 05/14] fix broken tests --- src/code/GetInstalledPSResource.cs | 6 ++++-- src/code/Utils.cs | 12 +++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/code/GetInstalledPSResource.cs b/src/code/GetInstalledPSResource.cs index e4246a8ef..43bb26893 100644 --- a/src/code/GetInstalledPSResource.cs +++ b/src/code/GetInstalledPSResource.cs @@ -132,12 +132,14 @@ protected override void ProcessRecord() } GetHelper getHelper = new GetHelper(this); + WriteVerbose("versionRange: " + _versionRange); string[] versionRangeParts = _versionRange.ToString().Trim(new char []{'[', ']', '(', ')'}).Split(','); + WriteVerbose("version range parts: " + String.Join(",", versionRangeParts)); foreach (PSResourceInfo pkg in getHelper.FilterPkgPaths(namesToSearch, _versionRange, _pathsToSearch)) { - if ((_versionRange != VersionRange.All) && (pkg.Version.ToString().StartsWith(versionRangeParts[0]) && !String.Equals(pkg.PrereleaseLabel, _prereleaseLabels[0], StringComparison.InvariantCultureIgnoreCase)) || - (pkg.Version.ToString().StartsWith(versionRangeParts[1]) && !String.Equals(pkg.PrereleaseLabel, _prereleaseLabels[1], StringComparison.InvariantCultureIgnoreCase))) + if ((_versionRange != VersionRange.All) && (!String.IsNullOrEmpty(versionRangeParts[0]) && pkg.Version.ToString().StartsWith(versionRangeParts[0]) && !String.Equals(pkg.PrereleaseLabel, _prereleaseLabels[0], StringComparison.InvariantCultureIgnoreCase)) || + (!String.IsNullOrEmpty(versionRangeParts[1]) && pkg.Version.ToString().StartsWith(versionRangeParts[1]) && !String.Equals(pkg.PrereleaseLabel, _prereleaseLabels[1], StringComparison.InvariantCultureIgnoreCase))) { continue; } diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 9d8cc0a4b..9445ad88f 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -121,25 +121,23 @@ public static string GetVersionWithoutPrerelease(string versionString, out strin List prereleaseLabelList = new List(); if (versionString.StartsWith("[") || versionString.StartsWith("(")) { - // TODO: do I need to check end cases? // this is a version range, i.e: [3.0.0-preview, ] or (2.9.0, 3.0.0-preview) // not supported, bc you can't install versions with same core version part side by side (3.0.0, 3.0.0-preview) - string[] versionRangeParts = versionString.Substring(1, versionString.Length - 2).Split(','); - // versionRangeParts should be like: ["3.0.0-preview", ""] or ("2.9.0", "3.0.0-preview") + string[] versionRangeParts = versionString.Trim(new char[]{'[', ']', '(', ')'}).Split(','); List versionOnlyParts = new List(); - foreach(string individualVersion in versionRangeParts) + foreach(string indivVersion in versionRangeParts) { - if (!String.IsNullOrEmpty(individualVersion)) + if (!String.IsNullOrEmpty(indivVersion)) { - versionOnlyParts.Add(GetVersionWithoutPrereleaseHelper(individualVersion, out string prereleaseLabel)); + versionOnlyParts.Add(GetVersionWithoutPrereleaseHelper(indivVersion, out string prereleaseLabel)); prereleaseLabelList.Add(prereleaseLabel); } else { + versionOnlyParts.Add(String.Empty); prereleaseLabelList.Add(String.Empty); } } - prereleaseLabels = prereleaseLabelList.ToArray(); return versionString.Substring(0, 1) + String.Join(",", versionOnlyParts) + versionString.Substring(versionString.Length-1); } From f75fbc5ef241ffcbd47e5fe5a658d5365a2238e5 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 26 Oct 2021 13:46:43 -0400 Subject: [PATCH 06/14] add tests for Get and Uninstall --- src/code/GetInstalledPSResource.cs | 2 -- src/code/UninstallPSResource.cs | 41 ++------------------------- src/code/Utils.cs | 1 + test/GetInstalledPSResource.Tests.ps1 | 22 ++++++++++++++ test/UninstallPSResource.Tests.ps1 | 38 ++++++++++++++++--------- 5 files changed, 50 insertions(+), 54 deletions(-) diff --git a/src/code/GetInstalledPSResource.cs b/src/code/GetInstalledPSResource.cs index 43bb26893..985f57bf3 100644 --- a/src/code/GetInstalledPSResource.cs +++ b/src/code/GetInstalledPSResource.cs @@ -132,9 +132,7 @@ protected override void ProcessRecord() } GetHelper getHelper = new GetHelper(this); - WriteVerbose("versionRange: " + _versionRange); string[] versionRangeParts = _versionRange.ToString().Trim(new char []{'[', ']', '(', ')'}).Split(','); - WriteVerbose("version range parts: " + String.Join(",", versionRangeParts)); foreach (PSResourceInfo pkg in getHelper.FilterPkgPaths(namesToSearch, _versionRange, _pathsToSearch)) { diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index b39462a80..886a6dc0b 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -204,15 +204,6 @@ private bool UninstallModuleHelper(string pkgPath, string pkgName, out ErrorReco errRecord = null; var successfullyUninstalledPkg = false; - // TODO: remove - // if Version provided by user contains prerelease label and installed package contains same prerelease label, then uninstall - // if (!String.IsNullOrEmpty(_prereleaseLabel) && !CheckIfPrerelease(isModule: true, - // pkgPath: pkgPath, - // pkgName: pkgName, - // expectedPrereleaseLabel: _prereleaseLabel)) - // { - // return false; - // } if (!CheckIfPrerelease(isModule: true, pkgName: pkgName, pkgPath: pkgPath)) { return false; @@ -268,15 +259,6 @@ private bool UninstallScriptHelper(string pkgPath, string pkgName, out ErrorReco errRecord = null; var successfullyUninstalledPkg = false; - // TODO: remove - // if Version provided by user contains prerelease label and installed package contains same prerelease label, then uninstall - // if (!String.IsNullOrEmpty(_prereleaseLabel) && !CheckIfPrerelease(isModule: true, - // pkgPath: pkgPath, - // pkgName: pkgName, - // expectedPrereleaseLabel: _prereleaseLabel)) - // { - // return false; - // } if (!CheckIfPrerelease(isModule: false, pkgName: pkgName, pkgPath: pkgPath)) { return false; @@ -365,7 +347,6 @@ private bool CheckIfDependency(string pkgName, out ErrorRecord errRecord) private bool CheckIfPrerelease(bool isModule, string pkgPath, string pkgName) { - string PSGetModuleInfoFilePath = isModule ? Path.Combine(pkgPath, "PSGetModuleInfo.xml") : Path.Combine(Path.GetDirectoryName(pkgPath), "InstalledScriptInfos", pkgName + "_InstalledScriptInfo.xml"); WriteVerbose("pkgPath: " + PSGetModuleInfoFilePath); if (!PSResourceInfo.TryRead(PSGetModuleInfoFilePath, out PSResourceInfo psGetInfo, out string errorMsg)) @@ -380,28 +361,10 @@ private bool CheckIfPrerelease(bool isModule, string pkgPath, string pkgName) { return false; } + return true; - - // // get module manifest path, same for modules and scripts: - // // ./Modules/TestModule/0.0.1/TestModule.psd1 - // // ./Scripts/TestScript/0.0.1/TestScript.psd1 - // string moduleManifestPath = Path.Combine(pkgPath, pkgName + ".psd1"); - - // if (!Utils.TryParseModuleManifest(moduleManifestPath, this, out Hashtable parsedMetadataHashtable)) - // { - // WriteError(new ErrorRecord( - // new PSInvalidOperationException("Module manifest could not be parsed for package: " + pkgName), - // "ErrorParsingModuleManifest", - // ErrorCategory.InvalidData, - // this)); - // return false; - // } - - // if (String.Equals(parsedPrereleaseLabel, expectedPrereleaseLabel, StringComparison.InvariantCultureIgnoreCase)) - // { - // return true; - // } } + #endregion } } diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 9445ad88f..1f38f1253 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -146,6 +146,7 @@ public static string GetVersionWithoutPrerelease(string versionString, out strin prereleaseLabels = new string[]{""}; return GetVersionWithoutPrereleaseHelper(versionString, out prereleaseLabels[0]); } + public static string GetVersionWithoutPrereleaseHelper(string versionString, out string prereleaseLabel) { if (versionString.Contains("-")) diff --git a/test/GetInstalledPSResource.Tests.ps1 b/test/GetInstalledPSResource.Tests.ps1 index 937ab4e72..cfac30845 100644 --- a/test/GetInstalledPSResource.Tests.ps1 +++ b/test/GetInstalledPSResource.Tests.ps1 @@ -7,6 +7,8 @@ Describe 'Test Get-InstalledPSResource for Module' { BeforeAll{ $TestGalleryName = Get-PoshTestGalleryName + $testModuleName = "test_module" + $testScriptName = "test_script" Get-NewPSResourceRepositoryFile Install-PSResource ContosoServer -Repository $TestGalleryName -TrustRepository @@ -106,4 +108,24 @@ $testCases = $pkgs = Get-InstalledPSResource -Name ContosoServer -Version "*" $pkgs.Count | Should -BeGreaterOrEqual 2 } + + It "Get prerelease version module when version with correct prerelease label is specified" { + Install-PSResource -Name $testModuleName -Version "5.2.5-alpha001" + $res = Get-InstalledPSResource -Name $testModuleName -Version "5.2.5" + $res | Should -BeNullOrEmpty + $res = Get-InstalledPSResource -Name $testModuleName -Version "5.2.5-alpha001" + $res.Name | Should -Be $testModuleName + $res.Version | Should -Be "5.2.5" + $res.PrereleaseLabel | Should -Be "alpha001" + } + + It "Get prerelease version script when version with correct prerelease label is specified" { + Install-PSResource -Name $testScriptName -Version "3.0.0-alpha001" + $res = Get-InstalledPSResource -Name $testScriptName -Version "3.0.0" + $res | Should -BeNullOrEmpty + $res = Get-InstalledPSResource -Name $testScriptName -Version "3.0.0-alpha001" + $res.Name | Should -Be $testScriptName + $res.Version | Should -Be "3.0.0" + $res.PrereleaseLabel | Should -Be "alpha001" + } } diff --git a/test/UninstallPSResource.Tests.ps1 b/test/UninstallPSResource.Tests.ps1 index 4cbb94b48..06add830a 100644 --- a/test/UninstallPSResource.Tests.ps1 +++ b/test/UninstallPSResource.Tests.ps1 @@ -9,6 +9,7 @@ Describe 'Test Uninstall-PSResource for Modules' { $TestGalleryName = Get-PoshTestGalleryName $PSGalleryName = Get-PSGalleryName $testModuleName = "test_module" + $testScriptName = "test_script" Get-NewPSResourceRepositoryFile $res = Uninstall-PSResource -name ContosoServer -Version "*" } @@ -137,23 +138,34 @@ Describe 'Test Uninstall-PSResource for Modules' { $pkg.Version | Should -Be "2.5" } - It "Uninstall version with prerelease" { - Install-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Version "1.1.0-preview" -Repository $PSGalleryName - Uninstall-PSResource -Name "Microsoft.PowerShell.SecretManagement" -Version "1.1.0-preview" - $res = Get-InstalledPSResource "Microsoft.PowerShell.SecretManagement" - $prereleaseVersionFound = $false - foreach ($item in $res) { - if ([System.Version]$item.Version -eq "1.1.0" -and $item.PrereleaseLabel -eq "preview") - { - $prereleaseVersionFound = $true - } - } + It "Uninstall prerelease version module when prerelease version specified" { + Install-PSResource -Name $testModuleName -Version "5.2.5-alpha001" -Repository $PSGalleryName + Uninstall-PSResource -Name $testModuleName -Version "5.2.5-alpha001" + $res = Get-InstalledPSResource $testModuleName -Version "5.2.5-alpha001" + $res | Should -BeNullOrEmpty + } - $prereleaseVersionFound | Should -Be $true + It "Not uninstall non-prerelease version module when similar prerelease version is specified" { + Install-PSResource -Name $testModuleName -Version "5.0.0.0" -Repository $PSGalleryName + Uninstall-PSResource -Name $testModuleName -Version "5.0.0-preview" + $res = Get-InstalledPSResource -Name $testModuleName -Version "5.0.0.0" + $res.Name | Should -Be $testModuleName + $res.Version | Should -Be "5.0.0.0" } - It "Not Uninstall non-prerelease when similar prerelease version is specified" { + It "Uninstall prerelease version script when prerelease version specified" { + Install-PSResource -Name $testScriptName -Version "3.0.0-alpha001" -Repository $TestGalleryName + Uninstall-PSResource -Name $testScriptName -Version "3.0.0-alpha001" + $res = Get-InstalledPSResource -Name $testScriptName + $res | Should -BeNullOrEmpty + } + It "Not uninstall non-prerelease version module when prerelease version specified" { + Install-PSResource -Name $testScriptName -Version "2.5.0.0" -Repository $TestGalleryName + Uninstall-PSResource -Name $testScriptName -Version "2.5.0-alpha001" + $res = Get-InstalledPSResource -Name $testScriptName -Version "2.5.0.0" + $res.Name | Should -Be $testScriptName + $res.Version | Should -Be "2.5.0.0" } It "Uninstall module using -WhatIf, should not uninstall the module" { From 5db31caaa98e849835df5c392e301d2ebe6516ad Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 27 Oct 2021 13:04:31 -0400 Subject: [PATCH 07/14] fix bug in tests --- test/GetInstalledPSResource.Tests.ps1 | 4 ++-- test/UninstallPSResource.Tests.ps1 | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/GetInstalledPSResource.Tests.ps1 b/test/GetInstalledPSResource.Tests.ps1 index cfac30845..95b51406d 100644 --- a/test/GetInstalledPSResource.Tests.ps1 +++ b/test/GetInstalledPSResource.Tests.ps1 @@ -110,7 +110,7 @@ $testCases = } It "Get prerelease version module when version with correct prerelease label is specified" { - Install-PSResource -Name $testModuleName -Version "5.2.5-alpha001" + Install-PSResource -Name $testModuleName -Version "5.2.5-alpha001" -Repository $TestGalleryName $res = Get-InstalledPSResource -Name $testModuleName -Version "5.2.5" $res | Should -BeNullOrEmpty $res = Get-InstalledPSResource -Name $testModuleName -Version "5.2.5-alpha001" @@ -120,7 +120,7 @@ $testCases = } It "Get prerelease version script when version with correct prerelease label is specified" { - Install-PSResource -Name $testScriptName -Version "3.0.0-alpha001" + Install-PSResource -Name $testScriptName -Version "3.0.0-alpha001" -Repository $TestGalleryName $res = Get-InstalledPSResource -Name $testScriptName -Version "3.0.0" $res | Should -BeNullOrEmpty $res = Get-InstalledPSResource -Name $testScriptName -Version "3.0.0-alpha001" diff --git a/test/UninstallPSResource.Tests.ps1 b/test/UninstallPSResource.Tests.ps1 index 06add830a..c6b0186ae 100644 --- a/test/UninstallPSResource.Tests.ps1 +++ b/test/UninstallPSResource.Tests.ps1 @@ -139,14 +139,14 @@ Describe 'Test Uninstall-PSResource for Modules' { } It "Uninstall prerelease version module when prerelease version specified" { - Install-PSResource -Name $testModuleName -Version "5.2.5-alpha001" -Repository $PSGalleryName + Install-PSResource -Name $testModuleName -Version "5.2.5-alpha001" -Repository $TestGalleryName Uninstall-PSResource -Name $testModuleName -Version "5.2.5-alpha001" $res = Get-InstalledPSResource $testModuleName -Version "5.2.5-alpha001" $res | Should -BeNullOrEmpty } It "Not uninstall non-prerelease version module when similar prerelease version is specified" { - Install-PSResource -Name $testModuleName -Version "5.0.0.0" -Repository $PSGalleryName + Install-PSResource -Name $testModuleName -Version "5.0.0.0" -Repository $TestGalleryName Uninstall-PSResource -Name $testModuleName -Version "5.0.0-preview" $res = Get-InstalledPSResource -Name $testModuleName -Version "5.0.0.0" $res.Name | Should -Be $testModuleName From 6428c9c5c10335491f7f8dd8069cdbefa55343be Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 27 Oct 2021 15:02:55 -0400 Subject: [PATCH 08/14] fix bug with InputObject pipeline support for Uninstall --- src/code/UninstallPSResource.cs | 12 +++++++++--- src/code/Utils.cs | 1 + test/UninstallPSResource.Tests.ps1 | 4 ++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index 886a6dc0b..69a57feec 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -56,7 +56,7 @@ public sealed class UninstallPSResource : PSCmdlet public static readonly string OsPlatform = System.Runtime.InteropServices.RuntimeInformation.OSDescription; VersionRange _versionRange; List _pathsToSearch = new List(); - string[] _prereleaseLabels = new string[]{}; + string[] _prereleaseLabels = new string[]{""}; #endregion #region Methods @@ -112,7 +112,14 @@ protected override void ProcessRecord() break; case InputObjectParameterSet: - if (!Utils.TryParseVersionOrVersionRange(version: Utils.GetVersionWithoutPrerelease(InputObject.Version.ToString(), out _prereleaseLabels), + // PSResourceInfo object will always have: + // specific version, not version range + // Version and PrereleaseLabel (if any) as separate properties, i.e "1.0.0-alpha" case wouldn't be piped in + + // if (!Utils.TryParseVersionOrVersionRange(version: Utils.GetVersionWithoutPrerelease(InputObject.Version.ToString(), out _prereleaseLabels), + // versionRange: out _versionRange)) + _prereleaseLabels[0] = InputObject.PrereleaseLabel; + if (!Utils.TryParseVersionOrVersionRange(version: InputObject.Version.ToString(), versionRange: out _versionRange)) { var exMessage = String.Format("Version '{0}' for resource '{1}' cannot be parsed.", InputObject.Version.ToString(), InputObject.Name); @@ -348,7 +355,6 @@ private bool CheckIfDependency(string pkgName, out ErrorRecord errRecord) private bool CheckIfPrerelease(bool isModule, string pkgPath, string pkgName) { string PSGetModuleInfoFilePath = isModule ? Path.Combine(pkgPath, "PSGetModuleInfo.xml") : Path.Combine(Path.GetDirectoryName(pkgPath), "InstalledScriptInfos", pkgName + "_InstalledScriptInfo.xml"); - WriteVerbose("pkgPath: " + PSGetModuleInfoFilePath); if (!PSResourceInfo.TryRead(PSGetModuleInfoFilePath, out PSResourceInfo psGetInfo, out string errorMsg)) { return false; diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 1f38f1253..ebf001b08 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -134,6 +134,7 @@ public static string GetVersionWithoutPrerelease(string versionString, out strin } else { + // prereleaseLabelList always has 2 entries, they might just be empty strings versionOnlyParts.Add(String.Empty); prereleaseLabelList.Add(String.Empty); } diff --git a/test/UninstallPSResource.Tests.ps1 b/test/UninstallPSResource.Tests.ps1 index c6b0186ae..1f4c24431 100644 --- a/test/UninstallPSResource.Tests.ps1 +++ b/test/UninstallPSResource.Tests.ps1 @@ -207,8 +207,8 @@ Describe 'Test Uninstall-PSResource for Modules' { # Powershell cannot create install locations indicating a prerelease version (with prerelease label indicated in install location). # To test we can uninstall prerelease versions, we must use the numeric part of the prerelease version only and it must be unique # of all versions installed for that module. - Get-InstalledPSResource -Name $testModuleName -Version "4.5.2" | Uninstall-PSResource - $res = Get-InstalledPSResource -Name $testModuleName -Version "4.5.2" + Get-InstalledPSResource -Name $testModuleName -Version "4.5.2-alpha001" | Uninstall-PSResource + $res = Get-InstalledPSResource -Name $testModuleName -Version "4.5.2-alpha001" $res | Should -BeNullOrEmpty } } From ceca6fa80029945ffa768d6673d749f908fc3c32 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 27 Oct 2021 15:04:33 -0400 Subject: [PATCH 09/14] remove commented out code --- src/code/UninstallPSResource.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index 69a57feec..d152a5cd4 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -116,8 +116,6 @@ protected override void ProcessRecord() // specific version, not version range // Version and PrereleaseLabel (if any) as separate properties, i.e "1.0.0-alpha" case wouldn't be piped in - // if (!Utils.TryParseVersionOrVersionRange(version: Utils.GetVersionWithoutPrerelease(InputObject.Version.ToString(), out _prereleaseLabels), - // versionRange: out _versionRange)) _prereleaseLabels[0] = InputObject.PrereleaseLabel; if (!Utils.TryParseVersionOrVersionRange(version: InputObject.Version.ToString(), versionRange: out _versionRange)) From 59100793e4cb1adaf2c53f39c780afc00fb10302 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 27 Oct 2021 15:09:32 -0400 Subject: [PATCH 10/14] fix typo --- src/code/UninstallPSResource.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index d152a5cd4..f88bbc876 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -115,7 +115,6 @@ protected override void ProcessRecord() // PSResourceInfo object will always have: // specific version, not version range // Version and PrereleaseLabel (if any) as separate properties, i.e "1.0.0-alpha" case wouldn't be piped in - _prereleaseLabels[0] = InputObject.PrereleaseLabel; if (!Utils.TryParseVersionOrVersionRange(version: InputObject.Version.ToString(), versionRange: out _versionRange)) From abd3b7f9ca9d6ef0686da16c47491ff9cc6a3800 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Fri, 29 Oct 2021 10:46:26 -0400 Subject: [PATCH 11/14] fix typo --- src/code/UninstallPSResource.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index f88bbc876..9e85b4c06 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -112,7 +112,7 @@ protected override void ProcessRecord() break; case InputObjectParameterSet: - // PSResourceInfo object will always have: + // PSResourceInfo object piped in will always have: // specific version, not version range // Version and PrereleaseLabel (if any) as separate properties, i.e "1.0.0-alpha" case wouldn't be piped in _prereleaseLabels[0] = InputObject.PrereleaseLabel; From 4d5004b8b073b9a23ada79688e65f2940a1da2a7 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Tue, 2 Nov 2021 13:48:03 -0400 Subject: [PATCH 12/14] check PrereleaseLabel info in GetHelper --- src/code/GetHelper.cs | 27 +++++----- src/code/GetInstalledPSResource.cs | 12 +---- src/code/UninstallPSResource.cs | 45 ++-------------- src/code/Utils.cs | 84 ++++++++++++++---------------- test/UninstallPSResource.Tests.ps1 | 3 -- 5 files changed, 58 insertions(+), 113 deletions(-) diff --git a/src/code/GetHelper.cs b/src/code/GetHelper.cs index 18cd5ab29..07527819a 100644 --- a/src/code/GetHelper.cs +++ b/src/code/GetHelper.cs @@ -112,16 +112,15 @@ public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, Li foreach (string versionPath in versionsDirs) { _cmdletPassedIn.WriteVerbose(string.Format("Searching through package version path: '{0}'", versionPath)); - DirectoryInfo dirInfo = new DirectoryInfo(versionPath); - - // if the version is not valid, we'll just skip it and output a debug message - if (!NuGetVersion.TryParse(dirInfo.Name, out NuGetVersion dirAsNugetVersion)) + if(!Utils.GetVersionFromPSGetModuleInfoFile(installedPkgPath: versionPath, + isModule: true, + cmdletPassedIn: _cmdletPassedIn, + out NuGetVersion dirAsNugetVersion)) { - _cmdletPassedIn.WriteVerbose(string.Format("Leaf directory in path '{0}' cannot be parsed into a version.", versionPath)); - // skip to next iteration of the loop continue; } + _cmdletPassedIn.WriteVerbose(string.Format("Directory parsed as NuGet version: '{0}'", dirAsNugetVersion)); if (versionRange.Satisfies(dirAsNugetVersion)) @@ -150,17 +149,17 @@ public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, Li // check to make sure it's within the version range. // script versions will be parsed from the script xml file PSResourceInfo scriptInfo = OutputPackageObject(pkgPath, _scriptDictionary); - if (scriptInfo == null) + if(!Utils.GetVersionFromPSGetModuleInfoFile(installedPkgPath: pkgPath, + isModule: false, + cmdletPassedIn: _cmdletPassedIn, + out NuGetVersion dirAsNugetVersion)) { - // if script was not found skip to the next iteration of the loop - continue; + // skip to next iteration of the loop + yield return pkgPath; } - if (!NuGetVersion.TryParse(scriptInfo.Version.ToString(), out NuGetVersion scriptVersion)) - { - _cmdletPassedIn.WriteVerbose(string.Format("Version '{0}' could not be properly parsed from the script metadata file from the script installed at '{1}'", scriptInfo.Version.ToString(), scriptInfo.InstalledLocation)); - } - else if (versionRange.Satisfies(scriptVersion)) + _cmdletPassedIn.WriteVerbose(string.Format("Directory parsed as NuGet version: '{0}'", dirAsNugetVersion)); + if (versionRange.Satisfies(dirAsNugetVersion)) { _scriptDictionary.Add(pkgPath, scriptInfo); yield return pkgPath; diff --git a/src/code/GetInstalledPSResource.cs b/src/code/GetInstalledPSResource.cs index 985f57bf3..dfcd7202b 100644 --- a/src/code/GetInstalledPSResource.cs +++ b/src/code/GetInstalledPSResource.cs @@ -22,7 +22,6 @@ public sealed class GetInstalledPSResource : PSCmdlet private VersionRange _versionRange; private List _pathsToSearch; - string[] _prereleaseLabels = new string[]{}; #endregion @@ -60,8 +59,7 @@ protected override void BeginProcessing() { _versionRange = VersionRange.All; } - else if (!Utils.TryParseVersionOrVersionRange(version: Utils.GetVersionWithoutPrerelease(Version, out _prereleaseLabels), - versionRange: out _versionRange)) + else if (!Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) { var exMessage = "Argument for -Version parameter is not in the proper format."; var ex = new ArgumentException(exMessage); @@ -132,16 +130,8 @@ protected override void ProcessRecord() } GetHelper getHelper = new GetHelper(this); - string[] versionRangeParts = _versionRange.ToString().Trim(new char []{'[', ']', '(', ')'}).Split(','); - foreach (PSResourceInfo pkg in getHelper.FilterPkgPaths(namesToSearch, _versionRange, _pathsToSearch)) { - if ((_versionRange != VersionRange.All) && (!String.IsNullOrEmpty(versionRangeParts[0]) && pkg.Version.ToString().StartsWith(versionRangeParts[0]) && !String.Equals(pkg.PrereleaseLabel, _prereleaseLabels[0], StringComparison.InvariantCultureIgnoreCase)) || - (!String.IsNullOrEmpty(versionRangeParts[1]) && pkg.Version.ToString().StartsWith(versionRangeParts[1]) && !String.Equals(pkg.PrereleaseLabel, _prereleaseLabels[1], StringComparison.InvariantCultureIgnoreCase))) - { - continue; - } - WriteObject(pkg); } } diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index 9e85b4c06..9f9c5021d 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using System; -using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; @@ -56,7 +55,6 @@ public sealed class UninstallPSResource : PSCmdlet public static readonly string OsPlatform = System.Runtime.InteropServices.RuntimeInformation.OSDescription; VersionRange _versionRange; List _pathsToSearch = new List(); - string[] _prereleaseLabels = new string[]{""}; #endregion #region Methods @@ -77,8 +75,7 @@ protected override void ProcessRecord() { _versionRange = VersionRange.All; } - else if (!Utils.TryParseVersionOrVersionRange(version: Utils.GetVersionWithoutPrerelease(Version, out _prereleaseLabels), - versionRange: out _versionRange)) + else if (!Utils.TryParseVersionOrVersionRange(Version, out _versionRange)) { var exMessage = "Argument for -Version parameter is not in the proper format."; var ex = new ArgumentException(exMessage); @@ -112,12 +109,9 @@ protected override void ProcessRecord() break; case InputObjectParameterSet: - // PSResourceInfo object piped in will always have: - // specific version, not version range - // Version and PrereleaseLabel (if any) as separate properties, i.e "1.0.0-alpha" case wouldn't be piped in - _prereleaseLabels[0] = InputObject.PrereleaseLabel; - if (!Utils.TryParseVersionOrVersionRange(version: InputObject.Version.ToString(), - versionRange: out _versionRange)) + string inputObjectPrereleaseLabel = InputObject.PrereleaseLabel; + string inputObjectVersion = String.IsNullOrEmpty(inputObjectPrereleaseLabel) ? InputObject.Version.ToString() : Utils.GetNormalizedVersionString(versionString: InputObject.Version.ToString(), prerelease: inputObjectPrereleaseLabel); + if (!Utils.TryParseVersionOrVersionRange(version: inputObjectVersion, versionRange: out _versionRange)) { var exMessage = String.Format("Version '{0}' for resource '{1}' cannot be parsed.", InputObject.Version.ToString(), InputObject.Name); var ex = new ArgumentException(exMessage); @@ -143,6 +137,7 @@ protected override void ProcessRecord() } } + private bool UninstallPkgHelper() { var successfullyUninstalled = false; @@ -208,11 +203,6 @@ private bool UninstallModuleHelper(string pkgPath, string pkgName, out ErrorReco errRecord = null; var successfullyUninstalledPkg = false; - if (!CheckIfPrerelease(isModule: true, pkgName: pkgName, pkgPath: pkgPath)) - { - return false; - } - // if -Force is not specified and the pkg is a dependency for another package, // an error will be written and we return false if (!Force && CheckIfDependency(pkgName, out errRecord)) @@ -263,11 +253,6 @@ private bool UninstallScriptHelper(string pkgPath, string pkgName, out ErrorReco errRecord = null; var successfullyUninstalledPkg = false; - if (!CheckIfPrerelease(isModule: false, pkgName: pkgName, pkgPath: pkgPath)) - { - return false; - } - // delete the appropriate file try { @@ -348,26 +333,6 @@ private bool CheckIfDependency(string pkgName, out ErrorRecord errRecord) } return false; } - - private bool CheckIfPrerelease(bool isModule, string pkgPath, string pkgName) - { - string PSGetModuleInfoFilePath = isModule ? Path.Combine(pkgPath, "PSGetModuleInfo.xml") : Path.Combine(Path.GetDirectoryName(pkgPath), "InstalledScriptInfos", pkgName + "_InstalledScriptInfo.xml"); - if (!PSResourceInfo.TryRead(PSGetModuleInfoFilePath, out PSResourceInfo psGetInfo, out string errorMsg)) - { - return false; - } - - string[] versionRangeParts = _versionRange.ToString().Trim(new char []{'[', ']', '(', ')'}).Split(','); - if ((_versionRange != VersionRange.All) && - (psGetInfo.Version.ToString().StartsWith(versionRangeParts[0]) && !String.Equals(psGetInfo.PrereleaseLabel, _prereleaseLabels[0], StringComparison.InvariantCultureIgnoreCase)) || - (psGetInfo.Version.ToString().StartsWith(versionRangeParts[1]) && !String.Equals(psGetInfo.PrereleaseLabel, _prereleaseLabels[1], StringComparison.InvariantCultureIgnoreCase))) - { - return false; - } - - return true; - } - #endregion } } diff --git a/src/code/Utils.cs b/src/code/Utils.cs index ebf001b08..fb984a857 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -116,51 +116,6 @@ public static string[] ProcessNameWildcards( #region Version methods - public static string GetVersionWithoutPrerelease(string versionString, out string[] prereleaseLabels) - { - List prereleaseLabelList = new List(); - if (versionString.StartsWith("[") || versionString.StartsWith("(")) - { - // this is a version range, i.e: [3.0.0-preview, ] or (2.9.0, 3.0.0-preview) - // not supported, bc you can't install versions with same core version part side by side (3.0.0, 3.0.0-preview) - string[] versionRangeParts = versionString.Trim(new char[]{'[', ']', '(', ')'}).Split(','); - List versionOnlyParts = new List(); - foreach(string indivVersion in versionRangeParts) - { - if (!String.IsNullOrEmpty(indivVersion)) - { - versionOnlyParts.Add(GetVersionWithoutPrereleaseHelper(indivVersion, out string prereleaseLabel)); - prereleaseLabelList.Add(prereleaseLabel); - } - else - { - // prereleaseLabelList always has 2 entries, they might just be empty strings - versionOnlyParts.Add(String.Empty); - prereleaseLabelList.Add(String.Empty); - } - } - prereleaseLabels = prereleaseLabelList.ToArray(); - return versionString.Substring(0, 1) + String.Join(",", versionOnlyParts) + versionString.Substring(versionString.Length-1); - } - - // just a specific version - prereleaseLabels = new string[]{""}; - return GetVersionWithoutPrereleaseHelper(versionString, out prereleaseLabels[0]); - } - - public static string GetVersionWithoutPrereleaseHelper(string versionString, out string prereleaseLabel) - { - if (versionString.Contains("-")) - { - string[] versionParts = versionString.Split('-'); - prereleaseLabel = versionParts[1]; - return versionParts[0]; - } - - prereleaseLabel = String.Empty; - return versionString; - } - public static string GetNormalizedVersionString( string versionString, string prerelease) @@ -225,6 +180,45 @@ public static bool TryParseVersionOrVersionRange( return VersionRange.TryParse(version, out versionRange); } + public static bool GetVersionFromPSGetModuleInfoFile( + string installedPkgPath, + bool isModule, + PSCmdlet cmdletPassedIn, + out NuGetVersion pkgNuGetVersion) + { + // for Modules, installedPkgPath will look like this: + // ./PowerShell/Modules/test_module/3.0.0 + // for Scripts, installedPkgPath will look like this: + // ./PowerShell/Scripts/test_script.ps1 + + string pkgName = String.Empty; + if (!isModule) + { + pkgName = Utils.GetInstalledPackageName(installedPkgPath); + } + + string PSGetModuleInfoFilePath = isModule ? Path.Combine(installedPkgPath, "PSGetModuleInfo.xml") : Path.Combine((new DirectoryInfo(installedPkgPath).Parent).FullName, "InstalledScriptInfos", $"{pkgName}_InstalledScriptInfo.xml"); + if (!PSResourceInfo.TryRead(PSGetModuleInfoFilePath, out PSResourceInfo psGetInfo, out string errorMsg)) + { + cmdletPassedIn.WriteVerbose(String.Format("The PSGetModuleInfo.xml file found at location: {0} cannot be parsed due to {1}", PSGetModuleInfoFilePath, errorMsg)); + NuGetVersion.TryParse(installedPkgPath, out pkgNuGetVersion); + return false; + } + + string version = psGetInfo.Version.ToString(); + string prereleaseLabel = psGetInfo.PrereleaseLabel; + + if (!NuGetVersion.TryParse( + value: String.IsNullOrEmpty(prereleaseLabel) ? version : GetNormalizedVersionString(version, prereleaseLabel), + version: out pkgNuGetVersion)) + { + cmdletPassedIn.WriteVerbose(String.Format("Leaf directory in path '{0}' cannot be parsed into a version.", installedPkgPath)); + return false; + } + + return true; + } + #endregion #region Url methods diff --git a/test/UninstallPSResource.Tests.ps1 b/test/UninstallPSResource.Tests.ps1 index 1f4c24431..225623dcf 100644 --- a/test/UninstallPSResource.Tests.ps1 +++ b/test/UninstallPSResource.Tests.ps1 @@ -204,9 +204,6 @@ Describe 'Test Uninstall-PSResource for Modules' { It "Uninstall PSResourceInfo object piped in for prerelease version object" { Install-PSResource -Name $testModuleName -Version "4.5.2-alpha001" -Repository $TestGalleryName - # Powershell cannot create install locations indicating a prerelease version (with prerelease label indicated in install location). - # To test we can uninstall prerelease versions, we must use the numeric part of the prerelease version only and it must be unique - # of all versions installed for that module. Get-InstalledPSResource -Name $testModuleName -Version "4.5.2-alpha001" | Uninstall-PSResource $res = Get-InstalledPSResource -Name $testModuleName -Version "4.5.2-alpha001" $res | Should -BeNullOrEmpty From 73a4319bee90cf2e1d22f728d5add7b8ad57c5ba Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Wed, 3 Nov 2021 13:19:38 -0400 Subject: [PATCH 13/14] PR feedback: renamed variables, added comments, not set NuGetVersion if returning false --- src/code/GetHelper.cs | 4 ++-- src/code/UninstallPSResource.cs | 4 +++- src/code/Utils.cs | 26 +++++++++++++++----------- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/code/GetHelper.cs b/src/code/GetHelper.cs index 07527819a..672361998 100644 --- a/src/code/GetHelper.cs +++ b/src/code/GetHelper.cs @@ -112,7 +112,7 @@ public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, Li foreach (string versionPath in versionsDirs) { _cmdletPassedIn.WriteVerbose(string.Format("Searching through package version path: '{0}'", versionPath)); - if(!Utils.GetVersionFromPSGetModuleInfoFile(installedPkgPath: versionPath, + if(!Utils.GetVersionForInstallPath(installedPkgPath: versionPath, isModule: true, cmdletPassedIn: _cmdletPassedIn, out NuGetVersion dirAsNugetVersion)) @@ -149,7 +149,7 @@ public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, Li // check to make sure it's within the version range. // script versions will be parsed from the script xml file PSResourceInfo scriptInfo = OutputPackageObject(pkgPath, _scriptDictionary); - if(!Utils.GetVersionFromPSGetModuleInfoFile(installedPkgPath: pkgPath, + if(!Utils.GetVersionForInstallPath(installedPkgPath: pkgPath, isModule: false, cmdletPassedIn: _cmdletPassedIn, out NuGetVersion dirAsNugetVersion)) diff --git a/src/code/UninstallPSResource.cs b/src/code/UninstallPSResource.cs index 9f9c5021d..7964c0deb 100644 --- a/src/code/UninstallPSResource.cs +++ b/src/code/UninstallPSResource.cs @@ -111,7 +111,9 @@ protected override void ProcessRecord() case InputObjectParameterSet: string inputObjectPrereleaseLabel = InputObject.PrereleaseLabel; string inputObjectVersion = String.IsNullOrEmpty(inputObjectPrereleaseLabel) ? InputObject.Version.ToString() : Utils.GetNormalizedVersionString(versionString: InputObject.Version.ToString(), prerelease: inputObjectPrereleaseLabel); - if (!Utils.TryParseVersionOrVersionRange(version: inputObjectVersion, versionRange: out _versionRange)) + if (!Utils.TryParseVersionOrVersionRange( + version: inputObjectVersion, + versionRange: out _versionRange)) { var exMessage = String.Format("Version '{0}' for resource '{1}' cannot be parsed.", InputObject.Version.ToString(), InputObject.Name); var ex = new ArgumentException(exMessage); diff --git a/src/code/Utils.cs b/src/code/Utils.cs index fb984a857..19e2ba077 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -180,28 +180,32 @@ public static bool TryParseVersionOrVersionRange( return VersionRange.TryParse(version, out versionRange); } - public static bool GetVersionFromPSGetModuleInfoFile( + public static bool GetVersionForInstallPath( string installedPkgPath, bool isModule, PSCmdlet cmdletPassedIn, out NuGetVersion pkgNuGetVersion) { + // this method returns false if the PSGetModuleInfo.xml or {pkgName}_InstalledScriptInfo.xml file + // could not be parsed properly, or the version from it could not be parsed into a NuGetVersion. + // In this case the caller method (i.e GetHelper.FilterPkgPathsByVersion()) should skip the current + // installed package path or reassign NuGetVersion variable passed in to a non-null value as it sees fit. + // for Modules, installedPkgPath will look like this: // ./PowerShell/Modules/test_module/3.0.0 // for Scripts, installedPkgPath will look like this: // ./PowerShell/Scripts/test_script.ps1 + string pkgName = isModule ? String.Empty : Utils.GetInstalledPackageName(installedPkgPath); - string pkgName = String.Empty; - if (!isModule) - { - pkgName = Utils.GetInstalledPackageName(installedPkgPath); - } - - string PSGetModuleInfoFilePath = isModule ? Path.Combine(installedPkgPath, "PSGetModuleInfo.xml") : Path.Combine((new DirectoryInfo(installedPkgPath).Parent).FullName, "InstalledScriptInfos", $"{pkgName}_InstalledScriptInfo.xml"); - if (!PSResourceInfo.TryRead(PSGetModuleInfoFilePath, out PSResourceInfo psGetInfo, out string errorMsg)) + string packageInfoXMLFilePath = isModule ? Path.Combine(installedPkgPath, "PSGetModuleInfo.xml") : Path.Combine((new DirectoryInfo(installedPkgPath).Parent).FullName, "InstalledScriptInfos", $"{pkgName}_InstalledScriptInfo.xml"); + if (!PSResourceInfo.TryRead(packageInfoXMLFilePath, out PSResourceInfo psGetInfo, out string errorMsg)) { - cmdletPassedIn.WriteVerbose(String.Format("The PSGetModuleInfo.xml file found at location: {0} cannot be parsed due to {1}", PSGetModuleInfoFilePath, errorMsg)); - NuGetVersion.TryParse(installedPkgPath, out pkgNuGetVersion); + cmdletPassedIn.WriteVerbose(String.Format( + "The {0} file found at location: {1} cannot be parsed due to {2}", + isModule ? "PSGetModuleInfo.xml" : $"{pkgName}_InstalledScriptInfo.xml", + packageInfoXMLFilePath, + errorMsg)); + pkgNuGetVersion = null; return false; } From c65a357133e590e76319e192345933c3aeca1e20 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Thu, 4 Nov 2021 18:08:16 -0400 Subject: [PATCH 14/14] change variable names from dir to package for NuGet version related variables and messages --- src/code/GetHelper.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/code/GetHelper.cs b/src/code/GetHelper.cs index 672361998..39881b633 100644 --- a/src/code/GetHelper.cs +++ b/src/code/GetHelper.cs @@ -115,15 +115,15 @@ public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, Li if(!Utils.GetVersionForInstallPath(installedPkgPath: versionPath, isModule: true, cmdletPassedIn: _cmdletPassedIn, - out NuGetVersion dirAsNugetVersion)) + out NuGetVersion pkgNugetVersion)) { // skip to next iteration of the loop continue; } - _cmdletPassedIn.WriteVerbose(string.Format("Directory parsed as NuGet version: '{0}'", dirAsNugetVersion)); + _cmdletPassedIn.WriteVerbose(string.Format("Package version parsed as NuGet version: '{0}'", pkgNugetVersion)); - if (versionRange.Satisfies(dirAsNugetVersion)) + if (versionRange.Satisfies(pkgNugetVersion)) { // This will be one version or a version range. // yield results then continue with this iteration of the loop @@ -152,14 +152,14 @@ public IEnumerable FilterPkgPathsByVersion(VersionRange versionRange, Li if(!Utils.GetVersionForInstallPath(installedPkgPath: pkgPath, isModule: false, cmdletPassedIn: _cmdletPassedIn, - out NuGetVersion dirAsNugetVersion)) + out NuGetVersion pkgNugetVersion)) { // skip to next iteration of the loop yield return pkgPath; } - _cmdletPassedIn.WriteVerbose(string.Format("Directory parsed as NuGet version: '{0}'", dirAsNugetVersion)); - if (versionRange.Satisfies(dirAsNugetVersion)) + _cmdletPassedIn.WriteVerbose(string.Format("Package version parsed as NuGet version: '{0}'", pkgNugetVersion)); + if (versionRange.Satisfies(pkgNugetVersion)) { _scriptDictionary.Add(pkgPath, scriptInfo); yield return pkgPath;