add command line parameter to print the version
The version is defined in build.zig. We use git describe to the the build version. For release versions we enforce that the version in build.zig and build.zig.zon must be equal to the output of git describe.
This commit is contained in:
56
build.zig
56
build.zig
@@ -1,11 +1,16 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
// TODO TODO
|
// Must match the version in build.zig.zon
|
||||||
|
const totp_version: std.SemanticVersion = .{ .major = 0, .minor = 1, .patch = 0, .pre = "dev" };
|
||||||
|
|
||||||
// Although this function looks imperative, note that its job is to
|
// Although this function looks imperative, note that its job is to
|
||||||
// declaratively construct a build graph that will be executed by an external
|
// declaratively construct a build graph that will be executed by an external
|
||||||
// runner.
|
// runner.
|
||||||
pub fn build(b: *std.Build) void {
|
pub fn build(b: *std.Build) void {
|
||||||
|
const version = getVersion(b);
|
||||||
|
const options = b.addOptions();
|
||||||
|
options.addOption(std.SemanticVersion, "version", version);
|
||||||
|
|
||||||
// Standard target options allows the person running `zig build` to choose
|
// Standard target options allows the person running `zig build` to choose
|
||||||
// what target to build for. Here we do not override the defaults, which
|
// 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
|
// means any target is allowed, and the default is native. Other options
|
||||||
@@ -37,6 +42,7 @@ pub fn build(b: *std.Build) void {
|
|||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
|
exe.root_module.addOptions("config", options);
|
||||||
|
|
||||||
// This declares intent for the executable to be installed into the
|
// This declares intent for the executable to be installed into the
|
||||||
// standard location when the user invokes the "install" step (the default
|
// standard location when the user invokes the "install" step (the default
|
||||||
@@ -91,3 +97,51 @@ pub fn build(b: *std.Build) void {
|
|||||||
test_step.dependOn(&run_lib_unit_tests.step);
|
test_step.dependOn(&run_lib_unit_tests.step);
|
||||||
test_step.dependOn(&run_exe_unit_tests.step);
|
test_step.dependOn(&run_exe_unit_tests.step);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn getVersion(b: *std.Build) std.SemanticVersion {
|
||||||
|
// if this is a release version , aka this is not a pre-release or build version,
|
||||||
|
// then use the specified version
|
||||||
|
if (totp_version.pre == null and totp_version.build == null) return totp_version;
|
||||||
|
|
||||||
|
// for pre-release version we use the git version
|
||||||
|
const args: []const []const u8 = &.{ "git", "-C", b.pathFromRoot("."), "describe", "--match", "*.*.*", "--tags" };
|
||||||
|
var out_code: u8 = undefined;
|
||||||
|
const output_untrimmed = b.runAllowFail(args, &out_code, .Ignore) catch |err| {
|
||||||
|
std.log.warn(
|
||||||
|
\\ failed to run git describe: {}
|
||||||
|
, .{err});
|
||||||
|
return totp_version;
|
||||||
|
};
|
||||||
|
|
||||||
|
const output_trimmed = std.mem.trim(u8, output_untrimmed, " \r\n");
|
||||||
|
switch (std.mem.count(u8, output_trimmed, "-")) {
|
||||||
|
0 => {
|
||||||
|
// release version, e.g. 1.0.0
|
||||||
|
if (!std.mem.eql(u8, output_trimmed, b.fmt("{}", .{totp_version}))) {
|
||||||
|
std.debug.panic("the version in build.zig and build.zig.zon must match the tag in git", .{});
|
||||||
|
}
|
||||||
|
return totp_version;
|
||||||
|
},
|
||||||
|
2 => {
|
||||||
|
// development version, e.g. 1.0.0-7-64es356
|
||||||
|
var iter = std.mem.splitScalar(u8, output_trimmed, '-');
|
||||||
|
const tag = iter.first();
|
||||||
|
const commits_since_tag = iter.next().?;
|
||||||
|
const commit_hash = iter.next().?;
|
||||||
|
|
||||||
|
const v: std.SemanticVersion = std.SemanticVersion.parse(tag) catch unreachable;
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.major = v.major,
|
||||||
|
.minor = v.minor,
|
||||||
|
.patch = v.patch,
|
||||||
|
.pre = b.fmt("dev.{s}", .{commits_since_tag}),
|
||||||
|
.build = commit_hash[1..],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
std.debug.print("unexpected output of git describe: '{s}'\n", .{output_untrimmed});
|
||||||
|
std.process.exit(1);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
.name = "zig-totp",
|
.name = "zig-totp",
|
||||||
// This is a [Semantic Version](https://semver.org/).
|
// This is a [Semantic Version](https://semver.org/).
|
||||||
// In a future version of Zig it will be used for package deduplication.
|
// In a future version of Zig it will be used for package deduplication.
|
||||||
.version = "0.0.0",
|
.version = "0.1.0-dev",
|
||||||
|
|
||||||
// This field is optional.
|
// This field is optional.
|
||||||
// This is currently advisory only; Zig does not yet do anything
|
// This is currently advisory only; Zig does not yet do anything
|
||||||
|
|||||||
12
src/main.zig
12
src/main.zig
@@ -10,6 +10,7 @@ const expect = testing.expect;
|
|||||||
const ArrayList = std.ArrayList;
|
const ArrayList = std.ArrayList;
|
||||||
const Base32 = @import("base32.zig").Base32;
|
const Base32 = @import("base32.zig").Base32;
|
||||||
const Base32Error = @import("base32.zig").Base32Error;
|
const Base32Error = @import("base32.zig").Base32Error;
|
||||||
|
const options = @import("config");
|
||||||
|
|
||||||
// otpauth://totp/AWS+Dev?secret=47STA47VFCMMLLWOLHWO3KY7MYNC36MLCDTHOLIYKJCTTSSAMKVM7YA3VWT2AJEP&digits=6&icon=Amazon
|
// otpauth://totp/AWS+Dev?secret=47STA47VFCMMLLWOLHWO3KY7MYNC36MLCDTHOLIYKJCTTSSAMKVM7YA3VWT2AJEP&digits=6&icon=Amazon
|
||||||
// otpauth://totp/Gitea%20%28git.lucares.de%29:andi?algorithm=SHA1&digits=6&issuer=Gitea&period=30&secret=MSP53Q672UJMSCLQVRCJKMMZKK7MWSMYFL77OQ24JBM65RZWY7F2Y45FMTNLYM36
|
// otpauth://totp/Gitea%20%28git.lucares.de%29:andi?algorithm=SHA1&digits=6&issuer=Gitea&period=30&secret=MSP53Q672UJMSCLQVRCJKMMZKK7MWSMYFL77OQ24JBM65RZWY7F2Y45FMTNLYM36
|
||||||
@@ -49,7 +50,9 @@ fn mainInternal() !void {
|
|||||||
|
|
||||||
const arg: Args = try parseArgs(allocator, args);
|
const arg: Args = try parseArgs(allocator, args);
|
||||||
//print("parsed Args: {?any}\n", arg);
|
//print("parsed Args: {?any}\n", arg);
|
||||||
if (arg.list) {
|
if (arg.print_version) {
|
||||||
|
try std.io.getStdOut().writer().print("{}", .{options.version});
|
||||||
|
} else if (arg.list) {
|
||||||
const names = try executeGetList(allocator, arg.config_location);
|
const names = try executeGetList(allocator, arg.config_location);
|
||||||
|
|
||||||
for (0..names.items.len) |i| {
|
for (0..names.items.len) |i| {
|
||||||
@@ -85,12 +88,13 @@ fn printHelp() void {
|
|||||||
\\ eval "$(zig-totp --bash)"
|
\\ eval "$(zig-totp --bash)"
|
||||||
\\ to your ~/.bashrc
|
\\ to your ~/.bashrc
|
||||||
\\ --config [path] The path to a config file (default is $XDG_CONFIG_HOME/zig-totp or $HOME/.zig-totp).
|
\\ --config [path] The path to a config file (default is $XDG_CONFIG_HOME/zig-totp or $HOME/.zig-totp).
|
||||||
|
\\ --version Print the version number
|
||||||
\\
|
\\
|
||||||
;
|
;
|
||||||
std.debug.print("{s}", .{msg});
|
std.debug.print("{s}", .{msg});
|
||||||
}
|
}
|
||||||
|
|
||||||
const Args = struct { list: bool, show: ?[]const u8, config_location: []const u8, validateAuthenticator: ?[]const u8, validateCode: ?[]const u8 };
|
const Args = struct { list: bool, show: ?[]const u8, config_location: []const u8, validateAuthenticator: ?[]const u8, validateCode: ?[]const u8, print_version: bool };
|
||||||
|
|
||||||
const OtpAuthUrl = struct { name: []const u8, secretEncoded: []const u8, url: []const u8, period: u32, digits: u4, algorithm: []const u8 };
|
const OtpAuthUrl = struct { name: []const u8, secretEncoded: []const u8, url: []const u8, period: u32, digits: u4, algorithm: []const u8 };
|
||||||
|
|
||||||
@@ -186,7 +190,7 @@ fn zeroPad(allocator: Allocator, digits: u4, x: anytype) ![]u8 {
|
|||||||
const ArgumentError = error{ InvalidOtpAuthUrl, UnknownParameter, MissingConfigLocation, AuthenticatorNotFound, MissingAuthenticatorParam, FailedToOpenConfigFile, TooManyParsinErrors };
|
const ArgumentError = error{ InvalidOtpAuthUrl, UnknownParameter, MissingConfigLocation, AuthenticatorNotFound, MissingAuthenticatorParam, FailedToOpenConfigFile, TooManyParsinErrors };
|
||||||
|
|
||||||
fn parseArgs(allocator: Allocator, args: []const []const u8) !Args {
|
fn parseArgs(allocator: Allocator, args: []const []const u8) !Args {
|
||||||
var result = Args{ .list = false, .show = null, .config_location = try configLocation(allocator), .validateAuthenticator = null, .validateCode = null };
|
var result = Args{ .list = false, .show = null, .config_location = try configLocation(allocator), .validateAuthenticator = null, .validateCode = null, .print_version = false };
|
||||||
var i: u17 = 1;
|
var i: u17 = 1;
|
||||||
while (i < args.len) : (i += 1) {
|
while (i < args.len) : (i += 1) {
|
||||||
const arg = args[i];
|
const arg = args[i];
|
||||||
@@ -220,6 +224,8 @@ fn parseArgs(allocator: Allocator, args: []const []const u8) !Args {
|
|||||||
return error.MissingConfigLocation;
|
return error.MissingConfigLocation;
|
||||||
}
|
}
|
||||||
result.config_location = args[i];
|
result.config_location = args[i];
|
||||||
|
} else if (eql(u8, "--version", arg)) {
|
||||||
|
result.print_version = true;
|
||||||
} else if (eql(u8, "list", arg)) {
|
} else if (eql(u8, "list", arg)) {
|
||||||
result.list = true;
|
result.list = true;
|
||||||
} else if (eql(u8, "show", arg)) {
|
} else if (eql(u8, "show", arg)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user