Skip to content

Commit e2b5aaa

Browse files
authored
Bug fix for deduping dependencies in Find-PSResource (#1382)
1 parent 27db036 commit e2b5aaa

File tree

3 files changed

+125
-27
lines changed

3 files changed

+125
-27
lines changed

src/code/FindHelper.cs

Lines changed: 100 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ internal class FindHelper
3434
private bool _includeDependencies = false;
3535
private bool _repositoryNameContainsWildcard = true;
3636
private NetworkCredential _networkCredential;
37+
private Dictionary<string, List<string>> _packagesFound;
3738

3839
#endregion
3940

@@ -46,6 +47,7 @@ public FindHelper(CancellationToken cancellationToken, PSCmdlet cmdletPassedIn,
4647
_cancellationToken = cancellationToken;
4748
_cmdletPassedIn = cmdletPassedIn;
4849
_networkCredential = networkCredential;
50+
_packagesFound = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
4951
}
5052

5153
#endregion
@@ -404,7 +406,7 @@ public IEnumerable<PSCommandResourceInfo> FindByCommandOrDscResource(
404406
{
405407
_cmdletPassedIn.WriteVerbose(errRecord.Exception.Message);
406408
}
407-
409+
408410
continue;
409411
}
410412

@@ -632,7 +634,6 @@ private IEnumerable<PSResourceInfo> SearchByNames(ServerApiCall currentServer, R
632634
{
633635
ErrorRecord errRecord = null;
634636
List<PSResourceInfo> parentPkgs = new List<PSResourceInfo>();
635-
HashSet<string> pkgsFound = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
636637
string tagsAsString = String.Empty;
637638

638639
_cmdletPassedIn.WriteDebug("In FindHelper::SearchByNames()");
@@ -677,8 +678,9 @@ private IEnumerable<PSResourceInfo> SearchByNames(ServerApiCall currentServer, R
677678
if (foundPkg.Type == _type || _type == ResourceType.None)
678679
{
679680
parentPkgs.Add(foundPkg);
680-
pkgsFound.Add(String.Format("{0}{1}", foundPkg.Name, foundPkg.Version.ToString()));
681+
TryAddToPackagesFound(foundPkg);
681682
_cmdletPassedIn.WriteDebug($"Found package '{foundPkg.Name}' version '{foundPkg.Version}'");
683+
682684
yield return foundPkg;
683685
}
684686
}
@@ -729,7 +731,8 @@ private IEnumerable<PSResourceInfo> SearchByNames(ServerApiCall currentServer, R
729731

730732
PSResourceInfo foundPkg = currentResult.returnedObject;
731733
parentPkgs.Add(foundPkg);
732-
pkgsFound.Add(String.Format("{0}{1}", foundPkg.Name, foundPkg.Version.ToString()));
734+
TryAddToPackagesFound(foundPkg);
735+
733736
yield return foundPkg;
734737
}
735738
}
@@ -778,7 +781,8 @@ private IEnumerable<PSResourceInfo> SearchByNames(ServerApiCall currentServer, R
778781

779782
PSResourceInfo foundPkg = currentResult.returnedObject;
780783
parentPkgs.Add(foundPkg);
781-
pkgsFound.Add(String.Format("{0}{1}", foundPkg.Name, foundPkg.Version.ToString()));
784+
TryAddToPackagesFound(foundPkg);
785+
782786
yield return foundPkg;
783787
}
784788
}
@@ -833,13 +837,14 @@ private IEnumerable<PSResourceInfo> SearchByNames(ServerApiCall currentServer, R
833837
"FindVersionConvertToPSResourceFailure",
834838
ErrorCategory.ObjectNotFound,
835839
this));
836-
840+
837841
continue;
838842
}
839843

840844
PSResourceInfo foundPkg = currentResult.returnedObject;
841845
parentPkgs.Add(foundPkg);
842-
pkgsFound.Add(String.Format("{0}{1}", foundPkg.Name, foundPkg.Version.ToString()));
846+
TryAddToPackagesFound(foundPkg);
847+
843848
yield return foundPkg;
844849
}
845850
}
@@ -915,7 +920,7 @@ private IEnumerable<PSResourceInfo> SearchByNames(ServerApiCall currentServer, R
915920
&& _versionRange.Satisfies(version))
916921
{
917922
parentPkgs.Add(foundPkg);
918-
pkgsFound.Add(String.Format("{0}{1}", foundPkg.Name, foundPkg.Version.ToString()));
923+
TryAddToPackagesFound(foundPkg);
919924

920925
yield return foundPkg;
921926
}
@@ -936,7 +941,7 @@ private IEnumerable<PSResourceInfo> SearchByNames(ServerApiCall currentServer, R
936941
foreach (PSResourceInfo currentPkg in parentPkgs)
937942
{
938943
_cmdletPassedIn.WriteDebug($"Finding dependency packages for '{currentPkg.Name}'");
939-
foreach (PSResourceInfo pkgDep in FindDependencyPackages(currentServer, currentResponseUtil, currentPkg, repository, pkgsFound))
944+
foreach (PSResourceInfo pkgDep in FindDependencyPackages(currentServer, currentResponseUtil, currentPkg, repository))
940945
{
941946
yield return pkgDep;
942947
}
@@ -962,6 +967,48 @@ private HashSet<string> GetPackageNamesPopulated(string[] pkgNames)
962967
return pkgsToDiscover;
963968
}
964969

970+
971+
private bool TryAddToPackagesFound(PSResourceInfo foundPkg)
972+
{
973+
bool addedToHash = false;
974+
string foundPkgName = foundPkg.Name;
975+
string foundPkgVersion = Utils.GetNormalizedVersionString(foundPkg.Version.ToString(), foundPkg.Prerelease);
976+
977+
if (_packagesFound.ContainsKey(foundPkgName))
978+
{
979+
List<string> pkgVersions = _packagesFound[foundPkgName] as List<string>;
980+
981+
if (!pkgVersions.Contains(foundPkgVersion))
982+
{
983+
pkgVersions.Add(foundPkgVersion);
984+
_packagesFound[foundPkgName] = pkgVersions;
985+
addedToHash = true;
986+
}
987+
}
988+
else
989+
{
990+
_packagesFound.Add(foundPkg.Name, new List<string> { foundPkgVersion });
991+
addedToHash = true;
992+
}
993+
994+
_cmdletPassedIn.WriteDebug($"Found package '{foundPkg.Name}' version '{foundPkg.Version}'");
995+
996+
return addedToHash;
997+
}
998+
999+
private string FormatPkgVersionString(PSResourceInfo pkg)
1000+
{
1001+
string fullPkgVersion = pkg.Version.ToString();
1002+
1003+
if (!string.IsNullOrWhiteSpace(pkg.Prerelease))
1004+
{
1005+
fullPkgVersion += $"-{pkg.Prerelease}";
1006+
}
1007+
_cmdletPassedIn.WriteDebug($"Formatted full package version is: '{fullPkgVersion}'");
1008+
1009+
return fullPkgVersion;
1010+
}
1011+
9651012
#endregion
9661013

9671014
#region Internal Client Search Methods
@@ -970,8 +1017,7 @@ internal IEnumerable<PSResourceInfo> FindDependencyPackages(
9701017
ServerApiCall currentServer,
9711018
ResponseUtil currentResponseUtil,
9721019
PSResourceInfo currentPkg,
973-
PSRepositoryInfo repository,
974-
HashSet<string> foundPkgs)
1020+
PSRepositoryInfo repository)
9751021
{
9761022
if (currentPkg.Dependencies.Length > 0)
9771023
{
@@ -1009,15 +1055,26 @@ internal IEnumerable<PSResourceInfo> FindDependencyPackages(
10091055
}
10101056

10111057
depPkg = currentResult.returnedObject;
1012-
string pkgHashKey = String.Format("{0}{1}", depPkg.Name, depPkg.Version.ToString());
10131058

1014-
if (!foundPkgs.Contains(pkgHashKey))
1059+
if (!_packagesFound.ContainsKey(depPkg.Name))
10151060
{
1016-
foreach (PSResourceInfo depRes in FindDependencyPackages(currentServer, currentResponseUtil, depPkg, repository, foundPkgs))
1061+
foreach (PSResourceInfo depRes in FindDependencyPackages(currentServer, currentResponseUtil, depPkg, repository))
10171062
{
10181063
yield return depRes;
10191064
}
10201065
}
1066+
else
1067+
{
1068+
List<string> pkgVersions = _packagesFound[depPkg.Name] as List<string>;
1069+
// _packagesFound has depPkg.name in it, but the version is not the same
1070+
if (!pkgVersions.Contains(FormatPkgVersionString(depPkg)))
1071+
{
1072+
foreach (PSResourceInfo depRes in FindDependencyPackages(currentServer, currentResponseUtil, depPkg, repository))
1073+
{
1074+
yield return depRes;
1075+
}
1076+
}
1077+
}
10211078
}
10221079
else
10231080
{
@@ -1066,7 +1123,7 @@ internal IEnumerable<PSResourceInfo> FindDependencyPackages(
10661123
if (foundDep.IsPrerelease) {
10671124
depVersionStr += $"-{foundDep.Prerelease}";
10681125
}
1069-
1126+
10701127
if (NuGetVersion.TryParse(depVersionStr, out NuGetVersion depVersion)
10711128
&& dep.VersionRange.Satisfies(depVersion))
10721129
{
@@ -1078,26 +1135,47 @@ internal IEnumerable<PSResourceInfo> FindDependencyPackages(
10781135
{
10791136
continue;
10801137
}
1081-
1082-
string pkgHashKey = String.Format("{0}{1}", depPkg.Name, depPkg.Version.ToString());
10831138

1084-
if (!foundPkgs.Contains(pkgHashKey))
1139+
if (!_packagesFound.ContainsKey(depPkg.Name))
10851140
{
1086-
foreach (PSResourceInfo depRes in FindDependencyPackages(currentServer, currentResponseUtil, depPkg, repository, foundPkgs))
1141+
foreach (PSResourceInfo depRes in FindDependencyPackages(currentServer, currentResponseUtil, depPkg, repository))
10871142
{
10881143
yield return depRes;
10891144
}
10901145
}
1146+
else {
1147+
List<string> pkgVersions = _packagesFound[depPkg.Name] as List<string>;
1148+
// _packagesFound has depPkg.name in it, but the version is not the same
1149+
if (!pkgVersions.Contains(FormatPkgVersionString(depPkg)))
1150+
{
1151+
foreach (PSResourceInfo depRes in FindDependencyPackages(currentServer, currentResponseUtil, depPkg, repository))
1152+
{
1153+
yield return depRes;
1154+
}
1155+
}
1156+
}
10911157
}
10921158
}
10931159
}
10941160

1095-
string currentPkgHashKey = String.Format("{0}{1}", currentPkg.Name, currentPkg.Version.ToString());
1096-
1097-
if (!foundPkgs.Contains(currentPkgHashKey))
1161+
if (!_packagesFound.ContainsKey(currentPkg.Name))
10981162
{
1163+
TryAddToPackagesFound(currentPkg);
1164+
10991165
yield return currentPkg;
11001166
}
1167+
else
1168+
{
1169+
List<string> pkgVersions = _packagesFound[currentPkg.Name] as List<string>;
1170+
// _packagesFound has currentPkg.name in it, but the version is not the same
1171+
if (!pkgVersions.Contains(FormatPkgVersionString(currentPkg)))
1172+
{
1173+
TryAddToPackagesFound(currentPkg);
1174+
1175+
yield return currentPkg;
1176+
}
1177+
}
1178+
11011179
}
11021180

11031181
#endregion

src/code/InstallHelper.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ private void MoveFilesIntoInstallPath(
486486
}
487487
}
488488
else
489-
{
489+
{
490490
var scriptXML = pkgInfo.Name + "_InstalledScriptInfo.xml";
491491
if (!_savePkg)
492492
{
@@ -509,8 +509,8 @@ private void MoveFilesIntoInstallPath(
509509
File.Delete(Path.Combine(finalModuleVersionDir, pkgInfo.Name + PSScriptFileExt));
510510
}
511511
}
512-
else {
513-
_cmdletPassedIn.WriteVerbose(string.Format("Moving '{0}' to '{1}'", Path.Combine(dirNameVersion, scriptXML), Path.Combine(installPath, scriptXML)));
512+
else {
513+
_cmdletPassedIn.WriteVerbose(string.Format("Moving '{0}' to '{1}'", Path.Combine(dirNameVersion, scriptXML), Path.Combine(installPath, scriptXML)));
514514
Utils.MoveFiles(Path.Combine(dirNameVersion, scriptXML), Path.Combine(installPath, scriptXML));
515515
}
516516

@@ -591,12 +591,11 @@ private List<PSResourceInfo> InstallPackages(
591591
_cmdletPassedIn.WriteWarning("Installing dependencies is not currently supported for V3 server protocol repositories. The package will be installed without installing dependencies.");
592592
}
593593

594-
HashSet<string> myHash = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
595594
// Get the dependencies from the installed package.
596595
if (parentPkgObj.Dependencies.Length > 0)
597596
{
598597
bool depFindFailed = false;
599-
foreach (PSResourceInfo depPkg in findHelper.FindDependencyPackages(currentServer, currentResponseUtil, parentPkgObj, repository, myHash))
598+
foreach (PSResourceInfo depPkg in findHelper.FindDependencyPackages(currentServer, currentResponseUtil, parentPkgObj, repository))
600599
{
601600
if (depPkg == null)
602601
{

test/FindPSResourceTests/FindPSResourceV2Server.Tests.ps1

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,4 +415,25 @@ Describe 'Test HTTP Find-PSResource for V2 Server Protocol' -tags 'ManualValidat
415415

416416
$res.Name | Should -Be $testModuleName
417417
}
418+
419+
It "find should not duplicate dependencies found" {
420+
$res = Find-PSResource -Name "Az" -IncludeDependencies -Repository $PSGalleryName
421+
$res | Should -Not -BeNullOrEmpty
422+
423+
$foundPkgs = [System.Collections.Generic.HashSet[String]]::new()
424+
$duplicatePkgsFound = $false
425+
foreach ($item in $res)
426+
{
427+
if ($foundPkgs.Contains($item.Name))
428+
{
429+
write-host "this pkg already found"
430+
$duplicatePkgsFound = $true
431+
break
432+
}
433+
434+
$foundPkgs.Add($item.Name)
435+
}
436+
437+
$duplicatePkgsFound | Should -BeFalse
438+
}
418439
}

0 commit comments

Comments
 (0)