Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

### Features

**autoupdate:** GitHub predefined hashes support ([#6416](https://github.com/ScoopInstaller/Scoop/issues/6416), [#6435](https://github.com/ScoopInstaller/Scoop/issues/6435))
- **scoop-forcekill:** Support killing running applications and services ([#6603](https://github.com/ScoopInstaller/Scoop/pull/6603))
- **autoupdate:** GitHub predefined hashes support ([#6416](https://github.com/ScoopInstaller/Scoop/issues/6416), [#6435](https://github.com/ScoopInstaller/Scoop/issues/6435))

### Bug Fixes

Expand Down
65 changes: 61 additions & 4 deletions lib/install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -532,20 +532,77 @@ function persist_permission($manifest, $global) {

# test if there are running processes
function test_running_process($app, $global) {
if (get_config NO_JUNCTION) {
$version = Select-CurrentVersion -App $app -Global:$global
} else {
$version = 'current'
}

$json = install_info $app $version $global
$forcekill = $false
$forcekill_services = @()

if ($json) {
if ($json.forcekill) { $forcekill = $true }
if ($json.forcekill_services) { $forcekill_services = $json.forcekill_services }
}

$processdir = appdir $app $global | Convert-Path
$running_processes = Get-Process | Where-Object { $_.Path -like "$processdir\*" } | Out-String

# Try finding services related to this path
$servicesToStop = @()
if ($forcekill) {
$foundServices = Get-CimInstance Win32_Service | Where-Object { $_.PathName -and $_.PathName -like "*$processdir*" }
if ($foundServices) {
$servicesToStop += $foundServices.Name
}
if ($forcekill_services) {
$servicesToStop += $forcekill_services
}

$servicesToStop = $servicesToStop | Select-Object -Unique

foreach ($svc in $servicesToStop) {
if (Get-Service -Name $svc -ErrorAction SilentlyContinue | Where-Object { $_.Status -eq 'Running' }) {
warn "Stopping service '$svc' associated with '$app'..."
Stop-Service -Name $svc -Force -ErrorAction SilentlyContinue
}
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

$running_processes = Get-Process | Where-Object { $_.Path -like "$processdir\*" }

if ($running_processes) {
if (get_config IGNORE_RUNNING_PROCESSES) {
if ($forcekill) {
warn "The following instances of `"$app`" are still running. Scoop is configured to force kill them."
Write-Host ($running_processes | Out-String)
$processesToRestart = $running_processes | Where-Object Path | Select-Object -ExpandProperty Path | Select-Object -Unique
$running_processes | Stop-Process -Force -ErrorAction SilentlyContinue

$result = @{
ServicesToRestart = @($servicesToStop)
ProcessesToRestart = @($processesToRestart)
}
if ($result.ServicesToRestart.Count -gt 0 -or $result.ProcessesToRestart.Count -gt 0) {
return $result
}
return $false
Comment thread
MetalDevOps marked this conversation as resolved.
Outdated
} elseif (get_config IGNORE_RUNNING_PROCESSES) {
warn "The following instances of `"$app`" are still running. Scoop is configured to ignore this condition."
Write-Host $running_processes
Write-Host ($running_processes | Out-String)
return $false
} else {
error "The following instances of `"$app`" are still running. Close them and try again."
Write-Host $running_processes
Write-Host ($running_processes | Out-String)
return $true
}
} else {
if ($forcekill -and $servicesToStop.Count -gt 0) {
return @{
ServicesToRestart = @($servicesToStop)
ProcessesToRestart = @()
}
}
return $false
}
}
Expand Down
88 changes: 88 additions & 0 deletions libexec/scoop-forcekill.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Usage: scoop forcekill <apps>
# Summary: Force close apps before updating
# Help: To mark a user-scoped app to force close:
# scoop forcekill <app>
#
# To mark a global app to force close:
# scoop forcekill -g <app>
#
# To explicitly define services to stop:
# scoop forcekill <app> --service <servicename>
#
# Options:
# -g, --global Force close globally installed apps
# -s, --service Services to stop (comma separated)

. "$PSScriptRoot\..\lib\getopt.ps1"
. "$PSScriptRoot\..\lib\json.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1"
. "$PSScriptRoot\..\lib\versions.ps1"
. "$PSScriptRoot\..\lib\core.ps1"
. "$PSScriptRoot\..\lib\install.ps1"

$opt, $apps, $err = getopt $args 'gs:' 'global', 'service='
if ($err) { "scoop forcekill: $err"; exit 1 }

$exitcode = 0

$global = $opt.g -or $opt.global

if (!$apps) {
my_usage
exit 1
}

if ($global -and !(is_admin)) {
error 'You need admin rights to mark a global app for forcekill.'
exit 1
}

foreach ($app in $apps) {
if (!(installed $app $global)) {
if ($global) {
error "'$app' is not installed globally."
} else {
error "'$app' is not installed."
}
$exitcode = 1
continue
}

if (get_config NO_JUNCTION) {
$version = Select-CurrentVersion -App $app -Global:$global
} else {
$version = 'current'
}
$dir = versiondir $app $version $global
$json = install_info $app $version $global
if (!$json) {
error "Failed to configure forcekill for '$app'."
$exitcode = 1
continue
}
$install = @{}
$json | Get-Member -MemberType Properties | ForEach-Object { $install.Add($_.Name, $json.($_.Name)) }

$install.forcekill = $true

if ($opt.service) {
$services = $opt.service -split ',' | ForEach-Object { $_.Trim() }
$valid_services = @()
foreach ($svc in $services) {
if (Get-Service -Name $svc -ErrorAction SilentlyContinue) {
$valid_services += $svc
} else {
warn "Could not find service '$svc'. Skipping."
$exitcode = 1
}
}
if ($valid_services.Count -gt 0) {
$install.forcekill_services = @($valid_services | Select-Object -Unique)
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

save_install_info $install $dir
success "$app is now marked to force close on update."
}

exit $exitcode
Comment thread
coderabbitai[bot] marked this conversation as resolved.
68 changes: 68 additions & 0 deletions libexec/scoop-unforcekill.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Usage: scoop unforcekill <apps>
# Summary: Remove force close setting from an app
# Help: To unmark a user-scoped app:
# scoop unforcekill <app>
#
# To unmark a global app:
# scoop unforcekill -g <app>
#
# Options:
# -g, --global Unmark globally installed apps

. "$PSScriptRoot\..\lib\getopt.ps1"
. "$PSScriptRoot\..\lib\json.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1"
. "$PSScriptRoot\..\lib\versions.ps1"
. "$PSScriptRoot\..\lib\core.ps1"
. "$PSScriptRoot\..\lib\install.ps1"

$opt, $apps, $err = getopt $args 'g' 'global'
if ($err) { "scoop unforcekill: $err"; exit 1 }

$global = $opt.g -or $opt.global

if (!$apps) {
my_usage
exit 1
}

if ($global -and !(is_admin)) {
error 'You need admin rights to unmark a global app.'
exit 1
}

foreach ($app in $apps) {
if (!(installed $app $global)) {
if ($global) {
error "'$app' is not installed globally."
} else {
error "'$app' is not installed."
}
continue
}

if (get_config NO_JUNCTION) {
$version = Select-CurrentVersion -App $app -Global:$global
} else {
$version = 'current'
}
$dir = versiondir $app $version $global
$json = install_info $app $version $global
if (!$json) {
error "Failed to unmark forcekill for '$app'."
continue
}
$install = @{}
$json | Get-Member -MemberType Properties | ForEach-Object { $install.Add($_.Name, $json.($_.Name)) }

if (!$install.forcekill -and !$install.forcekill_services) {
info "'$app' is not marked for forcekill."
continue
}
$install.Remove('forcekill')
$install.Remove('forcekill_services')
save_install_info $install $dir
success "$app is no longer marked to force close on update."
}

exit $exitcode
28 changes: 27 additions & 1 deletion libexec/scoop-update.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -294,9 +294,19 @@ function update($app, $global, $quiet = $false, $independent, $suggested, $use_c
Write-Host "Updating '$app' ($old_version -> $version)"

#region Workaround for #2952
if (test_running_process $app $global) {
$running_ret = test_running_process $app $global
$stopped_services = @()
$stopped_processes = @()
if ($running_ret -eq $true) {
Write-Host 'Running process detected, skip updating.'
return
} elseif ($running_ret -is [hashtable]) {
if ($running_ret.ServicesToRestart) {
$stopped_services = $running_ret.ServicesToRestart
}
if ($running_ret.ProcessesToRestart) {
$stopped_processes = $running_ret.ProcessesToRestart
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
#endregion Workaround for #2952

Expand Down Expand Up @@ -383,6 +393,22 @@ function update($app, $global, $quiet = $false, $independent, $suggested, $use_c
ensure_none_failed $apps
$apps.Where({ !(installed $_) }) + $app | ForEach-Object { install_app $_ $architecture $global $suggested $use_cache $check_hash }
}

if ($stopped_services.Count -gt 0) {
foreach ($svc in $stopped_services) {
warn "Restarting service '$svc' associated with '$app'..."
Start-Service -Name $svc -ErrorAction SilentlyContinue
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

if ($stopped_processes.Count -gt 0) {
foreach ($proc in $stopped_processes) {
warn "Restarting process '$(Split-Path $proc -Leaf)' associated with '$app'..."
if (Test-Path $proc) {
Start-Process -FilePath $proc -ErrorAction SilentlyContinue
}
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Comment thread
MetalDevOps marked this conversation as resolved.
}

if (-not ($apps -or $all)) {
Expand Down