diff --git a/cli/build.zig b/cli/build.zig index 7bc84ca..8a1fd24 100644 --- a/cli/build.zig +++ b/cli/build.zig @@ -2,6 +2,21 @@ const std = @import("std"); const compile = @import("compile.zig"); +fn getGitHash(allocator: std.mem.Allocator) ![]const u8 { + const args = &[_][]const u8{ "git", "rev-parse", "--short=10", "HEAD" }; + const proc = try std.process.Child.run(.{ + .allocator = allocator, + .argv = args, + }); + defer allocator.free(proc.stderr); + + const trimmed = std.mem.trim(u8, proc.stdout, &std.ascii.whitespace); + const hash = try allocator.alloc(u8, trimmed.len); + std.mem.copyForwards(u8, hash, trimmed); + allocator.free(proc.stdout); + return hash; +} + pub fn build(b: *std.Build) !void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); @@ -24,6 +39,24 @@ pub fn build(b: *std.Build) !void { exe.root_module.addImport("args", zig_args_dep.module("args")); exe.root_module.addImport("init_data", try compile.initDataModule(b)); + const version_config = @import("build.zig.zon"); + const version_str = version_config.version; + const raw_hash = try getGitHash(b.allocator); + defer b.allocator.free(raw_hash); + const hash = std.mem.trim(u8, raw_hash, &std.ascii.whitespace); + var content = std.ArrayList(u8).init(b.allocator); + defer content.deinit(); + try content.appendSlice("pub const version = \""); + try content.appendSlice(version_str); + try content.appendSlice("\";\n"); + try content.appendSlice("pub const commit_hash = \""); + try content.appendSlice(hash); + try content.appendSlice("\";\n"); + const write_files = b.addWriteFiles(); + const version_src = write_files.add("version.zig", content.items); + const version_module = b.createModule(.{ .root_source_file = version_src }); + exe.root_module.addImport("version", version_module); + b.installArtifact(exe); const run_cmd = b.addRunArtifact(exe); diff --git a/cli/cli.zig b/cli/cli.zig index 5db9282..f2d1ddb 100644 --- a/cli/cli.zig +++ b/cli/cli.zig @@ -10,6 +10,7 @@ pub const bundle = @import("commands/bundle.zig"); pub const tests = @import("commands/tests.zig"); pub const database = @import("commands/database.zig"); pub const auth = @import("commands/auth.zig"); +pub const version = @import("commands/version.zig"); pub const Environment = enum { development, testing, production }; @@ -49,6 +50,7 @@ const Verb = union(enum) { @"test": tests.Options, database: database.Options, auth: auth.Options, + version: version.Options, g: generate.Options, s: server.Options, r: routes.Options, @@ -91,6 +93,7 @@ pub fn main() !void { \\ database Manage the application's database. \\ auth Utilities for Jetzig authentication. \\ test Run app tests. + \\ version Print Jetzig version. \\ \\ Pass --help to any command for more information, e.g. `jetzig init --help` \\ @@ -124,6 +127,13 @@ fn run(allocator: std.mem.Allocator, options: args.ParseArgsResult(Options, Verb OptionsType, options, ), + .version => |opts| version.run( + allocator, + opts, + writer, + OptionsType, + options, + ), .s, .server => |opts| server.run( allocator, opts, diff --git a/cli/commands/version.zig b/cli/commands/version.zig new file mode 100644 index 0000000..7043f74 --- /dev/null +++ b/cli/commands/version.zig @@ -0,0 +1,26 @@ +const std = @import("std"); +const args = @import("args"); +const version = @import("version"); + +/// Command line options for the `version` command. +pub const Options = struct { + pub const meta = .{ + .usage_summary = "", + .full_text = "Print Jetzig version.", + }; +}; + +/// Run the `jetzig version` command. +pub fn run( + _: std.mem.Allocator, + _: Options, + writer: anytype, + T: type, + main_options: T, +) !void { + if (main_options.options.help) { + try args.printHelp(Options, "jetzig version", writer); + return; + } + std.debug.print("{s}+{s}\n", .{ version.version, version.commit_hash }); +}