config.zig refactorings
This commit is contained in:
parent
f936531721
commit
25a7d06d40
1 changed files with 33 additions and 31 deletions
|
|
@ -1,5 +1,7 @@
|
|||
const std = @import("std");
|
||||
|
||||
const EnvMap = std.StringHashMap([]const u8);
|
||||
|
||||
pub const Config = struct {
|
||||
twelvedata_key: ?[]const u8 = null,
|
||||
polygon_key: ?[]const u8 = null,
|
||||
|
|
@ -8,7 +10,10 @@ pub const Config = struct {
|
|||
openfigi_key: ?[]const u8 = null,
|
||||
cache_dir: []const u8,
|
||||
allocator: ?std.mem.Allocator = null,
|
||||
/// Raw .env file contents (keys/values in env_map point into this).
|
||||
env_buf: ?[]const u8 = null,
|
||||
/// Parsed KEY=VALUE pairs from .env file.
|
||||
env_map: ?EnvMap = null,
|
||||
|
||||
pub fn fromEnv(allocator: std.mem.Allocator) Config {
|
||||
var self = Config{
|
||||
|
|
@ -16,8 +21,11 @@ pub const Config = struct {
|
|||
.allocator = allocator,
|
||||
};
|
||||
|
||||
// Try loading .env file from the project directory or home directory
|
||||
self.env_buf = loadEnvFile(allocator);
|
||||
// Try loading .env file from the current working directory
|
||||
self.env_buf = std.fs.cwd().readFileAlloc(allocator, ".env", 4096) catch null;
|
||||
if (self.env_buf) |buf| {
|
||||
self.env_map = parseEnvFile(allocator, buf);
|
||||
}
|
||||
|
||||
self.twelvedata_key = self.resolve("TWELVEDATA_API_KEY");
|
||||
self.polygon_key = self.resolve("POLYGON_API_KEY");
|
||||
|
|
@ -27,8 +35,14 @@ pub const Config = struct {
|
|||
|
||||
const env_cache = self.resolve("ZFIN_CACHE_DIR");
|
||||
self.cache_dir = env_cache orelse blk: {
|
||||
// XDG Base Directory: $XDG_CACHE_HOME/zfin, falling back to $HOME/.cache/zfin
|
||||
const base = std.posix.getenv("XDG_CACHE_HOME") orelse fallback: {
|
||||
const home = std.posix.getenv("HOME") orelse "/tmp";
|
||||
break :blk std.fs.path.join(allocator, &.{ home, ".cache", "zfin" }) catch @panic("OOM");
|
||||
break :fallback std.fs.path.join(allocator, &.{ home, ".cache" }) catch @panic("OOM");
|
||||
};
|
||||
const base_allocated = std.posix.getenv("XDG_CACHE_HOME") == null;
|
||||
defer if (base_allocated) allocator.free(base);
|
||||
break :blk std.fs.path.join(allocator, &.{ base, "zfin" }) catch @panic("OOM");
|
||||
};
|
||||
|
||||
return self;
|
||||
|
|
@ -36,8 +50,13 @@ pub const Config = struct {
|
|||
|
||||
pub fn deinit(self: *Config) void {
|
||||
if (self.allocator) |a| {
|
||||
// Check if cache_dir was allocated (not from env/envfile) BEFORE freeing env_buf
|
||||
// cache_dir is allocated (via path.join) unless ZFIN_CACHE_DIR was set directly.
|
||||
// Check BEFORE freeing env_map/env_buf, since resolve() reads from them.
|
||||
const cache_dir_from_env = self.resolve("ZFIN_CACHE_DIR") != null;
|
||||
if (self.env_map) |*m| {
|
||||
var map = m.*;
|
||||
map.deinit();
|
||||
}
|
||||
if (self.env_buf) |buf| a.free(buf);
|
||||
if (!cache_dir_from_env) {
|
||||
a.free(self.cache_dir);
|
||||
|
|
@ -55,41 +74,24 @@ pub const Config = struct {
|
|||
/// Look up a key: environment variable first, then .env file fallback.
|
||||
fn resolve(self: Config, key: []const u8) ?[]const u8 {
|
||||
if (std.posix.getenv(key)) |v| return v;
|
||||
return envFileGet(self.env_buf, key);
|
||||
if (self.env_map) |m| return m.get(key);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/// Parse a KEY=VALUE line from .env content. Returns value for the given key.
|
||||
fn envFileGet(buf: ?[]const u8, key: []const u8) ?[]const u8 {
|
||||
const data = buf orelse return null;
|
||||
/// Parse all KEY=VALUE pairs from .env content into a HashMap.
|
||||
/// Values are slices into the original buffer (no extra allocations per entry).
|
||||
fn parseEnvFile(allocator: std.mem.Allocator, data: []const u8) ?EnvMap {
|
||||
var map = EnvMap.init(allocator);
|
||||
var iter = std.mem.splitScalar(u8, data, '\n');
|
||||
while (iter.next()) |line| {
|
||||
const trimmed = std.mem.trim(u8, line, &std.ascii.whitespace);
|
||||
if (trimmed.len == 0 or trimmed[0] == '#') continue;
|
||||
if (std.mem.indexOfScalar(u8, trimmed, '=')) |eq| {
|
||||
const k = std.mem.trim(u8, trimmed[0..eq], &std.ascii.whitespace);
|
||||
if (std.mem.eql(u8, k, key)) {
|
||||
return std.mem.trim(u8, trimmed[eq + 1 ..], &std.ascii.whitespace);
|
||||
const v = std.mem.trim(u8, trimmed[eq + 1 ..], &std.ascii.whitespace);
|
||||
map.put(k, v) catch return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Try to load .env from the executable's directory, then cwd.
|
||||
fn loadEnvFile(allocator: std.mem.Allocator) ?[]const u8 {
|
||||
// Try relative to the executable
|
||||
const exe_dir = std.fs.selfExeDirPathAlloc(allocator) catch null;
|
||||
defer if (exe_dir) |d| allocator.free(d);
|
||||
|
||||
if (exe_dir) |dir| {
|
||||
const path = std.fs.path.join(allocator, &.{ dir, "..", ".env" }) catch null;
|
||||
defer if (path) |p| allocator.free(p);
|
||||
if (path) |p| {
|
||||
if (std.fs.cwd().readFileAlloc(allocator, p, 4096)) |data| return data else |_| {}
|
||||
}
|
||||
}
|
||||
|
||||
// Try cwd
|
||||
return std.fs.cwd().readFileAlloc(allocator, ".env", 4096) catch null;
|
||||
return map;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue