a5062626
Gregory Mullen
const std = @import("std");
a5062626
Gregory Mullen
fa39ddb7
Jeremy Hertel
pub fn build(b: *std.Build) !void {
a5062626
Gregory Mullen
const target = b.standardTargetOptions(.{});
a5062626
Gregory Mullen
const optimize = b.standardOptimizeOption(.{});
adeb5b70
Gregory Mullen
adeb5b70
Gregory Mullen
const ver = version(b);
adeb5b70
Gregory Mullen
const options = b.addOptions();
adeb5b70
Gregory Mullen
options.addOption([]const u8, "version", ver);
adeb5b70
Gregory Mullen
07908ac4
Gregory Mullen
const verse_lib = b.addModule("verse", .{
61746c43
Jeremy Hertel
.root_source_file = b.path("src/verse.zig"),
a5062626
Gregory Mullen
.target = target,
a5062626
Gregory Mullen
.optimize = optimize,
a5062626
Gregory Mullen
});
a5062626
Gregory Mullen
adeb5b70
Gregory Mullen
verse_lib.addOptions("build_options", options);
adeb5b70
Gregory Mullen
a5062626
Gregory Mullen
const lib_unit_tests = b.addTest(.{
61746c43
Jeremy Hertel
.root_source_file = b.path("src/verse.zig"),
a5062626
Gregory Mullen
.target = target,
a5062626
Gregory Mullen
.optimize = optimize,
a5062626
Gregory Mullen
});
adeb5b70
Gregory Mullen
lib_unit_tests.root_module.addOptions("build_options", options);
a5062626
Gregory Mullen
96ccdf46
Gregory Mullen
var compiler = Compiler.init(b);
96ccdf46
Gregory Mullen
53b3cd68
Gregory Mullen
var comptime_structs: ?*std.Build.Module = null;
53b3cd68
Gregory Mullen
var comptime_templates: ?*std.Build.Module = null;
53b3cd68
Gregory Mullen
7c8f22bb
Gregory Mullen
if (std.fs.cwd().access("src/fallback_html/index.html", .{})) {
96ccdf46
Gregory Mullen
compiler.addDir("src/fallback_html/");
07908ac4
Gregory Mullen
compiler.addDir("examples/templates/");
96ccdf46
Gregory Mullen
compiler.collect() catch unreachable;
53b3cd68
Gregory Mullen
comptime_templates = compiler.buildTemplates() catch unreachable;
7c8f22bb
Gregory Mullen
// Zig build time doesn't expose it's state in a way I know how to check...
7c8f22bb
Gregory Mullen
// so we yolo it like python :D
53b3cd68
Gregory Mullen
lib_unit_tests.root_module.addImport("comptime_templates", comptime_templates orelse unreachable);
53b3cd68
Gregory Mullen
comptime_structs = compiler.buildStructs() catch unreachable;
53b3cd68
Gregory Mullen
lib_unit_tests.root_module.addImport("comptime_structs", comptime_structs orelse unreachable);
53b3cd68
Gregory Mullen
53b3cd68
Gregory Mullen
verse_lib.addImport("comptime_structs", comptime_structs orelse @panic("structs missing"));
53b3cd68
Gregory Mullen
verse_lib.addImport("comptime_templates", comptime_templates orelse @panic("structs missing"));
7c8f22bb
Gregory Mullen
} else |_| {}
a5062626
Gregory Mullen
const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);
a5062626
Gregory Mullen
const test_step = b.step("test", "Run unit tests");
a5062626
Gregory Mullen
test_step.dependOn(&run_lib_unit_tests.step);
fa39ddb7
Jeremy Hertel
31f30882
Gregory Mullen
const examples = [_][]const u8{
2c06156c
Gregory Mullen
"basic", "cookies", "template", "endpoint", "auth-cookie",
2c06156c
Gregory Mullen
"request-userdata", "api", "websocket",
31f30882
Gregory Mullen
};
2e1a1a62
Gregory Mullen
inline for (examples) |example| {
fa39ddb7
Jeremy Hertel
const example_exe = b.addExecutable(.{
fa39ddb7
Jeremy Hertel
.name = example,
2e1a1a62
Gregory Mullen
.root_source_file = b.path("examples/" ++ example ++ ".zig"),
fa39ddb7
Jeremy Hertel
.target = target,
fa39ddb7
Jeremy Hertel
.optimize = optimize,
fa39ddb7
Jeremy Hertel
});
5774d5cc
Gregory Mullen
// All Examples should compile for tests to pass
5774d5cc
Gregory Mullen
test_step.dependOn(&example_exe.step);
fa39ddb7
Jeremy Hertel
07908ac4
Gregory Mullen
example_exe.root_module.addImport("verse", verse_lib);
07908ac4
Gregory Mullen
fa39ddb7
Jeremy Hertel
const run_example = b.addRunArtifact(example_exe);
fa39ddb7
Jeremy Hertel
run_example.step.dependOn(b.getInstallStep());
fa39ddb7
Jeremy Hertel
fa39ddb7
Jeremy Hertel
if (b.args) |args| {
fa39ddb7
Jeremy Hertel
run_example.addArgs(args);
fa39ddb7
Jeremy Hertel
}
fa39ddb7
Jeremy Hertel
2e1a1a62
Gregory Mullen
const run_name = "run-" ++ example;
2e1a1a62
Gregory Mullen
const run_description = "Run example: " ++ example;
fa39ddb7
Jeremy Hertel
const run_step = b.step(run_name, run_description);
fa39ddb7
Jeremy Hertel
run_step.dependOn(&run_example.step);
fa39ddb7
Jeremy Hertel
}
a5062626
Gregory Mullen
}
a5062626
Gregory Mullen
a5062626
Gregory Mullen
pub const Compiler = struct {
96ccdf46
Gregory Mullen
b: *std.Build,
96ccdf46
Gregory Mullen
dirs: std.ArrayList([]const u8),
96ccdf46
Gregory Mullen
files: std.ArrayList([]const u8),
96ccdf46
Gregory Mullen
collected: std.ArrayList([]const u8),
96ccdf46
Gregory Mullen
templates: ?*std.Build.Module = null,
96ccdf46
Gregory Mullen
structs: ?*std.Build.Module = null,
07908ac4
Gregory Mullen
debugging: bool = false,
96ccdf46
Gregory Mullen
96ccdf46
Gregory Mullen
pub fn init(b: *std.Build) Compiler {
96ccdf46
Gregory Mullen
return .{
96ccdf46
Gregory Mullen
.b = b,
96ccdf46
Gregory Mullen
.dirs = std.ArrayList([]const u8).init(b.allocator),
96ccdf46
Gregory Mullen
.files = std.ArrayList([]const u8).init(b.allocator),
96ccdf46
Gregory Mullen
.collected = std.ArrayList([]const u8).init(b.allocator),
96ccdf46
Gregory Mullen
};
96ccdf46
Gregory Mullen
}
96ccdf46
Gregory Mullen
96ccdf46
Gregory Mullen
pub fn raze(self: Compiler) void {
96ccdf46
Gregory Mullen
for (self.dirs.items) |each| self.b.allocator.free(each);
96ccdf46
Gregory Mullen
self.dirs.deinit();
96ccdf46
Gregory Mullen
for (self.files.items) |each| self.b.allocator.free(each);
96ccdf46
Gregory Mullen
self.files.deinit();
96ccdf46
Gregory Mullen
for (self.collected.items) |each| self.b.allocator.free(each);
96ccdf46
Gregory Mullen
self.collected.deinit();
96ccdf46
Gregory Mullen
}
96ccdf46
Gregory Mullen
96ccdf46
Gregory Mullen
pub fn addDir(self: *Compiler, dir: []const u8) void {
96ccdf46
Gregory Mullen
const copy = self.b.allocator.dupe(u8, dir) catch @panic("OOM");
96ccdf46
Gregory Mullen
self.dirs.append(copy) catch @panic("OOM");
96ccdf46
Gregory Mullen
self.templates = null;
96ccdf46
Gregory Mullen
self.structs = null;
96ccdf46
Gregory Mullen
}
96ccdf46
Gregory Mullen
96ccdf46
Gregory Mullen
pub fn addFile(self: *Compiler, file: []const u8) void {
96ccdf46
Gregory Mullen
const copy = self.b.allocator.dupe(u8, file) catch @panic("OOM");
96ccdf46
Gregory Mullen
self.files.append(copy) catch @panic("OOM");
96ccdf46
Gregory Mullen
self.templates = null;
96ccdf46
Gregory Mullen
self.structs = null;
96ccdf46
Gregory Mullen
}
96ccdf46
Gregory Mullen
96ccdf46
Gregory Mullen
pub fn buildTemplates(self: *Compiler) !*std.Build.Module {
96ccdf46
Gregory Mullen
if (self.templates) |t| return t;
96ccdf46
Gregory Mullen
96ccdf46
Gregory Mullen
//std.debug.print("building for {}\n", .{self.collected.items.len});
96ccdf46
Gregory Mullen
a5062626
Gregory Mullen
const local_dir = std.fs.path.dirname(@src().file) orelse ".";
96ccdf46
Gregory Mullen
const compiled = self.b.createModule(.{
a5062626
Gregory Mullen
.root_source_file = .{
96ccdf46
Gregory Mullen
.cwd_relative = self.b.pathJoin(&.{ local_dir, "src/template/comptime.zig" }),
a5062626
Gregory Mullen
},
a5062626
Gregory Mullen
});
a5062626
Gregory Mullen
96ccdf46
Gregory Mullen
const found = self.b.addOptions();
96ccdf46
Gregory Mullen
found.addOption([]const []const u8, "names", self.collected.items);
a5062626
Gregory Mullen
compiled.addOptions("config", found);
a5062626
Gregory Mullen
96ccdf46
Gregory Mullen
for (self.collected.items) |file| {
a5062626
Gregory Mullen
_ = compiled.addAnonymousImport(file, .{
96ccdf46
Gregory Mullen
.root_source_file = self.b.path(file),
a5062626
Gregory Mullen
});
a5062626
Gregory Mullen
}
a5062626
Gregory Mullen
96ccdf46
Gregory Mullen
self.templates = compiled;
a5062626
Gregory Mullen
return compiled;
a5062626
Gregory Mullen
}
a5062626
Gregory Mullen
96ccdf46
Gregory Mullen
pub fn buildStructs(self: *Compiler) !*std.Build.Module {
96ccdf46
Gregory Mullen
if (self.structs) |s| return s;
96ccdf46
Gregory Mullen
07908ac4
Gregory Mullen
if (self.debugging) std.debug.print("building structs for {}\n", .{self.collected.items.len});
a5062626
Gregory Mullen
const local_dir = std.fs.path.dirname(@src().file) orelse ".";
96ccdf46
Gregory Mullen
const t_compiler = self.b.addExecutable(.{
a5062626
Gregory Mullen
.name = "template-compiler",
a5062626
Gregory Mullen
.root_source_file = .{
15c05a2a
Gregory Mullen
.cwd_relative = self.b.pathJoin(&.{ local_dir, "src/template/struct-emit.zig" }),
a5062626
Gregory Mullen
},
489f6b4b
Gregory Mullen
.target = self.b.graph.host,
a5062626
Gregory Mullen
});
a5062626
Gregory Mullen
96ccdf46
Gregory Mullen
const comptime_templates = try self.buildTemplates();
a5062626
Gregory Mullen
t_compiler.root_module.addImport("comptime_templates", comptime_templates);
96ccdf46
Gregory Mullen
const tc_build_run = self.b.addRunArtifact(t_compiler);
a5062626
Gregory Mullen
const tc_structs = tc_build_run.addOutputFileArg("compiled-structs.zig");
96ccdf46
Gregory Mullen
const module = self.b.createModule(.{
a5062626
Gregory Mullen
.root_source_file = tc_structs,
a5062626
Gregory Mullen
});
a5062626
Gregory Mullen
96ccdf46
Gregory Mullen
self.structs = module;
a5062626
Gregory Mullen
return module;
a5062626
Gregory Mullen
}
a5062626
Gregory Mullen
96ccdf46
Gregory Mullen
pub fn collect(self: *Compiler) !void {
a5062626
Gregory Mullen
var cwd = std.fs.cwd();
96ccdf46
Gregory Mullen
for (self.dirs.items) |srcdir| {
96ccdf46
Gregory Mullen
var idir = cwd.openDir(srcdir, .{ .iterate = true }) catch |err| {
96ccdf46
Gregory Mullen
std.debug.print("template build error {} for srcdir {s}\n", .{ err, srcdir });
96ccdf46
Gregory Mullen
return err;
96ccdf46
Gregory Mullen
};
96ccdf46
Gregory Mullen
defer idir.close();
96ccdf46
Gregory Mullen
96ccdf46
Gregory Mullen
var itr = idir.iterate();
96ccdf46
Gregory Mullen
while (try itr.next()) |file| {
96ccdf46
Gregory Mullen
if (!std.mem.endsWith(u8, file.name, ".html")) continue;
96ccdf46
Gregory Mullen
try self.collected.append(self.b.pathJoin(&[2][]const u8{ srcdir, file.name }));
96ccdf46
Gregory Mullen
}
96ccdf46
Gregory Mullen
}
96ccdf46
Gregory Mullen
for (self.files.items) |file| {
96ccdf46
Gregory Mullen
try self.collected.append(file);
a5062626
Gregory Mullen
}
a5062626
Gregory Mullen
}
a5062626
Gregory Mullen
};
adeb5b70
Gregory Mullen
adeb5b70
Gregory Mullen
fn version(b: *std.Build) []const u8 {
adeb5b70
Gregory Mullen
if (!std.process.can_spawn) {
adeb5b70
Gregory Mullen
std.debug.print("Can't get a version number\n", .{});
adeb5b70
Gregory Mullen
std.process.exit(1);
adeb5b70
Gregory Mullen
}
adeb5b70
Gregory Mullen
adeb5b70
Gregory Mullen
var code: u8 = undefined;
adeb5b70
Gregory Mullen
const git_wide = b.runAllowFail(
4ee7c385
Gregory Mullen
&[_][]const u8{
4ee7c385
Gregory Mullen
"git",
4ee7c385
Gregory Mullen
"-C",
4ee7c385
Gregory Mullen
b.build_root.path orelse ".",
4ee7c385
Gregory Mullen
"describe",
4ee7c385
Gregory Mullen
"--dirty",
4ee7c385
Gregory Mullen
"--always",
4ee7c385
Gregory Mullen
},
adeb5b70
Gregory Mullen
&code,
adeb5b70
Gregory Mullen
.Ignore,
4ee7c385
Gregory Mullen
) catch @panic("git is having a bad day");
adeb5b70
Gregory Mullen
adeb5b70
Gregory Mullen
var git = std.mem.trim(u8, git_wide, " \r\n");
adeb5b70
Gregory Mullen
if (git[0] == 'v') git = git[1..];
adeb5b70
Gregory Mullen
//std.debug.print("version {s}\n", .{git});
adeb5b70
Gregory Mullen
adeb5b70
Gregory Mullen
// semver is really dumb, so we need to increment this internally
adeb5b70
Gregory Mullen
var ver = std.SemanticVersion.parse(git) catch return "v0.0.0-dev";
adeb5b70
Gregory Mullen
if (ver.pre != null) {
adeb5b70
Gregory Mullen
ver.minor += 1;
adeb5b70
Gregory Mullen
ver.pre = std.fmt.allocPrint(b.allocator, "pre-{s}", .{ver.pre.?}) catch @panic("OOM");
adeb5b70
Gregory Mullen
}
adeb5b70
Gregory Mullen
adeb5b70
Gregory Mullen
const final = std.fmt.allocPrint(b.allocator, "{}", .{ver}) catch @panic("OOM");
adeb5b70
Gregory Mullen
//std.debug.print("version {s}\n", .{final});
adeb5b70
Gregory Mullen
return final;
adeb5b70
Gregory Mullen
}