Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
153 changes: 96 additions & 57 deletions bin/uninstall.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ param(
. "$PSScriptRoot\..\lib\core.ps1"
. "$PSScriptRoot\..\lib\system.ps1"
. "$PSScriptRoot\..\lib\install.ps1"
. "$PSScriptRoot\..\lib\uninstall.ps1" # 'uninstall_app'
. "$PSScriptRoot\..\lib\shortcuts.ps1"
. "$PSScriptRoot\..\lib\versions.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1"
Expand All @@ -31,77 +32,115 @@ if ($purge) {
$yn = Read-Host 'Are you sure? (yN)'
if ($yn -notlike 'y*') { exit }

$errors = $false

# Uninstall given app
function do_uninstall($app, $global) {
$version = Select-CurrentVersion -AppName $app -Global:$global
$dir = versiondir $app $version $global
$manifest = installed_manifest $app $version $global
$install = install_info $app $version $global
$architecture = $install.architecture

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

# If a junction was used during install, that will have been used
# as the reference directory. Othewise it will just be the version
# directory.
$refdir = unlink_current (appdir $app $global)

env_rm_path $manifest $refdir $global $architecture
env_rm $manifest $global $architecture

$appdir = appdir $app $global
try {
Remove-Item $appdir -Recurse -Force -ErrorAction Stop
} catch {
$errors = $true
warn "Couldn't remove $(friendly_path $appdir): $_.Exception"

# Run uninstallation for each app if necessary, continuing if there's
# a problem deleting a directory (which is quite likely)
function UninstallApps {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[bool]$global,
[Parameter(Mandatory = $true)]
[bool]$purge
)

$allDone = $true

foreach ($app in installed_apps $global) {
try {
$succ = uninstall_app -app $app -global $global -purge $purge
$errMsg = "Failed to uninstall $app."
} catch {
$succ = $false
$errMsg = "Failed to uninstall $app : $($_.Exception.Message)."
}

if (-not $succ) {
$allDone = $false
error $errMsg
}
}
}

function rm_dir($dir) {
try {
Remove-Item $dir -Recurse -Force -ErrorAction Stop
} catch {
abort "Couldn't remove $(friendly_path $dir): $_"
if (-not $allDone) {
abort 'Not all apps were uninstalled. Please try again or restart.'
}
}

# Remove all folders (except persist) inside given scoop directory.
function keep_onlypersist($directory) {
Get-ChildItem $directory -Exclude 'persist' | ForEach-Object { rm_dir $_ }
}
function RemoveDirs {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[bool]$global,
[Parameter(Mandatory = $true)]
[bool]$purge
)

# Run uninstallation for each app if necessary, continuing if there's
# a problem deleting a directory (which is quite likely)
if ($global) {
installed_apps $true | ForEach-Object { # global apps
do_uninstall $_ $true
$dirs = @()

# Remove the shortcut directory
$dirs += (shortcut_folder $global)

# Remove the scoop root directory
$scoopDir = basedir $global
$persistDir = "$scoopDir\persist"

$dirs += (Get-ChildItem $scoopDir -Exclude @('persist', 'apps', 'shims') | Select-Object -ExpandProperty FullName)

# Remove the persist directory if purge is specified or if it's empty
$rmPersist = $purge -or
((Get-ChildItem -Path $persistDir -Force -ErrorAction SilentlyContinue).Count -eq 0)

# Ensure shims dir and apps dir are removed last
if ($rmPersist) {
$dirs += @($persistDir, "$scoopDir\shims", "$scoopDir\apps", $scoopDir)
} else {
$dirs += @("$scoopDir\shims", "$scoopDir\apps")
}
}

installed_apps $false | ForEach-Object { # local apps
do_uninstall $_ $false
foreach ($dir in $dirs) {
try {
if (($null -ne $dir) -and (Test-Path -Path $dir)) {
Write-Host "Removing $(friendly_path $dir)..."

Remove-Item -Path "$dir" -Recurse -Force -ErrorAction Stop
}
} catch {
abort "Couldn't remove $(friendly_path $dir): $($_.Exception.Message)"
}
}
}

if ($errors) {
abort 'Not all apps could be deleted. Try again or restart.'
function RemoveEnvVars {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[bool]$global
)

# Remove environment variable "$scoopPathEnvVar"
if (get_config USE_ISOLATED_PATH) {
Remove-Path -Path ('%' + $scoopPathEnvVar + '%') -Global:$global -PassThru:$false
}
}

if ($purge) {
rm_dir $scoopdir
if ($global) { rm_dir $globaldir }
} else {
keep_onlypersist $scoopdir
if ($global) { keep_onlypersist $globaldir }
function Invoke-SelfUninstall{
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[bool]$global,
[Parameter(Mandatory = $true)]
[bool]$purge
)

UninstallApps -global $global -purge $purge
RemoveDirs -global $global -purge $purge
RemoveEnvVars -global $global
}

Remove-Path -Path (shimdir $global) -Global:$global
if (get_config USE_ISOLATED_PATH) {
Remove-Path -Path ('%' + $scoopPathEnvVar + '%') -Global:$global
if($global) {
Invoke-SelfUninstall -global $true -purge $purge
}

Invoke-SelfUninstall -global $false -purge $purge

success 'Scoop has been uninstalled.'
113 changes: 113 additions & 0 deletions lib/uninstall.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
function uninstall_app {
[CmdletBinding()]
[OutputType([bool])]
param(
[Parameter(Mandatory = $true)]
[string]$app,
[Parameter(Mandatory = $true)]
[bool]$global,
[Parameter(Mandatory = $true)]
[bool]$purge
)

$version = Select-CurrentVersion -AppName $app -Global:$global
$appDir = appdir $app $global
if ($version) {
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
$architecture = $install.architecture

Invoke-HookScript -HookType 'pre_uninstall' -Manifest $manifest -Arch $architecture

# region Workaround for #2952
# https://github.com/ScoopInstaller/Scoop/issues/2952
if (test_running_process $app $global) {
return $false
}
# endregion Workaround for #2952

try {
Test-Path $dir -ErrorAction Stop | Out-Null
} catch [UnauthorizedAccessException] {
error "Access denied: $dir. You might need to restart."
return $false
}

Invoke-Installer -Path $dir -Manifest $manifest -ProcessorArchitecture $architecture -Global:$global -Uninstall
rm_shims $app $manifest $global $architecture
rm_startmenu_shortcuts $manifest $global $architecture

# If a junction was used during install, that will have been used
# as the reference directory. Otherwise it will just be the version
# directory.
$refdir = unlink_current $dir

uninstall_psmodule $manifest $refdir $global

env_rm_path $manifest $refdir $global $architecture
env_rm $manifest $global $architecture

try {
# unlink all potential old link before doing recursive Remove-Item
unlink_persist_data $manifest $dir
Remove-Item $dir -Recurse -Force -ErrorAction Stop
} catch {
if (Test-Path $dir) {
error "Couldn't remove '$(friendly_path $dir)'; it may be in use."
return $false
}
}

Invoke-HookScript -HookType 'post_uninstall' -Manifest $manifest -Arch $architecture
}
# remove older versions
$oldVersions = @(Get-ChildItem $appDir -Name -Exclude 'current')
foreach ($version in $oldVersions) {
Write-Host "Removing older version ($version)."
$dir = versiondir $app $version $global
try {
# unlink all potential old link before doing recursive Remove-Item
unlink_persist_data $manifest $dir
Remove-Item $dir -Recurse -Force -ErrorAction Stop
} catch {
error "Couldn't remove '$(friendly_path $dir)'; it may be in use."
return $false
}
}
if (Test-Path ($currentDir = Join-Path $appDir 'current')) {
attrib $currentDir -R /L
Remove-Item $currentDir -ErrorAction Stop -Force
}
if (!(Get-ChildItem $appDir)) {
try {
# if last install failed, the directory seems to be locked and this
# will throw an error about the directory not existing
Remove-Item $appDir -Recurse -Force -ErrorAction Stop
} catch {
if ((Test-Path $appDir)) { throw } # only throw if the dir still exists
}
}

# purge persistant 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."
return $false
}
}
}

success "'$app' was uninstalled."
return $true
}
Loading
Loading