mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
crash: add directory listing, allocation free
This commit is contained in:
66
src/crash/dir.zig
Normal file
66
src/crash/dir.zig
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const internal_os = @import("../os/main.zig");
|
||||||
|
|
||||||
|
/// Returns a Dir for the default directory. The Dir.path field must be
|
||||||
|
/// freed with the given allocator.
|
||||||
|
pub fn defaultDir(alloc: Allocator) !Dir {
|
||||||
|
const crash_dir = try internal_os.xdg.state(alloc, .{ .subdir = "ghostty/crash" });
|
||||||
|
errdefer alloc.free(crash_dir);
|
||||||
|
return .{ .path = crash_dir };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const Dir = struct {
|
||||||
|
/// The directory where crash reports are stored. This memory is owned
|
||||||
|
/// by the caller.
|
||||||
|
path: []const u8,
|
||||||
|
|
||||||
|
/// Returns an iterator over the crash reports in this directory. This
|
||||||
|
/// iterator must be freed with `ReportIterator.deinit`. The iterator
|
||||||
|
/// may have no reports.
|
||||||
|
pub fn iterator(self: *const Dir) !ReportIterator {
|
||||||
|
var dir = std.fs.openDirAbsolute(
|
||||||
|
self.path,
|
||||||
|
.{ .iterate = true },
|
||||||
|
) catch return .{};
|
||||||
|
errdefer dir.close();
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.dir = dir,
|
||||||
|
.it = dir.iterate(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ReportIterator = struct {
|
||||||
|
dir: ?std.fs.Dir = null,
|
||||||
|
it: std.fs.Dir.Iterator = undefined,
|
||||||
|
|
||||||
|
pub fn deinit(self: *ReportIterator) void {
|
||||||
|
if (self.dir) |dir| dir.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next(self: *ReportIterator) !?Report {
|
||||||
|
// If we have no dir then we failed to open the directory.
|
||||||
|
const dir = self.dir orelse return null;
|
||||||
|
|
||||||
|
// Get the next file entry, if any.
|
||||||
|
const entry = entry: while (true) {
|
||||||
|
const entry = try self.it.next() orelse return null;
|
||||||
|
if (entry.kind != .file) continue;
|
||||||
|
break :entry entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
const stat = try dir.statFile(entry.name);
|
||||||
|
return .{
|
||||||
|
.name = entry.name,
|
||||||
|
.mtime = stat.mtime,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Report = struct {
|
||||||
|
name: []const u8,
|
||||||
|
mtime: i128,
|
||||||
|
};
|
@ -2,10 +2,15 @@
|
|||||||
//! whether that's setting up the system to catch crashes (Sentry client),
|
//! whether that's setting up the system to catch crashes (Sentry client),
|
||||||
//! introspecting crash reports, writing crash reports to disk, etc.
|
//! introspecting crash reports, writing crash reports to disk, etc.
|
||||||
|
|
||||||
|
const dir = @import("dir.zig");
|
||||||
const sentry_envelope = @import("sentry_envelope.zig");
|
const sentry_envelope = @import("sentry_envelope.zig");
|
||||||
|
|
||||||
pub const sentry = @import("sentry.zig");
|
pub const sentry = @import("sentry.zig");
|
||||||
pub const Envelope = sentry_envelope.Envelope;
|
pub const Envelope = sentry_envelope.Envelope;
|
||||||
|
pub const defaultDir = dir.defaultDir;
|
||||||
|
pub const Dir = dir.Dir;
|
||||||
|
pub const ReportIterator = dir.ReportIterator;
|
||||||
|
pub const Report = dir.Report;
|
||||||
|
|
||||||
// The main init/deinit functions for global state.
|
// The main init/deinit functions for global state.
|
||||||
pub const init = sentry.init;
|
pub const init = sentry.init;
|
||||||
|
@ -253,12 +253,12 @@ pub const Transport = struct {
|
|||||||
|
|
||||||
// Get our XDG state directory where we'll store the crash reports.
|
// Get our XDG state directory where we'll store the crash reports.
|
||||||
// This directory must exist for writing to work.
|
// This directory must exist for writing to work.
|
||||||
const crash_dir = try internal_os.xdg.state(alloc, .{ .subdir = "ghostty/crash" });
|
const dir = try crash.defaultDir(alloc);
|
||||||
try std.fs.cwd().makePath(crash_dir);
|
try std.fs.cwd().makePath(dir.path);
|
||||||
|
|
||||||
// Build our final path and write to it.
|
// Build our final path and write to it.
|
||||||
const path = try std.fs.path.join(alloc, &.{
|
const path = try std.fs.path.join(alloc, &.{
|
||||||
crash_dir,
|
dir.path,
|
||||||
try std.fmt.allocPrint(alloc, "{s}.ghosttycrash", .{uuid.string()}),
|
try std.fmt.allocPrint(alloc, "{s}.ghosttycrash", .{uuid.string()}),
|
||||||
});
|
});
|
||||||
const file = try std.fs.cwd().createFile(path, .{});
|
const file = try std.fs.cwd().createFile(path, .{});
|
||||||
@ -277,45 +277,3 @@ pub const Transport = struct {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const CrashReport = struct {
|
|
||||||
name: []const u8,
|
|
||||||
mtime: i128,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn listCrashReports(alloc: std.mem.Allocator) !?[]CrashReport {
|
|
||||||
const crash_dir = try internal_os.xdg.state(alloc, .{ .subdir = "ghostty/crash" });
|
|
||||||
defer alloc.free(crash_dir);
|
|
||||||
|
|
||||||
var dir = std.fs.openDirAbsolute(crash_dir, .{ .iterate = true }) catch return null;
|
|
||||||
|
|
||||||
defer dir.close();
|
|
||||||
|
|
||||||
var list = std.ArrayList(CrashReport).init(alloc);
|
|
||||||
errdefer {
|
|
||||||
for (list.items) |item| {
|
|
||||||
alloc.free(item.name);
|
|
||||||
}
|
|
||||||
list.deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
var it = dir.iterate();
|
|
||||||
while (try it.next()) |entry| {
|
|
||||||
switch (entry.kind) {
|
|
||||||
.file => {
|
|
||||||
if (std.mem.endsWith(u8, entry.name, ".ghosttycrash")) {
|
|
||||||
const stat = dir.statFile(entry.name) catch continue;
|
|
||||||
try list.append(.{
|
|
||||||
.name = try alloc.dupe(u8, entry.name),
|
|
||||||
.mtime = stat.mtime,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (list.items.len == 0) return null;
|
|
||||||
|
|
||||||
return try list.toOwnedSlice();
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user