A CLI tool to edit dinit service files with ease
at main 74 lines 2.8 kB view raw
1const std = @import("std"); 2 3const a = std.heap.smp_allocator; 4 5var service_dirs: std.ArrayListUnmanaged([:0]const u8) = .empty; 6 7var services: std.StringArrayHashMapUnmanaged([:0]const u8) = .empty; 8 9pub fn main() !void { 10 try load_definitions(); 11 12 if (std.os.argv.len == 1) try list_all(); 13 if (std.os.argv.len == 2) try edit(std.mem.span(std.os.argv[1])); 14} 15 16pub fn load_definitions() !void { 17 const uid = std.posix.system.getuid(); 18 19 if (uid == 0) { 20 var default_system = [_][:0]const u8{ "/etc/dinit.d", "/run/dinit.d", "/usr/local/lib/dinit.d", "/lib/dinit.d" }; 21 service_dirs = .fromOwnedSlice(&default_system); 22 } else { 23 service_dirs = try .initCapacity(a, 5); 24 if (std.posix.getenv("XDG_CONFIG_HOME")) |prefix| { 25 service_dirs.appendAssumeCapacity(try std.fmt.allocPrintZ(a, "{s}/dinit.d", .{prefix})); 26 } 27 if (std.posix.getenv("HOME")) |prefix| { 28 service_dirs.appendAssumeCapacity(try std.fmt.allocPrintZ(a, "{s}/.config/dinit.d", .{prefix})); 29 } 30 service_dirs.appendSliceAssumeCapacity(&.{ "/etc/dinit.d/user", "/usr/lib/dinit.d/user", "/usr/local/lib/dinit.d/user" }); 31 } 32 33 for (service_dirs.items) |dir_path| { 34 const dir = std.fs.openDirAbsoluteZ(dir_path, .{ .iterate = true }) catch |e| { 35 if (e == error.FileNotFound) continue; 36 return e; 37 }; 38 var iter = dir.iterate(); 39 while (try iter.next()) |entry| { 40 // std.log.info("{s}/{s}", .{ dir_path, entry.name }); 41 if (entry.kind == .file and !services.contains(entry.name)) { 42 try services.put(a, try a.dupe(u8, entry.name), try std.fmt.allocPrintZ(a, "{s}/{s}", .{ dir_path, entry.name })); 43 } 44 } 45 } 46} 47 48fn list_all() !void { 49 const stdout = std.io.getStdOut(); 50 var longest: usize = 0; 51 var iter = services.iterator(); 52 while (iter.next()) |entry| { 53 longest = @max(longest, entry.key_ptr.len); 54 } 55 const pad_buffer: [36]u8 = @splat(' '); 56 iter = services.iterator(); 57 while (iter.next()) |entry| { 58 const pad = pad_buffer[0 .. longest + 4 - entry.key_ptr.len]; 59 try stdout.writer().print("{s}{s}{s}\n", .{ entry.key_ptr.*, pad, entry.value_ptr.* }); 60 } 61} 62 63fn edit(service_name: []const u8) !void { 64 const editor = std.posix.getenvZ("EDITOR") orelse "/usr/bin/kak"; 65 var iter = services.iterator(); 66 while (iter.next()) |entry| { 67 if (std.mem.eql(u8, entry.key_ptr.*, service_name)) { 68 const command = try std.fmt.allocPrintZ(a, "{s} {s}", .{ editor, entry.value_ptr.* }); 69 return std.posix.execveZ("/bin/sh", &.{ "sh", "-c", command }, @ptrCast(std.os.environ)); 70 } 71 } 72 std.debug.print("Cannot find service file\n", .{}); 73 std.process.exit(1); 74}