switch to standalone nod tool rather than dolphin-tool

This commit is contained in:
theofficialgman committed 2026-08-29 12:06:58 -04:00
1 parent edc5fa1dd3
commit f09590aa5d
18 files changed
+346 -95

No files matched your search

@@ -0,0 +1,38 @@
using System.Text.RegularExpressions;
namespace WiiCompiled.NodTool;
/// <summary>Disc metadata parsed from `nodtool info`'s stdout.</summary>
public sealed record NodToolDiscInfo(string GameId, string Title, int Revision);
/// <summary>
/// Parses the plain-text stdout of `nodtool info &lt;iso&gt;`. nodtool has no JSON output mode, but
/// prints one unconditional disc-level Title/Game ID/Disc-Revision block (via its own
/// `print_header`) before any per-partition breakdown - Wii discs also have differently-scoped
/// "Title"/"Game ID" lines per update/channel partition further down, so the first match of each
/// pattern is always the disc-level one both installers want.
/// </summary>
public static partial class NodToolInfoParser
{
public static NodToolDiscInfo Parse(string infoStdout)
{
var gameIdMatch = GameIdLine().Match(infoStdout);
if (!gameIdMatch.Success)
throw new InvalidOperationException("nodtool did not return disc metadata.");
var titleMatch = TitleLine().Match(infoStdout);
var revisionMatch = RevisionLine().Match(infoStdout);
return new NodToolDiscInfo(
GameId: gameIdMatch.Groups[1].Value,
Title: titleMatch.Success ? titleMatch.Groups[1].Value : "",
Revision: revisionMatch.Success ? int.Parse(revisionMatch.Groups[1].Value) : 0);
}
[GeneratedRegex(@"^Game ID: (\S+)", RegexOptions.Multiline)]
private static partial Regex GameIdLine();
[GeneratedRegex(@"^Title: (.+)$", RegexOptions.Multiline)]
private static partial Regex TitleLine();
[GeneratedRegex(@"^Disc \d+, Revision (\d+)", RegexOptions.Multiline)]
private static partial Regex RevisionLine();
}
@@ -0,0 +1,67 @@
using System.Runtime.InteropServices;
namespace WiiCompiled.NodTool;
/// <summary>
/// Resolves the `nodtool` binary both installers use for Wii disc validation/extraction (see
/// NodToolInfoParser.cs), replacing the earlier dependency on `dolphin-tool`/`DolphinTool.exe`. A
/// caller can supply one directly; otherwise this downloads the matching prebuilt release binary
/// from encounter/nod and caches it at Launcher/artifacts/nodtool[.exe].
///
/// Shared by: WiiCompiled.Setup.Linux/DiscTool.cs (falls back to this at end-user install time on
/// a plain git checkout), and WiiCompiled.NodTool.Cli (invoked once at packaging time by both
/// build-appimage.sh and Build-Installer.ps1 to acquire the copy each bundles).
/// </summary>
public static class NodToolProvider
{
public const string Version = "v2.0.0-alpha.10";
public static async Task<string> ResolveAsync(string workspace, CancellationToken cancellationToken)
{
var cacheName = OperatingSystem.IsWindows() ? "nodtool.exe" : "nodtool";
var cachePath = Path.Combine(workspace, "Launcher", "artifacts", cacheName);
if (File.Exists(cachePath)) return cachePath;
var url = $"https://github.com/encounter/nod/releases/download/{Version}/{AssetName()}";
Directory.CreateDirectory(Path.GetDirectoryName(cachePath)!);
var tempPath = cachePath + ".tmp";
using (var http = new HttpClient())
using (var response = await http.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, cancellationToken))
{
response.EnsureSuccessStatusCode();
await using var fileStream = File.Create(tempPath);
await response.Content.CopyToAsync(fileStream, cancellationToken);
}
File.Move(tempPath, cachePath, overwrite: true);
if (!OperatingSystem.IsWindows())
{
File.SetUnixFileMode(cachePath,
UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute |
UnixFileMode.GroupRead | UnixFileMode.GroupExecute |
UnixFileMode.OtherRead | UnixFileMode.OtherExecute);
}
return cachePath;
}
private static string AssetName()
{
if (OperatingSystem.IsWindows())
{
return RuntimeInformation.OSArchitecture switch
{
Architecture.X64 => "nodtool-windows-x86_64.exe",
Architecture.Arm64 => "nodtool-windows-arm64.exe",
Architecture.X86 => "nodtool-windows-x86.exe",
var other => throw new PlatformNotSupportedException($"No prebuilt nodtool release for Windows {other}"),
};
}
return RuntimeInformation.OSArchitecture switch
{
Architecture.X64 => "nodtool-linux-x86_64",
Architecture.Arm64 => "nodtool-linux-aarch64",
Architecture.X86 => "nodtool-linux-i686",
var other => throw new PlatformNotSupportedException($"No prebuilt nodtool release for Linux {other}"),
};
}
}
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>WiiCompiled.NodTool</RootNamespace>
<AssemblyName>WiiCompiled.NodTool</AssemblyName>
<Version>0.2.22</Version>
<Authors>patchzy</Authors>
<Product>WiiCompiled</Product>
<Description>Shared nodtool acquisition/parsing logic used by both the Windows and Linux installers</Description>
<DebugType>embedded</DebugType>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
</PropertyGroup>
</Project>