Skip to content

Commit

Permalink
feat: Add Windows on ARM support
Browse files Browse the repository at this point in the history
  • Loading branch information
stranne committed Aug 14, 2024
1 parent d416ada commit 4d01aa2
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 4 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,6 @@ GodotEnv.sln.DotSettings.user

# File-based project format
*.iws

### Visual Studio ###
.vs/
29 changes: 29 additions & 0 deletions GodotEnv.Tests/src/common/clients/FileClientTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public TestJsonModel(string name) {
[Fact]
public void InitializesLinux() {
FileClient.IsOSPlatform = (platform) => platform == OSPlatform.Linux;
FileClient.ProcessorArchitecture = Architecture.X64;
var fs = GetFs('/');
var computer = new Mock<IComputer>();
var client = new FileClient(fs.Object, computer.Object, new Mock<IProcessRunner>().Object);
Expand All @@ -50,12 +51,15 @@ public void InitializesLinux() {
client.OSFamily.ShouldBe(OSFamily.Unix);
client.Separator.ShouldBe('/');
client.OS.ShouldBe(OSType.Linux);
client.Processor.ShouldBe(ProcessorType.other);
FileClient.IsOSPlatform = FileClient.IsOSPlatformDefault;
FileClient.ProcessorArchitecture = FileClient.ProcessorArchitectureDefault;
}

[Fact]
public void InitializesMacOS() {
FileClient.IsOSPlatform = (platform) => platform == OSPlatform.OSX;
FileClient.ProcessorArchitecture = Architecture.X64;
var fs = GetFs('/');
var computer = new Mock<IComputer>();
var client = new FileClient(
Expand All @@ -66,7 +70,9 @@ public void InitializesMacOS() {
client.OSFamily.ShouldBe(OSFamily.Unix);
client.Separator.ShouldBe('/');
client.OS.ShouldBe(OSType.MacOS);
client.Processor.ShouldBe(ProcessorType.other);
FileClient.IsOSPlatform = FileClient.IsOSPlatformDefault;
FileClient.ProcessorArchitecture = FileClient.ProcessorArchitectureDefault;
}

[Fact]
Expand All @@ -82,19 +88,42 @@ public void InitializesWindows() {
client.OSFamily.ShouldBe(OSFamily.Windows);
client.Separator.ShouldBe('\\');
client.OS.ShouldBe(OSType.Windows);
client.Processor.ShouldBe(ProcessorType.arm64);
FileClient.IsOSPlatform = FileClient.IsOSPlatformDefault;
}

[Fact]
public void InitializesWindowsArm() {
FileClient.IsOSPlatform = (platform) => platform == OSPlatform.Windows;
FileClient.ProcessorArchitecture = Architecture.Arm64;
var fs = GetFs('\\');
var computer = new Mock<IComputer>();
var client = new FileClient(
fs.Object, computer.Object, new Mock<IProcessRunner>().Object
);
client.ShouldBeAssignableTo<IFileClient>();
client.Files.ShouldBe(fs.Object);
client.OSFamily.ShouldBe(OSFamily.Windows);
client.Separator.ShouldBe('\\');
client.OS.ShouldBe(OSType.Windows);
client.Processor.ShouldBe(ProcessorType.arm64);
FileClient.IsOSPlatform = FileClient.IsOSPlatformDefault;
FileClient.ProcessorArchitecture = FileClient.ProcessorArchitectureDefault;
}

[Fact]
public void InitializesUnknownOS() {
FileClient.IsOSPlatform = (platform) => false;
FileClient.ProcessorArchitecture = Architecture.X64;
var fs = GetFs('\\');
var computer = new Mock<IComputer>();
var client = new FileClient(
fs.Object, computer.Object, new Mock<IProcessRunner>().Object
);
client.OS.ShouldBe(OSType.Unknown);
client.Processor.ShouldBe(ProcessorType.other);
FileClient.IsOSPlatform = FileClient.IsOSPlatformDefault;
FileClient.ProcessorArchitecture = FileClient.ProcessorArchitectureDefault;
}

[Fact]
Expand Down
31 changes: 31 additions & 0 deletions GodotEnv.Tests/src/features/godot/models/GodotEnvironmentTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace Chickensoft.GodotEnv.Tests.features.godot.models;

using Chickensoft.GodotEnv.Common.Models;
using Chickensoft.GodotEnv.Features.Godot.Models;
using Common.Clients;
using Common.Utilities;
Expand Down Expand Up @@ -37,6 +38,8 @@ public void GetsExpectedMacMonoDownloadUrl() {

[Fact]
public void GetsExpectedWindowsDownloadUrl() {
fileClient.Setup(f => f.Processor).Returns(ProcessorType.other);

var platform = new Windows(fileClient.Object, computer.Object);

var downloadUrl = platform.GetDownloadUrl(version4, false, false);
Expand All @@ -48,6 +51,8 @@ public void GetsExpectedWindowsDownloadUrl() {

[Fact]
public void GetsExpectedWindowsMonoDownloadUrl() {
fileClient.Setup(f => f.Processor).Returns(ProcessorType.other);

var platform = new Windows(fileClient.Object, computer.Object);

var downloadUrl = platform.GetDownloadUrl(version4, true, false);
Expand All @@ -57,6 +62,32 @@ public void GetsExpectedWindowsMonoDownloadUrl() {
downloadUrl.ShouldBe(GetExpectedDownloadUrl(version3, "stable_mono_win64"));
}

[Fact]
public void GetsExpectedWindowsArmDownloadUrl() {
fileClient.Setup(f => f.Processor).Returns(ProcessorType.arm64);

var platform = new Windows(fileClient.Object, computer.Object);

var downloadUrl = platform.GetDownloadUrl(version4, false, false);
downloadUrl.ShouldBe($"{GodotEnvironment.GODOT_URL_PREFIX}4.1.2-stable/Godot_v4.1.2-stable_windows_arm64.exe.zip");

downloadUrl = platform.GetDownloadUrl(version3, false, false);
downloadUrl.ShouldBe($"{GodotEnvironment.GODOT_URL_PREFIX}{version3.VersionString}-stable/Godot_v{version3.VersionString}-stable_windows_arm64.exe.zip");
}

[Fact]
public void GetsExpectedWindowsArmMonoDownloadUrl() {
fileClient.Setup(f => f.Processor).Returns(ProcessorType.arm64);

var platform = new Windows(fileClient.Object, computer.Object);

var downloadUrl = platform.GetDownloadUrl(version4, true, false);
downloadUrl.ShouldBe(GetExpectedDownloadUrl(version4, "stable_mono_windows_arm64"));

downloadUrl = platform.GetDownloadUrl(version3, true, false);
downloadUrl.ShouldBe(GetExpectedDownloadUrl(version3, "stable_mono_windows_arm64"));
}

[Fact]
public void GetsExpectedLinuxDownloadUrl() {
var platform = new Linux(fileClient.Object, computer.Object);
Expand Down
13 changes: 13 additions & 0 deletions GodotEnv/src/common/clients/FileClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ public interface IFileClient {
/// <summary>The operating system type.</summary>
OSType OS { get; }

/// <summary>The process architecture type.</summary>
ProcessorType Processor { get; }

/// <summary>Path directory separator.</summary>
char Separator { get; }

Expand Down Expand Up @@ -309,6 +312,7 @@ public class FileClient : IFileClient {
public IProcessRunner ProcessRunner { get; }
public OSFamily OSFamily { get; }
public OSType OS { get; }
public ProcessorType Processor { get; }
public char Separator { get; }

// Shims for testing.
Expand All @@ -319,6 +323,12 @@ public class FileClient : IFileClient {
public static Func<OSPlatform, bool> IsOSPlatform { get; set; } =
IsOSPlatformDefault;

public static Architecture ProcessorArchitectureDefault { get; } =
RuntimeInformation.ProcessArchitecture;

public static Architecture ProcessorArchitecture { get; set; } =
ProcessorArchitectureDefault;

public string UserDirectory => Path.TrimEndingDirectorySeparator(
Environment.GetFolderPath(
Environment.SpecialFolder.UserProfile,
Expand Down Expand Up @@ -353,6 +363,9 @@ public FileClient(
: IsOSPlatform(OSPlatform.Windows)
? OSType.Windows
: OSType.Unknown;
Processor = ProcessorArchitecture == Architecture.Arm64
? ProcessorType.arm64
: ProcessorType.other;
}

public string Sanitize(string path) =>
Expand Down
11 changes: 11 additions & 0 deletions GodotEnv/src/common/models/ProcessorType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Chickensoft.GodotEnv.Common.Models;

/// <summary>
/// Processor architecture type.
/// </summary>
public enum ProcessorType {
/// <summary>arm64.</summary>
arm64,
/// <summary>Other.</summary>
other,
}
14 changes: 10 additions & 4 deletions GodotEnv/src/features/godot/models/Windows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,25 @@ namespace Chickensoft.GodotEnv.Features.Godot.Models;
using System.IO.Abstractions;
using System.Threading.Tasks;
using Chickensoft.GodotEnv.Common.Clients;
using Chickensoft.GodotEnv.Common.Models;
using Chickensoft.GodotEnv.Common.Utilities;

public class Windows : GodotEnvironment {
public Windows(IFileClient fileClient, IComputer computer)
: base(fileClient, computer) { }

private string ProcessorArchitecture =>
FileClient.Processor == ProcessorType.arm64
? "windows_arm64"
: "win64";

public override string ExportTemplatesBasePath =>
FileClient.GetFullPath(
FileClient.Combine(FileClient.UserDirectory, "\\AppData\\Roaming\\Godot")
);

public override string GetInstallerNameSuffix(bool isDotnetVersion, SemanticVersion version) =>
isDotnetVersion ? "_mono_win64" : "_win64.exe";
isDotnetVersion ? $"_mono_{ProcessorArchitecture}" : $"_{ProcessorArchitecture}.exe";

public override Task<bool> IsExecutable(IShell shell, IFileInfo file) =>
Task.FromResult(file.Name.ToLower().EndsWith(".exe"));
Expand All @@ -27,13 +33,13 @@ public override string GetRelativeExtractedExecutablePath(
) {
var fsVersionString = GetFilenameVersionString(version);
var name = fsVersionString +
$"{(isDotnetVersion ? "_mono" : "")}_win64.exe";
$"{(isDotnetVersion ? "_mono" : "")}_{ProcessorArchitecture}.exe";

// Both versions extract to a folder. The dotnet folder name is different
// from the non-dotnet folder name :P

if (isDotnetVersion) {
return FileClient.Combine(fsVersionString + "_mono_win64", name);
return FileClient.Combine(fsVersionString + $"_mono_{ProcessorArchitecture}", name);
}

// There is no subfolder for non-dotnet versions.
Expand All @@ -44,6 +50,6 @@ public override string GetRelativeGodotSharpPath(
SemanticVersion version,
bool isDotnetVersion
) => FileClient.Combine(
GetFilenameVersionString(version) + "_mono_win64", "GodotSharp"
GetFilenameVersionString(version) + $"_mono_{ProcessorArchitecture}", "GodotSharp"
);
}

0 comments on commit 4d01aa2

Please sign in to comment.