Makko, the people-oriented static site generator made for blogging. forge.starlightnet.work/Team/Makko
ssg static-site-generator makko starlight-network
at main 5.9 kB view raw
1const std = @import("std"); 2 3const builtin = @import("builtin"); 4 5const helper = @import("helper.zig"); 6const Data = @import("Data.zig"); 7const Parsed = @import("Parsed.zig"); 8const Log = @import("Log.zig"); 9 10pub const Status = enum(c_int) { 11 unchanged = 0, 12 created, 13 deleted, 14 modified, 15}; 16 17pub const Change = struct { 18 status: Status, // never .unchanged 19 id: Data.Id, 20 21 source: ?[]const u8 = null, 22 output: ?[]const u8 = null, 23 24 title: ?[]const u8 = null, 25 description: ?[]const u8 = null, 26 author: ?[]const u8 = null, 27 28 timestamp: i64, 29 30 pub fn copy(self: Change, allocator: std.mem.Allocator) !Change { 31 return Change{ 32 .status = self.status, 33 .id = self.id, 34 35 .source = if (self.source) |src| 36 try allocator.dupe(u8, src) 37 else 38 null, 39 40 .output = if (self.output) |output| 41 try allocator.dupe(u8, output) 42 else 43 null, 44 45 .title = if (self.title) |title| 46 try allocator.dupe(u8, title) 47 else 48 null, 49 50 .description = if (self.description) |description| 51 try allocator.dupe(u8, description) 52 else 53 null, 54 55 .author = if (self.author) |author| 56 try allocator.dupe(u8, author) 57 else 58 null, 59 60 .timestamp = self.timestamp, 61 }; 62 } 63 64 pub fn deinit(self: Change, allocator: std.mem.Allocator) void { 65 if (self.source) |src| allocator.free(src); 66 if (self.output) |output| allocator.free(output); 67 if (self.title) |title| allocator.free(title); 68 if (self.description) |description| allocator.free(description); 69 if (self.author) |author| allocator.free(author); 70 } 71}; 72 73on_change: ?[]const u8 = null, 74on_create: ?[]const u8 = null, 75on_delete: ?[]const u8 = null, 76on_modify: ?[]const u8 = null, 77 78const Callbacks = @This(); 79 80fn callSystemProgram( 81 program: []const u8, 82 stdin_input: []const u8, 83 cwd: std.fs.Dir, 84 allocator: std.mem.Allocator, 85) !void { 86 var args = std.ArrayList([]const u8).init(allocator); 87 defer args.deinit(); 88 89 if (builtin.os.tag == .windows) { 90 try args.append("cmd.exe"); 91 try args.append("/C"); 92 } else { 93 try args.append("/bin/sh"); 94 try args.append("-c"); 95 } 96 try args.append(program); 97 98 var child = std.process.Child.init(args.items, allocator); 99 100 child.cwd_dir = cwd; 101 102 child.stdin_behavior = .Pipe; 103 child.stdout_behavior = .Ignore; 104 child.stderr_behavior = .Inherit; 105 106 var env_map = std.process.EnvMap.init(allocator); 107 defer env_map.deinit(); 108 109 try env_map.put("FROM_MAKKO", "YES"); 110 111 child.env_map = &env_map; 112 113 try child.spawn(); 114 115 if (child.stdin) |stdin| { 116 _ = try stdin.writeAll(stdin_input); 117 stdin.close(); 118 child.stdin = null; 119 } 120 121 _ = try child.wait(); 122} 123 124fn lessThan(context: void, a: Change, b: Change) bool { 125 _ = context; 126 return @intFromEnum(a.status) < @intFromEnum(b.status); 127} 128 129pub fn run( 130 callbacks: Callbacks, 131 changes: []Change, 132 cwd: std.fs.Dir, 133 log: Log, 134 allocator: std.mem.Allocator, 135) !void { 136 if (changes.len == 0) 137 return; 138 139 //std.sort.block(Change, changes, {}, lessThan); 140 141 var created_changes = std.ArrayList(Change).init(allocator); 142 var deleted_changes = std.ArrayList(Change).init(allocator); 143 var modified_changes = std.ArrayList(Change).init(allocator); 144 145 defer { 146 created_changes.deinit(); 147 deleted_changes.deinit(); 148 modified_changes.deinit(); 149 } 150 151 for (changes) |change| { 152 switch (change.status) { 153 .created => try created_changes.append(change), 154 .deleted => try deleted_changes.append(change), 155 .modified => try modified_changes.append(change), 156 157 .unchanged => {}, 158 } 159 } 160 161 if ((created_changes.items.len > 0 and callbacks.on_create != null) or 162 (deleted_changes.items.len > 0 and callbacks.on_delete != null) or 163 (modified_changes.items.len > 0 and callbacks.on_modify != null) or 164 callbacks.on_change != null) 165 log.header("Callbacks"); 166 167 if (callbacks.on_change) |on_change| { 168 const json = try std.json.stringifyAlloc( 169 allocator, 170 changes, 171 .{}, 172 ); 173 defer allocator.free(json); 174 175 log.raw("- on_change: {s}\n", .{on_change}); 176 try callSystemProgram(on_change, json, cwd, allocator); 177 } 178 179 if (callbacks.on_create) |on_create| { 180 if (created_changes.items.len > 0) { 181 const json = try std.json.stringifyAlloc( 182 allocator, 183 created_changes.items, 184 .{}, 185 ); 186 defer allocator.free(json); 187 188 log.raw("- on_create: {s}\n", .{on_create}); 189 try callSystemProgram(on_create, json, cwd, allocator); 190 } 191 } 192 193 if (callbacks.on_delete) |on_delete| { 194 if (deleted_changes.items.len > 0) { 195 const json = try std.json.stringifyAlloc( 196 allocator, 197 deleted_changes.items, 198 .{}, 199 ); 200 defer allocator.free(json); 201 202 log.raw("- on_delete: {s}\n", .{on_delete}); 203 try callSystemProgram(on_delete, json, cwd, allocator); 204 } 205 } 206 207 if (callbacks.on_modify) |on_modify| { 208 if (modified_changes.items.len > 0) { 209 const json = try std.json.stringifyAlloc( 210 allocator, 211 modified_changes.items, 212 .{}, 213 ); 214 defer allocator.free(json); 215 216 log.raw("- on_modify: {s}\n", .{on_modify}); 217 try callSystemProgram(on_modify, json, cwd, allocator); 218 } 219 } 220}