const std = @import("std"); const assert = std.debug.assert; const fs = @import("fs.zig"); const Env = @import("env.zig"); pub const Tree = struct { name: []const u8, root: fs.Path, pub fn port_path(self: Tree, port_name: []const u8) fs.Path { return .join(.{ self.root.name(), port_name }); } }; pub const Iterator = struct { root: fs.Path, dir: ?std.fs.Dir = null, iter: ?std.fs.Dir.Iterator = null, pub fn deinit(self: *Iterator) void { if (self.dir) |*dir| dir.close(); } pub fn next(self: *Iterator) !?Tree { if (self.iter) |*iter| { while (try iter.next()) |entry| { if (entry.kind == .directory) { return .{ .name = entry.name, .root = .join(.{ self.root.name(), entry.name }), }; } } } return null; } }; pub inline fn iterate(env: Env) !Iterator { const root = tree_root_dir(env); const dir = std.fs.openDirAbsoluteZ(root.name(), .{ .iterate = true }) catch |err| { if (err == error.FileNotFound) return .{ .root = undefined }; return err; }; return .{ .root = root, .dir = dir, .iter = dir.iterate(), }; } pub fn get(env: Env, tree_name: []const u8) !?Tree { var tree_root = tree_root_dir(env); tree_root.append(.{tree_name}); return .{ .name = tree_name, .root = tree_root }; } pub fn remove(env: Env, tree: Tree) !void { try fs.rm(tree.root); fs.rm(env.ports_tree_path(tree.name, .{})) catch {}; fs.rm(env.ports_src_path(tree.name, .{})) catch {}; } fn tree_root_dir(env: Env) fs.Path { return env.etc_path(.{"ports"}); }