From c906219fcb20c55f7eca65cbb09427625d95a8f1 Mon Sep 17 00:00:00 2001 From: Hsiao-nan Cheung Date: Sun, 12 May 2024 18:47:16 +0800 Subject: [PATCH] refactor(install): Separate archive extraction from downloader (#5951) --- CHANGELOG.md | 4 +++ lib/decompress.ps1 | 68 ++++++++++++++++++++++++++++++++++++++++++++++ lib/install.ps1 | 55 ++++--------------------------------- 3 files changed, 77 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ccef659319..a870da57f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,10 @@ - **core:** Fix "Invoke-ExternalCommand" quoting rules ([#5945](https://github.com/ScoopInstaller/Scoop/issues/5945)) - **scoop-info:** Fix download size estimating ([#5958](https://github.com/ScoopInstaller/Scoop/issues/5958)) +### Code Refactoring + +- **install:** Separate archive extraction from downloader ([#5951](https://github.com/ScoopInstaller/Scoop/issues/5951)) + ## [v0.4.1](https://github.com/ScoopInstaller/Scoop/compare/v0.4.0...v0.4.1) - 2024-04-25 ### Bug Fixes diff --git a/lib/decompress.ps1 b/lib/decompress.ps1 index c2b04800d5..3553621ced 100644 --- a/lib/decompress.ps1 +++ b/lib/decompress.ps1 @@ -1,3 +1,71 @@ +# Description: Functions for decompressing archives or installers + +function Invoke-Extraction { + param ( + [string] + $Path, + [string[]] + $Name, + [psobject] + $Manifest, + [Alias('Arch', 'Architecture')] + [string] + $ProcessorArchitecture + ) + + # 'url', 'extract_dir' and 'extract_to' are paired + $uri = @(url $Manifest $ProcessorArchitecture) + $extractDir = @(extract_dir $Manifest $ProcessorArchitecture) + $extractTo = @(extract_to $Manifest $ProcessorArchitecture) + + for ($i = 0; $i -lt $Name.Length; $i++) { + $fnArgs = @{ + Path = Join-Path $Path $Name[$i] + DestinationPath = Join-Path $Path $extractTo[$i] + ExtractDir = $extractDir[$i] + } + # work out extraction method, if applicable + $extractFn = $null + switch -regex ($fnArgs.Path) { + '\.zip$' { + if ((Test-HelperInstalled -Helper 7zip) -or ((get_config 7ZIPEXTRACT_USE_EXTERNAL) -and (Test-CommandAvailable 7z))) { + $extractFn = 'Expand-7zipArchive' + } else { + $extractFn = 'Expand-ZipArchive' + } + continue + } + '\.msi$' { + $extractFn = 'Expand-MsiArchive' + continue + } + '\.exe$' { + if ($Manifest.innosetup) { + $extractFn = 'Expand-InnoArchive' + } + continue + } + { Test-ZstdRequirement -Uri $_ } { + # Check Zstd first + $extractFn = 'Expand-ZstdArchive' + continue + } + { Test-7zipRequirement -Uri $_ } { + # Then check 7zip + $extractFn = 'Expand-7zipArchive' + continue + } + } + if ($extractFn) { + Write-Host 'Extracting ' -NoNewline + Write-Host $(url_remote_filename $uri[$i]) -ForegroundColor Cyan -NoNewline + Write-Host ' ... ' -NoNewline + & $extractFn @fnArgs -Removal + Write-Host 'done.' -ForegroundColor Green + } + } +} + function Expand-7zipArchive { [CmdletBinding()] param ( diff --git a/lib/install.ps1 b/lib/install.ps1 index 12d4220015..f70b1bf9e0 100644 --- a/lib/install.ps1 +++ b/lib/install.ps1 @@ -50,9 +50,10 @@ function install_app($app, $architecture, $global, $suggested, $use_cache = $tru $persist_dir = persistdir $app $global $fname = Invoke-ScoopDownload $app $version $manifest $bucket $architecture $dir $use_cache $check_hash + Invoke-Extraction -Path $dir -Name $fname -Manifest $manifest -ProcessorArchitecture $architecture Invoke-HookScript -HookType 'pre_install' -Manifest $manifest -Arch $architecture - run_installer $fname $manifest $architecture $dir $global + run_installer @($fname)[-1] $manifest $architecture $dir $global ensure_install_dir_not_in_path $dir $global $dir = link_current $dir create_shims $manifest $dir $global $architecture @@ -539,21 +540,12 @@ function Invoke-ScoopDownload ($app, $version, $manifest, $bucket, $architecture # we only want to show this warning once if (!$use_cache) { warn 'Cache is being ignored.' } - # can be multiple urls: if there are, then installer should go last, - # so that $fname is set properly + # can be multiple urls: if there are, then installer should go last to make 'installer.args' section work $urls = @(script:url $manifest $architecture) # can be multiple cookies: they will be used for all HTTP requests. $cookies = $manifest.cookie - $fname = $null - - # extract_dir and extract_to in manifest are like queues: for each url that - # needs to be extracted, will get the next dir from the queue - $extract_dirs = @(extract_dir $manifest $architecture) - $extract_tos = @(extract_to $manifest $architecture) - $extracted = 0 - # download first if (Test-Aria2Enabled) { Invoke-CachedAria2Download $app $version $manifest $architecture $dir $cookies $use_cache $check_hash @@ -587,44 +579,7 @@ function Invoke-ScoopDownload ($app, $version, $manifest, $bucket, $architecture } } - foreach ($url in $urls) { - $fname = url_filename $url - - $extract_dir = $extract_dirs[$extracted] - $extract_to = $extract_tos[$extracted] - - # work out extraction method, if applicable - $extract_fn = $null - if ($manifest.innosetup) { - $extract_fn = 'Expand-InnoArchive' - } elseif ($fname -match '\.zip$') { - # Use 7zip when available (more fast) - if (((get_config USE_EXTERNAL_7ZIP) -and (Test-CommandAvailable 7z)) -or (Test-HelperInstalled -Helper 7zip)) { - $extract_fn = 'Expand-7zipArchive' - } else { - $extract_fn = 'Expand-ZipArchive' - } - } elseif ($fname -match '\.msi$') { - $extract_fn = 'Expand-MsiArchive' - } elseif (Test-ZstdRequirement -Uri $fname) { - # Zstd first - $extract_fn = 'Expand-ZstdArchive' - } elseif (Test-7zipRequirement -Uri $fname) { - # 7zip - $extract_fn = 'Expand-7zipArchive' - } - - if ($extract_fn) { - Write-Host 'Extracting ' -NoNewline - Write-Host $fname -f Cyan -NoNewline - Write-Host ' ... ' -NoNewline - & $extract_fn -Path "$dir\$fname" -DestinationPath "$dir\$extract_to" -ExtractDir $extract_dir -Removal - Write-Host 'done.' -f Green - $extracted++ - } - } - - $fname # returns the last downloaded file + return $urls.ForEach({ url_filename $_ }) } function cookie_header($cookies) { @@ -710,7 +665,7 @@ function run_installer($fname, $manifest, $architecture, $dir, $global) { return } if ($installer) { - $prog = "$dir\$(coalesce $installer.file "$fname")" + $prog = "$dir\$(coalesce $installer.file $fname)" if (!(is_in_dir $dir $prog)) { abort "Error in manifest: Installer $prog is outside the app directory." }