aboutsummaryrefslogtreecommitdiff
path: root/converter/src/main.zig
blob: edaf51f56102d106354b80eac63d625e8a54d020 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
const std = @import("std");
const ziggy = @import("ziggy");

const Page = struct {
    title: ?[]const u8 = null,
    author: ?[]const u8 = null,
    date: ?[]const u8 = null,
    layout: ?[]const u8 = null,
    // draft: ?bool = null,
    // params: ?struct {
    //     comments: bool,
    // } = null,
};

pub fn main() !void {
    const a = std.heap.page_allocator;
    var args = std.process.args();
    if (!args.skip()) @panic("errors kipping program name?");
    const contentdirname = args.next() orelse return error.NoDir;
    const contentdir = try std.fs.cwd().openDir(contentdirname, .{ .iterate = true });
    var walker = try contentdir.walk(a);
    while (try walker.next()) |we| {
        if (std.mem.endsWith(u8, we.basename, ".md")) {
            std.log.info("converting file {s}", .{we.basename});
            const file = try we.dir.readFileAlloc(a, we.basename, 1_000_000);
            const start = (std.mem.indexOf(u8, file, "---\n") orelse return error.NoFrontmatter) + 4;
            const end = (std.mem.lastIndexOf(u8, file, "---\n") orelse return error.NoFrontMatter);

            var childproc = std.process.Child.init(&.{ "yq", "-o", "json" }, a);
            childproc.stdin_behavior = .Pipe;
            childproc.stdout_behavior = .Pipe;
            childproc.stderr_behavior = .Pipe;
            std.log.info("spawn", .{});
            try childproc.spawn();
            std.log.info("writeAll", .{});
            try childproc.stdin.?.writeAll(file[start..end]);
            childproc.stdin.?.close();
            childproc.stdin = null;

            var stdout = std.ArrayList(u8).init(a);
            var stderr = std.ArrayList(u8).init(a);
            std.log.info("collectOutput", .{});
            try childproc.collectOutput(&stdout, &stderr, 1_000_000);
            std.log.info("got output {s}", .{stdout.items});
            std.log.info("wait", .{});
            const term = try childproc.wait();
            if (term.Exited != 0) {
                return error.ProcessError;
            }
            const fm_json = try stdout.toOwnedSlice();
            // Now parse it and add missing fields
            const fm_json_parsed_value = try std.json.parseFromSlice(Page, a, fm_json, .{
                .ignore_unknown_fields = true,
            });
            defer fm_json_parsed_value.deinit();
            var fm_json_parsed = fm_json_parsed_value.value;
            fm_json_parsed.title = fm_json_parsed.title orelse "";
            fm_json_parsed.author = fm_json_parsed.author orelse "Martin Ashby";
            fm_json_parsed.date = fm_json_parsed.date orelse "1900-01-01T00:00:00Z";
            fm_json_parsed.layout = fm_json_parsed.layout orelse "single.html";

            var out = std.ArrayList(u8).init(a);
            defer out.deinit();
            try ziggy.stringify(fm_json_parsed, .{.whitespace = .space_2}, out.writer());
            const newfile = try std.mem.concat(a, u8, &.{ "---\n", out.items, "\n", file[end..] });
            try we.dir.writeFile(we.basename, newfile);
        }
    }
    std.log.info("done!", .{});
}