diff --git a/src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj b/src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj
index cf86490fb..f9341b591 100644
--- a/src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj
+++ b/src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj
@@ -94,7 +94,7 @@
-
+
diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/PingetCliHelper.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/PingetCliHelper.cs
index 7166f1e92..dd87579b7 100644
--- a/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/PingetCliHelper.cs
+++ b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/PingetCliHelper.cs
@@ -18,6 +18,7 @@ internal sealed partial class PingetCliHelper : IWinGetManagerHelper
private static readonly JsonSerializerOptions SerializationOptions = new()
{
PropertyNameCaseInsensitive = true,
+ PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
};
private static readonly PingetCliJsonContext SerializationContext = new(SerializationOptions);
@@ -77,7 +78,7 @@ public IReadOnlyList GetInstalledPackages_UnSafe()
{
ListResponse result = RunJson(
LoggableTaskType.ListInstalledPackages,
- "list --accept-source-agreements --output json"
+ "list --output json"
);
return result
@@ -97,7 +98,7 @@ public IReadOnlyList FindPackages_UnSafe(string query)
{
SearchResponse result = RunJson(
LoggableTaskType.FindPackages,
- $"search {Quote(query)} --accept-source-agreements --output json"
+ $"search {Quote(query)} --output json"
);
return result
@@ -115,9 +116,12 @@ public IReadOnlyList FindPackages_UnSafe(string query)
public IReadOnlyList GetSources_UnSafe()
{
+ // pinget 0.4.1 dropped JSON support for `source list`; `source export` is the
+ // equivalent JSON-emitting command (PascalCase keys, but case-insensitive matching
+ // in SerializationOptions binds them to our records).
PingetSourcesResponse result = RunJson(
LoggableTaskType.ListSources,
- "source list --output json"
+ "source export --output json"
);
return result
@@ -133,7 +137,7 @@ public IReadOnlyList GetInstallableVersions_Unsafe(IPackage package)
{
VersionsResult result = RunJson(
LoggableTaskType.LoadPackageVersions,
- $"show {WinGetPkgOperationHelper.GetIdNamePiece(package)} --versions --accept-source-agreements --output json"
+ $"show {WinGetPkgOperationHelper.GetIdNamePiece(package)} --versions --output json"
);
return result
@@ -203,9 +207,11 @@ private T RunJson(LoggableTaskType taskType, string arguments)
}
process.Start();
- string output = process.StandardOutput.ReadToEnd();
- string error = process.StandardError.ReadToEnd();
+ var stdoutTask = process.StandardOutput.ReadToEndAsync();
+ var stderrTask = process.StandardError.ReadToEndAsync();
process.WaitForExit();
+ string output = stdoutTask.GetAwaiter().GetResult();
+ string error = stderrTask.GetAwaiter().GetResult();
logger.AddToStdOut(output.Split(Environment.NewLine));
logger.AddToStdErr(error.Split(Environment.NewLine));
diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/PingetPackageDetailsProvider.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/PingetPackageDetailsProvider.cs
index 4fde3193e..4e225c639 100644
--- a/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/PingetPackageDetailsProvider.cs
+++ b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/PingetPackageDetailsProvider.cs
@@ -142,7 +142,6 @@ private static IReadOnlyList BuildShowArguments(PackageQuery query, stri
arguments.Add(query.Version);
}
- arguments.Add("--accept-source-agreements");
arguments.Add("--output");
arguments.Add("json");
return arguments;
diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/Helpers/WinGetPkgOperationHelper.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/Helpers/WinGetPkgOperationHelper.cs
index 7e0a04533..3e8bc3dd3 100644
--- a/src/UniGetUI.PackageEngine.Managers.WinGet/Helpers/WinGetPkgOperationHelper.cs
+++ b/src/UniGetUI.PackageEngine.Managers.WinGet/Helpers/WinGetPkgOperationHelper.cs
@@ -35,6 +35,12 @@ protected override IReadOnlyList _getOperationParameters(
OperationType operation
)
{
+ // Pinget 0.4.x does not accept --accept-source-agreements, --disable-interactivity,
+ // or --proxy on any verb; --accept-package-agreements, --force, --location, and
+ // --interactive are accepted on install/uninstall but rejected on upgrade.
+ bool usePinget =
+ ((WinGet)Manager).SelectedCliToolKind == WinGetCliToolKind.BundledPinget;
+
List parameters =
[
operation switch
@@ -51,7 +57,10 @@ OperationType operation
{
parameters.AddRange(["--source", package.Source.Name]);
}
- parameters.AddRange(["--accept-source-agreements", "--disable-interactivity"]);
+ if (!usePinget)
+ {
+ parameters.AddRange(["--accept-source-agreements", "--disable-interactivity"]);
+ }
// package.OverridenInstallationOptions.Scope is meaningless in WinGet packages. Default is unspecified, hence the _ => [].
parameters.AddRange(
@@ -76,7 +85,15 @@ operation is OperationType.Uninstall
parameters.AddRange(["--version", $"\"{options.Version}\""]);
}
- parameters.Add(options.InteractiveInstallation ? "--interactive" : "--silent");
+ if (usePinget && operation is OperationType.Update)
+ {
+ // pinget upgrade only supports --silent (no --interactive).
+ parameters.Add("--silent");
+ }
+ else
+ {
+ parameters.Add(options.InteractiveInstallation ? "--interactive" : "--silent");
+ }
if (operation is OperationType.Update)
{
@@ -90,16 +107,19 @@ operation is OperationType.Uninstall
}
parameters.Add("--include-unknown");
- if (options.CustomInstallLocation != "")
+ if (!usePinget)
{
- if (Settings.Get(Settings.K.WinGetForceLocationOnUpdate))
- parameters.AddRange(["--location", $"\"{options.CustomInstallLocation}\""]);
- }
- else
- {
- var detectedLocation = TryGetPortableInstallLocation(package);
- if (detectedLocation is not null)
- parameters.AddRange(["--location", $"\"{detectedLocation}\""]);
+ if (options.CustomInstallLocation != "")
+ {
+ if (Settings.Get(Settings.K.WinGetForceLocationOnUpdate))
+ parameters.AddRange(["--location", $"\"{options.CustomInstallLocation}\""]);
+ }
+ else
+ {
+ var detectedLocation = TryGetPortableInstallLocation(package);
+ if (detectedLocation is not null)
+ parameters.AddRange(["--location", $"\"{detectedLocation}\""]);
+ }
}
}
else if (operation is OperationType.Install)
@@ -110,7 +130,11 @@ operation is OperationType.Uninstall
if (operation is not OperationType.Uninstall)
{
- parameters.AddRange(["--accept-package-agreements", "--force"]);
+ // pinget upgrade does not accept --accept-package-agreements or --force.
+ if (!(usePinget && operation is OperationType.Update))
+ {
+ parameters.AddRange(["--accept-package-agreements", "--force"]);
+ }
if (options.SkipHashCheck)
parameters.Add("--ignore-security-hash");
@@ -189,7 +213,10 @@ or ElevationRequirement.ElevatesSelf
Logger.Error(ex);
}
- parameters.Add(WinGet.GetProxyArgument());
+ if (!usePinget)
+ {
+ parameters.Add(WinGet.GetProxyArgument());
+ }
parameters.AddRange(
operation switch
diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/UniGetUI.PackageEngine.Managers.WinGet.csproj b/src/UniGetUI.PackageEngine.Managers.WinGet/UniGetUI.PackageEngine.Managers.WinGet.csproj
index 9b9876968..f89198cdf 100644
--- a/src/UniGetUI.PackageEngine.Managers.WinGet/UniGetUI.PackageEngine.Managers.WinGet.csproj
+++ b/src/UniGetUI.PackageEngine.Managers.WinGet/UniGetUI.PackageEngine.Managers.WinGet.csproj
@@ -24,7 +24,7 @@
-
+
diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/WinGet.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/WinGet.cs
index 1f7205ef8..71980979e 100644
--- a/src/UniGetUI.PackageEngine.Managers.WinGet/WinGet.cs
+++ b/src/UniGetUI.PackageEngine.Managers.WinGet/WinGet.cs
@@ -725,7 +725,10 @@ public override void RefreshPackageIndexes()
FileName = Status.ExecutablePath,
Arguments =
Status.ExecutableCallArgs
- + " source update --disable-interactivity "
+ + " source update"
+ + (SelectedCliToolKind == WinGetCliToolKind.SystemWinGet
+ ? " --disable-interactivity "
+ : " ")
+ GetCliToolProxyArgument(),
UseShellExecute = false,
RedirectStandardOutput = true,
diff --git a/src/UniGetUI.PackageEngine.Tests/WinGetManagerTests.cs b/src/UniGetUI.PackageEngine.Tests/WinGetManagerTests.cs
index ab3a12f28..aeafbbe82 100644
--- a/src/UniGetUI.PackageEngine.Tests/WinGetManagerTests.cs
+++ b/src/UniGetUI.PackageEngine.Tests/WinGetManagerTests.cs
@@ -3,10 +3,12 @@
using UniGetUI.Core.Data;
using UniGetUI.Core.SettingsEngine;
using UniGetUI.PackageEngine.Classes.Manager;
+using UniGetUI.PackageEngine.Enums;
using UniGetUI.PackageEngine.Interfaces;
using UniGetUI.PackageEngine.Managers.WingetManager;
using UniGetUI.PackageEngine.ManagerClasses.Classes;
using UniGetUI.PackageEngine.PackageClasses;
+using UniGetUI.PackageEngine.Serializable;
using UniGetUI.PackageEngine.Tests.Infrastructure.Assertions;
using UniGetUI.PackageEngine.Tests.Infrastructure.Builders;
@@ -298,23 +300,24 @@ public void FindCandidateExecutableFilesReturnsEmptyWhenNoCliToolExists()
[Fact]
public void PingetCliHelperDeserializesListResponsesWithGeneratedContext()
{
+ // pinget 0.4.1+ emits snake_case keys.
const string json = """
{
"matches": [
{
"name": "Contoso Tool",
"id": "Contoso.Tool",
- "localId": null,
- "installedVersion": "1.2.3",
- "availableVersion": "2.0.0",
- "sourceName": "winget",
+ "local_id": null,
+ "installed_version": "1.2.3",
+ "available_version": "2.0.0",
+ "source_name": "winget",
"publisher": null,
"scope": null,
- "installerCategory": null,
- "installLocation": null,
- "packageFamilyNames": [],
- "productCodes": [],
- "upgradeCodes": []
+ "installer_category": null,
+ "install_location": null,
+ "package_family_names": [],
+ "product_codes": [],
+ "upgrade_codes": []
}
],
"warnings": [],
@@ -708,6 +711,149 @@ public void WinGetCliHelperUsesPingetProviderForPackageDetails()
);
}
+ [Theory]
+ [InlineData(0)] // OperationType.Install
+ [InlineData(1)] // OperationType.Update
+ [InlineData(2)] // OperationType.Uninstall
+ public void WinGetOperationHelperEmitsWinGetCompatibleFlagsForSystemCli(int operationType)
+ {
+ var manager = new WinGet();
+ SetCliToolKind(manager, WinGetCliToolKind.SystemWinGet);
+ var package = new PackageBuilder()
+ .WithManager(manager)
+ .WithId("Contoso.Tool")
+ .WithVersion("1.0.0")
+ .WithNewVersion("2.0.0")
+ .Build();
+
+ var parameters = manager.OperationHelper.GetParameters(
+ package,
+ new InstallOptions(),
+ (OperationType)operationType
+ );
+
+ Assert.Contains("--accept-source-agreements", parameters);
+ Assert.Contains("--disable-interactivity", parameters);
+ }
+
+ [Fact]
+ public void WinGetOperationHelperSkipsUnsupportedFlagsForPingetInstall()
+ {
+ var manager = new WinGet();
+ SetCliToolKind(manager, WinGetCliToolKind.BundledPinget);
+ var package = new PackageBuilder()
+ .WithManager(manager)
+ .WithId("Spotify.Spotify")
+ .Build();
+
+ var parameters = manager.OperationHelper.GetParameters(
+ package,
+ new InstallOptions(),
+ OperationType.Install
+ );
+
+ Assert.DoesNotContain("--accept-source-agreements", parameters);
+ Assert.DoesNotContain("--disable-interactivity", parameters);
+ // pinget install does accept these.
+ Assert.Contains("--accept-package-agreements", parameters);
+ Assert.Contains("--force", parameters);
+ Assert.Contains("--silent", parameters);
+ }
+
+ [Fact]
+ public void WinGetOperationHelperSkipsUnsupportedFlagsForPingetUpgrade()
+ {
+ var manager = new WinGet();
+ SetCliToolKind(manager, WinGetCliToolKind.BundledPinget);
+ var package = new PackageBuilder()
+ .WithManager(manager)
+ .WithId("Contoso.Tool")
+ .WithVersion("1.0.0")
+ .WithNewVersion("2.0.0")
+ .Build();
+ var options = new InstallOptions
+ {
+ InteractiveInstallation = true,
+ CustomInstallLocation = @"C:\Apps\Contoso",
+ };
+
+ var parameters = manager.OperationHelper.GetParameters(
+ package,
+ options,
+ OperationType.Update
+ );
+
+ Assert.DoesNotContain("--accept-source-agreements", parameters);
+ Assert.DoesNotContain("--disable-interactivity", parameters);
+ // pinget upgrade does NOT accept these even though winget upgrade does.
+ Assert.DoesNotContain("--accept-package-agreements", parameters);
+ Assert.DoesNotContain("--force", parameters);
+ Assert.DoesNotContain("--interactive", parameters);
+ Assert.DoesNotContain("--location", parameters);
+ // pinget upgrade still supports --include-unknown and --silent.
+ Assert.Contains("--include-unknown", parameters);
+ Assert.Contains("--silent", parameters);
+ }
+
+ [Fact]
+ public void WinGetOperationHelperSkipsUnsupportedFlagsForPingetUninstall()
+ {
+ var manager = new WinGet();
+ SetCliToolKind(manager, WinGetCliToolKind.BundledPinget);
+ var package = new PackageBuilder()
+ .WithManager(manager)
+ .WithId("Contoso.Tool")
+ .WithVersion("1.0.0")
+ .Build();
+
+ var parameters = manager.OperationHelper.GetParameters(
+ package,
+ new InstallOptions(),
+ OperationType.Uninstall
+ );
+
+ Assert.DoesNotContain("--accept-source-agreements", parameters);
+ Assert.DoesNotContain("--disable-interactivity", parameters);
+ }
+
+ [Fact]
+ public void WinGetOperationHelperOmitsProxyArgumentForPinget()
+ {
+ Settings.Set(Settings.K.EnableProxy, true);
+ Settings.Set(Settings.K.EnableProxyAuth, false);
+ Settings.SetValue(Settings.K.ProxyURL, "http://proxy.example.test:3128/");
+ try
+ {
+ var manager = new WinGet();
+ SetCliToolKind(manager, WinGetCliToolKind.BundledPinget);
+ var package = new PackageBuilder()
+ .WithManager(manager)
+ .WithId("Contoso.Tool")
+ .Build();
+
+ var parameters = manager.OperationHelper.GetParameters(
+ package,
+ new InstallOptions(),
+ OperationType.Install
+ );
+
+ Assert.DoesNotContain(parameters, p => p.StartsWith("--proxy", StringComparison.Ordinal));
+ }
+ finally
+ {
+ Settings.Set(Settings.K.EnableProxy, false);
+ Settings.SetValue(Settings.K.ProxyURL, "");
+ }
+ }
+
+ private static void SetCliToolKind(WinGet manager, WinGetCliToolKind kind)
+ {
+ typeof(WinGet)
+ .GetProperty(nameof(WinGet.SelectedCliToolKind), System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)!
+ .GetSetMethod(nonPublic: true)!
+ .Invoke(manager, [kind]);
+ }
+
private sealed class TestableWinGet : WinGet
{
public IReadOnlyList InvokeGetInstalledPackages() => base.GetInstalledPackages_UnSafe();
diff --git a/src/UniGetUI/UniGetUI.csproj b/src/UniGetUI/UniGetUI.csproj
index 79bd880ea..7396fb302 100644
--- a/src/UniGetUI/UniGetUI.csproj
+++ b/src/UniGetUI/UniGetUI.csproj
@@ -220,7 +220,7 @@
-
+