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: 3 additions & 1 deletion src/Languages/lang_en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1842,5 +1842,7 @@
"GitHub returned an empty access token.": "GitHub returned an empty access token.",
"GitHub sign-in failed ({0}): {1}": "GitHub sign-in failed ({0}): {1}",
"The GitHub sign-in code has expired. Please try again.": "The GitHub sign-in code has expired. Please try again.",
"WinGet repair exited with code {0}.": "WinGet repair exited with code {0}."
"WinGet repair exited with code {0}.": "WinGet repair exited with code {0}.",
"Waiting for another {0} operation to finish...": "Waiting for another {0} operation to finish...",
"A file of {package} is in use by another program. Close any program that may be using it, then try again": "A file of {package} is in use by another program. Close any program that may be using it, then try again"
}
1 change: 1 addition & 0 deletions src/UniGetUI.PackageEngine.Enums/ManagerCapabilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public struct ManagerCapabilities
public bool SupportsCustomScopesOnUpdate = true;
public bool SupportsCustomScopesOnUninstall = true;
public bool SupportsPreRelease = false;
public bool SerializesOperations = false;
public bool SupportsCustomLocations = false;
public bool SupportsCustomSources = false;
public bool SupportsCustomPackageIcons = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,22 @@ int returnCode
return OperationVeredict.AutoRetry;
}

if (package.OverridenOptions.Scope != PackageScope.User)
if (
operation is not OperationType.Update
&& package.OverridenOptions.Scope != PackageScope.User
)
{
package.OverridenOptions.Scope = PackageScope.User;
return OperationVeredict.AutoRetry;
}
}

if (output_string.Contains("--user") && package.OverridenOptions.Scope != PackageScope.User)
if (
operation is not OperationType.Update
&& output_string.Contains("--user")
&& !output_string.Contains("[WinError 32]")
&& package.OverridenOptions.Scope != PackageScope.User
Comment thread
GabrielDuf marked this conversation as resolved.
Resolved
)
{
package.OverridenOptions.Scope = PackageScope.User;
return OperationVeredict.AutoRetry;
Expand Down
1 change: 1 addition & 0 deletions src/UniGetUI.PackageEngine.Managers.Pip/Pip.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public Pip()
SupportsCustomScopes = true,
CanDownloadInstaller = true,
SupportsPreRelease = true,
SerializesOperations = true,
CanListDependencies = true,
SupportsProxy = ProxySupport.Yes,
SupportsProxyAuth = true,
Expand Down
32 changes: 28 additions & 4 deletions src/UniGetUI.PackageEngine.Operations/AbstractOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -319,15 +319,14 @@ private async Task MainThreadCore(CancellationTokenSource runCancellation)

while (
FORCE_HOLD_QUEUE
|| (IndexInQueue(this) >= MAX_OPERATIONS && !SKIP_QUEUE)
|| (SlotsTakenAhead(this) >= MAX_OPERATIONS && !SKIP_QUEUE)
)
{
int pos = IndexInQueue(this) - MAX_OPERATIONS + 1;

if (pos == -1)
if (IndexInQueue(this) - MAX_OPERATIONS + 1 == -1)
return;
// In this case, operation was canceled;

int pos = SlotsTakenAhead(this) - MAX_OPERATIONS + 1;
if (pos != lastPos)
{
lastPos = pos;
Expand Down Expand Up @@ -646,6 +645,31 @@ public static int IndexInQueue(AbstractOperation operation)
return OperationQueue.IndexOf(operation);
}

internal bool IsWaitingForManager
{
get => _isWaitingForManager;
set => _isWaitingForManager = value;
}
private volatile bool _isWaitingForManager;

private static int SlotsTakenAhead(AbstractOperation operation)
{
lock (QueueLock)
{
int index = OperationQueue.IndexOf(operation);
if (index < 0)
return index;

int taken = 0;
for (int i = 0; i < index; i++)
{
if (!OperationQueue[i].IsWaitingForManager)
taken++;
}
return taken;
}
}

public static int QueueLength()
{
lock (QueueLock)
Expand Down
56 changes: 55 additions & 1 deletion src/UniGetUI.PackageEngine.Operations/PackageOperations.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Text;
using UniGetUI.Core.Classes;
Expand Down Expand Up @@ -344,12 +345,53 @@ protected override async Task<OperationVeredict> PerformOperation()

if (!ShouldUseAgentBroker())
{
return await base.PerformOperation();
if (!Package.Manager.Capabilities.SerializesOperations)
return await base.PerformOperation();

SemaphoreSlim gate = ManagerOperationGates.GetOrAdd(
Package.Manager.Name,
_ => new SemaphoreSlim(1, 1)
);
if (!await gate.WaitAsync(0))
{
Line(
CoreTools.Translate(
"Waiting for another {0} operation to finish...",
Package.Manager.DisplayName
),
LineType.ProgressIndicator
);
IsWaitingForManager = true;
try
{
await gate.WaitAsync(CancellationToken);
}
catch (OperationCanceledException)
{
return OperationVeredict.Canceled;
}
finally
{
IsWaitingForManager = false;
}
}

try
{
return await base.PerformOperation();
}
finally
{
gate.Release();
}
}

return await PerformBrokerOperation();
}

private static readonly ConcurrentDictionary<string, SemaphoreSlim> ManagerOperationGates =
new();

/// <summary>
/// Determines whether this operation should be routed through the agent broker.
/// </summary>
Expand Down Expand Up @@ -1058,6 +1100,7 @@ List<string> Output
ExplainNotApplicableUpdate(Output, ReturnCode);
ExplainInstallerHashMismatch(ReturnCode);
ExplainApplicationCurrentlyRunning(Output, ReturnCode);
ExplainFileInUse(Output);
}

return Task.FromResult(veredict);
Expand Down Expand Up @@ -1197,6 +1240,17 @@ private void ExplainApplicationCurrentlyRunning(List<string> output, int returnC
#endif
}

private void ExplainFileInUse(List<string> output)
{
if (!output.Any(line => line.Contains("[WinError 32]", StringComparison.Ordinal)))
return;

Metadata.FailureMessage = CoreTools.Translate(
"A file of {package} is in use by another program. Close any program that may be using it, then try again",
new Dictionary<string, object?> { { "package", Package.Name } }
);
}

private void ExplainNotApplicableUpdate(List<string> output, int returnCode)
{
#if WINDOWS
Expand Down
Loading
Loading