mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-19 02:06:20 +03:00

Related to #7879 This commit updates `zig build test` to run Xcode tests, too. These run in parallel to the Zig tests, so they don't add any time to the test. The Xcode tests will _not_ run when: (1) the target is not macOS, or (2) the `-Dtest-filter` option is non-empty. This makes it so that this change doesn't affect non-macOS and doesn't affect the general dev cycle because you usually will run `-Dtest-filter` when developing a core feature. I didn't add a step to only run Xcode tests because I find that when I'm working in Xcode I'm probably going to run the tests from there anyways. The integration with `zig build test` is just a convenience, especially around CI. Speaking of CI, this change also makes it so this will run in CI.
202 lines
6.0 KiB
Zig
202 lines
6.0 KiB
Zig
const Ghostty = @This();
|
|
|
|
const std = @import("std");
|
|
const builtin = @import("builtin");
|
|
const RunStep = std.Build.Step.Run;
|
|
const Config = @import("Config.zig");
|
|
const Docs = @import("GhosttyDocs.zig");
|
|
const I18n = @import("GhosttyI18n.zig");
|
|
const Resources = @import("GhosttyResources.zig");
|
|
const XCFramework = @import("GhosttyXCFramework.zig");
|
|
|
|
build: *std.Build.Step.Run,
|
|
open: *std.Build.Step.Run,
|
|
copy: *std.Build.Step.Run,
|
|
xctest: *std.Build.Step.Run,
|
|
|
|
pub const Deps = struct {
|
|
xcframework: *const XCFramework,
|
|
docs: *const Docs,
|
|
i18n: *const I18n,
|
|
resources: *const Resources,
|
|
};
|
|
|
|
pub fn init(
|
|
b: *std.Build,
|
|
config: *const Config,
|
|
deps: Deps,
|
|
) !Ghostty {
|
|
const xc_config = switch (config.optimize) {
|
|
.Debug => "Debug",
|
|
.ReleaseSafe,
|
|
.ReleaseSmall,
|
|
.ReleaseFast,
|
|
=> "Release",
|
|
};
|
|
|
|
const xc_arch: ?[]const u8 = switch (deps.xcframework.target) {
|
|
// Universal is our default target, so we don't have to
|
|
// add anything.
|
|
.universal => null,
|
|
|
|
// Native we need to override the architecture in the Xcode
|
|
// project with the -arch flag.
|
|
.native => switch (builtin.cpu.arch) {
|
|
.aarch64 => "arm64",
|
|
.x86_64 => "x86_64",
|
|
else => @panic("unsupported macOS arch"),
|
|
},
|
|
};
|
|
|
|
const env = try std.process.getEnvMap(b.allocator);
|
|
const app_path = b.fmt("macos/build/{s}/Ghostty.app", .{xc_config});
|
|
|
|
// Our step to build the Ghostty macOS app.
|
|
const build = build: {
|
|
// External environment variables can mess up xcodebuild, so
|
|
// we create a new empty environment.
|
|
const env_map = try b.allocator.create(std.process.EnvMap);
|
|
env_map.* = .init(b.allocator);
|
|
if (env.get("PATH")) |v| try env_map.put("PATH", v);
|
|
|
|
const step = RunStep.create(b, "xcodebuild");
|
|
step.has_side_effects = true;
|
|
step.cwd = b.path("macos");
|
|
step.env_map = env_map;
|
|
step.addArgs(&.{
|
|
"xcodebuild",
|
|
"-target",
|
|
"Ghostty",
|
|
"-configuration",
|
|
xc_config,
|
|
});
|
|
|
|
// If we have a specific architecture, we need to pass it
|
|
// to xcodebuild.
|
|
if (xc_arch) |arch| step.addArgs(&.{ "-arch", arch });
|
|
|
|
// We need the xcframework
|
|
deps.xcframework.addStepDependencies(&step.step);
|
|
|
|
// We also need all these resources because the xcode project
|
|
// references them via symlinks.
|
|
deps.resources.addStepDependencies(&step.step);
|
|
deps.i18n.addStepDependencies(&step.step);
|
|
deps.docs.installDummy(&step.step);
|
|
|
|
// Expect success
|
|
step.expectExitCode(0);
|
|
|
|
break :build step;
|
|
};
|
|
|
|
const xctest = xctest: {
|
|
const env_map = try b.allocator.create(std.process.EnvMap);
|
|
env_map.* = .init(b.allocator);
|
|
if (env.get("PATH")) |v| try env_map.put("PATH", v);
|
|
|
|
const step = RunStep.create(b, "xcodebuild test");
|
|
step.has_side_effects = true;
|
|
step.cwd = b.path("macos");
|
|
step.env_map = env_map;
|
|
step.addArgs(&.{
|
|
"xcodebuild",
|
|
"test",
|
|
"-scheme",
|
|
"Ghostty",
|
|
});
|
|
if (xc_arch) |arch| step.addArgs(&.{ "-arch", arch });
|
|
|
|
// We need the xcframework
|
|
deps.xcframework.addStepDependencies(&step.step);
|
|
|
|
// We also need all these resources because the xcode project
|
|
// references them via symlinks.
|
|
deps.resources.addStepDependencies(&step.step);
|
|
deps.i18n.addStepDependencies(&step.step);
|
|
deps.docs.installDummy(&step.step);
|
|
|
|
// Expect success
|
|
step.expectExitCode(0);
|
|
|
|
break :xctest step;
|
|
};
|
|
|
|
// Our step to open the resulting Ghostty app.
|
|
const open = open: {
|
|
const disable_save_state = RunStep.create(b, "disable save state");
|
|
disable_save_state.has_side_effects = true;
|
|
disable_save_state.addArgs(&.{
|
|
"/usr/libexec/PlistBuddy",
|
|
"-c",
|
|
// We'll have to change this to `Set` if we ever put this
|
|
// into our Info.plist.
|
|
"Add :NSQuitAlwaysKeepsWindows bool false",
|
|
b.fmt("{s}/Contents/Info.plist", .{app_path}),
|
|
});
|
|
disable_save_state.expectExitCode(0);
|
|
disable_save_state.step.dependOn(&build.step);
|
|
|
|
const open = RunStep.create(b, "run Ghostty app");
|
|
open.has_side_effects = true;
|
|
open.cwd = b.path("");
|
|
open.addArgs(&.{b.fmt(
|
|
"{s}/Contents/MacOS/ghostty",
|
|
.{app_path},
|
|
)});
|
|
|
|
// Open depends on the app
|
|
open.step.dependOn(&build.step);
|
|
open.step.dependOn(&disable_save_state.step);
|
|
|
|
// This overrides our default behavior and forces logs to show
|
|
// up on stderr (in addition to the centralized macOS log).
|
|
open.setEnvironmentVariable("GHOSTTY_LOG", "1");
|
|
|
|
// Configure how we're launching
|
|
open.setEnvironmentVariable("GHOSTTY_MAC_LAUNCH_SOURCE", "zig_run");
|
|
|
|
if (b.args) |args| {
|
|
open.addArgs(args);
|
|
}
|
|
|
|
break :open open;
|
|
};
|
|
|
|
// Our step to copy the app bundle to the install path.
|
|
// We have to use `cp -R` because there are symlinks in the
|
|
// bundle.
|
|
const copy = copy: {
|
|
const step = RunStep.create(b, "copy app bundle");
|
|
step.addArgs(&.{ "cp", "-R" });
|
|
step.addFileArg(b.path(app_path));
|
|
step.addArg(b.fmt("{s}", .{b.install_path}));
|
|
step.step.dependOn(&build.step);
|
|
break :copy step;
|
|
};
|
|
|
|
return .{
|
|
.build = build,
|
|
.open = open,
|
|
.copy = copy,
|
|
.xctest = xctest,
|
|
};
|
|
}
|
|
|
|
pub fn install(self: *const Ghostty) void {
|
|
const b = self.copy.step.owner;
|
|
b.getInstallStep().dependOn(&self.copy.step);
|
|
}
|
|
|
|
pub fn installXcframework(self: *const Ghostty) void {
|
|
const b = self.build.step.owner;
|
|
b.getInstallStep().dependOn(&self.build.step);
|
|
}
|
|
|
|
pub fn addTestStepDependencies(
|
|
self: *const Ghostty,
|
|
other_step: *std.Build.Step,
|
|
) void {
|
|
other_step.dependOn(&self.xctest.step);
|
|
}
|