Skip to content

Commit 44e7be0

Browse files
Update UniGetUI Pinget consumer for 0.6.0 JSON contract
1 parent e529717 commit 44e7be0

3 files changed

Lines changed: 80 additions & 23 deletions

File tree

src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/PingetCliHelper.cs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ internal sealed partial class PingetCliHelper : IWinGetManagerHelper
1818
private static readonly JsonSerializerOptions SerializationOptions = new()
1919
{
2020
PropertyNameCaseInsensitive = true,
21-
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
2221
};
2322
private static readonly PingetCliJsonContext SerializationContext = new(SerializationOptions);
2423

@@ -55,7 +54,7 @@ public IReadOnlyList<Package> GetAvailableUpdates_UnSafe()
5554
match.Id,
5655
match.InstalledVersion,
5756
match.AvailableVersion!,
58-
GetSource(match.SourceName, match.Id),
57+
GetSource(match),
5958
Manager
6059
);
6160

@@ -87,7 +86,7 @@ public IReadOnlyList<Package> GetInstalledPackages_UnSafe()
8786
match.Name,
8887
match.Id,
8988
match.InstalledVersion,
90-
GetSource(match.SourceName, match.Id),
89+
GetSource(match),
9190
Manager
9291
)
9392
)
@@ -234,6 +233,32 @@ internal static T DeserializeJson<T>(string output)
234233
: throw new InvalidOperationException("Pinget returned empty JSON output.");
235234
}
236235

236+
internal static string? InferSourceName(ListMatch match)
237+
{
238+
if (!string.IsNullOrWhiteSpace(match.SourceName))
239+
{
240+
return match.SourceName;
241+
}
242+
243+
if (match.Id.Contains("_Microsoft.Winget.Source_8wekyb3d8bbwe", StringComparison.OrdinalIgnoreCase))
244+
{
245+
return "winget";
246+
}
247+
248+
if (!string.IsNullOrWhiteSpace(match.InstallLocation)
249+
&& match.InstallLocation.Contains("\\Microsoft\\WinGet\\Packages\\", StringComparison.OrdinalIgnoreCase))
250+
{
251+
return "winget";
252+
}
253+
254+
return null;
255+
}
256+
257+
private IManagerSource GetSource(ListMatch match)
258+
{
259+
return GetSource(InferSourceName(match), match.Id);
260+
}
261+
237262
private IManagerSource GetSource(string? sourceName, string packageId)
238263
{
239264
if (string.IsNullOrWhiteSpace(sourceName))

src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/PingetPackageDetailsProvider.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,10 @@ private IReadOnlyList<string> GetSourceNames(INativeTaskLogger logger)
8484
{
8585
try
8686
{
87-
string output = RunPinget(["source", "list", "--output", "json"], logger);
87+
string output = RunPinget(["source", "export", "--output", "json"], logger);
8888
using JsonDocument document = JsonDocument.Parse(output);
8989
if (
90-
!document.RootElement.TryGetProperty("sources", out JsonElement sources)
90+
!document.RootElement.TryGetProperty("Sources", out JsonElement sources)
9191
|| sources.ValueKind != JsonValueKind.Array
9292
)
9393
{
@@ -97,7 +97,7 @@ private IReadOnlyList<string> GetSourceNames(INativeTaskLogger logger)
9797
return sources
9898
.EnumerateArray()
9999
.Select(source =>
100-
source.TryGetProperty("name", out JsonElement name)
100+
source.TryGetProperty("Name", out JsonElement name)
101101
? name.GetString()
102102
: null
103103
)

src/UniGetUI.PackageEngine.Tests/WinGetManagerTests.cs

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -300,28 +300,28 @@ public void FindCandidateExecutableFilesReturnsEmptyWhenNoCliToolExists()
300300
[Fact]
301301
public void PingetCliHelperDeserializesListResponsesWithGeneratedContext()
302302
{
303-
// pinget 0.4.1+ emits snake_case keys.
303+
// Pinget emits PascalCase keys.
304304
const string json = """
305305
{
306-
"matches": [
306+
"Matches": [
307307
{
308-
"name": "Contoso Tool",
309-
"id": "Contoso.Tool",
310-
"local_id": null,
311-
"installed_version": "1.2.3",
312-
"available_version": "2.0.0",
313-
"source_name": "winget",
314-
"publisher": null,
315-
"scope": null,
316-
"installer_category": null,
317-
"install_location": null,
318-
"package_family_names": [],
319-
"product_codes": [],
320-
"upgrade_codes": []
308+
"Name": "Contoso Tool",
309+
"Id": "Contoso.Tool",
310+
"LocalId": null,
311+
"InstalledVersion": "1.2.3",
312+
"AvailableVersion": "2.0.0",
313+
"SourceName": "winget",
314+
"Publisher": null,
315+
"Scope": null,
316+
"InstallerCategory": null,
317+
"InstallLocation": null,
318+
"PackageFamilyNames": [],
319+
"ProductCodes": [],
320+
"UpgradeCodes": []
321321
}
322322
],
323-
"warnings": [],
324-
"truncated": false
323+
"Warnings": [],
324+
"Truncated": false
325325
}
326326
""";
327327

@@ -335,6 +335,38 @@ public void PingetCliHelperDeserializesListResponsesWithGeneratedContext()
335335
Assert.Equal("winget", match.SourceName);
336336
}
337337

338+
[Fact]
339+
public void PingetCliHelperInfersWingetSourceWhenInstalledSourceNameIsMissing()
340+
{
341+
const string json = """
342+
{
343+
"Matches": [
344+
{
345+
"Name": "Contoso Tool",
346+
"Id": "ARP\\User\\X64\\Contoso.Tool_Microsoft.Winget.Source_8wekyb3d8bbwe",
347+
"LocalId": null,
348+
"InstalledVersion": "1.2.3",
349+
"AvailableVersion": null,
350+
"SourceName": null,
351+
"Publisher": "Contoso",
352+
"Scope": "User",
353+
"InstallerCategory": "exe",
354+
"InstallLocation": "C:\\Users\\example\\AppData\\Local\\Microsoft\\WinGet\\Packages\\Contoso.Tool_Microsoft.Winget.Source_8wekyb3d8bbwe",
355+
"PackageFamilyNames": [],
356+
"ProductCodes": [],
357+
"UpgradeCodes": []
358+
}
359+
],
360+
"Warnings": [],
361+
"Truncated": false
362+
}
363+
""";
364+
365+
ListMatch match = Assert.Single(PingetCliHelper.DeserializeJson<ListResponse>(json).Matches);
366+
367+
Assert.Equal("winget", PingetCliHelper.InferSourceName(match));
368+
}
369+
338370
[Fact]
339371
public void GetCliToolPreferenceUsesEnvironmentBeforeSettings()
340372
{

0 commit comments

Comments
 (0)