feat: improve CLI and take confgen file as CLI argument

This commit is contained in:
LordMZTE 2023-05-01 23:05:02 +02:00
parent 459834e134
commit 8ebdb27fbf
Signed by: LordMZTE
GPG key ID: B64802DC33A64FF6
5 changed files with 130 additions and 61 deletions

View file

@ -1,29 +1,27 @@
const std = @import("std"); const std = @import("std");
pub fn build(b: *std.build.Builder) void { pub fn build(b: *std.Build) void {
// 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
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{}); const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
// Standard release options allow the person running `zig build` to select const zig_args = b.dependency("zig_args", .{
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. .target = target,
const mode = b.standardOptimizeOption(.{}); .optimize = optimize,
}).module("args");
const exe = b.addExecutable(.{ const exe = b.addExecutable(.{
.name = "confgen", .name = "confgen",
.root_source_file = .{ .path = "src/main.zig" }, .root_source_file = .{ .path = "src/main.zig" },
.target = target, .target = target,
.optimize = mode, .optimize = optimize,
}); });
exe.strip = mode != .Debug and mode != .ReleaseSafe; exe.strip = optimize != .Debug and optimize != .ReleaseSafe;
setupExe(exe); setupExe(exe, zig_args);
exe.install(); b.installArtifact(exe);
const run_cmd = exe.run(); const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep()); run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| { if (b.args) |args| {
run_cmd.addArgs(args); run_cmd.addArgs(args);
@ -35,17 +33,19 @@ pub fn build(b: *std.build.Builder) void {
const exe_tests = b.addTest(.{ const exe_tests = b.addTest(.{
.root_source_file = .{ .path = "src/main.zig" }, .root_source_file = .{ .path = "src/main.zig" },
.target = target, .target = target,
.optimize = mode, .optimize = optimize,
}); });
setupExe(exe_tests); setupExe(exe_tests, zig_args);
const test_step = b.step("test", "Run unit tests"); const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&exe_tests.step); test_step.dependOn(&b.addRunArtifact(exe_tests).step);
} }
fn setupExe(exe: *std.build.LibExeObjStep) void { fn setupExe(exe: *std.Build.CompileStep, zig_args: *std.Build.Module) void {
exe.linkLibC(); exe.linkLibC();
exe.linkSystemLibrary("luajit"); exe.linkSystemLibrary("luajit");
exe.addModule("args", zig_args);
exe.unwind_tables = true; exe.unwind_tables = true;
} }

11
build.zig.zon Normal file
View file

@ -0,0 +1,11 @@
.{
.name = "confgen",
.version = "0.0.0",
.dependencies = .{
.zig_args = .{
.url = "https://mzte.de/git/mirrors/zig-args/archive/cce1b8987723c155d1fa61c4e6cac717074a2e74.tar.gz",
.hash = "122087f17682383feb354fecb2505788fdced06639f34e750cf641909fc6dcd76801",
},
},
}

View file

@ -48,6 +48,23 @@ pub fn initLuaState(cgstate: *CgState) !*c.lua_State {
// open all lua libs // open all lua libs
c.luaL_openlibs(l); c.luaL_openlibs(l);
// Add root path to package.path
c.lua_getglobal(l, "_G");
c.lua_getfield(l, -1, "package");
const root_luapath_prefix = try std.fmt.allocPrintZ(
std.heap.c_allocator,
"{s}/?.lua;",
.{cgstate.rootpath},
);
defer std.heap.c_allocator.free(root_luapath_prefix);
c.lua_pushlstring(l, root_luapath_prefix.ptr, root_luapath_prefix.len);
c.lua_getfield(l, -2, "path");
c.lua_concat(l, 2);
c.lua_setfield(l, -2, "path");
c.lua_pop(l, 2);
// create opt table // create opt table
c.lua_newtable(l); c.lua_newtable(l);
@ -143,7 +160,10 @@ fn lAddPath(l: *c.lua_State) !c_int {
const state = getState(l); const state = getState(l);
var dir = try std.fs.cwd().openIterableDir(path, .{}); const resolved_path = try std.fs.path.join(std.heap.c_allocator, &.{ state.rootpath, path });
defer std.heap.c_allocator.free(resolved_path);
var dir = try std.fs.cwd().openIterableDir(resolved_path, .{});
defer dir.close(); defer dir.close();
var iter = try dir.walk(std.heap.c_allocator); var iter = try dir.walk(std.heap.c_allocator);
@ -179,9 +199,9 @@ fn lAddFile(l: *c.lua_State) !c_int {
const inpath = ffi.luaCheckString(l, 1); const inpath = ffi.luaCheckString(l, 1);
const outpath = if (argc >= 2) blk: { const outpath = if (argc >= 2)
break :blk ffi.luaCheckString(l, 2); ffi.luaCheckString(l, 2)
} else blk: { else blk: {
if (std.mem.endsWith(u8, inpath, ".cgt")) { if (std.mem.endsWith(u8, inpath, ".cgt")) {
break :blk inpath[0 .. inpath.len - 4]; break :blk inpath[0 .. inpath.len - 4];
} }

View file

@ -1,11 +1,11 @@
const std = @import("std"); const std = @import("std");
const args = @import("args");
const ffi = @import("ffi.zig"); const ffi = @import("ffi.zig");
const c = ffi.c; const c = ffi.c;
const luagen = @import("luagen.zig"); const luagen = @import("luagen.zig");
const lapi = @import("lua_api.zig"); const lapi = @import("lua_api.zig");
const rootfile = @import("rootfile.zig");
const Parser = @import("Parser.zig"); const Parser = @import("Parser.zig");
@ -19,23 +19,85 @@ pub const std_options = struct {
pub const log_level = if (@import("builtin").mode == .Debug) .debug else .info; pub const log_level = if (@import("builtin").mode == .Debug) .debug else .info;
}; };
pub fn main() !void { const Args = struct {
// TODO: add flag to emit generated lua files /// Compile template to Lua for debugging.
if (std.os.argv.len != 2) { compile: ?[]const u8 = null,
// TODO: print usage
std.log.err("Expected one argument.", .{}); pub const shorthands = .{
.c = "compile",
};
};
const usage =
\\==== Confgen - Config File Template Engine ====
\\LordMZTE <lord@mzte.de>
\\
\\Options:
\\ --compile, -c Compile a template to Lua instead of running. Useful for debugging.
\\
\\Usage:
\\ confgen [CONFGENFILE] [OUTPATH] Generate configs according the the supplied configuration file.
;
pub fn main() !u8 {
run() catch |e| {
switch (e) {
error.InvalidArgs => {
std.log.err(
\\Invalid Arguments.
\\{s}
, .{usage});
},
//error.Explained => {},
else => {
std.log.err("UNEXPECTED: {s}", .{@errorName(e)});
},
}
return 1;
};
return 0;
}
pub fn run() !void {
const arg = try args.parseForCurrentProcess(Args, std.heap.c_allocator, .print);
defer arg.deinit();
if (arg.options.compile) |filepath| {
if (arg.positionals.len != 0) {
std.log.err("Expected 0 positional arguments, got {}.", .{arg.positionals.len});
return error.InvalidArgs;
}
const file = try std.fs.cwd().openFile(filepath, .{});
defer file.close();
const content = try file.readToEndAlloc(std.heap.c_allocator, std.math.maxInt(usize));
defer std.heap.c_allocator.free(content);
var parser = Parser{
.str = content,
.pos = 0,
};
const tmpl = try luagen.generateLua(&parser, filepath);
defer tmpl.deinit();
try std.io.getStdOut().writeAll(tmpl.content);
return;
}
if (arg.positionals.len != 2) {
std.log.err("Expected 2 positional arguments, got {}.", .{arg.positionals.len});
return error.InvalidArgs; return error.InvalidArgs;
} }
const conf_dir = (try rootfile.findRootDir()) orelse { const cgfile = arg.positionals[0];
std.log.err("Couldn't find confgen.lua file!", .{});
return error.RootfileNotFound;
};
defer std.heap.c_allocator.free(conf_dir);
var state = lapi.CgState{ var state = lapi.CgState{
.outpath = std.mem.span(std.os.argv[1]), .outpath = arg.positionals[1],
.rootpath = conf_dir, .rootpath = std.fs.path.dirname(cgfile) orelse ".",
.files = std.ArrayList(lapi.CgFile).init(std.heap.c_allocator), .files = std.ArrayList(lapi.CgFile).init(std.heap.c_allocator),
}; };
defer state.deinit(); defer state.deinit();
@ -43,19 +105,13 @@ pub fn main() !void {
const l = try lapi.initLuaState(&state); const l = try lapi.initLuaState(&state);
defer c.lua_close(l); defer c.lua_close(l);
const conf_file_path = try std.fs.path.joinZ( if (c.luaL_loadfile(l, cgfile.ptr) != 0) {
std.heap.c_allocator, std.log.err("loading confgen file: {s}", .{ffi.luaToString(l, -1)});
&.{ conf_dir, "confgen.lua" },
);
defer std.heap.c_allocator.free(conf_file_path);
if (c.luaL_loadfile(l, conf_file_path.ptr) != 0) {
std.log.err("loading confgen.lua: {s}", .{ffi.luaToString(l, -1)});
return error.RootfileExec; return error.RootfileExec;
} }
if (c.lua_pcall(l, 0, 0, 0) != 0) { if (c.lua_pcall(l, 0, 0, 0) != 0) {
std.log.err("running confgen.lua: {s}", .{ffi.luaToString(l, -1)}); std.log.err("running confgen file: {s}", .{ffi.luaToString(l, -1)});
return error.RootfileExec; return error.RootfileExec;
} }

View file

@ -1,18 +0,0 @@
const std = @import("std");
const c = @import("ffi.zig").c;
/// Tries to find the confgen.lua file by walking up the directory tree.
/// Returns the directory path, NOT THE FILE PATH.
/// Returned path is malloc'd
pub fn findRootDir() !?[]const u8 {
// TODO: walk upwards
_ = std.fs.cwd().statFile("confgen.lua") catch |e| {
if (e == error.FileNotFound) {
return null;
}
return e;
};
return try std.heap.c_allocator.dupe(u8, ".");
}