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
2 changes: 1 addition & 1 deletion dotnet/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<Project>
<PropertyGroup Condition="'$(IsPackable)' == 'true'">
<PropertyGroup>
<Authors>Devolutions</Authors>
<Company>Devolutions Inc.</Company>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
Expand Down
57 changes: 57 additions & 0 deletions dotnet/src/Devolutions.Pinget.Core.Tests/CoreTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,53 @@ public void GetSqliteNativeLibraryCandidates_ProbesRootAndRidFolder()
Assert.Contains(Path.Combine(@"C:\module", "runtimes"), candidates[1]);
Assert.EndsWith(Path.Combine("native", "e_sqlite3.dll"), candidates[1], StringComparison.OrdinalIgnoreCase);
}

[Fact]
public void TryGetWinGetPackageIdentityFromLocalId_UsesSourceIdentifierSuffix()
{
SourceRecord source = new()
{
Name = "winget",
Kind = SourceKind.PreIndexed,
Arg = "https://cdn.winget.microsoft.com/cache",
Identifier = "Microsoft.Winget.Source_8wekyb3d8bbwe",
};

bool result = Repository.TryGetWinGetPackageIdentityFromLocalId(
@"ARP\User\X64\Atlassian.AtlassianCLI_Microsoft.Winget.Source_8wekyb3d8bbwe",
[source],
out string? packageId,
out string? sourceName
);

Assert.True(result);
Assert.Equal("Atlassian.AtlassianCLI", packageId);
Assert.Equal("winget", sourceName);
}

[Fact]
public void TryGetWinGetPackageIdentityFromLocalId_IgnoresUnknownSourceIdentifier()
{
SourceRecord source = new()
{
Name = "winget",
Kind = SourceKind.PreIndexed,
Arg = "https://cdn.winget.microsoft.com/cache",
Identifier = "Microsoft.Winget.Source_8wekyb3d8bbwe",
};

bool result = Repository.TryGetWinGetPackageIdentityFromLocalId(
@"ARP\Machine\X64\Contoso.Tool_Unknown.Source_1234",
[source],
out string? packageId,
out string? sourceName
);

Assert.False(result);
Assert.Null(packageId);
Assert.Null(sourceName);
}

}

public class PinStoreTests
Expand Down Expand Up @@ -1552,6 +1599,16 @@ public void ShowManifest_RestExactId_ReturnsSerializableManifestAndSelectedInsta
Assert.Empty(result.SourceWarnings);
Assert.Empty(diagnostics);

var typedResult = repo.Show(new PackageQuery
{
Id = TesslPackageId,
Exact = true,
Source = "test",
InstallerArchitecture = "x64",
});

Assert.Equal("Tessl short description", typedResult.Manifest.ShortDescription);

var json = JsonSerializer.Serialize(result, PingetJsonContext.Default.SerializableShowManifest);
using var document = JsonDocument.Parse(json);
Assert.Equal(TesslPackageId, document.RootElement.GetProperty(nameof(SerializableShowManifest.PackageIdentifier)).GetString());
Expand Down
3 changes: 2 additions & 1 deletion dotnet/src/Devolutions.Pinget.Core/Models.cs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ public record Manifest
public string Channel { get; init; } = "";
public string? Publisher { get; init; }
public string? Description { get; init; }
public string? ShortDescription { get; init; }
public string? Moniker { get; init; }
public string? PackageUrl { get; init; }
public string? PublisherUrl { get; init; }
Expand Down Expand Up @@ -343,7 +344,7 @@ public SerializableShowManifest ToSerializableManifest()
Author = Manifest.Author,
Moniker = Manifest.Moniker,
Description = Manifest.Description,
ShortDescription = GetString("ShortDescription"),
ShortDescription = Manifest.ShortDescription ?? GetString("ShortDescription"),
PackageUrl = Manifest.PackageUrl,
PublisherUrl = Manifest.PublisherUrl,
PublisherSupportUrl = Manifest.PublisherSupportUrl,
Expand Down
54 changes: 51 additions & 3 deletions dotnet/src/Devolutions.Pinget.Core/Repository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1562,6 +1562,7 @@ List<string> InstArr(string key)
Version = GetStr("PackageVersion"),
Publisher = GetOptStr("Publisher"),
Description = GetOptStr("Description") ?? GetOptStr("ShortDescription"),
ShortDescription = GetOptStr("ShortDescription"),
Moniker = GetOptStr("Moniker"),
PackageUrl = GetOptStr("PackageUrl"),
PublisherUrl = GetOptStr("PublisherUrl"),
Expand Down Expand Up @@ -1952,7 +1953,7 @@ private static int ListSortWeight(InstalledPackage pkg)
return 2;
}

private static ListMatch ListMatchFromInstalled(InstalledPackage pkg)
private ListMatch ListMatchFromInstalled(InstalledPackage pkg)
{
string? availableVersion = null;
if (pkg.Correlated?.Version is string av)
Expand All @@ -1961,14 +1962,27 @@ private static ListMatch ListMatchFromInstalled(InstalledPackage pkg)
RestSource.CompareVersionStrings(av, pkg.InstalledVersion) > 0)
availableVersion = av;
}

string packageId = pkg.Correlated?.Id ?? pkg.LocalId;
string? sourceName = pkg.Correlated?.SourceName;
if (sourceName is null && TryGetWinGetPackageIdentityFromLocalId(
pkg.LocalId,
_store.Sources,
out string? localPackageId,
out string? localSourceName))
{
packageId = localPackageId;
sourceName = localSourceName;
}

return new()
{
Name = pkg.Name,
Id = pkg.Correlated?.Id ?? pkg.LocalId,
Id = packageId,
LocalId = pkg.LocalId,
InstalledVersion = pkg.InstalledVersion,
AvailableVersion = availableVersion,
SourceName = pkg.Correlated?.SourceName,
SourceName = sourceName,
Publisher = pkg.Publisher,
Scope = pkg.Scope,
InstallerCategory = pkg.InstallerCategory,
Expand All @@ -1979,6 +1993,40 @@ private static ListMatch ListMatchFromInstalled(InstalledPackage pkg)
};
}

internal static bool TryGetWinGetPackageIdentityFromLocalId(
string localId,
IReadOnlyList<SourceRecord> sources,
[System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out string? packageId,
out string? sourceName)
{
packageId = null;
sourceName = null;

int packageIdStartIndex = localId.LastIndexOf('\\') + 1;
SourceRecord? source = null;
int sourceIdentifierStartIndex = -1;
foreach (SourceRecord candidate in sources)
{
string sourceSuffix = "_" + candidate.Identifier;
if (!localId.EndsWith(sourceSuffix, StringComparison.OrdinalIgnoreCase))
continue;

source = candidate;
sourceIdentifierStartIndex = localId.Length - sourceSuffix.Length;
break;
}

if (source is null)
return false;

if (sourceIdentifierStartIndex <= packageIdStartIndex)
return false;

packageId = localId[packageIdStartIndex..sourceIdentifierStartIndex];
sourceName = source.Name;
return !string.IsNullOrWhiteSpace(packageId);
}

private static bool ListQueryNeedsAvailableLookup(ListQuery query)
=> query.Query is not null || query.Id is not null || query.Name is not null ||
query.Moniker is not null || query.Tag is not null || query.Command is not null;
Expand Down
10 changes: 7 additions & 3 deletions dotnet/src/Devolutions.Pinget.Core/RestSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ public static RestInformation LoadInformation(HttpClient client, SourceRecord so
using var response = client.GetAsync(url).GetAwaiter().GetResult();
response.EnsureSuccessStatusCode();
var body = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
var json = JsonSerializer.Deserialize<JsonElement>(body);
using var document = JsonDocument.Parse(body);
var json = document.RootElement;

// The REST response wraps data in a "Data" property
var data = json.TryGetProperty("Data", out var d) ? d : json;
Expand Down Expand Up @@ -96,7 +97,8 @@ public static (List<RestMatchResult> Results, bool Truncated) Search(
response.EnsureSuccessStatusCode();

var responseBody = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
var json = JsonSerializer.Deserialize<JsonElement>(responseBody);
using var document = JsonDocument.Parse(responseBody);
var json = document.RootElement;

var data = json.TryGetProperty("Data", out var d) && d.ValueKind == JsonValueKind.Array
? d.EnumerateArray().ToList()
Expand Down Expand Up @@ -140,7 +142,8 @@ public static (Manifest Manifest, object StructuredDocuments) FetchManifestWithD
response.EnsureSuccessStatusCode();

var body = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
var json = JsonSerializer.Deserialize<JsonElement>(body);
using var document = JsonDocument.Parse(body);
var json = document.RootElement;

return ParseRestManifest(json, packageId, version, channel);
}
Expand Down Expand Up @@ -388,6 +391,7 @@ InstallerSwitches GetSwitches(JsonElement el)
Channel = channel,
Publisher = GetOptStr(defaultLocale, "Publisher"),
Description = GetOptStr(defaultLocale, "Description") ?? GetOptStr(defaultLocale, "ShortDescription"),
ShortDescription = GetOptStr(defaultLocale, "ShortDescription"),
Moniker = GetOptStr(data, "Moniker"),
PackageUrl = GetOptStr(defaultLocale, "PackageUrl"),
PublisherUrl = GetOptStr(defaultLocale, "PublisherUrl"),
Expand Down
4 changes: 3 additions & 1 deletion dotnet/src/Devolutions.Pinget.Core/SourceStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,9 @@ private static bool TryGetPackagedLocalStateRoot(string root, out string localSt
private static string GetPackagedSecureSettingsRoot()
{
var programData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
var sid = WindowsIdentity.GetCurrent().User?.Value ?? "UnknownSid";
var sid = OperatingSystem.IsWindows()
? WindowsIdentity.GetCurrent().User?.Value ?? "UnknownSid"
: "UnknownSid";
return Path.Combine(programData, "Microsoft", "WinGet", sid, "settings", "pkg", PackagedName);
}

Expand Down
Loading