Skip to content

Commit 2707e4f

Browse files
r15ch13niheavenrashil2000
authored andcommitted
perf(scoop-search): Improve performance for local search (ScoopInstaller#5644)
* perf(search): improve local search performance * Update libexec/scoop-search.ps1 Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com> * Update libexec/scoop-search.ps1 Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com> * Update libexec/scoop-search.ps1 Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com> * Update libexec/scoop-search.ps1 Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com> * Update libexec/scoop-search.ps1 Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com> * Update libexec/scoop-search.ps1 Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com> * Added [JsonDocument]::Parse for testing * Fix array length check * Used wrong function * Add fallback function for PowerShell 5 * Check for System.Text.Json in Assemblies instead * Show help output * Revert "Show help output" This reverts commit d3d6b01. * Update CHANGELOG.md --------- Co-authored-by: Hsiao-nan Cheung <niheaven@gmail.com> Co-authored-by: Rashil Gandhi <46838874+rashil2000@users.noreply.github.com>
1 parent aea3cf5 commit 2707e4f

2 files changed

Lines changed: 90 additions & 31 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,14 @@
2929
- **core:** Use relative path as fallback of `$scoopdir` ([#5544](https://github.com/ScoopInstaller/Scoop/issues/5544))
3030
- **scoop-checkup:** Skip defender check in Windows Sandbox ([#5519](https://github.com/ScoopInstaller/Scoop/issues/5519))
3131
- **buckets:** Avoid error messages for unexpected dir ([#5549](https://github.com/ScoopInstaller/Scoop/issues/5549))
32-
- **scoop-virustotal**: Fix `scoop-virustotal` when `--all' has been passed without app ([#5593](https://github.com/ScoopInstaller/Scoop/pull/5593))
32+
- **scoop-virustotal:** Fix `scoop-virustotal` when `--all` has been passed without app ([#5593](https://github.com/ScoopInstaller/Scoop/pull/5593))
3333
- **scoop-checkup:** Change the message level of helpers from ERROR to WARN ([#5549](https://github.com/ScoopInstaller/Scoop/issues/5614))
3434
- **scoop-(un)hold:** Correct output the messages when manifest not found, (already|not) held ([#5519](https://github.com/ScoopInstaller/Scoop/issues/5519))
3535

3636
### Performance Improvements
3737

3838
- **decompress:** Disable progress bar to improve `Expand-Archive` performance ([#5410](https://github.com/ScoopInstaller/Scoop/issues/5410))
39+
- **scoop-search:** Improve performance for local search ([#5324](https://github.com/ScoopInstaller/Scoop/issues/5324))
3940

4041
### Code Refactoring
4142

libexec/scoop-search.ps1

Lines changed: 88 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ param($query)
99
. "$PSScriptRoot\..\lib\manifest.ps1" # 'manifest'
1010
. "$PSScriptRoot\..\lib\versions.ps1" # 'Get-LatestVersion'
1111

12-
$list = @()
12+
$list = [System.Collections.Generic.List[PSCustomObject]]::new()
1313

1414
try {
1515
$query = New-Object Regex $query, 'IgnoreCase'
@@ -32,24 +32,90 @@ function bin_match($manifest, $query) {
3232
if ((strip_ext $fname) -match $query) { $fname }
3333
elseif ($alias -match $query) { $alias }
3434
}
35+
36+
if ($bins) { return $bins }
37+
else { return $false }
38+
}
39+
40+
function bin_match_json($json, $query) {
41+
[System.Text.Json.JsonElement]$bin = [System.Text.Json.JsonElement]::new()
42+
if (!$json.RootElement.TryGetProperty("bin", [ref] $bin)) { return $false }
43+
$bins = @()
44+
if($bin.ValueKind -eq [System.Text.Json.JsonValueKind]::String -and [System.IO.Path]::GetFileNameWithoutExtension($bin) -match $query) {
45+
$bins += [System.IO.Path]::GetFileName($bin)
46+
} elseif ($bin.ValueKind -eq [System.Text.Json.JsonValueKind]::Array) {
47+
foreach($subbin in $bin.EnumerateArray()) {
48+
if($subbin.ValueKind -eq [System.Text.Json.JsonValueKind]::String -and [System.IO.Path]::GetFileNameWithoutExtension($subbin) -match $query) {
49+
$bins += [System.IO.Path]::GetFileName($subbin)
50+
} elseif ($subbin.ValueKind -eq [System.Text.Json.JsonValueKind]::Array) {
51+
if([System.IO.Path]::GetFileNameWithoutExtension($subbin[0]) -match $query) {
52+
$bins += [System.IO.Path]::GetFileName($subbin[0])
53+
} elseif ($subbin.GetArrayLength() -ge 2 -and $subbin[1] -match $query) {
54+
$bins += $subbin[1]
55+
}
56+
}
57+
}
58+
}
59+
3560
if ($bins) { return $bins }
3661
else { return $false }
3762
}
3863

3964
function search_bucket($bucket, $query) {
40-
$apps = apps_in_bucket (Find-BucketDirectory $bucket) | ForEach-Object { @{ name = $_ } }
65+
$apps = Get-ChildItem (Find-BucketDirectory $bucket) -Filter '*.json' -Recurse
66+
67+
$apps | ForEach-Object {
68+
$json = [System.Text.Json.JsonDocument]::Parse([System.IO.File]::ReadAllText($_.FullName))
69+
$name = $_.BaseName
70+
71+
if ($name -match $query) {
72+
$list.Add([PSCustomObject]@{
73+
Name = $name
74+
Version = $json.RootElement.GetProperty("version")
75+
Source = $bucket
76+
Binaries = ""
77+
})
78+
} else {
79+
$bin = bin_match_json $json $query
80+
if ($bin) {
81+
$list.Add([PSCustomObject]@{
82+
Name = $name
83+
Version = $json.RootElement.GetProperty("version")
84+
Source = $bucket
85+
Binaries = $bin -join ' | '
86+
})
87+
}
88+
}
89+
}
90+
}
4191

42-
if ($query) {
43-
$apps = $apps | Where-Object {
44-
if ($_.name -match $query) { return $true }
45-
$bin = bin_match (manifest $_.name $bucket) $query
92+
# fallback function for PowerShell 5
93+
function search_bucket_legacy($bucket, $query) {
94+
$apps = Get-ChildItem (Find-BucketDirectory $bucket) -Filter '*.json' -Recurse
95+
96+
$apps | ForEach-Object {
97+
$manifest = [System.IO.File]::ReadAllText($_.FullName) | ConvertFrom-Json -ErrorAction Continue
98+
$name = $_.BaseName
99+
100+
if ($name -match $query) {
101+
$list.Add([PSCustomObject]@{
102+
Name = $name
103+
Version = $manifest.Version
104+
Source = $bucket
105+
Binaries = ""
106+
})
107+
} else {
108+
$bin = bin_match $manifest $query
46109
if ($bin) {
47-
$_.bin = $bin
48-
return $true
110+
$list.Add([PSCustomObject]@{
111+
Name = $name
112+
Version = $manifest.Version
113+
Source = $bucket
114+
Binaries = $bin -join ' | '
115+
})
49116
}
50117
}
51118
}
52-
$apps | ForEach-Object { $_.version = (Get-LatestVersion -AppName $_.name -Bucket $bucket); $_ }
53119
}
54120

55121
function download_json($url) {
@@ -96,43 +162,35 @@ function search_remotes($query) {
96162
(add them using 'scoop bucket add <bucket name>')"
97163
}
98164

165+
$remote_list = @()
99166
$results | ForEach-Object {
100-
$name = $_.bucket
167+
$bucket = $_.bucket
101168
$_.results | ForEach-Object {
102169
$item = [ordered]@{}
103170
$item.Name = $_
104-
$item.Source = $name
105-
$list += [PSCustomObject]$item
171+
$item.Source = $bucket
172+
$remote_list += [PSCustomObject]$item
106173
}
107174
}
108-
109-
$list
175+
$remote_list
110176
}
111177

112-
Get-LocalBucket | ForEach-Object {
113-
$res = search_bucket $_ $query
114-
$local_results = $local_results -or $res
115-
if ($res) {
116-
$name = "$_"
178+
$jsonTextAvailable = [System.AppDomain]::CurrentDomain.GetAssemblies() | Where-object { [System.IO.Path]::GetFileNameWithoutExtension($_.Location) -eq "System.Text.Json" }
117179

118-
$res | ForEach-Object {
119-
$item = [ordered]@{}
120-
$item.Name = $_.name
121-
$item.Version = $_.version
122-
$item.Source = $name
123-
$item.Binaries = ""
124-
if ($_.bin) { $item.Binaries = $_.bin -join ' | ' }
125-
$list += [PSCustomObject]$item
126-
}
180+
Get-LocalBucket | ForEach-Object {
181+
if ($jsonTextAvailable) {
182+
search_bucket $_ $query
183+
} else {
184+
search_bucket_legacy $_ $query
127185
}
128186
}
129187

130-
if ($list.Length -gt 0) {
188+
if ($list.Count -gt 0) {
131189
Write-Host "Results from local buckets..."
132190
$list
133191
}
134192

135-
if (!$local_results -and !(github_ratelimit_reached)) {
193+
if ($list.Count -eq 0 -and !(github_ratelimit_reached)) {
136194
$remote_results = search_remotes $query
137195
if (!$remote_results) {
138196
warn "No matches found."

0 commit comments

Comments
 (0)