Skip to content

Commit

Permalink
Merge pull request #2931 from marticliment/winget-native-package-caching
Browse files Browse the repository at this point in the history
  • Loading branch information
marticliment authored Nov 3, 2024
2 parents b5f2de6 + e8b0d92 commit c879ac0
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 149 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,7 @@ namespace UniGetUI.PackageEngine.Managers.WingetManager
internal sealed class WinGetPackageDetailsProvider : BasePackageDetailsProvider<UniGetUIManagers.PackageManager>
{
private static readonly Dictionary<string, string> __msstore_package_manifests = [];

private struct MicrosoftStoreProductType
{
public string productIds { get; set; }
}


public WinGetPackageDetailsProvider(WinGet manager) : base(manager) { }

protected override IEnumerable<string> GetInstallableVersions_UnSafe(IPackage package)
Expand Down Expand Up @@ -224,50 +219,8 @@ protected override IEnumerable<Uri> GetScreenshots_UnSafe(IPackage package)

private static CacheableIcon? GetWinGetPackageIcon(IPackage package)
{
if (WinGetHelper.Instance is not NativeWinGetHelper)
return null;

PackageManager WinGetManager = ((NativeWinGetHelper)WinGetHelper.Instance).WinGetManager;
WindowsPackageManager.Interop.WindowsPackageManagerFactory Factory = ((NativeWinGetHelper)WinGetHelper.Instance).Factory;

// Find the native package for the given Package object
PackageCatalogReference Catalog = WinGetManager.GetPackageCatalogByName(package.Source.Name);
if (Catalog is null)
{
Logger.Error("[WINGET COM] Failed to get catalog " + package.Source.Name + ". Is the package local?");
return null;
}

// Connect to catalog
Catalog.AcceptSourceAgreements = true;
ConnectResult ConnectResult = Catalog.Connect();
if (ConnectResult.Status != ConnectResultStatus.Ok)
{
Logger.Error("[WINGET COM] Failed to connect to catalog " + package.Source.Name);
return null;
}

// Match only the exact same Id
FindPackagesOptions packageMatchFilter = Factory.CreateFindPackagesOptions();
PackageMatchFilter filters = Factory.CreatePackageMatchFilter();
filters.Field = PackageMatchField.Id;
filters.Value = package.Id;
filters.Option = PackageFieldMatchOption.Equals;
packageMatchFilter.Filters.Add(filters);
packageMatchFilter.ResultLimit = 1;
FindPackagesResult SearchResult = ConnectResult.PackageCatalog.FindPackages(packageMatchFilter);

if (SearchResult.Matches is null || SearchResult.Matches.Count == 0)
{
Logger.Error($"[WINGET COM] Package with Id={package.Id} was NOT found in catalog id=" + package.Source.Name);
return null;
}

// Get the Native Package
CatalogPackage NativePackage = SearchResult.Matches.First().CatalogPackage;

// Extract data from NativeDetails
CatalogPackageMetadata NativeDetails = NativePackage.DefaultInstallVersion.GetCatalogPackageMetadata();
CatalogPackageMetadata? NativeDetails = NativePackageHandler.GetDetails(package);
if (NativeDetails is null) return null;

// Get the actual icon and return it
foreach (Icon? icon in NativeDetails.Icons.ToArray())
Expand Down
9 changes: 9 additions & 0 deletions src/UniGetUI.PackageEngine.Managers.WinGet/WinGet.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using ABI.System.Collections.Generic;
using UniGetUI.Core.Data;
using UniGetUI.Core.Logging;
using UniGetUI.Core.SettingsEngine;
Expand Down Expand Up @@ -231,6 +232,14 @@ protected override ManagerStatus LoadManager()
return status;
}

// For future usage
private void ReRegisterCOMServer()
{
WinGetHelper.Instance = new NativeWinGetHelper();
NativePackageHandler.Clear();
}


public override void RefreshPackageIndexes()
{
Process p = new()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
using System.Collections.Concurrent;
using Microsoft.Management.Deployment;
using UniGetUI.Core.Logging;
using UniGetUI.PackageEngine.Enums;
using UniGetUI.PackageEngine.Interfaces;

namespace UniGetUI.PackageEngine.Managers.WingetManager;

public static class NativePackageHandler
{
private static ConcurrentDictionary<long, CatalogPackage> __nativePackages = new();
private static ConcurrentDictionary<long, CatalogPackageMetadata> __nativeDetails = new();
private static ConcurrentDictionary<long, PackageInstallerInfo> __nativeInstallers_Install = new();
private static ConcurrentDictionary<long, PackageInstallerInfo> __nativeInstallers_Uninstall = new();

/// <summary>
/// Get (cache or load) the native package for the given package, if any;
/// </summary>
/// <returns></returns>
public static CatalogPackage? GetPackage(IPackage package)
{
if (NativeWinGetHelper.ExternalFactory is null || NativeWinGetHelper.ExternalManager is null)
return null;

__nativePackages.TryGetValue(package.GetHash(), out CatalogPackage? catalogPackage);
if (catalogPackage is not null)
return catalogPackage;

PackageCatalogReference Catalog = NativeWinGetHelper.ExternalManager.GetPackageCatalogByName(package.Source.Name);
if (Catalog is null)
{
Logger.Error("Failed to get catalog " + package.Source.Name + ". Is the package local?");
return null;
}

// Connect to catalog
Catalog.AcceptSourceAgreements = true;
ConnectResult ConnectResult = Catalog.Connect();
if (ConnectResult.Status != ConnectResultStatus.Ok)
{
Logger.Error("Failed to connect to catalog " + package.Source.Name);
return null;
}

// Match only the exact same Id
FindPackagesOptions packageMatchFilter = NativeWinGetHelper.ExternalFactory.CreateFindPackagesOptions();
PackageMatchFilter filters = NativeWinGetHelper.ExternalFactory.CreatePackageMatchFilter();
filters.Field = PackageMatchField.Id;
filters.Value = package.Id;
filters.Option = PackageFieldMatchOption.Equals;
packageMatchFilter.Filters.Add(filters);
packageMatchFilter.ResultLimit = 1;
var SearchResult = Task.Run(() => ConnectResult.PackageCatalog.FindPackages(packageMatchFilter));

if (SearchResult?.Result?.Matches is null ||
SearchResult.Result.Matches.Count == 0)
{
Logger.Error("Failed to find package " + package.Id + " in catalog " + package.Source.Name);
return null;
}

// Get the Native Package
catalogPackage = SearchResult.Result.Matches.First().CatalogPackage;
AddPackage(package, catalogPackage);

return catalogPackage;
}

/// <summary>
/// Adds an external CatalogPackage to the internal database
/// </summary>
public static void AddPackage(IPackage package, CatalogPackage catalogPackage)
{
__nativePackages[package.GetHash()] = catalogPackage;
}

/// <summary>
/// Get (cached or load) the native package details for the given package, if any;
/// </summary>
public static CatalogPackageMetadata? GetDetails(IPackage package)
{
if (__nativeDetails.TryGetValue(package.GetHash(), out CatalogPackageMetadata? metadata))
return metadata;

CatalogPackage? catalogPackage = GetPackage(package);
metadata = catalogPackage?.DefaultInstallVersion?.GetCatalogPackageMetadata();
metadata ??= catalogPackage?.InstalledVersion?.GetCatalogPackageMetadata();

if (metadata is not null)
__nativeDetails[package.GetHash()] = metadata;

return metadata;
}

/// <summary>
/// Get (cached or load) the native installer for the given package, if any. The operation type determines wether
/// </summary>
public static PackageInstallerInfo? GetInstallationOptions(IPackage package, OperationType operation)
{
if (NativeWinGetHelper.ExternalFactory is null)
return null;

PackageInstallerInfo? installerInfo = null;
if (operation is OperationType.Uninstall)
installerInfo = _getInstallationOptionsOnDict(package, ref __nativeInstallers_Uninstall, true);
else
installerInfo = _getInstallationOptionsOnDict(package, ref __nativeInstallers_Uninstall, false);

return installerInfo;
}

public static void Clear()
{
__nativePackages.Clear();;
__nativeDetails.Clear();;
__nativeInstallers_Install.Clear();;
__nativeInstallers_Uninstall.Clear();
}

private static PackageInstallerInfo? _getInstallationOptionsOnDict(IPackage package, ref ConcurrentDictionary<long, PackageInstallerInfo> source, bool installed)
{
if (source.TryGetValue(package.GetHash(), out PackageInstallerInfo? installerInfo))
return installerInfo;

PackageVersionInfo? catalogPackage;
if (installed) catalogPackage = GetPackage(package)?.InstalledVersion;
else catalogPackage = GetPackage(package)?.DefaultInstallVersion;

InstallOptions? options = NativeWinGetHelper.ExternalFactory?.CreateInstallOptions();
installerInfo = catalogPackage?.GetApplicableInstaller(options);

if (installerInfo is not null)
source[package.GetHash()] = installerInfo;

return installerInfo;
}
}
Loading

0 comments on commit c879ac0

Please sign in to comment.