Skip to content

Commit 936bf05

Browse files
Support snap as a package manager (#4646)
* Support snap as a package manager * fix whitespace --------- Co-authored-by: Sebastien Duquette <sduquette@fastmail.com>
1 parent ae86421 commit 936bf05

18 files changed

Lines changed: 1565 additions & 0 deletions

File tree

_plans/snap-package-manager.md

Lines changed: 512 additions & 0 deletions
Large diffs are not rendered by default.

src/UniGetUI.Avalonia.slnx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,12 @@
171171
<Platform Solution="*|x64" Project="x64" />
172172
</Project>
173173
</Folder>
174+
<Folder Name="/UniGetUI.PackageEngine.Managers.Snap/">
175+
<Project Path="UniGetUI.PackageEngine.Managers.Snap/UniGetUI.PackageEngine.Managers.Snap.csproj">
176+
<Platform Solution="*|arm64" Project="arm64" />
177+
<Platform Solution="*|x64" Project="x64" />
178+
</Project>
179+
</Folder>
174180
<Folder Name="/UniGetUI.PackageEngine.Managers.Vcpkg/">
175181
<Project Path="UniGetUI.PackageEngine.Managers.Vcpkg/UniGetUI.PackageEngine.Managers.Vcpkg.csproj">
176182
<Platform Solution="*|arm64" Project="arm64" />
@@ -213,4 +219,10 @@
213219
<Platform Solution="*|x64" Project="x64" />
214220
</Project>
215221
</Folder>
222+
<Folder Name="/UniGetUI.PackageEngine.Tests/">
223+
<Project Path="UniGetUI.PackageEngine.Tests/UniGetUI.PackageEngine.Tests.csproj">
224+
<Platform Solution="*|arm64" Project="arm64" />
225+
<Platform Solution="*|x64" Project="x64" />
226+
</Project>
227+
</Folder>
216228
</Solution>

src/UniGetUI.Interface.Enums/Enums.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ public enum IconType
8888
Apt = '\uE944',
8989
Dnf = '\uE945',
9090
Pacman = '\uE946',
91+
Snap = '\uE947',
9192
}
9293

9394
public class NotificationArguments
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
using System.Diagnostics;
2+
using UniGetUI.Core.IconEngine;
3+
using UniGetUI.PackageEngine.Classes.Manager.BaseProviders;
4+
using UniGetUI.PackageEngine.Enums;
5+
using UniGetUI.PackageEngine.Interfaces;
6+
using UniGetUI.PackageEngine.ManagerClasses.Classes;
7+
8+
namespace UniGetUI.PackageEngine.Managers.SnapManager;
9+
10+
internal sealed class SnapPkgDetailsHelper : BasePkgDetailsHelper
11+
{
12+
public SnapPkgDetailsHelper(Snap manager)
13+
: base(manager) { }
14+
15+
protected override void GetDetails_UnSafe(IPackageDetails details)
16+
{
17+
using var p = new Process
18+
{
19+
StartInfo = new ProcessStartInfo
20+
{
21+
FileName = Manager.Status.ExecutablePath,
22+
Arguments = $"info {details.Package.Id}",
23+
UseShellExecute = false,
24+
RedirectStandardOutput = true,
25+
RedirectStandardError = true,
26+
CreateNoWindow = true,
27+
},
28+
};
29+
p.StartInfo.Environment["LANG"] = "C";
30+
p.StartInfo.Environment["LC_ALL"] = "C";
31+
32+
IProcessTaskLogger logger = Manager.TaskLogger.CreateNew(
33+
LoggableTaskType.LoadPackageDetails, p);
34+
p.Start();
35+
36+
var descLines = new List<string>();
37+
bool inDescription = false;
38+
bool inChannels = false;
39+
40+
while (p.StandardOutput.ReadLine() is { } line)
41+
{
42+
logger.AddToStdOut(line);
43+
44+
if (line.StartsWith("channels:", StringComparison.Ordinal))
45+
{
46+
inChannels = true;
47+
inDescription = false;
48+
continue;
49+
}
50+
51+
if (inChannels && line.StartsWith(" "))
52+
continue;
53+
54+
if (inChannels && !line.StartsWith(" "))
55+
inChannels = false;
56+
57+
if (inDescription)
58+
{
59+
if (line.StartsWith(" "))
60+
{
61+
var descLine = line.TrimStart();
62+
if (descLine != ".") descLines.Add(descLine);
63+
continue;
64+
}
65+
else
66+
{
67+
inDescription = false;
68+
}
69+
}
70+
71+
var colonIdx = line.IndexOf(':', StringComparison.Ordinal);
72+
if (colonIdx <= 0) continue;
73+
74+
var key = line[..colonIdx].Trim().ToLowerInvariant();
75+
var value = line[(colonIdx + 1)..].Trim();
76+
77+
switch (key)
78+
{
79+
case "summary":
80+
details.Description = value;
81+
break;
82+
case "publisher":
83+
details.Publisher = value.Replace("\u2713", "").Trim();
84+
break;
85+
case "license":
86+
details.License = value;
87+
break;
88+
case "homepage":
89+
if (Uri.TryCreate(value, UriKind.Absolute, out var homepage))
90+
details.HomepageUrl = homepage;
91+
break;
92+
case "store-url":
93+
if (Uri.TryCreate(value, UriKind.Absolute, out var storeUrl))
94+
details.ManifestUrl = storeUrl;
95+
break;
96+
case "description":
97+
if (value == "|")
98+
{
99+
details.Description = "";
100+
inDescription = true;
101+
}
102+
else
103+
{
104+
details.Description = value;
105+
}
106+
break;
107+
}
108+
}
109+
110+
if (descLines.Count > 0)
111+
details.Description = (details.Description ?? "") + "\n" + string.Join("\n", descLines);
112+
113+
logger.AddToStdErr(p.StandardError.ReadToEnd());
114+
p.WaitForExit();
115+
logger.Close(p.ExitCode);
116+
}
117+
118+
protected override CacheableIcon? GetIcon_UnSafe(IPackage package)
119+
=> throw new NotImplementedException();
120+
121+
protected override IReadOnlyList<Uri> GetScreenshots_UnSafe(IPackage package)
122+
=> Array.Empty<Uri>();
123+
124+
protected override string? GetInstallLocation_UnSafe(IPackage package)
125+
=> $"/snap/{package.Id}/current";
126+
127+
protected override IReadOnlyList<string> GetInstallableVersions_UnSafe(IPackage package)
128+
=> throw new InvalidOperationException("Snap does not support installing arbitrary versions");
129+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using UniGetUI.PackageEngine.Classes.Manager.BaseProviders;
2+
using UniGetUI.PackageEngine.Enums;
3+
using UniGetUI.PackageEngine.Interfaces;
4+
using UniGetUI.PackageEngine.Serializable;
5+
6+
namespace UniGetUI.PackageEngine.Managers.SnapManager;
7+
8+
internal sealed class SnapPkgOperationHelper : BasePkgOperationHelper
9+
{
10+
public SnapPkgOperationHelper(Snap manager)
11+
: base(manager) { }
12+
13+
protected override IReadOnlyList<string> _getOperationParameters(
14+
IPackage package,
15+
InstallOptions options,
16+
OperationType operation)
17+
{
18+
options.RunAsAdministrator = true;
19+
20+
List<string> parameters =
21+
[
22+
operation switch
23+
{
24+
OperationType.Install => Manager.Properties.InstallVerb,
25+
OperationType.Uninstall => Manager.Properties.UninstallVerb,
26+
OperationType.Update => Manager.Properties.UpdateVerb,
27+
_ => throw new InvalidDataException("Invalid package operation"),
28+
},
29+
];
30+
31+
parameters.Add(package.Id);
32+
33+
if (operation == OperationType.Uninstall)
34+
parameters.Add("--purge");
35+
36+
parameters.AddRange(
37+
operation switch
38+
{
39+
OperationType.Update => options.CustomParameters_Update,
40+
OperationType.Uninstall => options.CustomParameters_Uninstall,
41+
_ => options.CustomParameters_Install,
42+
});
43+
44+
return parameters;
45+
}
46+
47+
protected override OperationVeredict _getOperationResult(
48+
IPackage package,
49+
OperationType operation,
50+
IReadOnlyList<string> processOutput,
51+
int returnCode)
52+
{
53+
return returnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure;
54+
}
55+
}

0 commit comments

Comments
 (0)