From 2745260fa55eb7e9a1be8edcdc423f2daf87df1a Mon Sep 17 00:00:00 2001 From: AdmiringWorm Date: Fri, 20 May 2022 12:57:10 +0200 Subject: [PATCH 1/3] (#1956) Ignore versioned directories in Local Repository This commit updates the ChocolateyLocalPackageRepository to allow a property being set which allows our code to control whether any directories that are versioned (side by side installed) to be ignored. This is done to prevent NuGet Core throwing an error when it finds multiple package versions of the same package being installed. --- .../nuget/ChocolateyLocalPackageRepository.cs | 49 +++++++++++++++++++ .../services/NugetService.cs | 9 +++- 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/chocolatey/infrastructure.app/nuget/ChocolateyLocalPackageRepository.cs b/src/chocolatey/infrastructure.app/nuget/ChocolateyLocalPackageRepository.cs index 71e5ec6d84..9618906071 100644 --- a/src/chocolatey/infrastructure.app/nuget/ChocolateyLocalPackageRepository.cs +++ b/src/chocolatey/infrastructure.app/nuget/ChocolateyLocalPackageRepository.cs @@ -48,6 +48,42 @@ public ChocolateyLocalPackageRepository(IPackagePathResolver pathResolver, IFile { } + public bool IgnoreVersionedDirectories { get; set; } + + public override IQueryable GetPackages() + { + var packages = base.GetPackages(); + + if (IgnoreVersionedDirectories) + { + packages = packages.Where(ExcludeVersionedDirectories).ToList().AsQueryable(); + } + + return packages; + } + + public override IPackage FindPackage(string packageId, SemanticVersion version) + { + if (IgnoreVersionedDirectories) + { + return FindPackagesById(packageId).FirstOrDefault(package => package.Version >= version); + } + + return base.FindPackage(packageId, version); + } + + public override IEnumerable FindPackagesById(string packageId) + { + var packages = base.FindPackagesById(packageId); + + if (IgnoreVersionedDirectories) + { + packages = packages.Where(ExcludeVersionedDirectories); + } + + return packages; + } + public override void AddPackage(IPackage package) { string packageFilePath = GetPackageFilePath(package); @@ -72,6 +108,19 @@ public override void AddPackage(IPackage package) } } + private bool ExcludeVersionedDirectories(IPackage package) + { + var directoryPath = PathResolver.GetInstallPath(package); + if (string.IsNullOrWhiteSpace(directoryPath)) + { + return true; + } + + var directoryName = Path.GetFileName(directoryPath); + + return string.Compare(directoryName, package.Id + "." + package.Version, StringComparison.OrdinalIgnoreCase) != 0; + } + private string GetManifestFilePath(string packageId, SemanticVersion version) { string packageDirectory = PathResolver.GetPackageDirectory(packageId, version); diff --git a/src/chocolatey/infrastructure.app/services/NugetService.cs b/src/chocolatey/infrastructure.app/services/NugetService.cs index c6d546c2fd..18fcae7b19 100644 --- a/src/chocolatey/infrastructure.app/services/NugetService.cs +++ b/src/chocolatey/infrastructure.app/services/NugetService.cs @@ -1,4 +1,4 @@ -// Copyright © 2017 - 2021 Chocolatey Software, Inc +// Copyright © 2017 - 2021 Chocolatey Software, Inc // Copyright © 2011 - 2017 RealDimensions Software, LLC // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -618,6 +618,13 @@ public virtual ConcurrentDictionary upgrade_run(Chocolate uninstallSuccessAction: null, addUninstallHandler: false); + var localRepository = packageManager.LocalRepository as ChocolateyLocalPackageRepository; + + if (localRepository != null) + { + localRepository.IgnoreVersionedDirectories = !config.AllowMultipleVersions; + } + var configIgnoreDependencies = config.IgnoreDependencies; set_package_names_if_all_is_specified(config, () => { config.IgnoreDependencies = true; }); config.IgnoreDependencies = configIgnoreDependencies; From 99fd2c2c9d714972bda8cfcf0748d4b27d3584e2 Mon Sep 17 00:00:00 2001 From: AdmiringWorm Date: Fri, 20 May 2022 12:57:47 +0200 Subject: [PATCH 2/3] (maint) Formatting + whitespace fix --- .../infrastructure.app/services/NugetService.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/chocolatey/infrastructure.app/services/NugetService.cs b/src/chocolatey/infrastructure.app/services/NugetService.cs index 18fcae7b19..eefca22520 100644 --- a/src/chocolatey/infrastructure.app/services/NugetService.cs +++ b/src/chocolatey/infrastructure.app/services/NugetService.cs @@ -1,4 +1,4 @@ -// Copyright © 2017 - 2021 Chocolatey Software, Inc +// Copyright © 2017 - 2021 Chocolatey Software, Inc // Copyright © 2011 - 2017 RealDimensions Software, LLC // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,25 +19,24 @@ namespace chocolatey.infrastructure.app.services using System; using System.Collections.Concurrent; using System.Collections.Generic; - using System.Globalization; using System.IO; using System.Linq; using System.Net; - using NuGet; using adapters; + using chocolatey.infrastructure.app.utility; using commandline; using configuration; using domain; using guards; using logging; using nuget; + using NuGet; using platforms; using results; using tolerance; using DateTime = adapters.DateTime; using Environment = System.Environment; using IFileSystem = filesystem.IFileSystem; - using chocolatey.infrastructure.app.utility; //todo: #2575 - this monolith is too large. Refactor once test coverage is up. @@ -934,7 +933,7 @@ public virtual ConcurrentDictionary get_outdated(Chocolat config.Prerelease = true; } - SemanticVersion version = null; + SemanticVersion version = null; var latestPackage = NugetList.find_package(packageName, null, config, packageManager.SourceRepository); if (latestPackage == null) @@ -1119,7 +1118,7 @@ public virtual void remove_packaging_files_prior_to_upgrade(string directoryPath // script could be incorrectly left in place during an upgrade operation. To guard against this, // remove any Chocolatey Packaging scripts, which will then be restored by the new package, if // they are still required - var filesToDelete = new List {"chocolateyinstall", "chocolateyuninstall", "chocolateybeforemodify"}; + var filesToDelete = new List { "chocolateyinstall", "chocolateyuninstall", "chocolateybeforemodify" }; var packagingScripts = _fileSystem.get_files(directoryPath, "*.ps1", SearchOption.AllDirectories) .Where(p => filesToDelete.Contains(_fileSystem.get_file_name_without_extension(p).to_lower())); From 3d5c4a5b7472f09a53122673809dfd9a40181664 Mon Sep 17 00:00:00 2001 From: AdmiringWorm Date: Fri, 20 May 2022 12:58:17 +0200 Subject: [PATCH 3/3] (#1956) Add e2e tests for SXS installations --- .../chocolatey-tests/choco-upgrade.Tests.ps1 | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 tests/chocolatey-tests/choco-upgrade.Tests.ps1 diff --git a/tests/chocolatey-tests/choco-upgrade.Tests.ps1 b/tests/chocolatey-tests/choco-upgrade.Tests.ps1 new file mode 100644 index 0000000000..96809a3e09 --- /dev/null +++ b/tests/chocolatey-tests/choco-upgrade.Tests.ps1 @@ -0,0 +1,155 @@ +Import-Module helpers/common-helpers + +Describe "choco upgrade" -Tag Chocolatey, UpgradeCommand { + BeforeAll { + Initialize-ChocolateyTestInstall + + New-ChocolateyInstallSnapshot + } + + AfterAll { + Remove-ChocolateyTestInstall + } + + Context "Can upgrade packages with dependencies containing side by side installations and outdated dependency" { + BeforeAll { + Restore-ChocolateyInstallSnapshot + + $null = Invoke-Choco install chocolatey-core.extension --version 1.3.0 --confirm + $null = Invoke-Choco install 7zip --version 16.04 --confirm + $null = Invoke-Choco install chocolatey-core.extension --version 1.3.5.1 --sxs --confirm + + $Output = Invoke-Choco upgrade 7zip --version 21.7 --confirm + } + + AfterAll { + $null = Invoke-Choco uninstall 7zip 7zip.install --confirm + } + + It "Exits with Success (0)" { + $Output.ExitCode | Should -Be 0 -Because $Output.String + } + + It "Upgrades version of the package " -ForEach @( + @{ Name = "7zip"; OldVersion = "16.04" } + @{ Name = "7zip.install"; OldVersion = "16.04" } + @{ Name = "chocolatey-core.extension"; OldVersion = "1.3.0" } + ) { + "$env:ChocolateyInstall\lib\$Name\$Name.nuspec" | Should -Exist + [xml]$XML = Get-Content "$env:ChocolateyInstall\lib\$Name\$Name.nuspec" + $XML.package.metadata.version | Should -Not -Be $OldVersion + } + + It "Have not upgraded side by side installation of v" -ForEach @( + @{ Name = "chocolatey-core.extension"; Version = "1.3.5.1" } + ) { + "$env:ChocolateyInstall\lib\$Name.$Version\$Name.$Version.nupkg" | Should -Exist + [xml]$XML = Get-Content "$env:ChocolateyInstall\lib\$Name.$Version\$Name.$Version.nuspec" + $XML.package.metadata.id | Should -Be $Name + $XML.package.metadata.version | Should -Be $Version + } + + It "Outputs a message showing that upgrading was successful" { + $Output.String | SHould -Match "Chocolatey upgraded 3/3 packages\." + } + } + + Context "Can upgrade packages with dependencies containing side by side installations and up to date dependency" { + BeforeAll { + Restore-ChocolateyInstallSnapshot + + $null = Invoke-Choco install chocolatey-core.extension --version 1.3.3 --confirm + $null = Invoke-Choco install 7zip --version 16.04 --confirm + $null = Invoke-Choco install chocolatey-core.extension --version 1.3.5.1 --sxs --confirm + + $Output = Invoke-Choco upgrade 7zip --version 21.7 --confirm + } + + AfterAll { + $null = Invoke-Choco uninstall 7zip 7zip.install --confirm + } + + It "Exits with Success (0)" { + $Output.ExitCode | Should -Be 0 -Because $Output.String + } + + It "Upgrades version of the package " -ForEach @( + @{ Name = "7zip"; OldVersion = "16.04" } + @{ Name = "7zip.install"; OldVersion = "16.04" } + ) { + "$env:ChocolateyInstall\lib\$Name\$Name.nuspec" | Should -Exist + [xml]$XML = Get-Content "$env:ChocolateyInstall\lib\$Name\$Name.nuspec" + $XML.package.metadata.version | Should -Not -Be $OldVersion + } + + It "Have not upgraded dependency " { + "$env:ChocolateyInstall\lib\chocolatey-core.extension\chocolatey-core.extension.nupkg" | Should -Exist + [xml]$XML = Get-Content "$env:ChocolateyInstall\lib\chocolatey-core.extension\chocolatey-core.extension.nuspec" + $XML.package.metadata.id | Should -Be 'chocolatey-core.extension' + $XML.package.metadata.version | Should -Be '1.3.3' + } + + It "Have not upgraded side by side installation of v" -ForEach @( + @{ Name = "chocolatey-core.extension"; Version = "1.3.5.1" } + ) { + "$env:ChocolateyInstall\lib\$Name.$Version\$Name.$Version.nupkg" | Should -Exist + [xml]$XML = Get-Content "$env:ChocolateyInstall\lib\$Name.$Version\$Name.$Version.nuspec" + $XML.package.metadata.id | Should -Be $Name + $XML.package.metadata.version | Should -Be $Version + } + + It "Outputs a message showing that upgrading was successful" { + $Output.String | SHould -Match "Chocolatey upgraded 2/2 packages\." + } + } + + + Context "Can upgrade packages with dependencies containing outdated side by side installations and up to date dependency" { + BeforeAll { + Restore-ChocolateyInstallSnapshot + + $null = Invoke-Choco install chocolatey-core.extension --version 1.3.3 --confirm + $null = Invoke-Choco install 7zip --version 16.04 --confirm + $null = Invoke-Choco install chocolatey-core.extension --version 1.3.0 --sxs --confirm + + $Output = Invoke-Choco upgrade 7zip --version 21.7 --confirm + } + + AfterAll { + $null = Invoke-Choco uninstall 7zip 7zip.install --confirm + } + + It "Exits with Success (0)" { + $Output.ExitCode | Should -Be 0 -Because $Output.String + } + + It "Upgrades version of the package " -ForEach @( + @{ Name = "7zip"; OldVersion = "16.04" } + @{ Name = "7zip.install"; OldVersion = "16.04" } + ) { + "$env:ChocolateyInstall\lib\$Name\$Name.nuspec" | Should -Exist + [xml]$XML = Get-Content "$env:ChocolateyInstall\lib\$Name\$Name.nuspec" + $XML.package.metadata.version | Should -Not -Be $OldVersion + } + + It "Have not upgraded dependency chocolatey-core.extension" { + "$env:ChocolateyInstall\lib\chocolatey-core.extension\chocolatey-core.extension.nupkg" | Should -Exist + [xml]$XML = Get-Content "$env:ChocolateyInstall\lib\chocolatey-core.extension\chocolatey-core.extension.nuspec" + $XML.package.metadata.id | Should -Be 'chocolatey-core.extension' + $XML.package.metadata.version | Should -Be '1.3.3' + } + + It "Have not upgraded side by side installation of v" -ForEach @( + @{ Name = "chocolatey-core.extension"; Version = "1.3.0" } + ) { + "$env:ChocolateyInstall\lib\$Name.$Version\$Name.$Version.nupkg" | Should -Exist + [xml]$XML = Get-Content "$env:ChocolateyInstall\lib\$Name.$Version\$Name.$Version.nuspec" + $XML.package.metadata.id | Should -Be $Name + $XML.package.metadata.version | Should -Be $Version + } + + It "Outputs a message showing that upgrading was successful" { + $Output.String | SHould -Match "Chocolatey upgraded 2/2 packages\." + } + } +}