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");
pub fn build(b: *std.build.Builder) 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.
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardOptimizeOption(.{});
const zig_args = b.dependency("zig_args", .{
.target = target,
.optimize = optimize,
}).module("args");
const exe = b.addExecutable(.{
.name = "confgen",
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = mode,
.optimize = optimize,
});
exe.strip = mode != .Debug and mode != .ReleaseSafe;
setupExe(exe);
exe.strip = optimize != .Debug and optimize != .ReleaseSafe;
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());
if (b.args) |args| {
run_cmd.addArgs(args);
@ -35,17 +33,19 @@ pub fn build(b: *std.build.Builder) void {
const exe_tests = b.addTest(.{
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = mode,
.optimize = optimize,
});
setupExe(exe_tests);
setupExe(exe_tests, zig_args);
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.linkSystemLibrary("luajit");
exe.addModule("args", zig_args);
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
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
c.lua_newtable(l);
@ -143,7 +160,10 @@ fn lAddPath(l: *c.lua_State) !c_int {
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();
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 outpath = if (argc >= 2) blk: {
break :blk ffi.luaCheckString(l, 2);
} else blk: {
const outpath = if (argc >= 2)
ffi.luaCheckString(l, 2)
else blk: {
if (std.mem.endsWith(u8, inpath, ".cgt")) {
break :blk inpath[0 .. inpath.len - 4];
}

View File

@ -1,11 +1,11 @@
const std = @import("std");
const args = @import("args");
const ffi = @import("ffi.zig");
const c = ffi.c;
const luagen = @import("luagen.zig");
const lapi = @import("lua_api.zig");
const rootfile = @import("rootfile.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 fn main() !void {
// TODO: add flag to emit generated lua files
if (std.os.argv.len != 2) {
// TODO: print usage
std.log.err("Expected one argument.", .{});
const Args = struct {
/// Compile template to Lua for debugging.
compile: ?[]const u8 = null,
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;
}
const conf_dir = (try rootfile.findRootDir()) orelse {
std.log.err("Couldn't find confgen.lua file!", .{});
return error.RootfileNotFound;
};
defer std.heap.c_allocator.free(conf_dir);
const cgfile = arg.positionals[0];
var state = lapi.CgState{
.outpath = std.mem.span(std.os.argv[1]),
.rootpath = conf_dir,
.outpath = arg.positionals[1],
.rootpath = std.fs.path.dirname(cgfile) orelse ".",
.files = std.ArrayList(lapi.CgFile).init(std.heap.c_allocator),
};
defer state.deinit();
@ -43,19 +105,13 @@ pub fn main() !void {
const l = try lapi.initLuaState(&state);
defer c.lua_close(l);
const conf_file_path = try std.fs.path.joinZ(
std.heap.c_allocator,
&.{ 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)});
if (c.luaL_loadfile(l, cgfile.ptr) != 0) {
std.log.err("loading confgen file: {s}", .{ffi.luaToString(l, -1)});
return error.RootfileExec;
}
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;
}

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, ".");
}