Add an optional installer-host column to package lists - #5320
Conversation
There was a problem hiding this comment.
Pull request overview
Adds an optional installer-host column to package lists, backed by lazy URL resolution and caching.
Changes:
- Adds configurable installer-host UI and settings integration.
- Resolves and caches installer URLs and hosts.
- Adds host-formatting utilities and unit tests.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/UniGetUI.PackageEngine.Managers.WinGet/WinGet.cs |
Exposes WinGet installer URL resolution. |
src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/PingetPackageDetailsProvider.cs |
Retrieves installer URLs from Pinget manifests. |
src/UniGetUI.Core.Tools/InstallerHostDisplay.cs |
Formats installer hosts and URL tooltips. |
src/UniGetUI.Core.Tools.Tests/InstallerHostDisplayTests.cs |
Tests URL and host formatting. |
src/UniGetUI.Core.Settings/SettingsEngine_Names.cs |
Registers the column setting. |
src/UniGetUI.Avalonia/Views/SoftwarePages/AbstractPackagesPage.axaml |
Adds the package-list column. |
src/UniGetUI.Avalonia/Views/Pages/SettingsPages/Interface_P.axaml |
Adds the interface setting control. |
src/UniGetUI.Avalonia/Views/Controls/PackageInstallerHostLoader.cs |
Starts loading for realized rows. |
src/UniGetUI.Avalonia/ViewModels/SoftwarePages/PackagesPageViewModel.cs |
Controls header text and visibility. |
src/UniGetUI.Avalonia/Models/PackageCollections.cs |
Implements resolution, caching, and display state. |
src/UniGetUI.Avalonia/Infrastructure/SettingsSearchIndex.cs |
Makes the setting searchable. |
src/Languages/lang_en.json |
Adds English localization strings. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated 1 comment.
Suppressed comments (2)
Previously missed (2) — in code that hasn't changed since the last review.
src/UniGetUI.Avalonia/Models/PackageCollections.cs:392
- Clearing the entire cache when adding entry 1,025 discards 1,024 valid network-derived results at once. On large result sets or subsequent page/list rebuilds, those packages must query their repositories again, creating periodic request bursts; the icon cache above avoids this with bounded LRU eviction (
PackageCollections.cs:39-44, 130-134). Evict only the least-recently-used/oldest entry instead of flushing the cache.
if (_installerHostCache.Count >= MaxInstallerHostCacheEntries
&& !_installerHostCache.ContainsKey(hash))
{
_installerHostCache.Clear();
}
src/UniGetUI.Avalonia/Models/PackageCollections.cs:330
- On an Updates row,
InstallerHostVersionselectsNewVersionString, but this non-WinGet path loadsPackage.Details, whose helpers resolve againstPackage.VersionString(the installed version). For example, Cargo selectsmanifest.versionsbydetails.Package.VersionString(CargoPkgDetailsHelper.cs:47-49), and NuGet builds its manifest URL with that same property (NuGetManifestLoader.cs:16-20). The column can therefore report the old installer’s host rather than the host from which the update will be downloaded. This path needs a version-aware details/URL resolver usingInstallerHostVersion.
if (!Package.Details.IsPopulated)
await Package.Details.Load().ConfigureAwait(false);
return Package.Details.InstallerUrl is { } url ? [url.ToString()] : null;
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.
Suppressed comments (3)
Previously missed (2) — in code that hasn't changed since the last review.
src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/PingetPackageDetailsProvider.cs:551
OrdinalIgnoreCaseapplies to the entire URL, but only the scheme and host are case-insensitive; path and query components can be case-sensitive. As a result, two distinct installer artifacts or signed URLs that differ only by path/query casing are dropped from the returned list (and the new test currently codifies that loss). Please deduplicate with URI-component-aware equality and update the expectation accordingly.
if (urls.Contains(installer.Url, StringComparer.OrdinalIgnoreCase))
continue;
urls.Add(installer.Url);
src/UniGetUI.Core.Tools/InstallerHostDisplay.cs:36
- This also compares the complete URL case-insensitively, so
JoinUrlshides valid distinct URLs whose path or query differs only by case. Use URI-aware comparison that folds scheme/host but preserves path/query case; the addedJoinUrlsListsDistinctUrlsOnSeparateLinestest should be adjusted as well.
string trimmed = (url ?? "").Trim();
if (trimmed.Length == 0 || distinct.Contains(trimmed, StringComparer.OrdinalIgnoreCase))
continue;
distinct.Add(trimmed);
src/UniGetUI.Avalonia/Models/PackageCollections.cs:294
- Marking the lookup unresolved does not arrange another call after
InstallerHostRetryInterval. Resetting_installerHostLoadStartedonly helps if virtualization later reattaches or changes this row's data context; a row that stays visible remains at “—” indefinitely after a transient failure. Schedule a lifetime-token-aware retry (and distinguish transient lookup failures from a successful no-URL result to avoid repeatedly querying packages that genuinely have no installer URL).
if (resolved.Host.Length > 0)
CacheInstallerHost(hash, resolved.Host, resolved.Urls);
else
MarkInstallerHostUnresolved(hash);
There was a problem hiding this comment.
🤖 Pull request was approved automatically: the AI review is complete and all its review threads are resolved. 🎉
Integration Details
{
"deliveryId": "d99c25e0-a090-11f1-9c19-b9898df72113",
"headSha": "4539d482ed61e014f439e267a7aa9d18e04e188d",
"reviewer": "copilot-pull-request-reviewer[bot]"
}
This pull request introduces a new feature that displays the installer host (i.e., the domain from which a package installer will be downloaded) in package lists. The implementation includes UI, settings, caching, and backend logic to efficiently resolve, display, and optionally hide this information. Additionally, utility and test code has been added to robustly extract and format installer host details.
Installer Host Column Feature:
Backend and Caching Logic:
PackageWrapperto resolve, cache, and expose the installer host and its tooltip, including concurrency controls and a cache eviction strategy.Utility and Test Code:
InstallerHostDisplayutility for extracting and formatting hostnames from installer URLs, with robust handling of edge cases.UI Infrastructure:
PackageInstallerHostLoader.Trackto trigger installer host loading when a package row is rendered, ensuring on-demand and efficient data loading.These changes collectively provide users with greater transparency about where package installers are sourced from, while maintaining performance and configurability.