os: more error handling on reading the app support dir

This commit is contained in:
Mitchell Hashimoto
2024-11-25 16:04:16 -08:00
parent 10e37a3dee
commit adc59be977
2 changed files with 49 additions and 31 deletions

View File

@ -1809,14 +1809,10 @@ pub fn deinit(self: *Config) void {
/// Load the configuration according to the default rules: /// Load the configuration according to the default rules:
/// ///
/// 1. Defaults /// 1. Defaults
/// 2. Configuration Files /// 2. XDG config dir
/// 3. CLI flags /// 3. "Application Support" directory (macOS only)
/// 4. Recursively defined configuration files /// 4. CLI flags
/// /// 5. Recursively defined configuration files
/// Configuration files are loaded in the follow order:
///
/// 1. XDG Config File
/// 2. "Application Support" Config File on macOS
/// ///
pub fn load(alloc_gpa: Allocator) !Config { pub fn load(alloc_gpa: Allocator) !Config {
var result = try default(alloc_gpa); var result = try default(alloc_gpa);
@ -2423,8 +2419,8 @@ pub fn loadDefaultFiles(self: *Config, alloc: Allocator) !void {
defer alloc.free(xdg_path); defer alloc.free(xdg_path);
self.loadOptionalFile(alloc, xdg_path); self.loadOptionalFile(alloc, xdg_path);
if (builtin.os.tag == .macos) { if (comptime builtin.os.tag == .macos) {
const app_support_path = try internal_os.macos.getAppSupportDir(alloc, "config"); const app_support_path = try internal_os.macos.appSupportDir(alloc, "config");
defer alloc.free(app_support_path); defer alloc.free(app_support_path);
self.loadOptionalFile(alloc, app_support_path); self.loadOptionalFile(alloc, app_support_path);
} }

View File

@ -4,15 +4,9 @@ const assert = std.debug.assert;
const objc = @import("objc"); const objc = @import("objc");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
pub const NSOperatingSystemVersion = extern struct {
major: i64,
minor: i64,
patch: i64,
};
/// Verifies that the running macOS system version is at least the given version. /// Verifies that the running macOS system version is at least the given version.
pub fn isAtLeastVersion(major: i64, minor: i64, patch: i64) bool { pub fn isAtLeastVersion(major: i64, minor: i64, patch: i64) bool {
assert(builtin.target.isDarwin()); comptime assert(builtin.target.isDarwin());
const NSProcessInfo = objc.getClass("NSProcessInfo").?; const NSProcessInfo = objc.getClass("NSProcessInfo").?;
const info = NSProcessInfo.msgSend(objc.Object, objc.sel("processInfo"), .{}); const info = NSProcessInfo.msgSend(objc.Object, objc.sel("processInfo"), .{});
@ -21,20 +15,24 @@ pub fn isAtLeastVersion(major: i64, minor: i64, patch: i64) bool {
}); });
} }
pub const NSSearchPathDirectory = enum(c_ulong) { pub const AppSupportDirError = Allocator.Error || error{AppleAPIFailed};
NSApplicationSupportDirectory = 14,
};
pub const NSSearchPathDomainMask = enum(c_ulong) { /// Return the path to the application support directory for Ghostty
NSUserDomainMask = 1, /// with the given sub path joined. This allocates the result using the
}; /// given allocator.
pub fn appSupportDir(
alloc: Allocator,
sub_path: []const u8,
) AppSupportDirError![]u8 {
comptime assert(builtin.target.isDarwin());
pub fn getAppSupportDir(alloc: Allocator, sub_path: []const u8) ![]u8 {
assert(builtin.target.isDarwin());
const err: ?*anyopaque = undefined;
const NSFileManager = objc.getClass("NSFileManager").?; const NSFileManager = objc.getClass("NSFileManager").?;
const manager = NSFileManager.msgSend(objc.Object, objc.sel("defaultManager"), .{}); const manager = NSFileManager.msgSend(
objc.Object,
objc.sel("defaultManager"),
.{},
);
const url = manager.msgSend( const url = manager.msgSend(
objc.Object, objc.Object,
objc.sel("URLForDirectory:inDomain:appropriateForURL:create:error:"), objc.sel("URLForDirectory:inDomain:appropriateForURL:create:error:"),
@ -43,12 +41,36 @@ pub fn getAppSupportDir(alloc: Allocator, sub_path: []const u8) ![]u8 {
NSSearchPathDomainMask.NSUserDomainMask, NSSearchPathDomainMask.NSUserDomainMask,
@as(?*anyopaque, null), @as(?*anyopaque, null),
true, true,
&err, @as(?*anyopaque, null),
}, },
); );
// I don't think this is possible but just in case.
if (url.value == null) return error.AppleAPIFailed;
// Get the UTF-8 string from the URL.
const path = url.getProperty(objc.Object, "path"); const path = url.getProperty(objc.Object, "path");
const c_str = path.getProperty([*:0]const u8, "UTF8String"); const c_str = path.getProperty(?[*:0]const u8, "UTF8String") orelse
return error.AppleAPIFailed;
const app_support_dir = std.mem.sliceTo(c_str, 0); const app_support_dir = std.mem.sliceTo(c_str, 0);
return try std.fs.path.join(alloc, &.{ app_support_dir, "com.mitchellh.ghostty", sub_path }); return try std.fs.path.join(alloc, &.{
app_support_dir,
"com.mitchellh.ghostty",
sub_path,
});
} }
pub const NSOperatingSystemVersion = extern struct {
major: i64,
minor: i64,
patch: i64,
};
pub const NSSearchPathDirectory = enum(c_ulong) {
NSApplicationSupportDirectory = 14,
};
pub const NSSearchPathDomainMask = enum(c_ulong) {
NSUserDomainMask = 1,
};