Skip to content

Commit e8616e3

Browse files
committed
feat: Add file lock to prevent concurrent executions
1 parent 03d831d commit e8616e3

File tree

3 files changed

+64
-35
lines changed

3 files changed

+64
-35
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
*.log
22
.DS_Store
33
._.DS_Store
4+
.lock
45
scoop.sublime-workspace
56
test/installer/tmp/*
67
test/tmp/*

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- **install:** Add separator at the end of notes, highlight suggestions ([#6418](https://github.com/ScoopInstaller/Scoop/issues/6418))
88
- **download|scoop-download:** Add GitHub issue prompt when the default downloader fails ([#6539](https://github.com/ScoopInstaller/Scoop/issues/6539))
99
- **download|scoop-config:** Allow disabling automatic fallback to the default downloader when Aria2c download fails ([#6538](https://github.com/ScoopInstaller/Scoop/issues/6538))
10+
- **core:** Add file lock to prevent concurrent executions ([#6557](https://github.com/ScoopInstaller/Scoop/issues/6557))
1011

1112
### Bug Fixes
1213

bin/scoop.ps1

Lines changed: 62 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,48 +6,75 @@ Set-StrictMode -Off
66
. "$PSScriptRoot\..\lib\commands.ps1"
77
. "$PSScriptRoot\..\lib\help.ps1"
88

9-
$subCommand = $Args[0]
9+
$lock_file_path = "$PSScriptRoot\..\.lock"
10+
$lock_stream = $null
11+
$lock_show_waiting_message = $true
1012

11-
# for aliases where there's a local function, re-alias so the function takes precedence
12-
$aliases = Get-Alias | Where-Object { $_.Options -notmatch 'ReadOnly|AllScope' } | ForEach-Object { $_.Name }
13-
Get-ChildItem Function: | Where-Object -Property Name -In -Value $aliases | ForEach-Object {
14-
Set-Alias -Name $_.Name -Value Local:$($_.Name) -Scope Script
13+
while (-not $lock_stream.CanWrite) {
14+
try {
15+
$lock_stream = [System.IO.File]::Open($lock_file_path, [System.IO.FileMode]::Create, [System.IO.FileAccess]::Write)
16+
} catch [System.IO.IOException] {
17+
# Only deal with ERROR_SHARING_VIOLATION or ERROR_LOCK_VIOLATION.
18+
$error_code = $_.Exception.HResult -band 0xFFFF
19+
if ($error_code -notin 32, 33) {
20+
throw
21+
}
22+
23+
if ($lock_show_waiting_message) {
24+
'Waiting for exclusive access...'
25+
$lock_show_waiting_message = $false
26+
}
27+
Start-Sleep -Seconds 1
28+
}
1529
}
1630

17-
switch ($subCommand) {
18-
({ $subCommand -in @($null, '-h', '--help', '/?') }) {
19-
exec 'help'
31+
try {
32+
$subCommand = $Args[0]
33+
34+
# for aliases where there's a local function, re-alias so the function takes precedence
35+
$aliases = Get-Alias | Where-Object { $_.Options -notmatch 'ReadOnly|AllScope' } | ForEach-Object { $_.Name }
36+
Get-ChildItem Function: | Where-Object -Property Name -In -Value $aliases | ForEach-Object {
37+
Set-Alias -Name $_.Name -Value Local:$($_.Name) -Scope Script
2038
}
21-
({ $subCommand -in @('-v', '--version') }) {
22-
Write-Host 'Current Scoop version:'
23-
if ((Test-GitAvailable) -and (Test-Path "$PSScriptRoot\..\.git") -and ((get_config SCOOP_BRANCH 'master') -ne 'master')) {
24-
Invoke-Git -Path "$PSScriptRoot\.." -ArgumentList @('--no-pager', 'log', 'HEAD', '-1', '--oneline')
25-
} else {
26-
$version = Select-String -Pattern '^## \[(v[\d.]+)\].*?([\d-]+)$' -Path "$PSScriptRoot\..\CHANGELOG.md"
27-
Write-Host $version.Matches.Groups[1].Value -ForegroundColor Cyan -NoNewline
28-
Write-Host " - Released at $($version.Matches.Groups[2].Value)"
39+
40+
switch ($subCommand) {
41+
({ $subCommand -in @($null, '-h', '--help', '/?') }) {
42+
exec 'help'
2943
}
30-
Write-Host ''
31-
32-
Get-LocalBucket | ForEach-Object {
33-
$bucketLoc = Find-BucketDirectory $_ -Root
34-
if ((Test-GitAvailable) -and (Test-Path "$bucketLoc\.git")) {
35-
Write-Host "'$_' bucket:"
36-
Invoke-Git -Path $bucketLoc -ArgumentList @('--no-pager', 'log', 'HEAD', '-1', '--oneline')
37-
Write-Host ''
44+
({ $subCommand -in @('-v', '--version') }) {
45+
Write-Host 'Current Scoop version:'
46+
if ((Test-GitAvailable) -and (Test-Path "$PSScriptRoot\..\.git") -and ((get_config SCOOP_BRANCH 'master') -ne 'master')) {
47+
Invoke-Git -Path "$PSScriptRoot\.." -ArgumentList @('--no-pager', 'log', 'HEAD', '-1', '--oneline')
48+
} else {
49+
$version = Select-String -Pattern '^## \[(v[\d.]+)\].*?([\d-]+)$' -Path "$PSScriptRoot\..\CHANGELOG.md"
50+
Write-Host $version.Matches.Groups[1].Value -ForegroundColor Cyan -NoNewline
51+
Write-Host " - Released at $($version.Matches.Groups[2].Value)"
52+
}
53+
Write-Host ''
54+
55+
Get-LocalBucket | ForEach-Object {
56+
$bucketLoc = Find-BucketDirectory $_ -Root
57+
if ((Test-GitAvailable) -and (Test-Path "$bucketLoc\.git")) {
58+
Write-Host "'$_' bucket:"
59+
Invoke-Git -Path $bucketLoc -ArgumentList @('--no-pager', 'log', 'HEAD', '-1', '--oneline')
60+
Write-Host ''
61+
}
3862
}
3963
}
40-
}
41-
({ $subCommand -in (commands) }) {
42-
[string[]]$arguments = $Args | Select-Object -Skip 1
43-
if ($null -ne $arguments -and $arguments[0] -in @('-h', '--help', '/?')) {
44-
exec 'help' @($subCommand)
45-
} else {
46-
exec $subCommand $arguments
64+
({ $subCommand -in (commands) }) {
65+
[string[]]$arguments = $Args | Select-Object -Skip 1
66+
if ($null -ne $arguments -and $arguments[0] -in @('-h', '--help', '/?')) {
67+
exec 'help' @($subCommand)
68+
} else {
69+
exec $subCommand $arguments
70+
}
71+
}
72+
default {
73+
warn "scoop: '$subCommand' isn't a scoop command. See 'scoop help'."
74+
exit 1
4775
}
4876
}
49-
default {
50-
warn "scoop: '$subCommand' isn't a scoop command. See 'scoop help'."
51-
exit 1
52-
}
77+
} finally {
78+
$lock_stream.Close()
79+
$lock_stream.Dispose()
5380
}

0 commit comments

Comments
 (0)