diff --git a/.gitignore b/.gitignore index fdc96d2a52..5981a92c56 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ test/installer/tmp/* test/tmp/* *~ TestResults.xml +.vscode diff --git a/lib/core.ps1 b/lib/core.ps1 index b971c484db..664711ddde 100644 --- a/lib/core.ps1 +++ b/lib/core.ps1 @@ -325,7 +325,14 @@ function currentdir($app, $global) { "$(appdir $app $global)\$version" } -function persistdir($app, $global) { "$(basedir $global)\persist\$app" } +function persistdir($app, $global) { + $persistBaseDir = "$(basedir $global)\persist" + if ($app) { + return Join-Path $persistBaseDir $app + } else { + return $persistBaseDir + } +} function usermanifestsdir { "$(basedir)\workspace" } function usermanifest($app) { "$(usermanifestsdir)\$app.json" } function cache_path($app, $version, $url) { "$cachedir\$app#$version#$($url -replace '[^\w\.\-]+', '_')" } @@ -1076,26 +1083,27 @@ function Confirm-InstallationStatus { ) $Installed = @() $Apps | Select-Object -Unique | Where-Object { $_ -ne 'scoop' } | ForEach-Object { - $App, $null, $null = parse_app $_ - if ($Global) { - if (Test-Path (appdir $App $true)) { - $Installed += , @($App, $true) - } elseif (Test-Path (appdir $App $false)) { - error "'$App' isn't installed globally, but it may be installed locally." - warn "Try again without the --global (or -g) flag instead." - } else { - error "'$App' isn't installed." - } + + $Status = Get-AppStatus -App $_ -Global $Global + $App = $Status.App; + + if ($Status.Installed -and ($Global -eq $Status.Global)) { + # Add installed + $Installed += , @($App, $Global); } else { - if (Test-Path (appdir $App $false)) { - $Installed += , @($App, $false) - } elseif (Test-Path (appdir $App $true)) { - error "'$App' isn't installed locally, but it may be installed globally." - warn "Try again with the --global (or -g) flag instead." + if ($Status.Installed) { + if ($Status.Global) { + error "'$App' isn't installed locally, but it may be installed globally." + warn 'Try again with the --global (or -g) flag instead.' + } else { + error "'$App' isn't installed globally, but it may be installed locally." + warn 'Try again without the --global (or -g) flag instead.' + } } else { error "'$App' isn't installed." } } + if (failed $App $Global) { error "'$App' isn't installed correctly." } @@ -1103,6 +1111,33 @@ function Confirm-InstallationStatus { return , $Installed } +Function Get-AppStatus { + [OutputType([Object[]])] + param( + [String]$App, + [Switch]$Global + ) + $App, $null, $null = parse_app $App + $IsInstalled = Test-Path (appdir $App $Global) + + $Status = [PSCustomObject]@{ + App = $App + Installed = $IsInstalled + Global = $Global + } + + if (!$IsInstalled) { + # Check if installed somewhere else + $Global = !$Global; + $Status.Installed = Test-Path (appdir $App $Global); + if ($Status.Installed) { + $Status.Global = $Global + } + } + + return $Status; +} + function strip_path($orig_path, $dir) { if($null -eq $orig_path) { $orig_path = '' } $stripped = [string]::join(';', @( $orig_path.split(';') | Where-Object { $_ -and $_ -ne $dir } )) diff --git a/lib/install.ps1 b/lib/install.ps1 index 519c26403d..3dbdcd8102 100644 --- a/lib/install.ps1 +++ b/lib/install.ps1 @@ -1203,6 +1203,33 @@ function unlink_persist_data($manifest, $dir) { } } +Function Remove-PersistentData { + [CmdletBinding(SupportsShouldProcess = $true)] + param( + [string]$App, + $Global + ) + + $Status = Get-AppStatus -App $App -Global:$Global + $App = $Status.App; + + if (!$Status.Installed) { + # remove persistend data if app not installed + Write-Host 'Removing persisted data.' + $persistDir = persistdir $App $Global + + if (Test-Path $persistDir) { + try { + Remove-Item $persistDir -Recurse -Force -ErrorAction Stop + } catch { + error "Couldn't remove '$(friendly_path $persistDir)'; it may be in use." + continue + } + } + } +} + + # check whether write permission for Users usergroup is set to global persist dir, if not then set function persist_permission($manifest, $global) { if($global -and $manifest.persist -and (is_admin)) { diff --git a/libexec/scoop-cleanup.ps1 b/libexec/scoop-cleanup.ps1 index 6ce40a211f..225fb69ced 100644 --- a/libexec/scoop-cleanup.ps1 +++ b/libexec/scoop-cleanup.ps1 @@ -9,16 +9,18 @@ # -a, --all Cleanup all apps (alternative to '*') # -g, --global Cleanup a globally installed app # -k, --cache Remove outdated download cache +# -p, --purge Remove persistent data . "$PSScriptRoot\..\lib\getopt.ps1" . "$PSScriptRoot\..\lib\manifest.ps1" # 'Select-CurrentVersion' (indirectly) . "$PSScriptRoot\..\lib\versions.ps1" # 'Select-CurrentVersion' . "$PSScriptRoot\..\lib\install.ps1" # persist related -$opt, $apps, $err = getopt $args 'agk' 'all', 'global', 'cache' +$opt, $apps, $err = getopt $args 'agkp' 'all', 'global', 'cache', 'purge' if ($err) { "scoop cleanup: $err"; exit 1 } $global = $opt.g -or $opt.global $cache = $opt.k -or $opt.cache +$purge = $opt.p -or $opt.purge $all = $opt.a -or $opt.all if (!$apps -and !$all) { 'ERROR: missing'; my_usage; exit 1 } @@ -27,7 +29,14 @@ if ($global -and !(is_admin)) { 'ERROR: you need admin rights to cleanup global apps'; exit 1 } -function cleanup($app, $global, $verbose, $cache) { +function cleanup { + param( + [String]$app, + $global, + $verbose, + $cache + ) + $current_version = Select-CurrentVersion -AppName $app -Global:$global if ($cache) { Remove-Item "$cachedir\$app#*" -Exclude "$app#$current_version#*" @@ -61,20 +70,34 @@ function cleanup($app, $global, $verbose, $cache) { Write-Host '' } +$installedApps = @() +$persistentApps = @() + if ($apps -or $all) { if ($apps -eq '*' -or $all) { $verbose = $false - $apps = applist (installed_apps $false) $false + $installedApps = applist (installed_apps $false) $false + $persistentApps = applist (persistent_apps $false) $false if ($global) { - $apps += applist (installed_apps $true) $true + $installedApps += applist (installed_apps $true) $true + $persistentApps += applist (persistent_apps $true) $true } } else { $verbose = $true - $apps = Confirm-InstallationStatus $apps -Global:$global + $installedApps = Confirm-InstallationStatus $apps -Global:$global + $persistentApps = applist $apps $global + } + + # $installedApps is a list of ($app, $global) tuples + foreach ($_ in $installedApps) { + cleanup -app $_[0] -global $_[1] -verbose $verbose -cache $cache -purge $purge } - # $apps is now a list of ($app, $global) tuples - $apps | ForEach-Object { cleanup @_ $verbose $cache } + if ($purge -and $persistentApps.Count -gt 0) { + foreach ($_ in $persistentApps) { + Remove-PersistentData -App $_[0] -Global $_[1] + } + } if ($cache) { Remove-Item "$cachedir\*.download" -ErrorAction Ignore diff --git a/libexec/scoop-uninstall.ps1 b/libexec/scoop-uninstall.ps1 index 44f5561db5..5a75cee3ca 100644 --- a/libexec/scoop-uninstall.ps1 +++ b/libexec/scoop-uninstall.ps1 @@ -40,10 +40,22 @@ if ($apps -eq 'scoop') { exit } -$apps = Confirm-InstallationStatus $apps -Global:$global -if (!$apps) { exit 0 } -:app_loop foreach ($_ in $apps) { +$installedApps = Confirm-InstallationStatus $apps -Global:$global +if (!$installedApps) { + + if ($purge) { + # make it possible to remove persintent data of already uninstalled apps + :app_loop foreach ($_ in $apps) { + ($app, $global) = $_ + Remove-PersistentData -App $app -Global:$global + } + } + + exit 0 +} + +:app_loop foreach ($_ in $installedApps) { ($app, $global) = $_ $version = Select-CurrentVersion -AppName $app -Global:$global @@ -52,7 +64,6 @@ if (!$apps) { exit 0 } Write-Host "Uninstalling '$app' ($version)." $dir = versiondir $app $version $global - $persist_dir = persistdir $app $global $manifest = installed_manifest $app $version $global $install = install_info $app $version $global @@ -128,19 +139,9 @@ if (!$apps) { exit 0 } } } - # purge persistant data + # purge persistent data if ($purge) { - Write-Host 'Removing persisted data.' - $persist_dir = persistdir $app $global - - if (Test-Path $persist_dir) { - try { - Remove-Item $persist_dir -Recurse -Force -ErrorAction Stop - } catch { - error "Couldn't remove '$(friendly_path $persist_dir)'; it may be in use." - continue - } - } + Remove-PersistentData -App $app -Global $global } success "'$app' was uninstalled."