winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

PackageManagerWrapper.cs (7335B)


      1 // -----------------------------------------------------------------------------
      2 // <copyright file="PackageManagerWrapper.cs" company="Microsoft Corporation">
      3 //     Copyright (c) Microsoft Corporation. Licensed under the MIT License.
      4 // </copyright>
      5 // -----------------------------------------------------------------------------
      6 
      7 namespace Microsoft.WinGet.Client.Engine.Helpers
      8 {
      9     using System;
     10     using System.Collections.Generic;
     11     using System.Runtime.InteropServices;
     12     using Microsoft.Management.Deployment;
     13     using Microsoft.WinGet.Client.Engine.Common;
     14     using Microsoft.WinGet.Client.Engine.Exceptions;
     15     using Windows.Foundation;
     16 
     17     /// <summary>
     18     /// Wrapper for PackageManager that handles rpc disconnections.
     19     /// The object is disconnected when the server is killed or on an update.
     20     /// </summary>
     21     internal sealed class PackageManagerWrapper
     22     {
     23         private static readonly Lazy<PackageManagerWrapper> Lazy = new (() => new PackageManagerWrapper());
     24 
     25         private PackageManager packageManager = null!;
     26 
     27         private PackageManagerWrapper()
     28         {
     29         }
     30 
     31         /// <summary>
     32         /// Gets the instance object.
     33         /// </summary>
     34         public static PackageManagerWrapper Instance
     35         {
     36             get { return Lazy.Value; }
     37         }
     38 
     39         /// <summary>
     40         /// Wrapper for InstallPackageAsync.
     41         /// </summary>
     42         /// <param name="package">The package to install.</param>
     43         /// <param name="options">The install options.</param>
     44         /// <returns>An async operation with progress.</returns>
     45         public IAsyncOperationWithProgress<InstallResult, InstallProgress> InstallPackageAsync(CatalogPackage package, InstallOptions options)
     46         {
     47             return this.Execute(
     48                 () => this.packageManager.InstallPackageAsync(package, options),
     49                 false);
     50         }
     51 
     52         /// <summary>
     53         /// Wrapper for UpgradePackageAsync.
     54         /// </summary>
     55         /// <param name="package">The package to upgrade.</param>
     56         /// <param name="options">The install options.</param>
     57         /// <returns>An async operation with progress.</returns>
     58         public IAsyncOperationWithProgress<InstallResult, InstallProgress> UpgradePackageAsync(CatalogPackage package, InstallOptions options)
     59         {
     60             return this.Execute(
     61                 () => this.packageManager.UpgradePackageAsync(package, options),
     62                 false);
     63         }
     64 
     65         /// <summary>
     66         /// Wrapper for UninstallPackageAsync.
     67         /// </summary>
     68         /// <param name="package">The package to uninstall.</param>
     69         /// <param name="options">The uninstall options.</param>
     70         /// <returns>An async operation with progress.</returns>
     71         public IAsyncOperationWithProgress<UninstallResult, UninstallProgress> UninstallPackageAsync(CatalogPackage package, UninstallOptions options)
     72         {
     73             return this.Execute(
     74                 () => this.packageManager.UninstallPackageAsync(package, options),
     75                 false);
     76         }
     77 
     78         /// <summary>
     79         /// Wrapper for DownloadPackageAsync.
     80         /// </summary>
     81         /// <param name="package">The package to download.</param>
     82         /// <param name="options">The download options.</param>
     83         /// <returns>An async operation with progress.</returns>
     84         public IAsyncOperationWithProgress<DownloadResult, PackageDownloadProgress> DownloadPackageAsync(CatalogPackage package, DownloadOptions options)
     85         {
     86             return this.Execute(
     87                 () => this.packageManager.DownloadPackageAsync(package, options),
     88                 false);
     89         }
     90 
     91         /// <summary>
     92         /// Wrapper for RepairPackagesAsync.
     93         /// </summary>
     94         /// <param name="package">The package to repair.</param>
     95         /// <param name="options">The repair options.</param>
     96         /// <returns>An async operation with progress.</returns>
     97         public IAsyncOperationWithProgress<RepairResult, RepairProgress> RepairPackageAsync(CatalogPackage package, RepairOptions options)
     98         {
     99             return this.Execute(
    100                 () => this.packageManager.RepairPackageAsync(package, options),
    101                 false);
    102         }
    103 
    104         /// <summary>
    105         /// Wrapper for GetPackageCatalogs.
    106         /// </summary>
    107         /// <returns>A list of PackageCatalogReferences.</returns>
    108         public IReadOnlyList<PackageCatalogReference> GetPackageCatalogs()
    109         {
    110             return this.Execute(
    111                 () => this.packageManager.GetPackageCatalogs(),
    112                 true);
    113         }
    114 
    115         /// <summary>
    116         /// Wrapper for GetPackageCatalogByName.
    117         /// </summary>
    118         /// <param name="source">The name of the source.</param>
    119         /// <returns>A PackageCatalogReference.</returns>
    120         public PackageCatalogReference GetPackageCatalogByName(string source)
    121         {
    122             return this.Execute(
    123                 () => this.packageManager.GetPackageCatalogByName(source),
    124                 true);
    125         }
    126 
    127         /// <summary>
    128         /// Wrapper for CreateCompositePackageCatalog.
    129         /// </summary>
    130         /// <param name="options">CreateCompositePackageCatalogOptions.</param>
    131         /// <returns>A PackageCatalogReference.</returns>
    132         public PackageCatalogReference CreateCompositePackageCatalog(CreateCompositePackageCatalogOptions options)
    133         {
    134             return this.Execute(
    135                 () => this.packageManager.CreateCompositePackageCatalog(options),
    136                 false);
    137         }
    138 
    139         /// <summary>
    140         /// Gets the version of the package manager that is running.
    141         /// </summary>
    142         /// <returns>The version string.</returns>
    143         public string? GetVersion()
    144         {
    145             try
    146             {
    147                 return this.Execute(() => this.packageManager.Version, true);
    148             }
    149             catch
    150             {
    151                 return null;
    152             }
    153         }
    154 
    155         private TReturn Execute<TReturn>(Func<TReturn> func, bool canRetry)
    156         {
    157             if (Utilities.UsesInProcWinget && Utilities.ThreadIsSTA)
    158             {
    159                 // If you failed here, then you didn't wrap your call in ManagementDeploymentCommand.Execute
    160                 throw new SingleThreadedApartmentException();
    161             }
    162 
    163             bool stopRetry = false;
    164             while (true)
    165             {
    166                 if (this.packageManager == null)
    167                 {
    168                     this.packageManager = ManagementDeploymentFactory.Instance.CreatePackageManager();
    169                 }
    170 
    171                 try
    172                 {
    173                     return func();
    174                 }
    175                 catch (COMException ex) when (ex.HResult == ErrorCode.RpcServerUnavailable || ex.HResult == ErrorCode.RpcCallFailed)
    176                 {
    177                     this.packageManager = null!;
    178 
    179                     if (stopRetry || !canRetry)
    180                     {
    181                         throw;
    182                     }
    183 
    184                     stopRetry = true;
    185                 }
    186             }
    187         }
    188     }
    189 }