Skip to content

Commit 0def3dc

Browse files
authored
Invalidate a manager's installed-package caches when an operation succeeds (#5586)
1 parent 7a42c58 commit 0def3dc

10 files changed

Lines changed: 85 additions & 7 deletions

File tree

‎src/UniGetUI.PackageEngine.Interfaces/IPackageManager.cs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ public interface IPackageManager
8585
/// </summary>
8686
public IReadOnlyList<IPackage> GetInstalledPackages();
8787

88+
public long InstalledPackagesGeneration { get; }
89+
90+
public void InvalidateInstalledPackages();
91+
8892
/// <summary>
8993
/// Refreshes the Package Manager sources/indexes
9094
/// Each manager MUST implement this method.

‎src/UniGetUI.PackageEngine.Managers.Generic.NuGet/BaseNuGet.cs‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -852,7 +852,14 @@ internal static List<Package> ParseUpdatesResponse(
852852
}
853853

854854
protected sealed override IReadOnlyList<Package> GetInstalledPackages_UnSafe() =>
855-
TaskRecycler<IReadOnlyList<Package>>.RunOrAttach(_getInstalledPackages_UnSafe);
855+
TaskRecycler<IReadOnlyList<Package>>.RunOrAttach(
856+
ListInstalledPackagesForGeneration,
857+
InstalledPackagesGeneration
858+
);
859+
860+
private IReadOnlyList<Package> ListInstalledPackagesForGeneration(
861+
long installedPackagesGeneration
862+
) => _getInstalledPackages_UnSafe();
856863

857864
protected abstract IReadOnlyList<Package> _getInstalledPackages_UnSafe();
858865
}

‎src/UniGetUI.PackageEngine.Managers.Scoop/Scoop.cs‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -440,9 +440,13 @@ protected override IReadOnlyList<Package> GetAvailableUpdates_UnSafe()
440440
}
441441

442442
protected override IReadOnlyList<Package> GetInstalledPackages_UnSafe() =>
443-
TaskRecycler<IReadOnlyList<Package>>.RunOrAttach(_getInstalledPackages_UnSafe, 15);
443+
TaskRecycler<IReadOnlyList<Package>>.RunOrAttach(
444+
_getInstalledPackages_UnSafe,
445+
InstalledPackagesGeneration,
446+
15
447+
);
444448

445-
private IReadOnlyList<Package> _getInstalledPackages_UnSafe()
449+
private IReadOnlyList<Package> _getInstalledPackages_UnSafe(long installedPackagesGeneration)
446450
{
447451
using Process p = new()
448452
{

‎src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -475,21 +475,24 @@ nativePackage.AvailableVersions is { } versions
475475

476476
private IReadOnlyList<CatalogPackage> GetCachedLocalWinGetPackages(int? cacheSeconds = null)
477477
{
478-
long sourceIndexGeneration = WinGet.SourceIndexGeneration;
478+
(long, long) generations = (
479+
WinGet.SourceIndexGeneration,
480+
Manager.InstalledPackagesGeneration
481+
);
479482

480483
return cacheSeconds is null
481484
? TaskRecycler<IReadOnlyList<CatalogPackage>>.RunOrAttach(
482485
EnumerateLocalWinGetPackages,
483-
sourceIndexGeneration
486+
generations
484487
)
485488
: TaskRecycler<IReadOnlyList<CatalogPackage>>.RunOrAttach(
486489
EnumerateLocalWinGetPackages,
487-
sourceIndexGeneration,
490+
generations,
488491
cacheSeconds.Value
489492
);
490493
}
491494

492-
private IReadOnlyList<CatalogPackage> EnumerateLocalWinGetPackages(long sourceIndexGeneration)
495+
private IReadOnlyList<CatalogPackage> EnumerateLocalWinGetPackages((long, long) generations)
493496
{
494497
return _localPackagesProvider is not null
495498
? _localPackagesProvider()

‎src/UniGetUI.PackageEngine.Operations/PackageOperations.cs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ public PackageOperation(
137137
if (status is OperationStatus.Canceled)
138138
Package.SetTag(PackageTag.Default);
139139
};
140+
OperationSucceeded += (_, _) => Package.Manager.InvalidateInstalledPackages();
140141
OperationSucceeded += (_, _) => RecordPendingRebootState();
141142
OperationSucceeded += (_, _) => HandleSuccess();
142143
OperationFailed += (_, _) => HandleFailure();

‎src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Classes/NullPackageManager.cs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ public class NullPackageManager : IPackageManager
2020

2121
public bool LastInstalledListingFailed => false;
2222

23+
public long InstalledPackagesGeneration => 0;
24+
25+
public void InvalidateInstalledPackages() { }
26+
2327
public static NullPackageManager Instance = new();
2428
public ManagerProperties Properties { get; }
2529
public ManagerCapabilities Capabilities { get; }

‎src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/PackageManager.cs‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,13 @@ private IReadOnlyList<IPackage> _getAvailableUpdates(bool SecondAttempt)
546546
/// </summary>
547547
public bool LastInstalledListingFailed { get; private set; }
548548

549+
private long _installedPackagesGeneration;
550+
551+
public long InstalledPackagesGeneration => Volatile.Read(ref _installedPackagesGeneration);
552+
553+
public void InvalidateInstalledPackages() =>
554+
Interlocked.Increment(ref _installedPackagesGeneration);
555+
549556
public IReadOnlyList<IPackage> GetInstalledPackages()
550557
{
551558
LastInstalledListingFailed = false;

‎src/UniGetUI.PackageEngine.Tests/PackageOperationsTests.cs‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,27 @@ private static Func<bool> ReportsWaitingOnTheGate(AbstractOperation operation)
544544
return () => reported;
545545
}
546546

547+
[Fact]
548+
public async Task ASuccessfulOperationInvalidatesTheInstalledPackagesOfItsManager()
549+
{
550+
if (!OperatingSystem.IsWindows())
551+
return;
552+
553+
var manager = CreateSlowProcessManager(serializesOperations: false);
554+
InitializeLoaders();
555+
long generationBefore = manager.InstalledPackagesGeneration;
556+
using var operation = new UpdatePackageOperation(
557+
new PackageBuilder().WithManager(manager).WithId("updated").Build(),
558+
new InstallOptions(),
559+
IgnoreParallelInstalls: true
560+
);
561+
562+
await operation.MainThread().WaitAsync(TimeSpan.FromSeconds(30));
563+
564+
Assert.Equal(OperationStatus.Succeeded, operation.Status);
565+
Assert.NotEqual(generationBefore, manager.InstalledPackagesGeneration);
566+
}
567+
547568
[Fact]
548569
public async Task OperationsOfASerializingManagerNeverRunTheirProcessesConcurrently()
549570
{

‎src/UniGetUI.PackageEngine.Tests/WinGetManagerTests.cs‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,31 @@ public void NativeWinGetHelperReusesTheCatalogSnapshotWhileTheSourceIndexIsUncha
900900
Assert.Equal(1, snapshots);
901901
}
902902

903+
[Fact]
904+
public void NativeWinGetHelperTakesAFreshSnapshotOnceTheInstalledPackagesAreInvalidated()
905+
{
906+
WinGet.MarkSourceIndexRefreshed();
907+
var manager = new TestableWinGet();
908+
int snapshots = 0;
909+
var helper = new NativeWinGetHelper(
910+
manager,
911+
systemCliHelperFactory: null,
912+
skipInitialization: true,
913+
localPackagesProvider: () =>
914+
{
915+
snapshots++;
916+
return [];
917+
}
918+
);
919+
920+
helper.GetInstalledPackages_UnSafe();
921+
manager.InvalidateInstalledPackages();
922+
helper.GetInstalledPackages_UnSafe();
923+
helper.GetAvailableUpdates_UnSafe();
924+
925+
Assert.Equal(2, snapshots);
926+
}
927+
903928
[Fact]
904929
public void RefreshPackageIndexesAdvancesTheSourceIndexGenerationWhenTheCliCallFails()
905930
{

‎src/UniGetUI.Tests/CatalogEditorTests.cs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,8 @@ private sealed class SearchManager : IPackageManager
665665
public bool IdentifiersAreQuotedOnCommandLine => true;
666666
public bool LastUpdatesListingFailed => false;
667667
public bool LastInstalledListingFailed => false;
668+
public long InstalledPackagesGeneration => 0;
669+
public void InvalidateInstalledPackages() { }
668670
public int? CompareVersions(string versionA, string versionB) => throw new NotSupportedException();
669671
public void Initialize() => throw new NotSupportedException();
670672
public bool IsEnabled() => true;

0 commit comments

Comments
 (0)