Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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 @@ -2607,5 +2607,7 @@
"Codex returned a plugin for the wrong marketplace.": "Codex returned a plugin for the wrong marketplace.",
"Provided by the Codex app, which restores it if removed. You can still turn it on or off.": "Provided by the Codex app, which restores it if removed. You can still turn it on or off.",
"Unsupported Codex marketplace inventory. Update the Codex CLI and try again.": "Unsupported Codex marketplace inventory. Update the Codex CLI and try again.",
"Open a marketplace or plugin confirmation form in the Copilot app. Manage the local installed inventory in GitHub Copilot.": "Open a marketplace or plugin confirmation form in the Copilot app. Manage the local installed inventory in GitHub Copilot."
"Open a marketplace or plugin confirmation form in the Copilot app. Manage the local installed inventory in GitHub Copilot.": "Open a marketplace or plugin confirmation form in the Copilot app. Manage the local installed inventory in GitHub Copilot.",
"Chocolatey did not update {0}: version {1} is the newest one its sources offer": "Chocolatey did not update {0}: version {1} is the newest one its sources offer",
"Chocolatey did not update {0}. The package may be pinned, or its sources may offer no newer version": "Chocolatey did not update {0}. The package may be pinned, or its sources may offer no newer version"
}
1 change: 1 addition & 0 deletions src/UniGetUI.Interface.IpcApi/IpcPackageApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,7 @@ IpcPackageActionRequest request
if (!string.IsNullOrWhiteSpace(request.Version))
{
options.Version = request.Version;
options.VersionIsExplicit = true;
}

if (!string.IsNullOrWhiteSpace(request.Scope))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,12 @@ public void ApplyOperationOverrides(
InstallOptions options,
OperationType operation
);

public string? GetFailureExplanation(
IPackage package,
OperationType operation,
IReadOnlyList<string> processOutput,
int returnCode
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ internal IReadOnlyList<Package> ParseAvailableUpdates(IEnumerable<string> lines)
FALSE_PACKAGE_IDS.Contains(elements[0])
|| FALSE_PACKAGE_VERSIONS.Contains(elements[1])
|| elements[1] == elements[2]
|| (elements.Length > 3 && elements[3].Equals("true", StringComparison.OrdinalIgnoreCase))
)
{
continue;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using UniGetUI.Core.SettingsEngine;
using UniGetUI.Core.Tools;
using UniGetUI.PackageEngine.Classes.Manager.BaseProviders;
Expand All @@ -8,11 +10,94 @@

namespace UniGetUI.PackageEngine.Managers.ChocolateyManager;

internal sealed class ChocolateyPkgOperationHelper : BasePkgOperationHelper
internal sealed partial class ChocolateyPkgOperationHelper : BasePkgOperationHelper
{
[GeneratedRegex(@"\bupgraded (\d+)/\d+ packages", RegexOptions.IgnoreCase)]
private static partial Regex UpgradeSummary();

[GeneratedRegex(@"^\s*(\S+) v(\S+) is the latest version available", RegexOptions.IgnoreCase)]
private static partial Regex LatestVersionAvailable();

private enum NoOpUpdate
{
None,
AlreadyCurrent,
NotUpgraded,
}

private static bool UpgradedNothing(IReadOnlyList<string> processOutput)
{
for (int i = processOutput.Count - 1; i >= 0; i--)
{
Match match = UpgradeSummary().Match(processOutput[i]);
if (match.Success)
return int.TryParse(match.Groups[1].Value, out int upgraded) && upgraded == 0;
}

return false;
}

private static string? LatestAvailableVersion(IPackage package, IReadOnlyList<string> processOutput)
{
for (int i = processOutput.Count - 1; i >= 0; i--)
{
Match match = LatestVersionAvailable().Match(processOutput[i]);
if (match.Success && match.Groups[1].Value.Equals(package.Id, StringComparison.OrdinalIgnoreCase))
return match.Groups[2].Value;
}

return null;
}

private readonly ConditionalWeakTable<IPackage, string> _requestedUpdateVersions = new();

private string? UpdateTarget(IPackage package)
{
if (_requestedUpdateVersions.TryGetValue(package, out string? requested) && requested.Length > 0)
return requested;

return package.IsUpgradable && package.NewVersionString.Length > 0 ? package.NewVersionString : null;
}

private static bool Reaches(IPackage package, string latest, string target) =>
package.Manager.CompareVersions(latest, target) is int comparison
? comparison >= 0
: latest.Equals(target, StringComparison.OrdinalIgnoreCase);

private NoOpUpdate ClassifyNoOpUpdate(
IPackage package,
OperationType operation,
IReadOnlyList<string> processOutput,
int returnCode
)
{
if (returnCode is not 0 || operation is not OperationType.Update || !UpgradedNothing(processOutput))
return NoOpUpdate.None;

if (LatestAvailableVersion(package, processOutput) is not { } latest)
return NoOpUpdate.NotUpgraded;

return UpdateTarget(package) is not { } target || Reaches(package, latest, target)
? NoOpUpdate.AlreadyCurrent
: NoOpUpdate.NotUpgraded;
}

public ChocolateyPkgOperationHelper(Chocolatey manager)
: base(manager) { }

protected override IReadOnlyList<string> _getOperationParameters(
IPackage package,
InstallOptions options,
OperationType operation,
bool standalone
)
{
if (operation is OperationType.Update && !standalone)
_requestedUpdateVersions.AddOrUpdate(package, options.Version);
Comment thread
GabrielDuf marked this conversation as resolved.
Resolved

return _getOperationParameters(package, options, operation);
}

protected override IReadOnlyList<string> _getOperationParameters(
IPackage package,
InstallOptions options,
Expand Down Expand Up @@ -82,6 +167,14 @@ int returnCode
return OperationVeredict.RestartRequired;
}

switch (ClassifyNoOpUpdate(package, operation, processOutput, returnCode))
{
case NoOpUpdate.AlreadyCurrent:
return OperationVeredict.Success;
case NoOpUpdate.NotUpgraded:
return OperationVeredict.Failure;
}

if (returnCode is 1614 or 1605 or 0)
{
return OperationVeredict.Success;
Expand Down Expand Up @@ -112,4 +205,26 @@ int returnCode

return OperationVeredict.Failure;
}

public override string? GetFailureExplanation(
IPackage package,
OperationType operation,
IReadOnlyList<string> processOutput,
int returnCode
)
{
if (ClassifyNoOpUpdate(package, operation, processOutput, returnCode) is not NoOpUpdate.NotUpgraded)
return null;

return LatestAvailableVersion(package, processOutput) is { } latest
? CoreTools.Translate(
"Chocolatey did not update {0}: version {1} is the newest one its sources offer",
package.Name,
latest
)
: CoreTools.Translate(
"Chocolatey did not update {0}. The package may be pinned, or its sources may offer no newer version",
package.Name
);
}
}
8 changes: 8 additions & 0 deletions src/UniGetUI.PackageEngine.Operations/AbstractOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,14 @@ private async Task<OperationVeredict> _runOperation()
}
}
}

if (result is OperationVeredict.AutoRetry)
{
Line($"", LineType.VerboseDetails);
Line($"-----------------------", LineType.VerboseDetails);
Line($"Retrying operation automatically", LineType.VerboseDetails);
Line($"", LineType.VerboseDetails);
}
} while (result is OperationVeredict.AutoRetry);

if (result is not (OperationVeredict.Success or OperationVeredict.RestartRequired))
Expand Down
12 changes: 12 additions & 0 deletions src/UniGetUI.PackageEngine.Operations/PackageOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ public PackageOperation(
{
Package = package;
Role = role;
if (role is OperationType.Update)
options = options.WithoutSavedVersion();
if (ReinstallsOnUpdate(package, options, role))
{
Options = PinReinstallVersion(package, options);
Expand Down Expand Up @@ -1207,6 +1209,16 @@ List<string> Output
FailedBecauseApplicationRunning = false;
if (veredict is OperationVeredict.Failure)
{
if (
Package.Manager.OperationHelper.GetFailureExplanation(
Package,
CommandRole,
Output,
ReturnCode
)
is { Length: > 0 } explanation
)
Metadata.FailureMessage = explanation;
if (CommandRole is OperationType.Update)
ExplainNotApplicableUpdate(Output, ReturnCode);
ExplainInstallerHashMismatch(ReturnCode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,5 +211,12 @@ public void ApplyOperationOverrides(
InstallOptions options,
OperationType operation
) => throw new NotImplementedException();

public string? GetFailureExplanation(
IPackage package,
OperationType operation,
IReadOnlyList<string> processOutput,
int returnCode
) => null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ private IReadOnlyList<string> BuildParameters(
bool standalone
)
{
if (operation is OperationType.Update)
options = options.WithoutSavedVersion();

// Every manager concatenates these onto a command line, so an identifier that looks like
// an option is smuggled in as one even where no shell is involved: a Pip identifier of
// "requests --index-url https://host" would otherwise add a real index to the install.
Expand Down Expand Up @@ -157,4 +160,11 @@ public virtual void ApplyOperationOverrides(
OperationType operation
)
{ }

public virtual string? GetFailureExplanation(
IPackage package,
OperationType operation,
IReadOnlyList<string> processOutput,
int returnCode
) => null;
}
13 changes: 13 additions & 0 deletions src/UniGetUI.PackageEngine.Serializable/InstallOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,18 @@ public List<string> KillBeforeOperation
// from the manager-wide default. Transient (not serialized): set by InstallOptionsFactory.
public bool CustomInstallLocationIsExplicit { get; set; }

public bool VersionIsExplicit { get; set; }

public InstallOptions WithoutSavedVersion()
{
if (Version.Length == 0 || VersionIsExplicit)
return this;

var cleared = Copy();
cleared.Version = "";
return cleared;
}

public override InstallOptions Copy()
{
var copy = new InstallOptions();
Expand All @@ -247,6 +259,7 @@ public override InstallOptions Copy()
// Handle non-automated properties
copy.OverridesNextLevelOpts = OverridesNextLevelOpts;
copy.CustomInstallLocationIsExplicit = CustomInstallLocationIsExplicit;
copy.VersionIsExplicit = VersionIsExplicit;
return copy;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public void SourceAndStandaloneCommandsPinTheExactSelectedVersion(OperationType
Assert.Equal(expected, manager.OperationHelper.GetParameters(package, options, operation));
Assert.Equal(expected, manager.OperationHelper.GetStandaloneParameters(package, options, operation));

options.VersionIsExplicit = true;
options.Version = "15.0.0-rc.2";
expected[3] = CoreTools.EscapeCommandLineArgument("15.0.0-rc.2");
Assert.Equal(expected, manager.OperationHelper.GetParameters(package, options, operation));
Expand Down
Loading
Loading