mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-06 01:00:14 +02:00
switch to standalone nod tool rather than dolphin-tool
This commit is contained in:
18 files changed
+346
-95
No files matched your search
@@ -1,7 +1,6 @@
|
|||||||
[CmdletBinding(PositionalBinding = $false)]
|
[CmdletBinding(PositionalBinding = $false)]
|
||||||
param(
|
param(
|
||||||
[string]$OutputDirectory = 'Launcher/dist',
|
[string]$OutputDirectory = 'Launcher/dist',
|
||||||
[string]$DolphinToolPath,
|
|
||||||
[string]$PortableToolsDirectory = 'Launcher/artifacts/portable-tools',
|
[string]$PortableToolsDirectory = 'Launcher/artifacts/portable-tools',
|
||||||
[string]$DependencySourceDirectory = 'Launcher/artifacts/dependencies',
|
[string]$DependencySourceDirectory = 'Launcher/artifacts/dependencies',
|
||||||
[string]$VcRuntimeDirectory,
|
[string]$VcRuntimeDirectory,
|
||||||
@@ -15,10 +14,6 @@ Set-StrictMode -Version 3.0
|
|||||||
# helpers shared with LocalBuild.ps1 and Prepare-NativePrebuilt.ps1.
|
# helpers shared with LocalBuild.ps1 and Prepare-NativePrebuilt.ps1.
|
||||||
. (Join-Path $PSScriptRoot 'NativeBuildFlags.ps1')
|
. (Join-Path $PSScriptRoot 'NativeBuildFlags.ps1')
|
||||||
|
|
||||||
if ([string]::IsNullOrWhiteSpace($DolphinToolPath)) {
|
|
||||||
throw 'Build-Installer.ps1 requires -DolphinToolPath pointing to DolphinTool.exe.'
|
|
||||||
}
|
|
||||||
|
|
||||||
$repoRoot = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..'))
|
$repoRoot = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..'))
|
||||||
$outputRoot = [IO.Path]::GetFullPath((Join-Path $repoRoot $OutputDirectory))
|
$outputRoot = [IO.Path]::GetFullPath((Join-Path $repoRoot $OutputDirectory))
|
||||||
$portableTools = [IO.Path]::GetFullPath((Join-Path $repoRoot $PortableToolsDirectory))
|
$portableTools = [IO.Path]::GetFullPath((Join-Path $repoRoot $PortableToolsDirectory))
|
||||||
@@ -91,7 +86,6 @@ function Compress-Zip([string]$Source, [string]$Destination, [string[]]$Entries)
|
|||||||
|
|
||||||
Assert-File $setupProject '.NET setup project'
|
Assert-File $setupProject '.NET setup project'
|
||||||
Assert-File $translatorProject 'Translator CLI project'
|
Assert-File $translatorProject 'Translator CLI project'
|
||||||
Assert-File $DolphinToolPath 'DolphinTool'
|
|
||||||
|
|
||||||
if (-not (Test-Path -LiteralPath (Join-Path $portableTools 'llvm-mingw\bin\x86_64-w64-mingw32-clang++.exe'))) {
|
if (-not (Test-Path -LiteralPath (Join-Path $portableTools 'llvm-mingw\bin\x86_64-w64-mingw32-clang++.exe'))) {
|
||||||
& (Join-Path $PSScriptRoot 'Prepare-PortableTools.ps1') -Destination $portableTools
|
& (Join-Path $PSScriptRoot 'Prepare-PortableTools.ps1') -Destination $portableTools
|
||||||
@@ -169,6 +163,15 @@ $translator = Join-Path $publish 'translator\Translator.Cli.exe'
|
|||||||
Assert-File $setupHost 'Published setup host'
|
Assert-File $setupHost 'Published setup host'
|
||||||
Assert-File $translator 'Self-contained translator'
|
Assert-File $translator 'Self-contained translator'
|
||||||
|
|
||||||
|
# Resolved via the shared WiiCompiled.NodTool.Cli helper (also used by build-appimage.sh on Linux)
|
||||||
|
# rather than a separate download/version-pin copy here: it downloads and caches the same way
|
||||||
|
# NodToolProvider.cs always does (Launcher/artifacts/nodtool.exe), replacing the old manual
|
||||||
|
# -DolphinToolPath handoff with an automated, pinned acquisition step.
|
||||||
|
$nodToolCliProject = Join-Path $PSScriptRoot 'WiiCompiled.NodTool.Cli'
|
||||||
|
$nodTool = (& dotnet run --project $nodToolCliProject -c Release -- --workspace $repoRoot | Select-Object -Last 1)
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw "nodtool resolution failed with exit code $LASTEXITCODE." }
|
||||||
|
Assert-File $nodTool 'Resolved nodtool'
|
||||||
|
|
||||||
Write-Host '[2/6] Staging the explicit, game-code-free payload allowlist...'
|
Write-Host '[2/6] Staging the explicit, game-code-free payload allowlist...'
|
||||||
# The staged layout mirrors the installed layout exactly (Toolkit, BuildWorkspace): payload
|
# The staged layout mirrors the installed layout exactly (Toolkit, BuildWorkspace): payload
|
||||||
# identities hash relative paths, so the names here are part of the fingerprint contract.
|
# identities hash relative paths, so the names here are part of the fingerprint contract.
|
||||||
@@ -191,7 +194,7 @@ Get-ChildItem -LiteralPath (Join-Path $toolkit 'llvm-mingw\bin') -File |
|
|||||||
Remove-Item -Force
|
Remove-Item -Force
|
||||||
[IO.Directory]::CreateDirectory((Join-Path $toolkit 'Translator')) | Out-Null
|
[IO.Directory]::CreateDirectory((Join-Path $toolkit 'Translator')) | Out-Null
|
||||||
Copy-Item -LiteralPath $translator -Destination (Join-Path $toolkit 'Translator\Translator.Cli.exe')
|
Copy-Item -LiteralPath $translator -Destination (Join-Path $toolkit 'Translator\Translator.Cli.exe')
|
||||||
Copy-Item -LiteralPath $DolphinToolPath -Destination (Join-Path $toolkit 'DolphinTool.exe')
|
Copy-Item -LiteralPath $nodTool -Destination (Join-Path $toolkit 'nodtool.exe')
|
||||||
[IO.Directory]::CreateDirectory((Join-Path $toolkit 'Redist')) | Out-Null
|
[IO.Directory]::CreateDirectory((Join-Path $toolkit 'Redist')) | Out-Null
|
||||||
Copy-Item -Path (Join-Path $vcRuntime '*.dll') -Destination (Join-Path $toolkit 'Redist')
|
Copy-Item -Path (Join-Path $vcRuntime '*.dll') -Destination (Join-Path $toolkit 'Redist')
|
||||||
Copy-Item -Path (Join-Path $vcRuntime '*.dll') -Destination (Join-Path $toolkit 'CMake\bin')
|
Copy-Item -Path (Join-Path $vcRuntime '*.dll') -Destination (Join-Path $toolkit 'CMake\bin')
|
||||||
@@ -225,18 +228,38 @@ Copy-Item (Join-Path $dependencySources 'cppwinrt\LICENSE.txt') (Join-Path $payl
|
|||||||
# The precompiled aurora/third-party archives are built from the very sources
|
# The precompiled aurora/third-party archives are built from the very sources
|
||||||
# already shipped under build-workspace\Dependencies and aurora-main, so they add
|
# already shipped under build-workspace\Dependencies and aurora-main, so they add
|
||||||
# no third-party component and therefore no new license obligation.
|
# no third-party component and therefore no new license obligation.
|
||||||
$dolphinLicense = Join-Path (Split-Path -Parent $DolphinToolPath) 'COPYING'
|
|
||||||
if (Test-Path $dolphinLicense) { Copy-Item $dolphinLicense (Join-Path $payloadRoot 'licenses\Dolphin-COPYING.txt') }
|
|
||||||
@"
|
@"
|
||||||
DolphinTool source offer
|
nodtool (disc image extraction)
|
||||||
|
|
||||||
Project and complete corresponding source: https://github.com/dolphin-emu/dolphin
|
Project: https://github.com/encounter/nod
|
||||||
Dolphin is licensed under GPLv2+ with additional per-file SPDX licenses.
|
Dual-licensed under MIT OR Apache-2.0.
|
||||||
"@ | Set-Content (Join-Path $payloadRoot 'licenses\Dolphin-SOURCE.txt') -Encoding UTF8
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright 2021 Luke Street.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
"@ | Set-Content (Join-Path $payloadRoot 'licenses\nodtool-LICENSE-MIT.txt') -Encoding UTF8
|
||||||
@"
|
@"
|
||||||
Microsoft Visual C++ Runtime
|
Microsoft Visual C++ Runtime
|
||||||
|
|
||||||
Redistributable x64 runtime DLLs are included app-locally for DolphinTool and third-party renderer DLLs.
|
Redistributable x64 runtime DLLs are included app-locally for nodtool and third-party renderer DLLs.
|
||||||
Microsoft license terms: https://visualstudio.microsoft.com/license-terms/
|
Microsoft license terms: https://visualstudio.microsoft.com/license-terms/
|
||||||
"@ | Set-Content (Join-Path $payloadRoot 'licenses\Microsoft-VC-Runtime.txt') -Encoding UTF8
|
"@ | Set-Content (Join-Path $payloadRoot 'licenses\Microsoft-VC-Runtime.txt') -Encoding UTF8
|
||||||
# Compute the payload's content identities once, here, with the same code every installed host
|
# Compute the payload's content identities once, here, with the same code every installed host
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
[CmdletBinding(PositionalBinding = $false)]
|
[CmdletBinding(PositionalBinding = $false)]
|
||||||
param(
|
param(
|
||||||
[string]$DolphinToolPath,
|
|
||||||
[string]$PortableToolsDirectory = 'Launcher/artifacts/portable-tools',
|
[string]$PortableToolsDirectory = 'Launcher/artifacts/portable-tools',
|
||||||
[string]$DependencySourceDirectory = 'Launcher/artifacts/dependencies',
|
[string]$DependencySourceDirectory = 'Launcher/artifacts/dependencies',
|
||||||
[string]$VcRuntimeDirectory,
|
[string]$VcRuntimeDirectory,
|
||||||
@@ -10,12 +9,7 @@ param(
|
|||||||
$ErrorActionPreference = 'Stop'
|
$ErrorActionPreference = 'Stop'
|
||||||
Set-StrictMode -Version 3.0
|
Set-StrictMode -Version 3.0
|
||||||
|
|
||||||
if ([string]::IsNullOrWhiteSpace($DolphinToolPath)) {
|
|
||||||
throw 'Prepare-Release.ps1 requires -DolphinToolPath pointing to DolphinTool.exe.'
|
|
||||||
}
|
|
||||||
|
|
||||||
$arguments = @{
|
$arguments = @{
|
||||||
DolphinToolPath = $DolphinToolPath
|
|
||||||
PortableToolsDirectory = $PortableToolsDirectory
|
PortableToolsDirectory = $PortableToolsDirectory
|
||||||
DependencySourceDirectory = $DependencySourceDirectory
|
DependencySourceDirectory = $DependencySourceDirectory
|
||||||
ToolkitReleaseTag = $ToolkitReleaseTag
|
ToolkitReleaseTag = $ToolkitReleaseTag
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
using WiiCompiled.NodTool;
|
||||||
|
|
||||||
|
// A packaging-time-only helper - never shipped, never run by an end user. Both
|
||||||
|
// Launcher/build-appimage.sh and Launcher/Build-Installer.ps1 invoke this to obtain the nodtool
|
||||||
|
// binary they bundle, so there is exactly one place (NodToolProvider) that knows the pinned
|
||||||
|
// version/URL/platform-asset mapping, instead of a separate copy per packaging script.
|
||||||
|
//
|
||||||
|
// Usage: WiiCompiled.NodTool.Cli --workspace <repo-root>
|
||||||
|
// Prints the resolved nodtool path to stdout.
|
||||||
|
|
||||||
|
string? workspace = null;
|
||||||
|
for (var i = 0; i < args.Length; i++)
|
||||||
|
{
|
||||||
|
if (args[i] == "--workspace" && i + 1 < args.Length)
|
||||||
|
{
|
||||||
|
workspace = args[++i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workspace is null)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine("Usage: WiiCompiled.NodTool.Cli --workspace <repo-root>");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var path = await NodToolProvider.ResolveAsync(workspace, CancellationToken.None);
|
||||||
|
Console.WriteLine(path);
|
||||||
|
return 0;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<RootNamespace>WiiCompiled.NodTool.Cli</RootNamespace>
|
||||||
|
<AssemblyName>WiiCompiled.NodTool.Cli</AssemblyName>
|
||||||
|
<Version>0.2.22</Version>
|
||||||
|
<Authors>patchzy</Authors>
|
||||||
|
<Product>WiiCompiled</Product>
|
||||||
|
<Description>Packaging-time helper: resolves (downloading if needed) the nodtool binary bundled by build-appimage.sh and Build-Installer.ps1</Description>
|
||||||
|
<DebugType>embedded</DebugType>
|
||||||
|
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\WiiCompiled.NodTool\WiiCompiled.NodTool.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -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 <iso>`. 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>
|
||||||
@@ -1,28 +1,32 @@
|
|||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text.Json;
|
using WiiCompiled.NodTool;
|
||||||
|
|
||||||
namespace WiiCompiled.Setup.Linux;
|
namespace WiiCompiled.Setup.Linux;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Validates and extracts the user's own Mario Kart Wii disc via the system-installed
|
/// Validates and extracts the user's own Mario Kart Wii disc via `nodtool` (see
|
||||||
/// `dolphin-tool` (required prerequisite, per the project's scoping decision to depend on system
|
/// WiiCompiled.NodTool/NodToolProvider.cs) - a prebuilt, MIT/Apache-2.0-licensed CLI from
|
||||||
/// tools rather than bundling one) - the Linux analogue of the Windows installer shelling out to a
|
/// encounter/nod, replacing the earlier dependency on a system-installed `dolphin-tool`
|
||||||
/// bundled DolphinTool.exe.
|
/// (GPL-2.0-or-later, and not reliably packaged standalone by every distro).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class DiscTool
|
internal static class DiscTool
|
||||||
{
|
{
|
||||||
public static async Task ValidateAndExtractAsync(
|
public static async Task ValidateAndExtractAsync(
|
||||||
string isoPath, ProjectManifest manifest, string assetsDirectory,
|
string isoPath, ProjectManifest manifest, string assetsDirectory, string workspace,
|
||||||
IInstallReporter reporter, CancellationToken cancellationToken)
|
string? nodToolBin, IInstallReporter reporter, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
var nodTool = nodToolBin ?? await NodToolProvider.ResolveAsync(workspace, cancellationToken);
|
||||||
|
|
||||||
|
// `nodtool info` only decodes the disc/partition headers (milliseconds); `nodtool extract`
|
||||||
|
// copies the whole data partition to disk (tens of seconds for a custom-track-heavy MKWii
|
||||||
|
// ISO). Checking the game ID first, before extracting, means a wrong disc fails fast -
|
||||||
|
// matching the original dolphin-tool `header` step this replaces.
|
||||||
reporter.Progress(InstallStages.ExtractDisc, "Reading the disc header", 2);
|
reporter.Progress(InstallStages.ExtractDisc, "Reading the disc header", 2);
|
||||||
var headerJson = await RunAsync(["header", "-i", isoPath, "-j"], cancellationToken);
|
var info = NodToolInfoParser.Parse(await RunInfoAsync(nodTool, isoPath, cancellationToken));
|
||||||
using var header = JsonDocument.Parse(headerJson);
|
if (!string.Equals(info.GameId, manifest.GameId, StringComparison.Ordinal))
|
||||||
var gameId = header.RootElement.GetProperty("game_id").GetString();
|
|
||||||
if (!string.Equals(gameId, manifest.GameId, StringComparison.Ordinal))
|
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
$"This disc is '{gameId}', not the expected '{manifest.GameId}' (Mario Kart Wii, region {manifest.Region}). " +
|
$"This disc is '{info.GameId}', not the expected '{manifest.GameId}' (Mario Kart Wii, region {manifest.Region}). " +
|
||||||
"Only your own legally-owned copy of that exact game/region can be used.");
|
"Only your own legally-owned copy of that exact game/region can be used.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,12 +35,12 @@ internal static class DiscTool
|
|||||||
Directory.CreateDirectory(scratch);
|
Directory.CreateDirectory(scratch);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await RunAsync(["extract", "-i", isoPath, "-g", "-o", scratch, "-q"], cancellationToken);
|
await RunExtractAsync(nodTool, isoPath, scratch, cancellationToken);
|
||||||
|
|
||||||
var dolPath = Path.Combine(scratch, "DATA", "sys", "main.dol");
|
var dolPath = Path.Combine(scratch, "sys", "main.dol");
|
||||||
var relPath = Path.Combine(scratch, "DATA", "files", "rel", "StaticR.rel");
|
var relPath = Path.Combine(scratch, "files", "rel", "StaticR.rel");
|
||||||
if (!File.Exists(dolPath)) throw new FileNotFoundException("dolphin-tool did not produce main.dol", dolPath);
|
if (!File.Exists(dolPath)) throw new FileNotFoundException("nodtool did not produce main.dol", dolPath);
|
||||||
if (!File.Exists(relPath)) throw new FileNotFoundException("dolphin-tool did not produce StaticR.rel", relPath);
|
if (!File.Exists(relPath)) throw new FileNotFoundException("nodtool did not produce StaticR.rel", relPath);
|
||||||
|
|
||||||
var dolSha = Sha256Of(dolPath);
|
var dolSha = Sha256Of(dolPath);
|
||||||
var relSha = Sha256Of(relPath);
|
var relSha = Sha256Of(relPath);
|
||||||
@@ -64,32 +68,53 @@ internal static class DiscTool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string Sha256Of(string path)
|
private static async Task<string> RunInfoAsync(string nodTool, string isoPath, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
using var stream = File.OpenRead(path);
|
var startInfo = new System.Diagnostics.ProcessStartInfo(nodTool)
|
||||||
return Convert.ToHexString(SHA256.HashData(stream)).ToLowerInvariant();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task<string> RunAsync(string[] arguments, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var startInfo = new System.Diagnostics.ProcessStartInfo("dolphin-tool")
|
|
||||||
{
|
{
|
||||||
|
ArgumentList = { "info", isoPath },
|
||||||
RedirectStandardOutput = true,
|
RedirectStandardOutput = true,
|
||||||
RedirectStandardError = true,
|
RedirectStandardError = true,
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
};
|
};
|
||||||
foreach (var argument in arguments) startInfo.ArgumentList.Add(argument);
|
|
||||||
|
|
||||||
using var process = System.Diagnostics.Process.Start(startInfo)
|
using var process = System.Diagnostics.Process.Start(startInfo)
|
||||||
?? throw new InvalidOperationException("Failed to start dolphin-tool. Is it installed and on PATH?");
|
?? throw new InvalidOperationException($"Failed to start {nodTool}.");
|
||||||
var stdout = await process.StandardOutput.ReadToEndAsync(cancellationToken);
|
var stdout = await process.StandardOutput.ReadToEndAsync(cancellationToken);
|
||||||
var stderr = await process.StandardError.ReadToEndAsync(cancellationToken);
|
var stderr = await process.StandardError.ReadToEndAsync(cancellationToken);
|
||||||
await process.WaitForExitAsync(cancellationToken);
|
await process.WaitForExitAsync(cancellationToken);
|
||||||
if (process.ExitCode != 0)
|
if (process.ExitCode != 0)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
$"dolphin-tool {string.Join(' ', arguments)} failed (exit {process.ExitCode}): {stderr}");
|
$"nodtool could not read this disc image (exit {process.ExitCode}): {stderr}{stdout}".Trim());
|
||||||
}
|
}
|
||||||
return stdout;
|
return stdout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string Sha256Of(string path)
|
||||||
|
{
|
||||||
|
using var stream = File.OpenRead(path);
|
||||||
|
return Convert.ToHexString(SHA256.HashData(stream)).ToLowerInvariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task RunExtractAsync(string nodTool, string isoPath, string outDir, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var startInfo = new System.Diagnostics.ProcessStartInfo(nodTool)
|
||||||
|
{
|
||||||
|
ArgumentList = { "extract", isoPath, outDir, "-q" },
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
UseShellExecute = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
using var process = System.Diagnostics.Process.Start(startInfo)
|
||||||
|
?? throw new InvalidOperationException($"Failed to start {nodTool}.");
|
||||||
|
var stdout = await process.StandardOutput.ReadToEndAsync(cancellationToken);
|
||||||
|
var stderr = await process.StandardError.ReadToEndAsync(cancellationToken);
|
||||||
|
await process.WaitForExitAsync(cancellationToken);
|
||||||
|
if (process.ExitCode != 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"nodtool extract {isoPath} failed (exit {process.ExitCode}): {stderr}{stdout}");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,8 @@ internal static class Program
|
|||||||
reporter.Progress(InstallStages.Validate, "Checking prerequisites", 1);
|
reporter.Progress(InstallStages.Validate, "Checking prerequisites", 1);
|
||||||
if (flags.TryGetValue("game", out var isoPath) && !string.IsNullOrEmpty(isoPath))
|
if (flags.TryGetValue("game", out var isoPath) && !string.IsNullOrEmpty(isoPath))
|
||||||
{
|
{
|
||||||
await DiscTool.ValidateAndExtractAsync(isoPath, manifest, assetsDir, reporter, token);
|
await DiscTool.ValidateAndExtractAsync(isoPath, manifest, assetsDir, workspace,
|
||||||
|
flags.GetValueOrDefault("disc-tool-bin"), reporter, token);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -261,7 +262,8 @@ internal static class Program
|
|||||||
|
|
||||||
install --profile {base|retro-rewind|both} [--game ISO_PATH] [--install-dir DIR]
|
install --profile {base|retro-rewind|both} [--game ISO_PATH] [--install-dir DIR]
|
||||||
[--retro-rewind-package-dir DIR] [--retro-wfc-offline-dir DIR | --skip-retro-wfc-payload]
|
[--retro-rewind-package-dir DIR] [--retro-wfc-offline-dir DIR | --skip-retro-wfc-payload]
|
||||||
[--force-clean-build] [--translator-bin PATH] [--progress-json] [--workspace DIR]
|
[--force-clean-build] [--translator-bin PATH] [--disc-tool-bin PATH]
|
||||||
|
[--progress-json] [--workspace DIR]
|
||||||
uninstall [--profile {base|retro-rewind|both|all}]
|
uninstall [--profile {base|retro-rewind|both|all}]
|
||||||
launch-base
|
launch-base
|
||||||
launch-retro
|
launch-retro
|
||||||
|
|||||||
@@ -14,4 +14,7 @@
|
|||||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||||
<InvariantGlobalization>true</InvariantGlobalization>
|
<InvariantGlobalization>true</InvariantGlobalization>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\WiiCompiled.NodTool\WiiCompiled.NodTool.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -63,8 +63,8 @@ internal static class ConsoleCommands
|
|||||||
{
|
{
|
||||||
using var payload = PayloadArchive.OpenCurrent();
|
using var payload = PayloadArchive.OpenCurrent();
|
||||||
var manifest = payload.ReadManifest();
|
var manifest = payload.ReadManifest();
|
||||||
var tool = Path.Combine(temp, "DolphinTool.exe");
|
var tool = Path.Combine(temp, "nodtool.exe");
|
||||||
payload.ExtractEntry(InstalledLayout.ToolkitEntryPrefix + "DolphinTool.exe", tool);
|
payload.ExtractEntry(InstalledLayout.ToolkitEntryPrefix + "nodtool.exe", tool);
|
||||||
payload.ExtractDirectory(InstalledLayout.ToolkitEntryPrefix + "Redist", temp);
|
payload.ExtractDirectory(InstalledLayout.ToolkitEntryPrefix + "Redist", temp);
|
||||||
reporter?.Progress(InstallStages.Validate, "Checking the Wii disc image...", 10);
|
reporter?.Progress(InstallStages.Validate, "Checking the Wii disc image...", 10);
|
||||||
var header = InputValidation.ReadDiscHeaderAsync(tool, command.GamePath!).GetAwaiter().GetResult();
|
var header = InputValidation.ReadDiscHeaderAsync(tool, command.GamePath!).GetAwaiter().GetResult();
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.Buffers.Binary;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using WiiCompiled.NodTool;
|
||||||
|
|
||||||
namespace WiiCompiled.Setup;
|
namespace WiiCompiled.Setup;
|
||||||
|
|
||||||
@@ -47,23 +48,37 @@ internal static class InputValidation
|
|||||||
"Select a complete Wii disc image in ISO, GCM, GCZ, CISO, WBFS, WIA, or RVZ format.");
|
"Select a complete Wii disc image in ISO, GCM, GCZ, CISO, WBFS, WIA, or RVZ format.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<DiscHeader> ReadDiscHeaderAsync(string dolphinTool, string gamePath,
|
public static async Task<DiscHeader> ReadDiscHeaderAsync(string nodTool, string gamePath,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
ValidateExtension(gamePath);
|
ValidateExtension(gamePath);
|
||||||
var result = await ProcessRunner.RunAsync(dolphinTool,
|
var result = await ProcessRunner.RunAsync(nodTool,
|
||||||
["header", "-i", Path.GetFullPath(gamePath), "-j"], null, cancellationToken);
|
["info", Path.GetFullPath(gamePath)], null, cancellationToken);
|
||||||
if (result.ExitCode != 0)
|
if (result.ExitCode != 0)
|
||||||
throw new InvalidDataException("DolphinTool could not read this disc image. " + result.CombinedOutput.Trim());
|
throw new InvalidDataException("nodtool could not read this disc image. " + result.CombinedOutput.Trim());
|
||||||
|
|
||||||
var json = result.StandardOutput.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries)
|
var info = NodToolInfoParser.Parse(result.StandardOutput);
|
||||||
.FirstOrDefault(line => line.TrimStart().StartsWith('{'));
|
return new DiscHeader
|
||||||
if (json is null)
|
{
|
||||||
throw new InvalidDataException("DolphinTool did not return disc metadata.");
|
GameId = info.GameId,
|
||||||
return JsonSerializer.Deserialize<DiscHeader>(json)
|
InternalName = info.Title,
|
||||||
?? throw new InvalidDataException("DolphinTool returned invalid disc metadata.");
|
Region = RegionFromGameId(info.GameId),
|
||||||
|
Revision = info.Revision,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string RegionFromGameId(string gameId) => gameId.Length >= 4
|
||||||
|
? gameId[3] switch
|
||||||
|
{
|
||||||
|
'P' => "PAL",
|
||||||
|
'E' => "NTSC-U",
|
||||||
|
'J' => "NTSC-J",
|
||||||
|
'K' => "Korea",
|
||||||
|
'W' => "Taiwan",
|
||||||
|
_ => gameId[3].ToString(),
|
||||||
|
}
|
||||||
|
: "Unknown";
|
||||||
|
|
||||||
public static void EnsureCompatibleDisc(DiscHeader header, PayloadManifest manifest)
|
public static void EnsureCompatibleDisc(DiscHeader header, PayloadManifest manifest)
|
||||||
{
|
{
|
||||||
if (!header.GameId.Equals(manifest.ExpectedGameId, StringComparison.OrdinalIgnoreCase))
|
if (!header.GameId.Equals(manifest.ExpectedGameId, StringComparison.OrdinalIgnoreCase))
|
||||||
|
|||||||
@@ -57,9 +57,9 @@ internal sealed class InstallerEngine
|
|||||||
|
|
||||||
var runtimeAssetsCurrent = sameToolkit && RuntimeAssetsAreCurrent(existing,
|
var runtimeAssetsCurrent = sameToolkit && RuntimeAssetsAreCurrent(existing,
|
||||||
candidateRuntimeAssetsFingerprint, cancellationToken);
|
candidateRuntimeAssetsFingerprint, cancellationToken);
|
||||||
var installedDolphinTool = Path.Combine(existing.ToolkitDirectory, "DolphinTool.exe");
|
var installedNodTool = Path.Combine(existing.ToolkitDirectory, "nodtool.exe");
|
||||||
var extractToolkit = MustRefreshToolkit(sameToolkit, samePackageContent,
|
var extractToolkit = MustRefreshToolkit(sameToolkit, samePackageContent,
|
||||||
File.Exists(installedDolphinTool));
|
File.Exists(installedNodTool));
|
||||||
var extractWorkspace = !sameToolkit || !runtimeAssetsCurrent;
|
var extractWorkspace = !sameToolkit || !runtimeAssetsCurrent;
|
||||||
|
|
||||||
_reporter.Progress(InstallStages.ExtractToolkit,
|
_reporter.Progress(InstallStages.ExtractToolkit,
|
||||||
@@ -77,9 +77,9 @@ internal sealed class InstallerEngine
|
|||||||
payload.ExtractEntry(InstalledLayout.PayloadManifestFileName,
|
payload.ExtractEntry(InstalledLayout.PayloadManifestFileName,
|
||||||
Path.Combine(staging, InstalledLayout.PayloadManifestFileName));
|
Path.Combine(staging, InstalledLayout.PayloadManifestFileName));
|
||||||
|
|
||||||
var dolphinTool = extractToolkit ? Path.Combine(toolkit, "DolphinTool.exe") : installedDolphinTool;
|
var nodTool = extractToolkit ? Path.Combine(toolkit, "nodtool.exe") : installedNodTool;
|
||||||
_reporter.Progress(InstallStages.Validate, "Checking the Wii disc image...", 2);
|
_reporter.Progress(InstallStages.Validate, "Checking the Wii disc image...", 2);
|
||||||
var header = await InputValidation.ReadDiscHeaderAsync(dolphinTool, options.GamePath,
|
var header = await InputValidation.ReadDiscHeaderAsync(nodTool, options.GamePath,
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
InputValidation.EnsureCompatibleDisc(header, manifest);
|
InputValidation.EnsureCompatibleDisc(header, manifest);
|
||||||
var canonicalRetroRoot = options.RetroDirectoryPath is null
|
var canonicalRetroRoot = options.RetroDirectoryPath is null
|
||||||
@@ -153,7 +153,7 @@ internal sealed class InstallerEngine
|
|||||||
|
|
||||||
if (reusableGameAssets is null)
|
if (reusableGameAssets is null)
|
||||||
{
|
{
|
||||||
await ExtractGameAssetsAsync(dolphinTool, options.GamePath,
|
await ExtractGameAssetsAsync(nodTool, options.GamePath,
|
||||||
Path.Combine(staging, "GameAssets"), manifest, cancellationToken);
|
Path.Combine(staging, "GameAssets"), manifest, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,8 +164,8 @@ internal sealed class InstallerEngine
|
|||||||
|
|
||||||
|
|
||||||
internal static bool MustRefreshToolkit(bool sameToolkit, bool samePackageContent,
|
internal static bool MustRefreshToolkit(bool sameToolkit, bool samePackageContent,
|
||||||
bool dolphinToolPresent) =>
|
bool nodToolPresent) =>
|
||||||
!sameToolkit || !samePackageContent || !dolphinToolPresent;
|
!sameToolkit || !samePackageContent || !nodToolPresent;
|
||||||
|
|
||||||
private static void AddComponent(List<InstallTransactionEntry> entries, string staging,
|
private static void AddComponent(List<InstallTransactionEntry> entries, string staging,
|
||||||
string installDirectory, string name) =>
|
string installDirectory, string name) =>
|
||||||
@@ -469,18 +469,23 @@ internal sealed class InstallerEngine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ExtractGameAssetsAsync(string dolphinTool, string gamePath, string destination,
|
private async Task ExtractGameAssetsAsync(string nodTool, string gamePath, string destination,
|
||||||
PayloadManifest manifest, CancellationToken cancellationToken)
|
PayloadManifest manifest, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
_reporter.Progress(InstallStages.ExtractDisc,
|
_reporter.Progress(InstallStages.ExtractDisc,
|
||||||
"Extracting the game disc. This is the longest preparation step...", 6);
|
"Extracting the game disc. This is the longest preparation step...", 6);
|
||||||
var extraction = await ProcessRunner.RunAsync(dolphinTool,
|
// Extracted straight into a "DATA" subfolder so the on-disk layout matches what
|
||||||
["extract", "-i", Path.GetFullPath(gamePath), "-o", destination, "-g", "-q"],
|
// Installation.GameDataDirectory and every other reader of it already expect - nodtool
|
||||||
|
// itself has no such wrapper (it extracts sys/+files/ directly to whatever <outdir> is
|
||||||
|
// given), so this is purely destination-side, not a nodtool convention.
|
||||||
|
var dataRoot = Path.Combine(destination, "DATA");
|
||||||
|
var extraction = await ProcessRunner.RunAsync(nodTool,
|
||||||
|
["extract", Path.GetFullPath(gamePath), dataRoot, "-q"],
|
||||||
line => { if (!string.IsNullOrWhiteSpace(line)) _reporter.Diagnostic(line); },
|
line => { if (!string.IsNullOrWhiteSpace(line)) _reporter.Diagnostic(line); },
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
if (extraction.ExitCode != 0)
|
if (extraction.ExitCode != 0)
|
||||||
throw new InvalidDataException("Game extraction failed. " + extraction.CombinedOutput.Trim());
|
throw new InvalidDataException("Game extraction failed. " + extraction.CombinedOutput.Trim());
|
||||||
ValidateExtractedGame(Path.Combine(destination, "DATA"), manifest);
|
ValidateExtractedGame(dataRoot, manifest);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ValidateExtractedGame(string dataRoot, PayloadManifest manifest)
|
private static void ValidateExtractedGame(string dataRoot, PayloadManifest manifest)
|
||||||
|
|||||||
@@ -143,17 +143,17 @@ internal static class SelfTests
|
|||||||
private static void TestToolkitRefreshDecision()
|
private static void TestToolkitRefreshDecision()
|
||||||
{
|
{
|
||||||
if (!InstallerEngine.MustRefreshToolkit(sameToolkit: false, samePackageContent: true,
|
if (!InstallerEngine.MustRefreshToolkit(sameToolkit: false, samePackageContent: true,
|
||||||
dolphinToolPresent: true))
|
nodToolPresent: true))
|
||||||
throw new Exception("A republished workspace kept the installed toolkit; the shipped " +
|
throw new Exception("A republished workspace kept the installed toolkit; the shipped " +
|
||||||
"translator and project file could come from different releases.");
|
"translator and project file could come from different releases.");
|
||||||
if (!InstallerEngine.MustRefreshToolkit(sameToolkit: true, samePackageContent: false,
|
if (!InstallerEngine.MustRefreshToolkit(sameToolkit: true, samePackageContent: false,
|
||||||
dolphinToolPresent: true))
|
nodToolPresent: true))
|
||||||
throw new Exception("Changed toolkit package content was not extracted.");
|
throw new Exception("Changed toolkit package content was not extracted.");
|
||||||
if (!InstallerEngine.MustRefreshToolkit(sameToolkit: true, samePackageContent: true,
|
if (!InstallerEngine.MustRefreshToolkit(sameToolkit: true, samePackageContent: true,
|
||||||
dolphinToolPresent: false))
|
nodToolPresent: false))
|
||||||
throw new Exception("A missing DolphinTool.exe did not force toolkit extraction.");
|
throw new Exception("A missing nodtool.exe did not force toolkit extraction.");
|
||||||
if (InstallerEngine.MustRefreshToolkit(sameToolkit: true, samePackageContent: true,
|
if (InstallerEngine.MustRefreshToolkit(sameToolkit: true, samePackageContent: true,
|
||||||
dolphinToolPresent: true))
|
nodToolPresent: true))
|
||||||
throw new Exception("An unchanged toolkit was needlessly re-extracted.");
|
throw new Exception("An unchanged toolkit was needlessly re-extracted.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1010,7 +1010,7 @@ internal static class SelfTests
|
|||||||
throw new Exception("The toolkit fingerprint is not stable.");
|
throw new Exception("The toolkit fingerprint is not stable.");
|
||||||
|
|
||||||
// A file that has nothing to do with generated code must not invalidate every install.
|
// A file that has nothing to do with generated code must not invalidate every install.
|
||||||
File.WriteAllText(Path.Combine(root, "Toolkit", "DolphinTool.exe"), "irrelevant");
|
File.WriteAllText(Path.Combine(root, "Toolkit", "nodtool.exe"), "irrelevant");
|
||||||
if (ToolkitFingerprint.Compute(root) != first)
|
if (ToolkitFingerprint.Compute(root) != first)
|
||||||
throw new Exception("An unrelated toolkit file changed the fingerprint.");
|
throw new Exception("An unrelated toolkit file changed the fingerprint.");
|
||||||
|
|
||||||
@@ -1177,7 +1177,7 @@ internal static class SelfTests
|
|||||||
"x86_64-w64-mingw32-clang++.exe", "x86_64-w64-mingw32-windres.exe"
|
"x86_64-w64-mingw32-clang++.exe", "x86_64-w64-mingw32-windres.exe"
|
||||||
})
|
})
|
||||||
File.WriteAllText(Path.Combine(root, "Toolkit", "llvm-mingw", "bin", executable), executable);
|
File.WriteAllText(Path.Combine(root, "Toolkit", "llvm-mingw", "bin", executable), executable);
|
||||||
File.WriteAllText(Path.Combine(root, "Toolkit", "DolphinTool.exe"), "tool");
|
File.WriteAllText(Path.Combine(root, "Toolkit", "nodtool.exe"), "tool");
|
||||||
File.WriteAllText(Path.Combine(root, "BuildWorkspace", "LocalBuild.ps1"), "# build");
|
File.WriteAllText(Path.Combine(root, "BuildWorkspace", "LocalBuild.ps1"), "# build");
|
||||||
File.WriteAllText(Path.Combine(root, "BuildWorkspace", "NativeBuildFlags.ps1"), "# flags");
|
File.WriteAllText(Path.Combine(root, "BuildWorkspace", "NativeBuildFlags.ps1"), "# flags");
|
||||||
File.WriteAllText(Path.Combine(root, "BuildWorkspace", "projects", "mkwii", "recomp.yml"), "profiles: {}");
|
File.WriteAllText(Path.Combine(root, "BuildWorkspace", "projects", "mkwii", "recomp.yml"), "profiles: {}");
|
||||||
|
|||||||
@@ -78,12 +78,12 @@ internal static class ToolkitFingerprint
|
|||||||
var workspace = InstalledLayout.Workspace(root);
|
var workspace = InstalledLayout.Workspace(root);
|
||||||
var entries = new SortedDictionary<string, string>(StringComparer.Ordinal);
|
var entries = new SortedDictionary<string, string>(StringComparer.Ordinal);
|
||||||
|
|
||||||
// DolphinTool validates/extracts the user disc but does not influence generated products.
|
// nodtool validates/extracts the user disc but does not influence generated products.
|
||||||
// Everything else in Toolkit can affect translation, compilation, linking, or copied
|
// Everything else in Toolkit can affect translation, compilation, linking, or copied
|
||||||
// runtime support and therefore belongs to the compile identity.
|
// runtime support and therefore belongs to the compile identity.
|
||||||
AddDirectory(entries, root, toolkit, null,
|
AddDirectory(entries, root, toolkit, null,
|
||||||
cancellationToken,
|
cancellationToken,
|
||||||
file => !Path.GetFileName(file).Equals("DolphinTool.exe", StringComparison.OrdinalIgnoreCase));
|
file => !Path.GetFileName(file).Equals("nodtool.exe", StringComparison.OrdinalIgnoreCase));
|
||||||
AddFile(entries, root, Path.Combine(workspace, "LocalBuild.ps1"), cancellationToken);
|
AddFile(entries, root, Path.Combine(workspace, "LocalBuild.ps1"), cancellationToken);
|
||||||
AddFile(entries, root, Path.Combine(workspace, "NativeBuildFlags.ps1"), cancellationToken);
|
AddFile(entries, root, Path.Combine(workspace, "NativeBuildFlags.ps1"), cancellationToken);
|
||||||
AddDirectory(entries, root, Path.Combine(workspace, "projects"), null, cancellationToken);
|
AddDirectory(entries, root, Path.Combine(workspace, "projects"), null, cancellationToken);
|
||||||
|
|||||||
@@ -14,4 +14,7 @@
|
|||||||
<DebugType>embedded</DebugType>
|
<DebugType>embedded</DebugType>
|
||||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\WiiCompiled.NodTool\WiiCompiled.NodTool.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Packages Launcher/WiiCompiled.Setup.Linux as a self-contained AppImage: a single file Wheel
|
# Packages Launcher/WiiCompiled.Setup.Linux as a self-contained AppImage: a single file Wheel
|
||||||
# Wizard (or anyone else) can fetch and execute with no git clone and no `dotnet` install at all -
|
# Wizard (or anyone else) can fetch and execute with no git clone, no `dotnet` install, and no
|
||||||
# both the installer and the translator are published as self-contained binaries and bundled, so
|
# `dolphin-tool` package required at all. The installer and translator are published as
|
||||||
# AppRun passes --translator-bin to skip local-build.sh's own dotnet-build-from-source step. It
|
# self-contained binaries, and `nodtool` (a prebuilt MIT/Apache-2.0 CLI from encounter/nod, see
|
||||||
# still shells out to system clang/cmake/ninja/dolphin-tool - no C/C++ toolchain is bundled,
|
# NodToolProvider.cs) is downloaded and bundled too - AppRun passes --translator-bin and
|
||||||
# matching Launcher/local-build.sh's own remaining prerequisites.
|
# --disc-tool-bin so local-build.sh/DiscTool.cs skip their from-source/download fallbacks entirely.
|
||||||
|
# It still shells out to system clang/cmake/ninja - no C/C++ toolchain is bundled, matching
|
||||||
|
# Launcher/local-build.sh's own remaining prerequisites.
|
||||||
#
|
#
|
||||||
# An AppImage mounts read-only, but local-build.sh writes generated/, native-build/, Assets/, etc.
|
# An AppImage mounts read-only, but local-build.sh writes generated/, native-build/, Assets/, etc.
|
||||||
# into the workspace it's given. So AppRun (written below) copies the bundled workspace snapshot
|
# into the workspace it's given. So AppRun (written below) copies the bundled workspace snapshot
|
||||||
@@ -59,6 +61,16 @@ dotnet publish "$workspace/translator/src/Translator.Cli" -c Release -r linux-x6
|
|||||||
cp "$translator_publish_tmp/Translator.Cli" "$appdir/usr/bin/translator-cli"
|
cp "$translator_publish_tmp/Translator.Cli" "$appdir/usr/bin/translator-cli"
|
||||||
chmod +x "$appdir/usr/bin/translator-cli"
|
chmod +x "$appdir/usr/bin/translator-cli"
|
||||||
|
|
||||||
|
# Resolved via the shared WiiCompiled.NodTool.Cli helper (also used by Build-Installer.ps1 on
|
||||||
|
# Windows) rather than a second curl/version-pin copy here: it downloads and caches the same way
|
||||||
|
# NodToolProvider.cs always does (Launcher/artifacts/nodtool), so there is exactly one place that
|
||||||
|
# knows the nodtool version/URL/platform-asset mapping.
|
||||||
|
echo "Resolving nodtool..."
|
||||||
|
nodtool_path=$(dotnet run --project "$workspace/Launcher/WiiCompiled.NodTool.Cli" -c Release -- \
|
||||||
|
--workspace "$workspace" | tail -n1)
|
||||||
|
cp "$nodtool_path" "$appdir/usr/bin/nodtool"
|
||||||
|
chmod +x "$appdir/usr/bin/nodtool"
|
||||||
|
|
||||||
echo "Staging the bundled workspace snapshot..."
|
echo "Staging the bundled workspace snapshot..."
|
||||||
for dir in runtime aurora-main projects; do
|
for dir in runtime aurora-main projects; do
|
||||||
cp -r "$workspace/$dir" "$appdir/workspace/$dir"
|
cp -r "$workspace/$dir" "$appdir/workspace/$dir"
|
||||||
@@ -94,7 +106,9 @@ if [ ! -f "$CACHE/.bundle-version" ] || \
|
|||||||
cp "$HERE/workspace/Launcher/local-build.sh" "$CACHE/Launcher/local-build.sh"
|
cp "$HERE/workspace/Launcher/local-build.sh" "$CACHE/Launcher/local-build.sh"
|
||||||
cp "$HERE/workspace/.bundle-version" "$CACHE/.bundle-version"
|
cp "$HERE/workspace/.bundle-version" "$CACHE/.bundle-version"
|
||||||
fi
|
fi
|
||||||
exec "$HERE/usr/bin/wiicompiled-setup" --workspace "$CACHE" --translator-bin "$HERE/usr/bin/translator-cli" "$@"
|
exec "$HERE/usr/bin/wiicompiled-setup" --workspace "$CACHE" \
|
||||||
|
--translator-bin "$HERE/usr/bin/translator-cli" \
|
||||||
|
--disc-tool-bin "$HERE/usr/bin/nodtool" "$@"
|
||||||
APPRUN
|
APPRUN
|
||||||
chmod +x "$appdir/AppRun"
|
chmod +x "$appdir/AppRun"
|
||||||
|
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ included in the installer's `licenses/` folder.
|
|||||||
| SQLite | 3.51.3 amalgamation | Public domain | <https://sqlite.org/> |
|
| SQLite | 3.51.3 amalgamation | Public domain | <https://sqlite.org/> |
|
||||||
| Tracy Profiler | pinned commit | BSD-3-Clause | <https://github.com/wolfpld/tracy> |
|
| Tracy Profiler | pinned commit | BSD-3-Clause | <https://github.com/wolfpld/tracy> |
|
||||||
| C++/WinRT | - | MIT (Microsoft) | <https://github.com/microsoft/cppwinrt> |
|
| C++/WinRT | - | MIT (Microsoft) | <https://github.com/microsoft/cppwinrt> |
|
||||||
|
| nodtool (disc image extraction) | v2.0.0-alpha.10 | MIT OR Apache-2.0 | <https://github.com/encounter/nod> |
|
||||||
|
|
||||||
### Dual-licensed components - elections made by this project
|
### Dual-licensed components - elections made by this project
|
||||||
|
|
||||||
@@ -164,16 +165,15 @@ unmodified, with their license texts, in the installer's `licenses/` folder.
|
|||||||
| llvm-mingw (Clang, LLD, libc++, libunwind, MinGW-w64 runtime) | Apache-2.0 with LLVM Exception; MinGW-w64 runtime under its own permissive terms; bundled GNU utilities under GPL-2.0-or-later or GPL-3.0-or-later | <https://github.com/mstorsjo/llvm-mingw> |
|
| llvm-mingw (Clang, LLD, libc++, libunwind, MinGW-w64 runtime) | Apache-2.0 with LLVM Exception; MinGW-w64 runtime under its own permissive terms; bundled GNU utilities under GPL-2.0-or-later or GPL-3.0-or-later | <https://github.com/mstorsjo/llvm-mingw> |
|
||||||
| CMake | BSD-3-Clause | <https://cmake.org/> |
|
| CMake | BSD-3-Clause | <https://cmake.org/> |
|
||||||
| Ninja | Apache-2.0 | <https://ninja-build.org/> |
|
| Ninja | Apache-2.0 | <https://ninja-build.org/> |
|
||||||
| DolphinTool (disc image extraction) | GPL-2.0-or-later | <https://github.com/dolphin-emu/dolphin> |
|
| nodtool (disc image extraction) | MIT OR Apache-2.0 | <https://github.com/encounter/nod> |
|
||||||
| Microsoft Visual C++ Runtime (`vcruntime140.dll`, `vcruntime140_1.dll`, `msvcp140.dll`) | Microsoft redistributable terms | Microsoft Visual Studio |
|
| Microsoft Visual C++ Runtime (`vcruntime140.dll`, `vcruntime140_1.dll`, `msvcp140.dll`) | Microsoft redistributable terms | Microsoft Visual Studio |
|
||||||
| `dxil.dll` | Microsoft redistributable (proprietary signing library) | Microsoft |
|
| `dxil.dll` | Microsoft redistributable (proprietary signing library) | Microsoft |
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> Several toolkit components are GPL-licensed (DolphinTool, and the GNU utilities inside
|
> The GNU utilities bundled inside llvm-mingw are GPL-licensed. Their complete corresponding source
|
||||||
> llvm-mingw). Their complete corresponding source is available from the upstream projects linked
|
> is available from the upstream project linked above at its pinned version, and this project will
|
||||||
> above at their pinned versions, and this project will supply it on request for the exact versions
|
> supply it on request for the exact version shipped in any given release. Pins live in
|
||||||
> shipped in any given release. Pins live in `Launcher/Prepare-PortableTools.ps1` and
|
> `Launcher/Prepare-PortableTools.ps1` and `Launcher/NativeBuildFlags.ps1`.
|
||||||
> `Launcher/NativeBuildFlags.ps1`.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user