diff --git a/.gitignore b/.gitignore index e00c239..cb627aa 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ zig-out/ /evmone/ /lib/evmone/ .vscode +src/version.zig \ No newline at end of file diff --git a/build.zig b/build.zig index 638b1cb..2800e04 100644 --- a/build.zig +++ b/build.zig @@ -1,10 +1,59 @@ const std = @import("std"); const LazyPath = std.Build.LazyPath; +// extract version string from build.zig.zon. The zon parser hasn't been merged +// into the std yet as of zig 0.13.0. +fn extractVersionFromZon(allocator: std.mem.Allocator) ![]const u8 { + const version_field_decl = ".version = \""; + var build_zon_file = try std.fs.cwd().openFile("build.zig.zon", .{}); + const build_zon_stat = try build_zon_file.stat(); + const build_zon = try build_zon_file.readToEndAlloc(allocator, build_zon_stat.size); + const version_start = std.mem.indexOf(u8, build_zon, version_field_decl); + if (version_start == null) { + return error.CantFindVersionFieldStart; + } + const version_offset = version_start.? + version_field_decl.len; + const version_end = std.mem.indexOf(u8, build_zon[version_offset..], "\""); + if (version_end == null) { + return error.CantFindVersionFieldEnd; + } + return build_zon[version_offset .. version_offset + version_end.?]; +} + +fn gitRevision(b: *std.Build) []const u8 { + var returncode: u8 = undefined; + const git_run = b.runAllowFail(&[_][]const u8{ + "git", + "rev-parse", + "--short", + "HEAD", + }, &returncode, .Ignore) catch v: { + break :v "unstable"; + }; + return std.mem.trim(u8, git_run, " \t\n\r"); +} + // Although this function looks imperative, note that its job is to // declaratively construct a build graph that will be executed by an external // runner. -pub fn build(b: *std.Build) void { +pub fn build(b: *std.Build) !void { + const version_file_path = "src/version.zig"; + + var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + defer arena.deinit(); + const allocator = arena.allocator(); + + const version = try extractVersionFromZon(allocator); + + var version_file = try std.fs.cwd().createFile(version_file_path, .{}); + defer version_file.close(); + + const git_rev = gitRevision(b); + + try version_file.writeAll(b.fmt( + \\pub const version = "{s}+{s}"; + , .{ version, git_rev })); + // Standard target options allows the person running `zig build` to choose // what target to build for. Here we do not override the defaults, which // means any target is allowed, and the default is native. Other options diff --git a/src/main.zig b/src/main.zig index a27e880..81edcb7 100644 --- a/src/main.zig +++ b/src/main.zig @@ -15,6 +15,7 @@ const httpz = @import("httpz"); const engine_api = @import("engine_api/engine_api.zig"); const json = std.json; const simargs = @import("simargs"); +const version = @import("version.zig").version; fn engineAPIHandler(req: *httpz.Request, res: *httpz.Response) !void { if (try req.json(engine_api.EngineAPIRequest)) |payload| { @@ -53,7 +54,7 @@ pub fn main() !void { // TODO print usage upon failure (requires upstream changes) // TODO generate version from build and add it here - const opts = try simargs.parse(gpa.allocator(), PhantArgs, "", null); + const opts = try simargs.parse(gpa.allocator(), PhantArgs, "", version); defer opts.deinit(); const port: u16 = if (opts.args.engine_api_port == null) 8551 else opts.args.engine_api_port.?; @@ -70,6 +71,7 @@ pub fn main() !void { } std.log.info("Welcome to phant! 🐘", .{}); + std.log.info("version: {s}", .{version}); try config.dump(allocator); var engine_api_server = try httpz.Server().init(allocator, .{