From 9d0536abf97d2eb71a56521daac010bfb60966d7 Mon Sep 17 00:00:00 2001
From: Hsiao-nan Cheung <niheaven@gmail.com>
Date: Fri, 17 May 2024 09:56:14 +0800
Subject: [PATCH] refactor(decompress): Use 7zip to extract Zstd archive
 (#5973)

---
 CHANGELOG.md                           |   1 +
 lib/core.ps1                           |   5 ++--
 lib/decompress.ps1                     |  40 ++-----------------------
 lib/depends.ps1                        |  19 ++----------
 test/Scoop-Decompress.Tests.ps1        |  37 +----------------------
 test/Scoop-Depends.Tests.ps1           |   6 ----
 test/bin/test.ps1                      |  13 --------
 test/fixtures/decompress/TestCases.zip | Bin 532697 -> 532327 bytes
 8 files changed, 9 insertions(+), 112 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5053136f2f..4c4a027211 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@
 
 ### Code Refactoring
 
+- **decompress:** Use 7zip to extract Zstd archive ([#5973](https://github.com/ScoopInstaller/Scoop/issues/5973))
 - **install:** Separate archive extraction from downloader ([#5951](https://github.com/ScoopInstaller/Scoop/issues/5951))
 - **install:** Replace 'run_(un)installer()' with 'Invoke-Installer()' ([#5968](https://github.com/ScoopInstaller/Scoop/issues/5968), [#5971](https://github.com/ScoopInstaller/Scoop/issues/5971))
 
diff --git a/lib/core.ps1 b/lib/core.ps1
index 22bac33920..e9311eb9cf 100644
--- a/lib/core.ps1
+++ b/lib/core.ps1
@@ -498,7 +498,7 @@ function Get-HelperPath {
     [OutputType([String])]
     param(
         [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
-        [ValidateSet('Git', '7zip', 'Lessmsi', 'Innounp', 'Dark', 'Aria2', 'Zstd')]
+        [ValidateSet('Git', '7zip', 'Lessmsi', 'Innounp', 'Dark', 'Aria2')]
         [String]
         $Helper
     )
@@ -525,7 +525,6 @@ function Get-HelperPath {
                 }
             }
             'Aria2' { $HelperPath = Get-AppFilePath 'aria2' 'aria2c.exe' }
-            'Zstd' { $HelperPath = Get-AppFilePath 'zstd' 'zstd.exe' }
         }
 
         return $HelperPath
@@ -572,7 +571,7 @@ function Test-HelperInstalled {
     [CmdletBinding()]
     param(
         [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
-        [ValidateSet('7zip', 'Lessmsi', 'Innounp', 'Dark', 'Aria2', 'Zstd')]
+        [ValidateSet('7zip', 'Lessmsi', 'Innounp', 'Dark', 'Aria2')]
         [String]
         $Helper
     )
diff --git a/lib/decompress.ps1 b/lib/decompress.ps1
index 3553621ced..968f6196f0 100644
--- a/lib/decompress.ps1
+++ b/lib/decompress.ps1
@@ -45,13 +45,7 @@ function Invoke-Extraction {
                 }
                 continue
             }
-            { Test-ZstdRequirement -Uri $_ } {
-                # Check Zstd first
-                $extractFn = 'Expand-ZstdArchive'
-                continue
-            }
             { Test-7zipRequirement -Uri $_ } {
-                # Then check 7zip
                 $extractFn = 'Expand-7zipArchive'
                 continue
             }
@@ -164,37 +158,9 @@ function Expand-ZstdArchive {
         [Switch]
         $Removal
     )
-    $ZstdPath = Get-HelperPath -Helper Zstd
-    $LogPath = Join-Path (Split-Path $Path) 'zstd.log'
-    $DestinationPath = $DestinationPath.TrimEnd('\')
-    ensure $DestinationPath | Out-Null
-    $ArgList = @('-d', $Path, '--output-dir-flat', $DestinationPath, '-f', '-v')
-
-    if ($Switches) {
-        $ArgList += (-split $Switches)
-    }
-    if ($Removal) {
-        # Remove original archive file
-        $ArgList += '--rm'
-    }
-    $Status = Invoke-ExternalCommand $ZstdPath $ArgList -LogPath $LogPath
-    if (!$Status) {
-        abort "Failed to extract files from $Path.`nLog file:`n  $(friendly_path $LogPath)`n$(new_issue_msg $app $bucket 'decompress error')"
-    }
-    $IsTar = (strip_ext $Path) -match '\.tar$'
-    if ($IsTar) {
-        # Check for tar
-        $TarFile = Join-Path $DestinationPath (strip_ext (fname $Path))
-        Expand-7zipArchive -Path $TarFile -DestinationPath $DestinationPath -ExtractDir $ExtractDir -Removal
-    }
-    if (!$IsTar -and $ExtractDir) {
-        movedir (Join-Path $DestinationPath $ExtractDir) $DestinationPath | Out-Null
-        # Remove temporary directory
-        Remove-Item "$DestinationPath\$($ExtractDir -replace '[\\/].*')" -Recurse -Force -ErrorAction Ignore
-    }
-    if (Test-Path $LogPath) {
-        Remove-Item $LogPath -Force
-    }
+    # TODO: Remove this function after 2024/12/31
+    Show-DeprecatedWarning $MyInvocation 'Expand-7zipArchive'
+    Expand-7zipArchive -Path $Path -DestinationPath $DestinationPath -ExtractDir $ExtractDir -Switches $Switches -Removal:$Removal
 }
 
 function Expand-MsiArchive {
diff --git a/lib/depends.ps1 b/lib/depends.ps1
index bd4ed19cf2..3a38ca2b23 100644
--- a/lib/depends.ps1
+++ b/lib/depends.ps1
@@ -118,11 +118,8 @@ function Get-InstallationHelper {
         if ($script -like '*Expand-DarkArchive *') {
             $helper += 'dark'
         }
-        if ((Test-ZstdRequirement -Uri $url) -or ($script -like '*Expand-ZstdArchive *')) {
-            $helper += 'zstd'
-        }
         if (!$All) {
-            '7zip', 'lessmsi', 'innounp', 'dark', 'zstd' | ForEach-Object {
+            '7zip', 'lessmsi', 'innounp', 'dark' | ForEach-Object {
                 if (Test-HelperInstalled -Helper $_) {
                     $helper = $helper -ne $_
                 }
@@ -144,22 +141,10 @@ function Test-7zipRequirement {
         $Uri
     )
     return ($Uri | Where-Object {
-            $_ -match '\.((gz)|(tar)|(t[abgpx]z2?)|(lzma)|(bz2?)|(7z)|(001)|(rar)|(iso)|(xz)|(lzh)|(nupkg))(\.[^\d.]+)?$'
+            $_ -match '\.(001|7z|bz(ip)?2?|gz|img|iso|lzma|lzh|nupkg|rar|tar|t[abgpx]z2?|t?zst|xz)(\.[^\d.]+)?$'
         }).Count -gt 0
 }
 
-function Test-ZstdRequirement {
-    [CmdletBinding()]
-    [OutputType([Boolean])]
-    param (
-        [Parameter(Mandatory = $true)]
-        [AllowNull()]
-        [String[]]
-        $Uri
-    )
-    return ($Uri | Where-Object { $_ -match '\.zst$' }).Count -gt 0
-}
-
 function Test-LessmsiRequirement {
     [CmdletBinding()]
     [OutputType([Boolean])]
diff --git a/test/Scoop-Decompress.Tests.ps1 b/test/Scoop-Decompress.Tests.ps1
index 86220af5cb..4ec31a4ece 100644
--- a/test/Scoop-Decompress.Tests.ps1
+++ b/test/Scoop-Decompress.Tests.ps1
@@ -25,7 +25,7 @@ Describe 'Decompression function' -Tag 'Scoop', 'Windows', 'Decompress' {
         }
         It 'Test cases should exist and hash should match' {
             $testcases | Should -Exist
-            (Get-FileHash -Path $testcases -Algorithm SHA256).Hash.ToLower() | Should -Be '23a23a63e89ff95f5ef27f0cacf08055c2779cf41932266d8f509c2e200b8b63'
+            (Get-FileHash -Path $testcases -Algorithm SHA256).Hash.ToLower() | Should -Be 'afb86b0552187b8d630ce25d02835fb809af81c584f07e54cb049fb74ca134b6'
         }
         It 'Test cases should be extracted correctly' {
             { Microsoft.PowerShell.Archive\Expand-Archive -Path $testcases -DestinationPath $working_dir } | Should -Not -Throw
@@ -152,41 +152,6 @@ Describe 'Decompression function' -Tag 'Scoop', 'Windows', 'Decompress' {
         }
     }
 
-    Context 'zstd extraction' {
-
-        BeforeAll {
-            if ($env:CI) {
-                Mock Get-AppFilePath { $env:SCOOP_ZSTD_PATH } -ParameterFilter { $Helper -eq 'zstd' }
-                Mock Get-AppFilePath { '7z.exe' } -ParameterFilter { $Helper -eq '7zip' }
-            } elseif (!(installed zstd)) {
-                scoop install zstd
-            }
-
-            $test1 = "$working_dir\ZstdTest.zst"
-            $test2 = "$working_dir\ZstdTest.tar.zst"
-        }
-
-        It 'extract normal compressed file' {
-            $to = test_extract 'Expand-ZstdArchive' $test1
-            $to | Should -Exist
-            "$to\ZstdTest" | Should -Exist
-            (Get-ChildItem $to).Count | Should -Be 1
-        }
-
-        It 'extract nested compressed file' {
-            $to = test_extract 'Expand-ZstdArchive' $test2
-            $to | Should -Exist
-            "$to\ZstdTest" | Should -Exist
-            (Get-ChildItem $to).Count | Should -Be 1
-        }
-
-        It 'works with "-Removal" switch ($removal param)' {
-            $test1 | Should -Exist
-            test_extract 'Expand-ZstdArchive' $test1 $true
-            $test1 | Should -Not -Exist
-        }
-    }
-
     Context 'msi extraction' {
 
         BeforeAll {
diff --git a/test/Scoop-Depends.Tests.ps1 b/test/Scoop-Depends.Tests.ps1
index d80d7d2652..79b868ef90 100644
--- a/test/Scoop-Depends.Tests.ps1
+++ b/test/Scoop-Depends.Tests.ps1
@@ -14,11 +14,6 @@ Describe 'Package Dependencies' -Tag 'Scoop' {
             Test-7zipRequirement -Uri 'test.bin' | Should -BeFalse
             Test-7zipRequirement -Uri @('test.xz', 'test.bin') | Should -BeTrue
         }
-        It 'Test Zstd requirement' {
-            Test-ZstdRequirement -Uri 'test.zst' | Should -BeTrue
-            Test-ZstdRequirement -Uri 'test.bin' | Should -BeFalse
-            Test-ZstdRequirement -Uri @('test.zst', 'test.bin') | Should -BeTrue
-        }
         It 'Test lessmsi requirement' {
             Mock get_config { $true }
             Test-LessmsiRequirement -Uri 'test.msi' | Should -BeTrue
@@ -27,7 +22,6 @@ Describe 'Package Dependencies' -Tag 'Scoop' {
         }
         It 'Allow $Uri be $null' {
             Test-7zipRequirement -Uri $null | Should -BeFalse
-            Test-ZstdRequirement -Uri $null | Should -BeFalse
             Test-LessmsiRequirement -Uri $null | Should -BeFalse
         }
     }
diff --git a/test/bin/test.ps1 b/test/bin/test.ps1
index ffb35351a7..a25940ccb9 100644
--- a/test/bin/test.ps1
+++ b/test/bin/test.ps1
@@ -70,19 +70,6 @@ if ($env:CI -eq $true) {
                 Invoke-WebRequest -Uri $source -OutFile $destination
                 & 7z.exe x "$env:SCOOP_HELPERS_PATH\innounp.rar" -o"$env:SCOOP_HELPERS_PATH\innounp" -y | Out-Null
             }
-
-            # Only download zstd for AppVeyor, GitHub Actions has zstd installed by default
-            if ($env:BHBuildSystem -eq 'AppVeyor') {
-                $env:SCOOP_ZSTD_PATH = "$env:SCOOP_HELPERS_PATH\zstd\zstd.exe"
-                if (!(Test-Path $env:SCOOP_ZSTD_PATH)) {
-                    $source = 'https://github.com/facebook/zstd/releases/download/v1.5.1/zstd-v1.5.1-win32.zip'
-                    $destination = "$env:SCOOP_HELPERS_PATH\zstd.zip"
-                    Invoke-WebRequest -Uri $source -OutFile $destination
-                    & 7z.exe x "$env:SCOOP_HELPERS_PATH\zstd.zip" -o"$env:SCOOP_HELPERS_PATH\zstd" -y | Out-Null
-                }
-            } else {
-                $env:SCOOP_ZSTD_PATH = (Get-Command zstd.exe).Path
-            }
         }
     }
 
diff --git a/test/fixtures/decompress/TestCases.zip b/test/fixtures/decompress/TestCases.zip
index d558faac39f56ea74413651db246885badf93995..d2cd98c0f2340427f32cdbc031b6fcfd91f073d9 100644
GIT binary patch
delta 78
zcmcb4P~rJLg@zW!7N!>F7M2#)7Pc+yF|(%kD{x3{*O<+|v}Jm)0*9Jf#4L6OzhKYc
ekksN5z0``-0B=?{1|Z-E!c0~Mh8L0?Kpp@lOBM+L

delta 442
zcmaF9PvPc4g@zW!7N!>F7M2#)7Pc+yF|+Eq7(jq!$=u-fiaUD(fou>K0OF|Pl9Z6t
z;u5`*#3H?_;u4Lm`hOWZT$vc2Fu|l43=9nn%uGxe3>XZJj13J9&CQL?jm%BV7!(W`
zN{fLS84L^<I2o24;7>4aW_-zDel|p#k!>9dgSADYa)388i!sFh?ThCIhrc=_$O*I;
zgn5wdhuW>cz{tP=(lcFFo<nMT*(~;@E%o*cxICZ&Gy((^fH-0nJBD|-z%mR#LnRm(
zLKG!7{JG9}$WH8<TgDAI9pKH#1hWCti9j37K{kL5x{hoG(8Vam->f~n9%%gjgH2J2
t%{LgYrA`-==P*#?n$6DO7wj1f4&~H})BtZ*HjsIOK&T01&645(@&J&&Z}$KI