Skip to content

Commit

Permalink
perf(scoop-search): Improve performance for local search (ScoopInstal…
Browse files Browse the repository at this point in the history
…ler#5644)

* perf(search): improve local search performance

* Update libexec/scoop-search.ps1

Co-authored-by: Hsiao-nan Cheung <[email protected]>

* Update libexec/scoop-search.ps1

Co-authored-by: Hsiao-nan Cheung <[email protected]>

* Update libexec/scoop-search.ps1

Co-authored-by: Hsiao-nan Cheung <[email protected]>

* Update libexec/scoop-search.ps1

Co-authored-by: Hsiao-nan Cheung <[email protected]>

* Update libexec/scoop-search.ps1

Co-authored-by: Hsiao-nan Cheung <[email protected]>

* Update libexec/scoop-search.ps1

Co-authored-by: Hsiao-nan Cheung <[email protected]>

* 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 <[email protected]>
Co-authored-by: Rashil Gandhi <[email protected]>
  • Loading branch information
3 people authored and CrendKing committed Oct 3, 2023
1 parent aea3cf5 commit 2707e4f
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 31 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,14 @@
- **core:** Use relative path as fallback of `$scoopdir` ([#5544](https://github.com/ScoopInstaller/Scoop/issues/5544))
- **scoop-checkup:** Skip defender check in Windows Sandbox ([#5519](https://github.com/ScoopInstaller/Scoop/issues/5519))
- **buckets:** Avoid error messages for unexpected dir ([#5549](https://github.com/ScoopInstaller/Scoop/issues/5549))
- **scoop-virustotal**: Fix `scoop-virustotal` when `--all' has been passed without app ([#5593](https://github.com/ScoopInstaller/Scoop/pull/5593))
- **scoop-virustotal:** Fix `scoop-virustotal` when `--all` has been passed without app ([#5593](https://github.com/ScoopInstaller/Scoop/pull/5593))
- **scoop-checkup:** Change the message level of helpers from ERROR to WARN ([#5549](https://github.com/ScoopInstaller/Scoop/issues/5614))
- **scoop-(un)hold:** Correct output the messages when manifest not found, (already|not) held ([#5519](https://github.com/ScoopInstaller/Scoop/issues/5519))

### Performance Improvements

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

### Code Refactoring

Expand Down
118 changes: 88 additions & 30 deletions libexec/scoop-search.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ param($query)
. "$PSScriptRoot\..\lib\manifest.ps1" # 'manifest'
. "$PSScriptRoot\..\lib\versions.ps1" # 'Get-LatestVersion'

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

try {
$query = New-Object Regex $query, 'IgnoreCase'
Expand All @@ -32,24 +32,90 @@ function bin_match($manifest, $query) {
if ((strip_ext $fname) -match $query) { $fname }
elseif ($alias -match $query) { $alias }
}

if ($bins) { return $bins }
else { return $false }
}

function bin_match_json($json, $query) {
[System.Text.Json.JsonElement]$bin = [System.Text.Json.JsonElement]::new()
if (!$json.RootElement.TryGetProperty("bin", [ref] $bin)) { return $false }
$bins = @()
if($bin.ValueKind -eq [System.Text.Json.JsonValueKind]::String -and [System.IO.Path]::GetFileNameWithoutExtension($bin) -match $query) {
$bins += [System.IO.Path]::GetFileName($bin)
} elseif ($bin.ValueKind -eq [System.Text.Json.JsonValueKind]::Array) {
foreach($subbin in $bin.EnumerateArray()) {
if($subbin.ValueKind -eq [System.Text.Json.JsonValueKind]::String -and [System.IO.Path]::GetFileNameWithoutExtension($subbin) -match $query) {
$bins += [System.IO.Path]::GetFileName($subbin)
} elseif ($subbin.ValueKind -eq [System.Text.Json.JsonValueKind]::Array) {
if([System.IO.Path]::GetFileNameWithoutExtension($subbin[0]) -match $query) {
$bins += [System.IO.Path]::GetFileName($subbin[0])
} elseif ($subbin.GetArrayLength() -ge 2 -and $subbin[1] -match $query) {
$bins += $subbin[1]
}
}
}
}

if ($bins) { return $bins }
else { return $false }
}

function search_bucket($bucket, $query) {
$apps = apps_in_bucket (Find-BucketDirectory $bucket) | ForEach-Object { @{ name = $_ } }
$apps = Get-ChildItem (Find-BucketDirectory $bucket) -Filter '*.json' -Recurse

$apps | ForEach-Object {
$json = [System.Text.Json.JsonDocument]::Parse([System.IO.File]::ReadAllText($_.FullName))
$name = $_.BaseName

if ($name -match $query) {
$list.Add([PSCustomObject]@{
Name = $name
Version = $json.RootElement.GetProperty("version")
Source = $bucket
Binaries = ""
})
} else {
$bin = bin_match_json $json $query
if ($bin) {
$list.Add([PSCustomObject]@{
Name = $name
Version = $json.RootElement.GetProperty("version")
Source = $bucket
Binaries = $bin -join ' | '
})
}
}
}
}

if ($query) {
$apps = $apps | Where-Object {
if ($_.name -match $query) { return $true }
$bin = bin_match (manifest $_.name $bucket) $query
# fallback function for PowerShell 5
function search_bucket_legacy($bucket, $query) {
$apps = Get-ChildItem (Find-BucketDirectory $bucket) -Filter '*.json' -Recurse

$apps | ForEach-Object {
$manifest = [System.IO.File]::ReadAllText($_.FullName) | ConvertFrom-Json -ErrorAction Continue
$name = $_.BaseName

if ($name -match $query) {
$list.Add([PSCustomObject]@{
Name = $name
Version = $manifest.Version
Source = $bucket
Binaries = ""
})
} else {
$bin = bin_match $manifest $query
if ($bin) {
$_.bin = $bin
return $true
$list.Add([PSCustomObject]@{
Name = $name
Version = $manifest.Version
Source = $bucket
Binaries = $bin -join ' | '
})
}
}
}
$apps | ForEach-Object { $_.version = (Get-LatestVersion -AppName $_.name -Bucket $bucket); $_ }
}

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

$remote_list = @()
$results | ForEach-Object {
$name = $_.bucket
$bucket = $_.bucket
$_.results | ForEach-Object {
$item = [ordered]@{}
$item.Name = $_
$item.Source = $name
$list += [PSCustomObject]$item
$item.Source = $bucket
$remote_list += [PSCustomObject]$item
}
}

$list
$remote_list
}

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

$res | ForEach-Object {
$item = [ordered]@{}
$item.Name = $_.name
$item.Version = $_.version
$item.Source = $name
$item.Binaries = ""
if ($_.bin) { $item.Binaries = $_.bin -join ' | ' }
$list += [PSCustomObject]$item
}
Get-LocalBucket | ForEach-Object {
if ($jsonTextAvailable) {
search_bucket $_ $query
} else {
search_bucket_legacy $_ $query
}
}

if ($list.Length -gt 0) {
if ($list.Count -gt 0) {
Write-Host "Results from local buckets..."
$list
}

if (!$local_results -and !(github_ratelimit_reached)) {
if ($list.Count -eq 0 -and !(github_ratelimit_reached)) {
$remote_results = search_remotes $query
if (!$remote_results) {
warn "No matches found."
Expand Down

0 comments on commit 2707e4f

Please sign in to comment.