𝒉𝒂𝒏𝒅𝒍𝒊𝒏𝒈 𝒆𝒏𝒗𝒊𝒓𝒐𝒏𝒎𝒆𝒏𝒕 𝒗𝒂𝒓𝒊𝒂𝒃𝒍𝒆𝒔 𝒊𝒏 𝒂 𝒕𝒚𝒑𝒆-𝒔𝒂𝒇𝒆 𝒘𝒂𝒚.
NOTE: Minimum Supported Zig Version is 0.12.0-dev.2058+04ac028a2
struct-env
provides a way to handle environment variables using struct fields.
Its advantage is the automatic deserialization of environment variables into the specified types.
For example, instead of using std.mem.eql(u8, foo, "true")
to determine the truth value of an env-var,
struct-env
allows us to simply use foo: bool
to deserialize it into a boolean type.
Below is a basic example:
const std = @import("std");
const struct_env = @import("struct-env");
const MyEnv = struct {
home: []const u8,
foo: ?[]const u8,
bar: []const u8 = "bar",
};
pub fn main() !void {
const allocator = std.heap.page_allocator;
const env = try struct_env.fromEnv(allocator, MyEnv);
defer struct_env.free(allocator, env);
std.debug.print("HOME is {s}\n", .{env.home});
std.debug.print("FOO is {any}\n", .{env.foo == null});
std.debug.print("BAR is {s}\n", .{env.bar});
}
Here are some examples of this program's output.
You can find more examples in the examples
directory.
$ zig run [file]
HOME is /home/username
FOO is true
BAR is bar
$ FOO="foo" BAR="bar" zig run [file]
HOME is /home/username
FOO is false
BAR is bar
struct-env
assumes that there is an environment variable corresponding to each struct field, with the same name in all uppercase letters.
For instance, a struct field foo_bar
would be expected to have an environment variable named FOO_BAR
.
Structs with fields of type Optional(?
prefix) can be successfully deserialized even if their associated environment variable is not present.
Of course, if the variable does not exist, you can set a default value.
struct-env
also supports deserializing slice from comma separated env var values.
The common pattern for prefixeing env var names for a specific app is supported using the fromPrefixedEnv
.
Asumming your env vars are prefixed with APP_
, the example may look like
const MyEnv = struct {
// APP_NAME
name : []const u8,
};
const env = try struct_env.fromPrefixedEnv(allocator, MyEnv, "APP_");
defer struct_env.free(allocator, env);
- Built-in types, such as
[]const u8
,i32
- Optional types, such as
?u32
- Slice types, such as
[][]const u8
Add struct-env
as dependency in build.zig.zon
:
.{
.name = "my-project",
.version = "0.1.0",
.dependencies = .{
.struct_env= .{
.url = "https://github.com/Hanaasagi/struct-env/archive/refs/tags/v0.2.0.tar.gz",
.hash = "1220224c50ca0178c6061fb96721fc331ed1136641ebb8a86cff55cc74481d66a4b9",
},
},
}
Expose struct-env
as a module in build.zig
:
diff --git a/build.zig b/build.zig
index 60fb4c2..0255ef3 100644
--- a/build.zig
+++ b/build.zig
@@ -15,6 +15,9 @@ pub fn build(b: *std.Build) void {
// set a preferred release mode, allowing the user to decide how to optimize.
const optimize = b.standardOptimizeOption(.{});
+ const opts = .{ .target = target, .optimize = optimize };
+ const struct_env_module = b.dependency("struct_env", opts).module("struct-env");
+
const exe = b.addExecutable(.{
.name = "m",
// In this case the main source file is merely a path, however, in more
@@ -23,6 +26,7 @@ pub fn build(b: *std.Build) void {
.target = target,
.optimize = optimize,
});
+ exe.addModule("struct-env", struct_env_module);
// This declares intent for the executable to be installed into the
// standard location when the user invokes the "install" step (the default
MIT
Thanks to those who have helped me on Reddit and Stack Overflow.