Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/UniGetUI.PackageEngine.Interfaces/IPackageManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ public interface IPackageManager
/// </summary>
public IReadOnlyList<IPackage> GetInstalledPackages();

public long InstalledPackagesGeneration { get; }

public void InvalidateInstalledPackages();

/// <summary>
/// Refreshes the Package Manager sources/indexes
/// Each manager MUST implement this method.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -852,7 +852,14 @@ internal static List<Package> ParseUpdatesResponse(
}

protected sealed override IReadOnlyList<Package> GetInstalledPackages_UnSafe() =>
TaskRecycler<IReadOnlyList<Package>>.RunOrAttach(_getInstalledPackages_UnSafe);
TaskRecycler<IReadOnlyList<Package>>.RunOrAttach(
ListInstalledPackagesForGeneration,
InstalledPackagesGeneration
);

private IReadOnlyList<Package> ListInstalledPackagesForGeneration(
long installedPackagesGeneration
) => _getInstalledPackages_UnSafe();

protected abstract IReadOnlyList<Package> _getInstalledPackages_UnSafe();
}
Expand Down
8 changes: 6 additions & 2 deletions src/UniGetUI.PackageEngine.Managers.Scoop/Scoop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -440,9 +440,13 @@ protected override IReadOnlyList<Package> GetAvailableUpdates_UnSafe()
}

protected override IReadOnlyList<Package> GetInstalledPackages_UnSafe() =>
TaskRecycler<IReadOnlyList<Package>>.RunOrAttach(_getInstalledPackages_UnSafe, 15);
TaskRecycler<IReadOnlyList<Package>>.RunOrAttach(
_getInstalledPackages_UnSafe,
InstalledPackagesGeneration,
15
);

private IReadOnlyList<Package> _getInstalledPackages_UnSafe()
private IReadOnlyList<Package> _getInstalledPackages_UnSafe(long installedPackagesGeneration)
{
using Process p = new()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@
nativePackage.DefaultInstallVersion.PackageCatalog.Info.Name
);

string? reportedVersion = nativePackage.InstalledVersion.Version;

Check warning on line 359 in src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

View workflow job for this annotation

GitHub Actions / Windows (Avalonia)

Dereference of a possibly null reference.

Check warning on line 359 in src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

View workflow job for this annotation

GitHub Actions / Windows (Avalonia)

Dereference of a possibly null reference.

Check warning on line 359 in src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

View workflow job for this annotation

GitHub Actions / Windows (NativeAOT)

Dereference of a possibly null reference.

Check warning on line 359 in src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

View workflow job for this annotation

GitHub Actions / Windows (NativeAOT)

Dereference of a possibly null reference.

Check warning on line 359 in src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

View workflow job for this annotation

GitHub Actions / test-codebase

Dereference of a possibly null reference.

Check warning on line 359 in src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

View workflow job for this annotation

GitHub Actions / test-codebase

Dereference of a possibly null reference.

Check warning on line 359 in src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

View workflow job for this annotation

GitHub Actions / test-codebase

Dereference of a possibly null reference.

Check warning on line 359 in src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

View workflow job for this annotation

GitHub Actions / test-codebase

Dereference of a possibly null reference.

Check warning on line 359 in src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

View workflow job for this annotation

GitHub Actions / test-codebase

Dereference of a possibly null reference.

Check warning on line 359 in src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

View workflow job for this annotation

GitHub Actions / test-codebase

Dereference of a possibly null reference.

Check warning on line 359 in src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

View workflow job for this annotation

GitHub Actions / test-codebase

Dereference of a possibly null reference.
string version = WinGetPkgOperationHelper.ResolveReportedInstalledVersion(
nativePackage.Id,
reportedVersion
Expand Down Expand Up @@ -436,7 +436,7 @@
source = Manager.GetLocalSource(nativePackage.Id);
}

string? reportedVersion = nativePackage.InstalledVersion.Version;

Check warning on line 439 in src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

View workflow job for this annotation

GitHub Actions / Windows (Avalonia)

Dereference of a possibly null reference.

Check warning on line 439 in src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

View workflow job for this annotation

GitHub Actions / Windows (Avalonia)

Dereference of a possibly null reference.

Check warning on line 439 in src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

View workflow job for this annotation

GitHub Actions / Windows (NativeAOT)

Dereference of a possibly null reference.

Check warning on line 439 in src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

View workflow job for this annotation

GitHub Actions / Windows (NativeAOT)

Dereference of a possibly null reference.

Check warning on line 439 in src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

View workflow job for this annotation

GitHub Actions / test-codebase

Dereference of a possibly null reference.

Check warning on line 439 in src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

View workflow job for this annotation

GitHub Actions / test-codebase

Dereference of a possibly null reference.

Check warning on line 439 in src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

View workflow job for this annotation

GitHub Actions / test-codebase

Dereference of a possibly null reference.

Check warning on line 439 in src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

View workflow job for this annotation

GitHub Actions / test-codebase

Dereference of a possibly null reference.

Check warning on line 439 in src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

View workflow job for this annotation

GitHub Actions / test-codebase

Dereference of a possibly null reference.

Check warning on line 439 in src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

View workflow job for this annotation

GitHub Actions / test-codebase

Dereference of a possibly null reference.

Check warning on line 439 in src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

View workflow job for this annotation

GitHub Actions / test-codebase

Dereference of a possibly null reference.
string version = WinGetPkgOperationHelper.ResolveReportedInstalledVersion(
nativePackage.Id,
reportedVersion
Expand Down Expand Up @@ -475,21 +475,24 @@

private IReadOnlyList<CatalogPackage> GetCachedLocalWinGetPackages(int? cacheSeconds = null)
{
long sourceIndexGeneration = WinGet.SourceIndexGeneration;
(long, long) generations = (
WinGet.SourceIndexGeneration,
Manager.InstalledPackagesGeneration
);

return cacheSeconds is null
? TaskRecycler<IReadOnlyList<CatalogPackage>>.RunOrAttach(
EnumerateLocalWinGetPackages,
sourceIndexGeneration
generations
)
: TaskRecycler<IReadOnlyList<CatalogPackage>>.RunOrAttach(
EnumerateLocalWinGetPackages,
sourceIndexGeneration,
generations,
cacheSeconds.Value
);
}

private IReadOnlyList<CatalogPackage> EnumerateLocalWinGetPackages(long sourceIndexGeneration)
private IReadOnlyList<CatalogPackage> EnumerateLocalWinGetPackages((long, long) generations)
{
return _localPackagesProvider is not null
? _localPackagesProvider()
Expand Down
1 change: 1 addition & 0 deletions src/UniGetUI.PackageEngine.Operations/PackageOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ public PackageOperation(
if (status is OperationStatus.Canceled)
Package.SetTag(PackageTag.Default);
};
OperationSucceeded += (_, _) => Package.Manager.InvalidateInstalledPackages();
OperationSucceeded += (_, _) => RecordPendingRebootState();
OperationSucceeded += (_, _) => HandleSuccess();
OperationFailed += (_, _) => HandleFailure();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ public class NullPackageManager : IPackageManager

public bool LastInstalledListingFailed => false;

public long InstalledPackagesGeneration => 0;

public void InvalidateInstalledPackages() { }

public static NullPackageManager Instance = new();
public ManagerProperties Properties { get; }
public ManagerCapabilities Capabilities { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,13 @@ private IReadOnlyList<IPackage> _getAvailableUpdates(bool SecondAttempt)
/// </summary>
public bool LastInstalledListingFailed { get; private set; }

private long _installedPackagesGeneration;

public long InstalledPackagesGeneration => Volatile.Read(ref _installedPackagesGeneration);

public void InvalidateInstalledPackages() =>
Interlocked.Increment(ref _installedPackagesGeneration);

public IReadOnlyList<IPackage> GetInstalledPackages()
{
LastInstalledListingFailed = false;
Expand Down
21 changes: 21 additions & 0 deletions src/UniGetUI.PackageEngine.Tests/PackageOperationsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,27 @@ private static Func<bool> ReportsWaitingOnTheGate(AbstractOperation operation)
return () => reported;
}

[Fact]
public async Task ASuccessfulOperationInvalidatesTheInstalledPackagesOfItsManager()
{
if (!OperatingSystem.IsWindows())
return;

var manager = CreateSlowProcessManager(serializesOperations: false);
InitializeLoaders();
long generationBefore = manager.InstalledPackagesGeneration;
using var operation = new UpdatePackageOperation(
new PackageBuilder().WithManager(manager).WithId("updated").Build(),
new InstallOptions(),
IgnoreParallelInstalls: true
);

await operation.MainThread().WaitAsync(TimeSpan.FromSeconds(30));

Assert.Equal(OperationStatus.Succeeded, operation.Status);
Assert.NotEqual(generationBefore, manager.InstalledPackagesGeneration);
}

[Fact]
public async Task OperationsOfASerializingManagerNeverRunTheirProcessesConcurrently()
{
Expand Down
25 changes: 25 additions & 0 deletions src/UniGetUI.PackageEngine.Tests/WinGetManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,31 @@ public void NativeWinGetHelperReusesTheCatalogSnapshotWhileTheSourceIndexIsUncha
Assert.Equal(1, snapshots);
}

[Fact]
public void NativeWinGetHelperTakesAFreshSnapshotOnceTheInstalledPackagesAreInvalidated()
{
WinGet.MarkSourceIndexRefreshed();
var manager = new TestableWinGet();
int snapshots = 0;
var helper = new NativeWinGetHelper(
manager,
systemCliHelperFactory: null,
skipInitialization: true,
localPackagesProvider: () =>
{
snapshots++;
return [];
}
);

helper.GetInstalledPackages_UnSafe();
manager.InvalidateInstalledPackages();
helper.GetInstalledPackages_UnSafe();
helper.GetAvailableUpdates_UnSafe();

Assert.Equal(2, snapshots);
}

[Fact]
public void RefreshPackageIndexesAdvancesTheSourceIndexGenerationWhenTheCliCallFails()
{
Expand Down
2 changes: 2 additions & 0 deletions src/UniGetUI.Tests/CatalogEditorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,8 @@ private sealed class SearchManager : IPackageManager
public bool IdentifiersAreQuotedOnCommandLine => true;
public bool LastUpdatesListingFailed => false;
public bool LastInstalledListingFailed => false;
public long InstalledPackagesGeneration => 0;
public void InvalidateInstalledPackages() { }
public int? CompareVersions(string versionA, string versionB) => throw new NotSupportedException();
public void Initialize() => throw new NotSupportedException();
public bool IsEnabled() => true;
Expand Down
Loading