Private/Start-PackageDetailJobs.ps1
|
function Start-PackageDetailJobs { param( [string[]]$PackageIds, [string]$ConfigDir ) $maxConcurrentJobs = 100 $totalPackages = $PackageIds.Count if ($totalPackages -eq 0) { return @(), @{} } $packagesPerJob = [Math]::Ceiling($totalPackages / $maxConcurrentJobs) if ($packagesPerJob -lt 1) { $packagesPerJob = 1 } $actualJobCount = [Math]::Ceiling($totalPackages / $packagesPerJob) $jobs = [System.Collections.Generic.List[Object]]::new() $jobPackageMap = @{} # Resolve winget.exe path for detail fetching (COM API has limited fields) $wingetExe = $null $testPaths = @( "$env:LOCALAPPDATA\Microsoft\WindowsApps\winget.exe", "C:\Users\$env:USERNAME\AppData\Local\Microsoft\WindowsApps\winget.exe" ) foreach ($tp in $testPaths) { if (Test-Path $tp) { $wingetExe = $tp; break } } # Also check if winget is in PATH if (-not $wingetExe) { $cmd = Get-Command winget -ErrorAction SilentlyContinue if ($cmd) { $wingetExe = $cmd.Source } } $jobScript = { param($packageList, $cacheDir, $ParseSB, $WingetPath) $results = @{} # Define Parse-WingetShowOutput in the job scope from the passed script block if ($ParseSB) { Set-Item -Path function:Parse-WingetShowOutput -Value $ParseSB } $cacheFile = Join-Path $cacheDir "package_cache.json" $localCache = @{} # Read cache once at start of job if (Test-Path $cacheFile) { try { $cacheJson = Get-Content $cacheFile -Raw | ConvertFrom-Json if ($cacheJson) { $cacheJson.PSObject.Properties | ForEach-Object { $localCache[$_.Name] = $_.Value } } } catch { } } foreach ($pkgIdItem in $packageList) { $packageId = [string]$pkgIdItem $cachedInfo = $null # Try to get from cache first if ($localCache.ContainsKey($packageId)) { $entry = $localCache[$packageId] if ($entry -and $entry.CachedDate) { try { $cachedDate = [DateTime]$entry.CachedDate $daysSinceCached = ((Get-Date) - $cachedDate).TotalDays if ($daysSinceCached -lt 30) { $cachedInfo = $entry.Details } } catch { } } } if ($cachedInfo) { $results[$packageId] = $cachedInfo continue } # Not in cache - try winget.exe for rich details, fall back to COM API for basic info $info = $null if ($WingetPath -and (Test-Path $WingetPath)) { try { $output = & $WingetPath show --id $packageId --no-progress --disable-interactivity 2>&1 | Out-String $info = Parse-WingetShowOutput -Output $output -PackageId $packageId } catch { # Fall through to COM API } } if (-not $info -or -not $info.Version) { # Fallback: Use COM API (limited fields but always works) try { Import-Module Microsoft.WinGet.Client -ErrorAction SilentlyContinue $comResult = Find-WinGetPackage -Id $packageId -Exact -ErrorAction SilentlyContinue | Select-Object -First 1 if ($comResult) { $info = @{ Id = $packageId Version = $comResult.Version Publisher = $null PublisherName = $null PublisherUrl = $null PublisherGitHub = $null Author = $null Homepage = $null Description = $null Category = $null Tags = @() License = $null LicenseUrl = $null Copyright = $null CopyrightUrl = $null PrivacyUrl = $null PackageUrl = $null ReleaseNotes = $null ReleaseNotesUrl = $null Installer = $null Pricing = $null StoreLicense = $null FreeTrial = $null AgeRating = $null Moniker = $null Name = $comResult.Name } } } catch { } } if (-not $info) { $info = @{ Id = $packageId } } $results[$packageId] = $info } return $results } for ($i = 0; $i -lt $actualJobCount; $i++) { $startIndex = $i * $packagesPerJob $endIndex = [Math]::Min($startIndex + $packagesPerJob - 1, $totalPackages - 1) if ($startIndex -gt $endIndex) { break } $packageBatch = $PackageIds[$startIndex..$endIndex] $job = Start-WingetBatchJob -ScriptBlock $jobScript -ArgumentList (,$packageBatch), $ConfigDir, $function:Parse-WingetShowOutput, $wingetExe $jobs.Add($job) $jobPackageMap[$job.Id] = $packageBatch } return $jobs, $jobPackageMap } |