const std = @import("std"); const process = std.process; const Io = std.Io; const Allocator = std.mem.Allocator; const fern = @import("fern"); const maivi = @import("maivi"); const Handler = maivi.Handler; const helpers = maivi.helpers; const Status = helpers.Status; const mlua = @import("mlua.zig"); pub fn main(init: process.Init) !void { var args = init.minimal.args.iterate(); _ = args.skip(); if (args.next()) |arg| { if (std.mem.eql(u8, arg, "build")) maivi.build = true else if (std.mem.eql(u8, arg, "dev")) maivi.dev = true else if (std.mem.eql(u8, arg, "-l")) return mlua.main(init); } maivi.dev = maivi.dev or (!maivi.build and (if (init.environ_map.get("MAIVI_DEV")) |_| true else false)); const config: maivi.Config = try .init(init.io, init.arena, init.environ_map); try fern.init(init.io, init.gpa, .{ .level = config.log_level, }); defer fern.deinit(); var rev_buf: [0x80]u8 = undefined; if (!maivi.dev) maivi.rev = init.environ_map.get("MAIVI_REV") orelse rev_str(init.io, &rev_buf, config.root) catch |e| blk: { fern.warn().msg("version info cannot be retrieved from git. version must be provided using MAIVI_REV").err(e).log(); break :blk null; }; try maivi.init(init.io, init.gpa, &config); defer maivi.deinit(init.io); try maivi.lua.setup(init.io); if (maivi.build) return maivi.gen.generate(init.io); try maivi.server(init.io); try maivi.listen(init.io); } fn rev_str(io: Io, buf: []u8, root: []const u8) ![]const u8 { if (!process.can_spawn) { return error.NoChildProcess; } const rev = try spawn(io, buf, &[_][]const u8{ "git", "-C", root, // affects the --git-dir argument "--git-dir", ".git", // affected by the -C argument "rev-parse", "HEAD", }); return std.mem.trim(u8, rev, std.ascii.whitespace[0..]); } fn spawn(io: Io, buf: []u8, argv: []const []const u8) ![]u8 { var child = try process.spawn(io, .{ .argv = argv, .stdin = .ignore, .stdout = .pipe, .stderr = .ignore, }); errdefer child.kill(io); var rbuf: [0x80]u8 = undefined; var stdout_reader = child.stdout.?.readerStreaming(io, &rbuf); const n = try stdout_reader.interface.readSliceShort(buf); const term = try child.wait(io); return switch (term) { .exited => |code| if (code != 0) error.ExitCodeFailure else return buf[0..n], .signal, .stopped => error.ProcessTerminated, .unknown => error.ProcessTerminated, }; }