utils.zig
1 const std = @import("std"); 2 const fs = std.fs; 3 const mem = std.mem; 4 const os = std.os; 5 6 const RED = "\x1b[38;2;246;96;96m"; 7 const YELLOW = "\x1b[38;2;255;237;129m"; 8 const GREEN = "\x1b[38;2;179;255;114m"; 9 const BLUE = "\x1b[38;2;86;164;255m"; 10 const GRAY = "\x1b[38;2;57;62;65m"; 11 const DEFAULT = "\x1b[0m"; 12 const MAX_KEY_LEN = 50; 13 const whitespaces = [_]u8{ ' ', '\t' }; 14 15 fn baseLogger(comptime color: []const u8, comptime label: []const u8, comptime fmt: []const u8, args: anytype) !void { 16 const timestamp: u64 = @truncate(@abs(std.time.timestamp())); 17 var stdout = std.io.getStdOut(); 18 19 try std.fmt.format(stdout.writer(), "{s}[{any}:{any}:{any}]{s} {s}{s}{s} \t-- " ++ fmt ++ "\n", .{ 20 GRAY, 21 @as(u5, @truncate((timestamp / 3600) % 24)), 22 @as(u6, @truncate((timestamp / 60) % 60)), 23 @as(u6, @truncate(timestamp % 60)), 24 DEFAULT, 25 color, 26 label, 27 DEFAULT, 28 } ++ args); 29 } 30 31 pub fn info(comptime fmt: []const u8, args: anytype) !void { 32 try baseLogger(BLUE, "INFO", fmt, args); 33 } 34 35 pub fn warn(comptime fmt: []const u8, args: anytype) !void { 36 try baseLogger(YELLOW, "WARN", fmt, args); 37 } 38 39 pub fn err(comptime fmt: []const u8, args: anytype) !void { 40 try baseLogger(RED, "ERROR", fmt, args); 41 } 42 43 pub fn success(comptime fmt: []const u8, args: anytype) !void { 44 try baseLogger(GREEN, "SUCESS", fmt, args); 45 } 46 47 pub fn parseKVPair(reader: anytype, key: []const u8, buffer: []u8, delimiter: u8) !?[]const u8 { 48 var valuebuffer_stream = std.io.fixedBufferStream(buffer); 49 const value_writer = valuebuffer_stream.writer(); 50 51 var keybuffer: [MAX_KEY_LEN]u8 = undefined; 52 var keybuffer_stream = std.io.fixedBufferStream(&keybuffer); 53 var key_writer = keybuffer_stream.writer(); 54 55 while (reader.readByte()) |byte| { 56 if (byte == '\t') continue; 57 if (byte == delimiter) { 58 if (mem.eql(u8, key, keybuffer_stream.getWritten())) { 59 // Note : We could write our own implementation of streamUntilDelimiter to account for whitespaces, 60 // trimming the spaces in one go 61 reader.streamUntilDelimiter(value_writer, '\n', buffer.len) catch |e| { 62 err("parseKVPair : {s}", .{@errorName(e)}) catch {}; 63 break; 64 }; 65 return mem.trim(u8, valuebuffer_stream.getWritten(), " "); 66 } 67 keybuffer_stream.reset(); 68 try reader.skipUntilDelimiterOrEof('\n'); 69 continue; 70 } 71 72 try key_writer.writeByte(byte); 73 } else |e| { 74 err("Key not found: {s} ({s})", .{ key, @errorName(e) }) catch {}; 75 76 return null; 77 } 78 unreachable; 79 } 80 81 pub fn parseKVPairOpenFile(path: []const u8, key: []const u8, buffer: []u8, delimiter: u8) !?[]const u8 { 82 var file_descriptor = try fs.openFileAbsolute(path, .{ .intended_io_mode = .blocking }); 83 defer file_descriptor.close(); 84 85 return parseKVPair(file_descriptor.reader(), key, buffer, delimiter); 86 } 87 88 pub fn getenv(name: []const u8, buffer: []u8) ?[]const u8 { 89 var file_descriptor = std.fs.cwd().openFile(".env", .{}) catch |e| { 90 switch (e) { 91 error.FileNotFound => { 92 warn("Unable to find .env in current working directory, resorting to environment variable !", .{}) catch {}; 93 }, 94 error.AccessDenied => { 95 warn("Missing read permission for .env file, resorting to environment variable !", .{}) catch {}; 96 }, 97 else => {}, 98 } 99 return os.getenv(name); 100 }; 101 defer file_descriptor.close(); 102 return parseKVPair(file_descriptor.reader(), name, buffer, '=') catch null; 103 }