Finding and formatting all .zon files in a build.zig b.addFmt() step

I’m starting to use the new Zig 0.14.0 release and I have a certain amount of constant data that works really well being factored out into separate .zon files for each table. Almost everything is working great with that!

The one thing I haven’t got yet is a build step to format all the .zon files at once. (Nothing wrong with fmt-on-save in an editor, nothing wrong with individual ‘zig fmt myfile.zon’ calls, that’s just not what I’m looking for.)

I’ve got a “zig build fmt” build step that uses b.addFmt() to scan directories and format zig files. I specify a parent directory and it finds all the .zig files. I see that I can add each individual .zon file in the .paths, but can I set it up to find all my .zon files without naming each one?

1 Like

The std.Build can get you access to the build_root which is a Directory struct. That has access to the actual fs.Dir which can let you walk the directory: Zig Documentation

So one option is to do something like the following:

const dir = b.build_root.handle;
var walker = try dir.walk(b.allocator);
while (try walker.next()) |file| {
    if (file.kind != .file) continue;
    // Check if file.basename ends in `.zon`
    // Then add it for your addFmt call
}
4 Likes

I hoped there would be a more declarative way but since it seems like there isn’t, that was exactly what I needed!

For anyone else that needs it, I used this and then passed fmt_paths.items into b.addFmt():

(edited after I found out my Windows build didn’t work until I reopened the dir with .iterate true)

    var walkable_dir: std.fs.Dir = switch (builtin.os.tag) {
        .windows => try b.build_root.handle.openDir(".", .{ .iterate = true }),
        else => b.build_root.handle,
    };
    var fmt_paths: std.ArrayListUnmanaged([]const u8) = .{};
    try fmt_paths.append(b.allocator, ".");
    var walker = try walkable_dir.walk(b.allocator);
    while (try walker.next()) |file| {
        if (file.kind != .file) continue;
        if (std.mem.endsWith(u8, file.basename, ".zon")) {
            const dup = b.dupe(file.path);
            try fmt_paths.append(b.allocator, dup);
        }
    }
2 Likes

Have you verified this alone isn’t enough? zig fmt . will format all .zig and .zon files recursively.

$ zig fmt .
./dir/recur.zon
./test.zon

Here’s what the zig build fmt step looks like for the main Zig repository FWIW:

6 Likes

I tested it before I asked. If you are saying you have verified it, then maybe something else was wrong with my test. Are you saying you have verified that arbitrary .zon files are formatted?

Oh, I see it. Need sleep. But I see it. I’ll look tomorrow for interesting differences in my example.

Step.Fmt ultimately just spawns a zig fmt process, so it works the same:

const std = @import("std");

pub fn build(b: *std.Build) void {
    const do_fmt = b.addFmt(.{
        .paths = &.{"."},
    });
    b.step("fmt", "run zig fmt").dependOn(&do_fmt.step);
}
$ cat test.zon
.{.abc,}

$ cat dir/recur.zon
.{

}

$ zig build fmt
Build Summary: 2/2 steps succeeded
fmt success
└─ zig fmt success

$ cat test.zon
.{
    .abc,
}

$ cat dir/recur.zon
.{}
3 Likes

Sorry! Forgive me for being unclear in my first response and ensuing quick edit. I was half-asleep and should have waited 'til I wasn’t. Here’s what I wanted to say, with less confusion:

Yes, I now see that your message (the first one) clearly shows that “zig fmt .” formats arbitrary .zon files in subfolders.

Yes, I did verify it before I posted the question, but I saw a different result than you did. (And I wasn’t sure if it was supposed to work like that, I didn’t recall reading anything about it.)

Now that I know that it should have just worked, I will go retest it and see if I can reproduce it. I will report back.

I retested, I was wrong, this was never an issue.

At least I can revert to the simpler code with the &.{“.”} that I started with. (And I’ll probably never know exactly how I fooled myself to begin with. Something-something-editor buffer out of sync, or I was just ‘holding it wrong’.)

Thank you for making it clear, squeek502!

1 Like