Make Ghostty release channel aware

Ghostty now has a release channel build configuration. Current valid
values are "tip" and "stable" but I imagine more will be added in the
future.

The release channel is inferred whether the version we specify with the
`-Dversion-string` build flag has a prerelease tag or not. If it does,
the release channel is "tip". If it doesn't, the release channel is
"stable".

This also adds a configuration to specify the release channel for
auto-updates for the macOS application.
This commit is contained in:
Mitchell Hashimoto
2024-12-20 13:52:15 -08:00
parent 0abd4ea8a2
commit 8f15f1a066
8 changed files with 89 additions and 9 deletions

View File

@ -139,7 +139,11 @@ jobs:
# GhosttyKit is the framework that is built from Zig for our native
# Mac app to access. Build this in release mode.
- name: Build GhosttyKit
run: nix develop -c zig build -Doptimize=ReleaseFast
run: |
nix develop -c \
zig build \
-Doptimize=ReleaseFast \
-Dversion-string=${GHOSTTY_VERSION}
# The native app is built with native XCode tooling. This also does
# codesigning. IMPORTANT: this must NOT run in a Nix environment.

View File

@ -52,8 +52,8 @@ channel = et.find("channel")
# the same version, Sparkle will report invalid signatures if it picks
# the wrong one when updating.
for item in channel.findall("item"):
version = item.find("sparkle:version", namespaces)
if version is not None and version.text == build:
sparkle_version = item.find("sparkle:version", namespaces)
if sparkle_version is not None and sparkle_version.text == build:
channel.remove(item)
# We also remove any item that doesn't have a pubDate. This should

View File

@ -3,11 +3,17 @@ import Cocoa
class UpdaterDelegate: NSObject, SPUUpdaterDelegate {
func feedURLString(for updater: SPUUpdater) -> String? {
// Eventually w want to support multiple channels. Sparkle itself supports
// channels but we probably don't want some appcasts in the same file (i.e.
// tip) so this would be the place to change that. For now, we hardcode the
// tip appcast URL since it is all we support.
return "https://tip.files.ghostty.org/appcast.xml"
guard let appDelegate = NSApplication.shared.delegate as? AppDelegate else {
return nil
}
// Sparkle supports a native concept of "channels" but it requires that
// you share a single appcast file. We don't want to do that so we
// do this instead.
switch (appDelegate.ghostty.config.autoUpdateChannel) {
case .tip: return "https://tip.files.ghostty.org/appcast.xml"
case .stable: return "https://release.files.ghostty.org/appcast.xml"
}
}
func updaterWillRelaunchApplication(_ updater: SPUUpdater) {

View File

@ -408,6 +408,17 @@ extension Ghostty {
return AutoUpdate(rawValue: str) ?? defaultValue
}
var autoUpdateChannel: AutoUpdateChannel {
let defaultValue = AutoUpdateChannel.stable
guard let config = self.config else { return defaultValue }
var v: UnsafePointer<Int8>? = nil
let key = "auto-update-channel"
guard ghostty_config_get(config, &v, key, UInt(key.count)) else { return defaultValue }
guard let ptr = v else { return defaultValue }
let str = String(cString: ptr)
return AutoUpdateChannel(rawValue: str) ?? defaultValue
}
var autoSecureInput: Bool {
guard let config = self.config else { return true }
var v = false;

View File

@ -200,7 +200,12 @@ extension Ghostty {
case visible
case hidden
}
/// Enum for auto-update-channel config option
enum AutoUpdateChannel: String {
case tip
case stable
}
}
// MARK: Surface Notification

View File

@ -58,6 +58,15 @@ pub const BuildConfig = struct {
"{}",
.{self.version},
));
step.addOption(
ReleaseChannel,
"release_channel",
channel: {
const pre = self.version.pre orelse break :channel .stable;
if (pre.len == 0) break :channel .stable;
break :channel .tip;
},
);
}
/// Rehydrate our BuildConfig from the comptime options. Note that not all
@ -82,6 +91,9 @@ pub const BuildConfig = struct {
pub const version = options.app_version;
pub const version_string = options.app_version_string;
/// The release channel for this build.
pub const release_channel = std.meta.stringToEnum(ReleaseChannel, @tagName(options.release_channel)).?;
/// The optimization mode as a string.
pub const mode_string = mode: {
const m = @tagName(builtin.mode);
@ -180,3 +192,12 @@ pub const ExeEntrypoint = enum {
bench_grapheme_break,
bench_page_init,
};
/// The release channel for the build.
pub const ReleaseChannel = enum {
/// Unstable builds on every commit.
tip,
/// Stable tagged releases.
stable,
};

View File

@ -25,6 +25,10 @@ pub fn run(alloc: Allocator) !u8 {
try stdout.print("Ghostty {s}\n\n", .{build_config.version_string});
if (tty) try stdout.print("\x1b]8;;\x1b\\", .{});
try stdout.print("Version\n", .{});
try stdout.print(" - version: {s}\n", .{build_config.version_string});
try stdout.print(" - channel: {s}\n", .{@tagName(build_config.release_channel)});
try stdout.print("Build Config\n", .{});
try stdout.print(" - Zig version: {s}\n", .{builtin.zig_version_string});
try stdout.print(" - build mode : {}\n", .{builtin.mode});

View File

@ -12,6 +12,7 @@ const Config = @This();
const std = @import("std");
const builtin = @import("builtin");
const build_config = @import("../build_config.zig");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator;
@ -1843,6 +1844,28 @@ term: []const u8 = "xterm-ghostty",
/// Changing this value at runtime works after a small delay.
@"auto-update": AutoUpdate = .check,
/// The release channel to use for auto-updates.
///
/// The default value of this matches the release channel of the currently
/// running Ghostty version. If you download a pre-release version of Ghostty
/// then this will be set to `tip` and you will receive pre-release updates.
/// If you download a stable version of Ghostty then this will be set to
/// `stable` and you will receive stable updates.
///
/// Valid values are:
///
/// * `stable` - Stable, tagged releases such as "1.0.0".
/// * `tip` - Pre-release versions generated from each commit to the
/// main branch. This is the version that was in use during private
/// beta testing by thousands of people. It is generally stable but
/// will likely have more bugs than the stable channel.
///
/// Changing this configuration requires a full restart of
/// Ghostty to take effect.
///
/// This only works on macOS since only macOS has an auto-update feature.
@"auto-update-channel": ?build_config.ReleaseChannel = null,
/// This is set by the CLI parser for deinit.
_arena: ?ArenaAllocator = null,
@ -3055,6 +3078,12 @@ pub fn finalize(self: *Config) !void {
);
}
}
// We can't set this as a struct default because our config is
// loaded in environments where a build config isn't available.
if (self.@"auto-update-channel" == null) {
self.@"auto-update-channel" = build_config.release_channel;
}
}
/// Callback for src/cli/args.zig to allow us to handle special cases