master
 1const Directory = @This();
 2const std = @import("../../std.zig");
 3const assert = std.debug.assert;
 4const fs = std.fs;
 5const fmt = std.fmt;
 6const Allocator = std.mem.Allocator;
 7
 8/// This field is redundant for operations that can act on the open directory handle
 9/// directly, but it is needed when passing the directory to a child process.
10/// `null` means cwd.
11path: ?[]const u8,
12handle: fs.Dir,
13
14pub fn clone(d: Directory, arena: Allocator) Allocator.Error!Directory {
15    return .{
16        .path = if (d.path) |p| try arena.dupe(u8, p) else null,
17        .handle = d.handle,
18    };
19}
20
21pub fn cwd() Directory {
22    return .{
23        .path = null,
24        .handle = fs.cwd(),
25    };
26}
27
28pub fn join(self: Directory, allocator: Allocator, paths: []const []const u8) ![]u8 {
29    if (self.path) |p| {
30        // TODO clean way to do this with only 1 allocation
31        const part2 = try fs.path.join(allocator, paths);
32        defer allocator.free(part2);
33        return fs.path.join(allocator, &[_][]const u8{ p, part2 });
34    } else {
35        return fs.path.join(allocator, paths);
36    }
37}
38
39pub fn joinZ(self: Directory, allocator: Allocator, paths: []const []const u8) ![:0]u8 {
40    if (self.path) |p| {
41        // TODO clean way to do this with only 1 allocation
42        const part2 = try fs.path.join(allocator, paths);
43        defer allocator.free(part2);
44        return fs.path.joinZ(allocator, &[_][]const u8{ p, part2 });
45    } else {
46        return fs.path.joinZ(allocator, paths);
47    }
48}
49
50/// Whether or not the handle should be closed, or the path should be freed
51/// is determined by usage, however this function is provided for convenience
52/// if it happens to be what the caller needs.
53pub fn closeAndFree(self: *Directory, gpa: Allocator) void {
54    self.handle.close();
55    if (self.path) |p| gpa.free(p);
56    self.* = undefined;
57}
58
59pub fn format(self: Directory, writer: *std.Io.Writer) std.Io.Writer.Error!void {
60    if (self.path) |p| {
61        try writer.writeAll(p);
62        try writer.writeAll(fs.path.sep_str);
63    }
64}
65
66pub fn eql(self: Directory, other: Directory) bool {
67    return self.handle.fd == other.handle.fd;
68}