Skip to content
Open
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ test/tmp/*
*~
TestResults.xml
supporting/sqlite/*
.vscode/*
*.sln
5 changes: 5 additions & 0 deletions lib/core.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -835,8 +835,13 @@ function get_app_name($path) {
$appName = $Matches[1].ToLower()
} elseif ((Test-Path (appsdir $true)) -and ($path -match "$([Regex]::Escape($(Convert-Path (appsdir $true))))[/\\]([^/\\]+)")) {
$appName = $Matches[1].ToLower()
} elseif ($path -match '[/\\]([^/\\]+?)(?:\.[^/\\"]+?)') {
# Fallback: extract the executable file name (with extension if present): [/\\]([^/\\]+?)(?:\.?[^./\\]+?)`"
$appName = $Matches[1].ToLower()
Write-Host $path + '1' + $appName
} else {
$appName = ''
Write-Host $path + '2' + $appName
}
return $appName
}
Expand Down
139 changes: 117 additions & 22 deletions libexec/scoop-shim.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
#
# scoop shim rm <shim_name> [<shim_name>...]
#
# To list all shims or matching shims, use the 'list' subcommand:
# To list all shims or matching shims, use the 'list' subcommand (`--added` to show shims added by user in config):
#
# scoop shim list [<regex_pattern>...]
# scoop shim list --added [<regex_pattern>...]
#
# To show a shim's information, use the 'info' subcommand:
#
Expand All @@ -31,12 +31,68 @@
#
# scoop shim add myapp 'D:\path\myapp.exe' '--' myapp_args --global

# Main updated features:
# 1) `scoop shim add/rm` persist shims in the config file,
# 2) `scoop shim list` supports the --added [pattern|optional] option to display or search only user-added shims.

param($SubCommand)

. "$PSScriptRoot\..\lib\getopt.ps1"
. "$PSScriptRoot\..\lib\core.ps1" # for config related ops
. "$PSScriptRoot\..\lib\install.ps1" # for rm_shim
. "$PSScriptRoot\..\lib\system.ps1" # 'Add-Path' (indirectly)


# Read the configuration of manually added shims
function Get-AddedShimsConfig {
$added = get_config 'added'
if ($null -eq $added) {
return [PSCustomObject]@{}
}
return $added
}

# Add shim to config
function Add-ShimToConfig($shimName, $global, $commandPath, $commandArgs) {
$added = Get-AddedShimsConfig

# Use new structure: shimName as key, global as a boolean field
$shimInfo = [PSCustomObject]@{
CommandPath = $commandPath
CommandArgs = $commandArgs -join ' '
AddedDate = (Get-Date).ToString('yyyy-MM-dd HH:mm:ss')
global = $global
}

# If shimName does not exist, add it
if (-not $added.PSObject.Properties[$shimName]) {
$added | Add-Member -MemberType NoteProperty -Name $shimName -Value $shimInfo
} else {
$added.$shimName = $shimInfo
}

set_config 'added' $added | Out-Null
}
Comment on lines +56 to +75
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid dotted property access for arbitrary shim names; use PSObject property bag.

Shim names may contain dots/hyphens. $added.$shimName will break. Use PSObject.Properties[$name] for both add and update. Also store args as an array to preserve tokens.

 function Add-ShimToConfig($shimName, $global, $commandPath, $commandArgs) {
     $added = Get-AddedShimsConfig
 
     # Use new structure: shimName as key, global as a boolean field
     $shimInfo = [PSCustomObject]@{
         CommandPath = $commandPath
-        CommandArgs = $commandArgs -join ' '
+        CommandArgs = $commandArgs
         AddedDate = (Get-Date).ToString('yyyy-MM-dd HH:mm:ss')
         global = $global
     }
 
-    # If shimName does not exist, add it
-    if (-not $added.PSObject.Properties[$shimName]) {
-        $added | Add-Member -MemberType NoteProperty -Name $shimName -Value $shimInfo
-    } else {
-        $added.$shimName = $shimInfo
-    }
+    $prop = $added.PSObject.Properties[$shimName]
+    if ($prop) {
+        $prop.Value = $shimInfo
+    } else {
+        $added | Add-Member -MemberType NoteProperty -Name $shimName -Value $shimInfo
+    }
 
     set_config 'added' $added | Out-Null
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function Add-ShimToConfig($shimName, $global, $commandPath, $commandArgs) {
$added = Get-AddedShimsConfig
# Use new structure: shimName as key, global as a boolean field
$shimInfo = [PSCustomObject]@{
CommandPath = $commandPath
CommandArgs = $commandArgs -join ' '
AddedDate = (Get-Date).ToString('yyyy-MM-dd HH:mm:ss')
global = $global
}
# If shimName does not exist, add it
if (-not $added.PSObject.Properties[$shimName]) {
$added | Add-Member -MemberType NoteProperty -Name $shimName -Value $shimInfo
} else {
$added.$shimName = $shimInfo
}
set_config 'added' $added | Out-Null
}
function Add-ShimToConfig($shimName, $global, $commandPath, $commandArgs) {
$added = Get-AddedShimsConfig
# Use new structure: shimName as key, global as a boolean field
$shimInfo = [PSCustomObject]@{
CommandPath = $commandPath
CommandArgs = $commandArgs
AddedDate = (Get-Date).ToString('yyyy-MM-dd HH:mm:ss')
global = $global
}
$prop = $added.PSObject.Properties[$shimName]
if ($prop) {
$prop.Value = $shimInfo
} else {
$added | Add-Member -MemberType NoteProperty -Name $shimName -Value $shimInfo
}
set_config 'added' $added | Out-Null
}


# Remove shim from config
function Remove-ShimFromConfig($shimName, $global) {
$added = Get-AddedShimsConfig

# Check if shim exists and matches global flag
if ($added.PSObject.Properties[$shimName] -and $added.$shimName.global -eq $global) {
$added.PSObject.Properties.Remove($shimName)
set_config 'added' $added | Out-Null
}
}
Comment on lines +77 to +86
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Property removal must not rely on dotted access; compare flag via property value.

Direct $added.$shimName.global fails for keys with special chars. Use the property bag value.

 function Remove-ShimFromConfig($shimName, $global) {
     $added = Get-AddedShimsConfig
 
     # Check if shim exists and matches global flag
-    if ($added.PSObject.Properties[$shimName] -and $added.$shimName.global -eq $global) {
-        $added.PSObject.Properties.Remove($shimName)
+    $prop = $added.PSObject.Properties[$shimName]
+    if ($prop -and $prop.Value.global -eq $global) {
+        [void]$added.PSObject.Properties.Remove($shimName)
         set_config 'added' $added | Out-Null
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Remove shim from config
function Remove-ShimFromConfig($shimName, $global) {
$added = Get-AddedShimsConfig
# Check if shim exists and matches global flag
if ($added.PSObject.Properties[$shimName] -and $added.$shimName.global -eq $global) {
$added.PSObject.Properties.Remove($shimName)
set_config 'added' $added | Out-Null
}
}
# Remove shim from config
function Remove-ShimFromConfig($shimName, $global) {
$added = Get-AddedShimsConfig
# Check if shim exists and matches global flag
$prop = $added.PSObject.Properties[$shimName]
if ($prop -and $prop.Value.global -eq $global) {
[void]$added.PSObject.Properties.Remove($shimName)
set_config 'added' $added | Out-Null
}
}
🤖 Prompt for AI Agents
In libexec/scoop-shim.ps1 around lines 77 to 86, the code uses dotted access
($added.$shimName.global) which breaks for property names with special
characters; instead retrieve the property object and read its Value field.
Change the condition to get the property: $prop =
$added.PSObject.Properties[$shimName]; then check if ($prop -and
$prop.Value.global -eq $global) before removing the property and calling
set_config 'added' $added | Out-Null.


# Test if shim is manually added
function Test-ShimAdded($shimName, $gqlobal) {
$added = Get-AddedShimsConfig

# Check if shim exists and matches global flag
return ($added.PSObject.Properties[$shimName] -and $added.$shimName.global -eq $global)
}
Comment on lines +89 to +94
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Fix parameter name typo causing undefined variable reference.

Line 89 declares the parameter as $gqlobal (typo), but line 93 references $global, which is undefined in this function scope. This will cause the function to always return $false or produce incorrect results.

Apply this diff to fix the typo:

-function Test-ShimAdded($shimName, $gqlobal) {
+function Test-ShimAdded($shimName, $global) {
     $added = Get-AddedShimsConfig
 
     # Check if shim exists and matches global flag
     return ($added.PSObject.Properties[$shimName] -and $added.$shimName.global -eq $global)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function Test-ShimAdded($shimName, $gqlobal) {
$added = Get-AddedShimsConfig
# Check if shim exists and matches global flag
return ($added.PSObject.Properties[$shimName] -and $added.$shimName.global -eq $global)
}
function Test-ShimAdded($shimName, $global) {
$added = Get-AddedShimsConfig
# Check if shim exists and matches global flag
return ($added.PSObject.Properties[$shimName] -and $added.$shimName.global -eq $global)
}
🤖 Prompt for AI Agents
In libexec/scoop-shim.ps1 around lines 89 to 94, the function Test-ShimAdded
declares the parameter as $gqlobal but later checks $global, causing an
undefined variable reference; rename the parameter to $global (or update all
references to match the intended name) so the parameter and its usage are
consistent, then run a quick syntax check to ensure no other references to the
misspelled name remain.


if ($SubCommand -notin @('add', 'rm', 'list', 'info', 'alter')) {
if (!$SubCommand) {
error '<subcommand> missing'
Expand All @@ -47,14 +103,16 @@ if ($SubCommand -notin @('add', 'rm', 'list', 'info', 'alter')) {
exit 1
}

$opt, $other, $err = getopt $Args 'g' 'global'
# Update getopt parsing to support --added option
$opt, $other, $err = getopt $Args 'ga' 'global', 'added'
if ($err) { "scoop shim: $err"; exit 1 }

$global = $opt.g -or $opt.global
$showOnlyAdded = $opt.a -or $opt.added

if ($SubCommand -ne 'list' -and $other.Length -eq 0) {
error "<shim_name> must be specified for subcommand '$SubCommand'"
my_usage
my_usages
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify function name change.

Line 115 calls my_usages (plural), but the help text at the top shows my_usage (singular). Ensure this function exists in the imported modules.


🏁 Script executed:

#!/bin/bash
# Search for my_usage and my_usages function definitions
rg -n "function (my_usage|my_usages)" lib/ supporting/ libexec/

Length of output: 71


Rename function call to match defined helper
In libexec/scoop-shim.ps1 at line 115, the code calls my_usages, but only my_usage (singular) is defined (lib/help.ps1:14). Update the invocation:

-    my_usages
+    my_usage
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
my_usages
my_usage
🤖 Prompt for AI Agents
In libexec/scoop-shim.ps1 around line 115, the script calls my_usages but the
defined helper is my_usage (singular); replace the incorrect call with my_usage
so the correct function is invoked and avoid undefined function errors.

exit 1
}

Expand All @@ -77,6 +135,8 @@ function Get-ShimInfo($ShimPath) {
}
$info.IsGlobal = $ShimPath.StartsWith("$globalShimDir")
$info.IsHidden = !((Get-Command -Name $info.Name).Path -eq $info.Path)
# Add "Added" field
$info.IsAdded = Test-ShimAdded $info.Name $info.IsGlobal
[PSCustomObject]$info
}

Expand All @@ -95,7 +155,7 @@ switch ($SubCommand) {
error "<command_path> must be specified for subcommand 'add'"
my_usage
exit 1
}
}
$shimName = $other[0]
$commandPath = $other[1]
if ($other.Length -gt 2) {
Expand All @@ -108,14 +168,16 @@ switch ($SubCommand) {
$exCommand = Get-Command $shortPath -ErrorAction SilentlyContinue
if ($exCommand -and $exCommand.CommandType -eq 'Application') {
$commandPath = $exCommand.Path
} # TODO - add support for more command types: Alias, Cmdlet, ExternalScript, Filter, Function, Script, and Workflow
}
}
}
if ($commandPath -and (Test-Path $commandPath)) {
Write-Host "Adding $(if ($global) { 'global' } else { 'local' }) shim " -NoNewline
Write-Host $shimName -ForegroundColor Cyan -NoNewline
Write-Host '...'
shim $commandPath $global $shimName $commandArgs
# Save shim to config
Add-ShimToConfig $shimName $global $commandPath $commandArgs
} else {
Write-Host "ERROR: Command path does not exist: " -ForegroundColor Red -NoNewline
Write-Host $($other[1]) -ForegroundColor Cyan
Expand All @@ -127,6 +189,8 @@ switch ($SubCommand) {
$other | ForEach-Object {
if (Get-ShimPath $_ $global) {
rm_shim $_ (shimdir $global)
# Remove shim from config
Remove-ShimFromConfig $_ $global
} else {
$failed += $_
}
Expand All @@ -140,9 +204,11 @@ switch ($SubCommand) {
}
}
'list' {
$other = @($other) -ne '*'
# Validate all given patterns before matching.
$other | ForEach-Object {
# Handle pattern matching
$patterns = @($other) -ne '*'

# Validate regex patterns
$patterns | ForEach-Object {
try {
$pattern = $_
[void][Regex]::New($pattern)
Expand All @@ -152,19 +218,48 @@ switch ($SubCommand) {
exit 1
}
}
$pattern = $other -join '|'
$shims = @()
if (!$global) {
$shims += Get-ChildItem -Path $localShimDir -Recurse -Include '*.shim', '*.ps1' |
Where-Object { !$pattern -or ($_.BaseName -match $pattern) } |
Select-Object -ExpandProperty FullName
}
if (Test-Path $globalShimDir) {
$shims += Get-ChildItem -Path $globalShimDir -Recurse -Include '*.shim', '*.ps1' |
Where-Object { !$pattern -or ($_.BaseName -match $pattern) } |
Select-Object -ExpandProperty FullName

$pattern = $patterns -join '|'
$shimInfos = @()

if ($showOnlyAdded) {
# When --added option is used, read from config directly
$added = Get-AddedShimsConfig

# Iterate over each shim in config
$added.PSObject.Properties | ForEach-Object {
$shimName = $_.Name
$shimConfig = $_.Value

# Apply regex filter
if (!$pattern -or ($shimName -match $pattern)) {
# Determine shim path based on global flag
$shimPath = Get-ShimPath $shimName $shimConfig.global

if ($shimPath) {
$shimInfos += Get-ShimInfo $shimPath
}
}
}
} else {
Comment on lines +225 to +244
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Honor -g with --added; current code lists both scopes.

Mirror the non---added behavior: without -g, show both; with -g, show only global.

-                # Apply regex filter
-                if (!$pattern -or ($shimName -match $pattern)) {
-                    # Determine shim path based on global flag
-                    $shimPath = Get-ShimPath $shimName $shimConfig.global
-                    if ($shimPath) {
-                        $shimInfos += Get-ShimInfo $shimPath
-                    }
-                }
+                # Apply regex filter and optional -g scope filter
+                if ((-not $pattern -or ($shimName -match $pattern)) -and ((-not $global) -or $shimConfig.global)) {
+                    $shimPath = Get-ShimPath $shimName $shimConfig.global
+                    if ($shimPath) { $shimInfos += Get-ShimInfo $shimPath }
+                }
🤖 Prompt for AI Agents
In libexec/scoop-shim.ps1 around lines 225 to 244, the --added branch currently
ignores the -g/$global switch and always uses the shim's configured scope;
adjust the loop to honor -g by filtering added entries: if $global is set only
include shims whose $shimConfig.global is true, otherwise include all added
shims (no scope filter). Implement this by checking the $global switch inside
the ForEach-Object and skipping entries that are not global when $global is
present, then continue to call Get-ShimPath/Get-ShimInfo as before.

# Original logic: scan file system
$shims = @()

if (!$global) {
$shims += Get-ChildItem -Path $localShimDir -Recurse -Include '*.shim', '*.ps1' |
Where-Object { !$pattern -or ($_.BaseName -match $pattern) } |
Select-Object -ExpandProperty FullName
}
if (Test-Path $globalShimDir) {
$shims += Get-ChildItem -Path $globalShimDir -Recurse -Include '*.shim', '*.ps1' |
Where-Object { !$pattern -or ($_.BaseName -match $pattern) } |
Select-Object -ExpandProperty FullName
}

$shimInfos = $shims.ForEach({ Get-ShimInfo $_ })
}
$shims.ForEach({ Get-ShimInfo $_ }) | Add-Member -TypeName 'ScoopShims' -PassThru

$shimInfos | Format-Table -Property * -AutoSize
}
'info' {
$shimName = $other[0]
Expand Down Expand Up @@ -232,7 +327,7 @@ switch ($SubCommand) {
Write-Host "run 'scoop shim alter $shimName$(if (!$global) { ' --global' })' to alternate its source"
exit 2
}
exit 3
exit
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Return a consistent non-zero exit code on error path.

Use exit 3 (as above) instead of bare exit.

-            exit
+            exit 3
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
exit
exit 3
🤖 Prompt for AI Agents
In libexec/scoop-shim.ps1 around line 330, the error path uses a bare "exit"
which returns a zero/ambiguous status; change it to "exit 3" to return a
consistent non-zero exit code (matching other error paths). Replace the bare
exit statement with exit 3 so callers can reliably detect failure.

}
}
}
Expand Down