Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
691c233
fix(scoop-download): Fix function `nightly_version` not defined error…
AkariiinMKII Aug 14, 2025
c9f0728
fix(autoupdate): Use origin url to handle urls with fragment in githu…
HUMORCE Aug 20, 2025
ff38652
fix(buckets|scoop-info): Switch git log date format to ISO 8601 to av…
z-Fng Aug 21, 2025
04b7ce7
fix(scoop-version): Fix logic error caused by missing brackets (#6463)
z-Fng Aug 27, 2025
25d3500
fix(core|manifest): Avoid error when searching non-existent 'deprecat…
z-Fng Sep 24, 2025
b592b38
feat(install): Add separator at the end of notes, highlight suggestio…
z-Fng Sep 24, 2025
db8d554
fix(scoop-update): Force sync tags w/ remote branch while scoop updat…
niheaven Sep 26, 2025
4c55e7a
feat(scoop-uninstall): Allow access to $bucket in uninstall scripts (…
abgox Sep 26, 2025
2a63736
fix(scoop-uninstall): Correct `-Global` switch during uninstalling/up…
HUMORCE Sep 26, 2025
ca0506c
refactor(output): Replace raw prints with functions for standardized …
abgox Sep 29, 2025
20a178b
fix(checkver): Allow script to run when URL fetch fails but script ex…
z-Fng Oct 13, 2025
19e1e3c
Fix for Expand-7zipArchive
o-l-a-v Oct 13, 2025
48782a2
Use shorter temp directory name, a GUID can be a bit long?
o-l-a-v Oct 13, 2025
2db3db8
Both zip and 7z should extract to TEMP when ExtractDir
o-l-a-v Oct 13, 2025
0192d79
Add named parameters and use $null = instead of | Out-Null
o-l-a-v Oct 13, 2025
5d39120
Added changelog item
o-l-a-v Oct 13, 2025
4deb0df
Merge branch 'develop' into 6515-fix-remove-empty-dir-recursively-wit…
o-l-a-v Oct 13, 2025
5b8b248
typo
o-l-a-v Oct 13, 2025
ebfebbf
Use the same logic as in Extract-ZipArchive
o-l-a-v Oct 13, 2025
0a117c1
Highlight that this can be a breaking change in some instances
o-l-a-v Oct 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
## [Unreleased](https://github.com/ScoopInstaller/Scoop/compare/v0.5.3...develop)

### Features

- **scoop-uninstall**: Allow access to `$bucket` in uninstall scripts ([#6380](https://github.com/ScoopInstaller/Scoop/issues/6380))
- **install:** Add separator at the end of notes, highlight suggestions ([#6418](https://github.com/ScoopInstaller/Scoop/issues/6418))

### Bug Fixes

- **scoop-download**: Fix function `nightly_version` not defined error ([#6386](https://github.com/ScoopInstaller/Scoop/issues/6386))
- **scoop-uninstall:**: Correct `-Global` Switch ([#6454](https://github.com/ScoopInstaller/Scoop/issues/6454))
- **scoop-update**: Force sync tags w/ remote branch while scoop update ([#6439](https://github.com/ScoopInstaller/Scoop/issues/6439))
- **autoupdate:** Use origin URL to handle URLs with fragment in GitHub mode ([#6455](https://github.com/ScoopInstaller/Scoop/issues/6455))
- **buckets|scoop-info:** Switch git log date format to ISO 8601 to avoid locale issues ([#6446](https://github.com/ScoopInstaller/Scoop/issues/6446))
- **scoop-version:** Fix logic error caused by missing brackets ([#6463](https://github.com/ScoopInstaller/Scoop/issues/6463))
- **core|manifest:** Avoid error messages when searching non-existent 'deprecated' directory ([#6471](https://github.com/ScoopInstaller/Scoop/issues/6471))
- **checkver:** Allow script to run when URL fetch fails but script exists ([#6490](https://github.com/ScoopInstaller/Scoop/issues/6490))

### BREAKING CHANGE

- **decompress:** Expand to temp directory if `$ExtractDir` is specified with `Expand-7zipArchive` and `Expand-ZipArchive`, to make it more robust ([#6515](https://github.com/ScoopInstaller/Scoop/issues/6515))
- Changes extraction semantics when `extract_dir` is used; manifests relying on post-extraction cleanup workarounds may need updates.

### Code Refactoring

- **output**: Replace raw prints with functions for standardized output ([#6449](https://github.com/ScoopInstaller/Scoop/issues/6449))

## [v0.5.3](https://github.com/ScoopInstaller/Scoop/compare/v0.5.2...v0.5.3) - 2025-08-11

### Features
Expand Down
11 changes: 8 additions & 3 deletions bin/checkver.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -281,11 +281,16 @@ while ($in_progress -gt 0) {
}
$err = $ev.SourceEventArgs.Error
if ($err) {
next "$($err.message)`r`nURL $url is not valid"
continue
if (!$script) {
next "$($err.message)`r`nURL $url is not valid"
continue
} else {
# Run script despite URL download failure
Write-Host "$($err.message)`r`nURL $url is not valid. Falling back to checkver.script ..."
}
}

if ($url) {
if ($url -and !$err) {
$ms = New-Object System.IO.MemoryStream
$ms.Write($result, 0, $result.Length)
$ms.Seek(0, 0) | Out-Null
Expand Down
8 changes: 4 additions & 4 deletions bin/scoop.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ switch ($subCommand) {
}
({ $subCommand -in @('-v', '--version') }) {
Write-Host 'Current Scoop version:'
if (Test-GitAvailable -and (Test-Path "$PSScriptRoot\..\.git") -and (get_config SCOOP_BRANCH 'master') -ne 'master') {
Invoke-Git -Path "$PSScriptRoot\.." -ArgumentList @('log', 'HEAD', '-1', '--oneline')
if ((Test-GitAvailable) -and (Test-Path "$PSScriptRoot\..\.git") -and ((get_config SCOOP_BRANCH 'master') -ne 'master')) {
Invoke-Git -Path "$PSScriptRoot\.." -ArgumentList @('--no-pager', 'log', 'HEAD', '-1', '--oneline')
} else {
$version = Select-String -Pattern '^## \[(v[\d.]+)\].*?([\d-]+)$' -Path "$PSScriptRoot\..\CHANGELOG.md"
Write-Host $version.Matches.Groups[1].Value -ForegroundColor Cyan -NoNewline
Expand All @@ -31,9 +31,9 @@ switch ($subCommand) {

Get-LocalBucket | ForEach-Object {
$bucketLoc = Find-BucketDirectory $_ -Root
if (Test-GitAvailable -and (Test-Path "$bucketLoc\.git")) {
if ((Test-GitAvailable) -and (Test-Path "$bucketLoc\.git")) {
Write-Host "'$_' bucket:"
Invoke-Git -Path $bucketLoc -ArgumentList @('log', 'HEAD', '-1', '--oneline')
Invoke-Git -Path $bucketLoc -ArgumentList @('--no-pager', 'log', 'HEAD', '-1', '--oneline')
Write-Host ''
}
}
Expand Down
2 changes: 1 addition & 1 deletion bin/uninstall.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ function do_uninstall($app, $global) {
$architecture = $install.architecture

Write-Output "Uninstalling '$app'"
Invoke-Installer -Path $dir -Manifest $manifest -ProcessorArchitecture $architecture -Uninstall
Invoke-Installer -Path $dir -Manifest $manifest -ProcessorArchitecture $architecture -Global:$global -Uninstall
rm_shims $app $manifest $global $architecture

# If a junction was used during install, that will have been used
Expand Down
11 changes: 7 additions & 4 deletions lib/autoupdate.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
function format_hash([String] $hash) {
$hash = $hash.toLower()

# Workaround for GitHub API:
# `"digest": "sha256:<SHA256_STRING>"`
if ($hash -like 'sha256:*') {
$hash = $hash.Substring(7) # Remove prefix 'sha256:'
}
Expand Down Expand Up @@ -209,13 +211,14 @@ function get_hash_for_app([String] $app, $config, [String] $version, [String] $u
$hash = $null

$hashmode = $config.mode
$originurl = strip_fragment $url
$basename = [System.Web.HttpUtility]::UrlDecode((url_remote_filename($url)))

$substitutions = $substitutions.Clone()
$substitutions.Add('$url', (strip_fragment $url))
$substitutions.Add('$baseurl', (strip_filename (strip_fragment $url)).TrimEnd('/'))
$substitutions.Add('$url', $originurl)
$substitutions.Add('$baseurl', (strip_filename $originurl).TrimEnd('/'))
$substitutions.Add('$basename', $basename)
$substitutions.Add('$urlNoExt', (strip_ext (strip_fragment $url)))
$substitutions.Add('$urlNoExt', (strip_ext $originurl))
$substitutions.Add('$basenameNoExt', (strip_ext $basename))

debug $substitutions
Expand Down Expand Up @@ -297,7 +300,7 @@ function get_hash_for_app([String] $app, $config, [String] $version, [String] $u
}
'github' {
$hashfile_url = "https://api.github.com/repos/$($matches['owner'])/$($matches['repo'])/releases"
$hash = find_hash_in_json $hashfile_url $substitutions ("$..assets[?(@.browser_download_url == '" + $url + "')].digest")
$hash = find_hash_in_json $hashfile_url $substitutions ("$..assets[?(@.browser_download_url == '" + $originurl + "')].digest")
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/buckets.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ function list_buckets {
$path = Find-BucketDirectory $_ -Root
if ((Test-Path (Join-Path $path '.git')) -and (Get-Command git -ErrorAction SilentlyContinue)) {
$bucket.Source = Invoke-Git -Path $path -ArgumentList @('config', 'remote.origin.url')
$bucket.Updated = Invoke-Git -Path $path -ArgumentList @('log', '--format=%aD', '-n', '1') | Get-Date
$bucket.Updated = Invoke-Git -Path $path -ArgumentList @('log', '--format=%aI', '-n', '1') | Get-Date
} else {
$bucket.Source = friendly_path $path
$bucket.Updated = (Get-Item "$path\bucket" -ErrorAction SilentlyContinue).LastWriteTime
Expand Down
4 changes: 2 additions & 2 deletions lib/core.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ function load_cfg($file) {
$content = [System.IO.File]::ReadAllLines($file)
return ($content | ConvertFrom-Json -ErrorAction Stop)
} catch {
Write-Host "ERROR loading $file`: $($_.exception.message)"
error "loading $file`: $($_.exception.message)"
}
}

Expand Down Expand Up @@ -555,7 +555,7 @@ function app_status($app, $global) {
$status.hold = ($install_info.hold -eq $true)

$deprecated_dir = (Find-BucketDirectory -Name $install_info.bucket -Root) + "\deprecated"
$status.deprecated = (Get-ChildItem $deprecated_dir -Filter "$(sanitary_path $app).json" -Recurse).FullName
$status.deprecated = (Get-ChildItem $deprecated_dir -Filter "$(sanitary_path $app).json" -Recurse -ErrorAction Ignore).FullName

$manifest = manifest $app $install_info.bucket $install_info.url
$status.removed = (!$manifest)
Expand Down
55 changes: 29 additions & 26 deletions lib/decompress.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -84,18 +84,22 @@ function Expand-7zipArchive {
)
if ((get_config USE_EXTERNAL_7ZIP)) {
try {
$7zPath = (Get-Command '7z' -CommandType Application -ErrorAction Stop | Select-Object -First 1).Source
$7zPath = (Get-Command -Name '7z' -CommandType Application -ErrorAction Stop | Select-Object -First 1).Source
} catch [System.Management.Automation.CommandNotFoundException] {
abort "`nCannot find external 7-Zip (7z.exe) while 'use_external_7zip' is 'true'!`nRun 'scoop config use_external_7zip false' or install 7-Zip manually and try again."
}
} else {
$7zPath = Get-HelperPath -Helper 7zip
}
$LogPath = "$(Split-Path $Path)\7zip.log"
$DestinationPath = $DestinationPath.TrimEnd('\')
$LogPath = "$(Split-Path -Path $Path)\7zip.log"
$IsTar = ((strip_ext -fname $Path) -match '\.tar$') -or ($Path -match '\.t[abgpx]z2?$')
$DestinationPath = [string] $DestinationPath.TrimEnd('\')
if ($ExtractDir) {
$OriDestinationPath = [string] $DestinationPath
$DestinationPath = [System.IO.Path]::Combine($env:TEMP, [guid]::NewGuid().'Guid')
}
$ArgList = @('x', $Path, "-o$DestinationPath", '-xr!*.nsis', '-y')
$IsTar = ((strip_ext $Path) -match '\.tar$') -or ($Path -match '\.t[abgpx]z2?$')
if (!$IsTar -and $ExtractDir) {
if ($ExtractDir -and -not $IsTar) {
$ArgList += "-ir!$ExtractDir\*"
}
if ($Switches) {
Expand All @@ -106,42 +110,40 @@ function Expand-7zipArchive {
'Skip' { $ArgList += '-aos' }
'Rename' { $ArgList += '-aou' }
}
$Status = Invoke-ExternalCommand $7zPath $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')"
$Status = Invoke-ExternalCommand -FilePath $7zPath -ArgumentList $ArgList -LogPath $LogPath
if (-not $Status) {
abort "Failed to extract files from $Path.`nLog file:`n $(friendly_path -path $LogPath)`n$(new_issue_msg $app $bucket 'decompress error')"
}
if ($IsTar) {
# Check for tar
$Status = Invoke-ExternalCommand $7zPath @('l', $Path) -LogPath $LogPath
$Status = Invoke-ExternalCommand -FilePath $7zPath -ArgumentList @('l', $Path) -LogPath $LogPath
if ($Status) {
# get inner tar file name
# Get inner tar file name
$TarFile = (Select-String -Path $LogPath -Pattern '[^ ]*tar$').Matches.Value
Expand-7zipArchive -Path "$DestinationPath\$TarFile" -DestinationPath $DestinationPath -ExtractDir $ExtractDir -Removal
} else {
abort "Failed to list files in $Path.`nNot a 7-Zip supported archive file."
}
}
if (!$IsTar -and $ExtractDir) {
movedir "$DestinationPath\$ExtractDir" $DestinationPath | Out-Null
# Remove temporary directory if it is empty
$ExtractDirTopPath = [string] "$DestinationPath\$($ExtractDir -replace '[\\/].*')"
if ((Get-ChildItem -Path $ExtractDirTopPath -Force -ErrorAction Ignore).Count -eq 0) {
Remove-Item -Path $ExtractDirTopPath -Recurse -Force -ErrorAction Ignore
}
if ($ExtractDir -and -not $IsTar) {
# Move content to original destination path
$null = movedir -from "$DestinationPath\$ExtractDir" -to $OriDestinationPath
# Remove temporary directory
Remove-Item -Path $DestinationPath -Recurse -Force -ErrorAction Ignore
}
if (Test-Path $LogPath) {
Remove-Item $LogPath -Force
if (Test-Path -Path $LogPath -PathType 'Leaf') {
Remove-Item -Path $LogPath -Force
}
if ($Removal) {
if (($Path -replace '.*\.([^\.]*)$', '$1') -eq '001') {
# Remove splitted 7-zip archive parts
Get-ChildItem "$($Path -replace '\.[^\.]*$', '').???" | Remove-Item -Force
Get-ChildItem -Path "$($Path -replace '\.[^\.]*$', '').???" | Remove-Item -Force
} elseif (($Path -replace '.*\.part(\d+)\.rar$', '$1')[-1] -eq '1') {
# Remove splitted RAR archive parts
Get-ChildItem "$($Path -replace '\.part(\d+)\.rar$', '').part*.rar" | Remove-Item -Force
} else {
# Remove original archive file
Remove-Item $Path -Force
Remove-Item -Path $Path -Force
}
}
}
Expand Down Expand Up @@ -280,9 +282,10 @@ function Expand-ZipArchive {
[Switch]
$Removal
)
$DestinationPath = [string] $DestinationPath.TrimEnd('\')
if ($ExtractDir) {
$OriDestinationPath = $DestinationPath
$DestinationPath = "$DestinationPath\_tmp"
$OriDestinationPath = [string] $DestinationPath
$DestinationPath = [string] [System.IO.Path]::Combine($env:TEMP, [guid]::NewGuid().'Guid')
}
# Disable progress bar to gain performance
$oldProgressPreference = $ProgressPreference
Expand All @@ -293,12 +296,12 @@ function Expand-ZipArchive {

$global:ProgressPreference = $oldProgressPreference
if ($ExtractDir) {
movedir "$DestinationPath\$ExtractDir" $OriDestinationPath | Out-Null
Remove-Item $DestinationPath -Recurse -Force
$null = movedir "$DestinationPath\$ExtractDir" $OriDestinationPath
Remove-Item -Path $DestinationPath -Recurse -Force
}
if ($Removal) {
# Remove original archive file
Remove-Item $Path -Force
Remove-Item -Path $Path -Force
}
}

Expand Down
5 changes: 3 additions & 2 deletions lib/install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ function ensure_install_dir_not_in_path($dir, $global) {

$fixed, $removed = find_dir_or_subdir $path "$dir"
if ($removed) {
$removed | ForEach-Object { "Installer added '$(friendly_path $_)' to path. Removing." }
$removed | ForEach-Object { Write-Output "Installer added '$(friendly_path $_)' to path. Removing." }
Set-EnvVar -Name 'PATH' -Value $fixed -Global:$global
}

Expand Down Expand Up @@ -359,6 +359,7 @@ function show_notes($manifest, $dir, $original_dir, $persist_dir) {
Write-Output 'Notes'
Write-Output '-----'
Write-Output (wraptext (substitute $manifest.notes @{ '$dir' = $dir; '$original_dir' = $original_dir; '$persist_dir' = $persist_dir }))
Write-Output '-----'
}
}

Expand Down Expand Up @@ -419,7 +420,7 @@ function show_suggestions($suggested) {
}

if (!$fulfilled) {
Write-Host "'$app' suggests installing '$([string]::join("' or '", $feature_suggestions))'."
Write-Host "'$app' suggests installing '$([string]::join("' or '", $feature_suggestions))'." -ForegroundColor DarkYellow
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/manifest.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ function Get-Manifest($app) {
$manifest = manifest $app $bucket
if (!$manifest) {
$deprecated_dir = (Find-BucketDirectory -Name $bucket -Root) + '\deprecated'
$manifest = parse_json (Get-ChildItem $deprecated_dir -Filter "$(sanitary_path $app).json" -Recurse).FullName
$manifest = parse_json (Get-ChildItem $deprecated_dir -Filter "$(sanitary_path $app).json" -Recurse -ErrorAction Ignore).FullName
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion libexec/scoop-alias.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ if ($SubCommand -notin $SubCommands) {
}

$opt, $other, $err = getopt $Args 'v' 'verbose'
if ($err) { "scoop alias: $err"; exit 1 }
if ($err) { error "scoop alias: $err"; exit 1 }

$name, $command, $description = $other
$verbose = $opt.v -or $opt.verbose
Expand Down
8 changes: 4 additions & 4 deletions libexec/scoop-bucket.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ $usage_rm = 'usage: scoop bucket rm <name>'
switch ($cmd) {
'add' {
if (!$name) {
'<name> missing'
error '<name> missing'
$usage_add
exit 1
}
if (!$repo) {
$repo = known_bucket_repo $name
if (!$repo) {
"Unknown bucket '$name'. Try specifying <repo>."
error "Unknown bucket '$name'. Try specifying <repo>."
$usage_add
exit 1
}
Expand All @@ -51,7 +51,7 @@ switch ($cmd) {
}
'rm' {
if (!$name) {
'<name> missing'
error '<name> missing'
$usage_rm
exit 1
}
Expand All @@ -73,7 +73,7 @@ switch ($cmd) {
exit 0
}
default {
"scoop bucket: cmd '$cmd' not supported"
error "scoop bucket: cmd '$cmd' not supported"
my_usage
exit 1
}
Expand Down
2 changes: 1 addition & 1 deletion libexec/scoop-cache.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function cacheshow($app) {

function cacheremove($app) {
if (!$app) {
'ERROR: <app(s)> missing'
error '<app(s)> missing'
my_usage
exit 1
} elseif ($app -eq '*' -or $app -eq '-a' -or $app -eq '--all') {
Expand Down
6 changes: 3 additions & 3 deletions libexec/scoop-cleanup.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@
. "$PSScriptRoot\..\lib\install.ps1" # persist related

$opt, $apps, $err = getopt $args 'agk' 'all', 'global', 'cache'
if ($err) { "scoop cleanup: $err"; exit 1 }
if ($err) { error "scoop cleanup: $err"; exit 1 }
$global = $opt.g -or $opt.global
$cache = $opt.k -or $opt.cache
$all = $opt.a -or $opt.all

if (!$apps -and !$all) { 'ERROR: <app> missing'; my_usage; exit 1 }
if (!$apps -and !$all) { error '<app> missing'; my_usage; exit 1 }

if ($global -and !(is_admin)) {
'ERROR: you need admin rights to cleanup global apps'; exit 1
error 'you need admin rights to cleanup global apps'; exit 1
}

function cleanup($app, $global, $verbose, $cache) {
Expand Down
1 change: 1 addition & 0 deletions libexec/scoop-download.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
. "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion'
. "$PSScriptRoot\..\lib\manifest.ps1" # 'generate_user_manifest' 'Get-Manifest'
. "$PSScriptRoot\..\lib\download.ps1"
. "$PSScriptRoot\..\lib\install.ps1" # 'nightly_version'
if (get_config USE_SQLITE_CACHE) {
. "$PSScriptRoot\..\lib\database.ps1"
}
Expand Down
6 changes: 3 additions & 3 deletions libexec/scoop-help.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,17 @@ function print_summaries {

$commands = commands

if(!($cmd)) {
if (!($cmd)) {
Write-Host "Usage: scoop <command> [<args>]

Available commands are listed below.

Type 'scoop help <command>' to get more help for a specific command."
print_summaries
} elseif($commands -contains $cmd) {
} elseif ($commands -contains $cmd) {
print_help $cmd
} else {
warn "scoop help: no such command '$cmd'"
error "scoop help: no such command '$cmd'"
exit 1
}

Expand Down
Loading
Loading