Skip to content

Commit 17325a4

Browse files
committed
Port the Setup class
1 parent 9479b9a commit 17325a4

File tree

5 files changed

+175
-200
lines changed

5 files changed

+175
-200
lines changed

src/Cmdlets/Install-Release.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
namespace Belin.SetupHashLink.Cmdlets;
22

33
/// <summary>
4-
/// Installs Apache Ant, after downloading it.
4+
/// Installs the HashLink VM, after downloading it.
55
/// </summary>
66
[Cmdlet(VerbsLifecycle.Install, "Release", DefaultParameterSetName = "Constraint")]
77
[OutputType(typeof(string))]
@@ -19,12 +19,6 @@ public class InstallReleaseCommand: PSCmdlet {
1919
[Parameter(Mandatory = true, ParameterSetName = "InputObject", ValueFromPipeline = true)]
2020
public required Release InputObject { get; set; }
2121

22-
/// <summary>
23-
/// Value indicating whether to fetch the Ant optional tasks.
24-
/// </summary>
25-
[Parameter]
26-
public SwitchParameter OptionalTasks { get; set; }
27-
2822
/// <summary>
2923
/// Performs execution of this command.
3024
/// </summary>

src/Setup.cs

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,135 @@
11
namespace Belin.SetupHashLink;
2+
3+
using System.Diagnostics;
4+
using System.IO;
5+
using System.IO.Compression;
6+
using System.Threading;
7+
8+
/// <summary>
9+
/// Manages the download and installation of the HashLink VM.
10+
/// </summary>
11+
/// <param name="release">The release to download and install.</param>
12+
public class Setup(Release release) {
13+
14+
/// <summary>
15+
/// The release to download and install.
16+
/// </summary>
17+
public Release Release => release;
18+
19+
/// <summary>
20+
/// Downloads and extracts the ZIP archive of the HashLink VM.
21+
/// </summary>
22+
/// <param name="cancellationToken">The token to cancel the operation.</param>
23+
/// <returns>The path to the extracted directory.</returns>
24+
public async Task<string> Download(CancellationToken cancellationToken = default) {
25+
using var httpClient = new HttpClient();
26+
var version = GetType().Assembly.GetName().Version!;
27+
httpClient.DefaultRequestHeaders.Add("User-Agent", $".NET/{Environment.Version.ToString(3)} | SetupHashLink/{version.ToString(3)}");
28+
29+
var bytes = await httpClient.GetByteArrayAsync(Release.Url, cancellationToken);
30+
var file = Path.GetTempFileName();
31+
await File.WriteAllBytesAsync(file, bytes, cancellationToken);
32+
33+
var directory = Path.Join(Path.GetTempPath(), Guid.NewGuid().ToString());
34+
// TODO (.NET 10) await ZipFile.ExtractToDirectoryAsync(file, directory, cancellationToken);
35+
ZipFile.ExtractToDirectory(file, directory);
36+
return Path.Join(directory, Path.GetFileName(Directory.EnumerateDirectories(directory).Single()));
37+
}
38+
39+
/// <summary>
40+
/// Installs the HashLink VM, after downloading it.
41+
/// </summary>
42+
/// <param name="cancellationToken">The token to cancel the operation.</param>
43+
/// <returns>The path to the installation directory.</returns>
44+
public async Task<string> Install(CancellationToken cancellationToken = default) {
45+
var directory = await Download(cancellationToken);
46+
if (Release.IsSource && Environment.GetEnvironmentVariable("CI") is not null) await Compile(directory, cancellationToken);
47+
48+
var binFolder = Release.IsSource ? Path.Join(directory, "bin") : directory;
49+
Environment.SetEnvironmentVariable("PATH", $"{Environment.GetEnvironmentVariable("PATH")}{Path.PathSeparator}{binFolder}");
50+
await File.AppendAllTextAsync(Environment.GetEnvironmentVariable("GITHUB_PATH")!, binFolder, cancellationToken);
51+
return directory;
52+
}
53+
54+
/// <summary>
55+
/// Compiles the sources of the HashLink VM located in the specified directory.
56+
/// </summary>
57+
/// <param name="directory">The path to the directory containing the HashLink sources.</param>
58+
/// <param name="cancellationToken">The token to cancel the operation.</param>
59+
/// <returns>The path to the output directory.</returns>
60+
/// <exception cref="PlatformNotSupportedException">The compilation is not supported on Windows platform.</exception>
61+
private async Task<string> Compile(string directory, CancellationToken cancellationToken) {
62+
var platform = PlatformExtensions.GetCurrent();
63+
if (platform == Platform.Windows) throw new PlatformNotSupportedException("Compilation is not supported on Windows platform.");
64+
65+
var workingDirectory = Environment.CurrentDirectory;
66+
Environment.CurrentDirectory = directory;
67+
var path = platform == Platform.MacOS ? await CompileMacOS(cancellationToken) : await CompileLinux(cancellationToken);
68+
Environment.CurrentDirectory = workingDirectory;
69+
return path;
70+
}
71+
72+
/// <summary>
73+
/// Compiles the HashLink sources on the Linux platform.
74+
/// </summary>
75+
/// <returns>The path to the output directory.</returns>
76+
/// <exception cref="ApplicationFailedException">An error occurred while executing a native command.</exception>
77+
private static async Task<string> CompileLinux(CancellationToken cancellationToken) {
78+
var dependencies = new[] {
79+
"libglu1-mesa-dev",
80+
"libmbedtls-dev",
81+
"libopenal-dev",
82+
"libpng-dev",
83+
"libsdl2-dev",
84+
"libsqlite3-dev",
85+
"libturbojpeg-dev",
86+
"libuv1-dev",
87+
"libvorbis-dev"
88+
};
89+
90+
var commands = new[] {
91+
("sudo", "apt-get update"),
92+
("sudo", $"apt-get install --assume-yes --no-install-recommends {string.Join(" ", dependencies)}"),
93+
("make", ""),
94+
("sudo", "make install"),
95+
("sudo", "ldconfig")
96+
};
97+
98+
foreach (var (fileName, arguments) in commands) {
99+
using var process = Process.Start(fileName, arguments) ?? throw new ApplicationFailedException(fileName);
100+
await process.WaitForExitAsync(cancellationToken);
101+
if (process.ExitCode != 0) throw new ApplicationFailedException(fileName);
102+
}
103+
104+
var prefix = "/usr/local";
105+
var ldLibraryPath = $"{Environment.GetEnvironmentVariable("LD_LIBRARY_PATH")}{Path.PathSeparator}{prefix}/bin";
106+
Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", ldLibraryPath);
107+
await File.AppendAllTextAsync(Environment.GetEnvironmentVariable("GITHUB_ENV")!, $"LD_LIBRARY_PATH={ldLibraryPath}", cancellationToken);
108+
return prefix;
109+
}
110+
111+
/// <summary>
112+
/// Compiles the HashLink sources on the macOS platform.
113+
/// </summary>
114+
/// <param name="cancellationToken">The token to cancel the operation.</param>
115+
/// <returns>The path to the output directory.</returns>
116+
/// <exception cref="ApplicationFailedException">An error occurred while executing a native command.</exception>
117+
private static async Task<string> CompileMacOS(CancellationToken cancellationToken) {
118+
var prefix = "/usr/local";
119+
var commands = new[] {
120+
("brew", "bundle"),
121+
("make", ""),
122+
("sudo", "make codesign_osx"),
123+
("sudo", "make install"),
124+
("sudo", $"install_name_tool -change libhl.dylib {prefix}/lib/libhl.dylib {prefix}/bin/hl")
125+
};
126+
127+
foreach (var (fileName, arguments) in commands) {
128+
using var process = Process.Start(fileName, arguments) ?? throw new ApplicationFailedException(fileName);
129+
await process.WaitForExitAsync(cancellationToken);
130+
if (process.ExitCode != 0) throw new ApplicationFailedException(fileName);
131+
}
132+
133+
return prefix;
134+
}
135+
}

src/Setup.psm1

Lines changed: 0 additions & 146 deletions
This file was deleted.

test/Setup.Tests.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
namespace Belin.SetupHashLink;
2+
3+
/// <summary>
4+
/// Tests the features of the <see cref="Setup"/> class.
5+
/// </summary>
6+
/// <param name="testContext">The test context.</param>
7+
[TestClass]
8+
public sealed class SetupTests(TestContext testContext) {
9+
10+
/// <summary>
11+
/// The current platform.
12+
/// </summary>
13+
private readonly Platform platform = PlatformExtensions.GetCurrent();
14+
15+
[ClassInitialize]
16+
public static void ClassInitialize(TestContext testContext) {
17+
if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("GITHUB_ENV"))) Environment.SetEnvironmentVariable("GITHUB_ENV", "var/GitHub-Env.txt");
18+
if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("GITHUB_PATH"))) Environment.SetEnvironmentVariable("GITHUB_PATH", "var/GitHub-Path.txt");
19+
}
20+
21+
[TestMethod]
22+
public async Task Download() {
23+
var setup = new Setup(Release.Latest);
24+
var path = await setup.Download(testContext.CancellationToken);
25+
26+
var executable = $"hl{(setup.Release.IsSource ? ".vcxproj" : platform == Platform.Windows ? ".exe" : "")}";
27+
IsTrue(File.Exists(Path.Join(path, executable)));
28+
29+
var dynamicLibrary = $"libhl{(setup.Release.IsSource ? ".vcxproj" : platform == Platform.MacOS ? ".dylib" : platform == Platform.Linux ? ".so" : ".dll")}";
30+
IsTrue(File.Exists(Path.Join(path, dynamicLibrary)));
31+
}
32+
33+
[TestMethod]
34+
public async Task Install() {
35+
var setup = new Setup(Release.Latest);
36+
var path = await setup.Install(testContext.CancellationToken);
37+
Contains(path, Environment.GetEnvironmentVariable("PATH")!);
38+
if (platform == Platform.Linux && setup.Release.IsSource) Contains("/usr/local/bin", Environment.GetEnvironmentVariable("LD_LIBRARY_PATH")!);
39+
}
40+
}

test/Setup.Tests.ps1

Lines changed: 0 additions & 47 deletions
This file was deleted.

0 commit comments

Comments
 (0)