feat: add git.workspace_path function
And refactor the git module.
This commit is contained in:
		
							parent
							
								
									8582d223f7
								
							
						
					
					
						commit
						20ce7279d2
					
				
					 1 changed files with 88 additions and 17 deletions
				
			
		
							
								
								
									
										105
									
								
								src/git.zig
									
										
									
									
									
								
							
							
						
						
									
										105
									
								
								src/git.zig
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -3,30 +3,101 @@ const tp = @import("thespian");
 | 
			
		|||
const shell = @import("shell");
 | 
			
		||||
const bin_path = @import("bin_path");
 | 
			
		||||
 | 
			
		||||
pub const Error = error{ OutOfMemory, GitNotFound, GitCallFailed };
 | 
			
		||||
 | 
			
		||||
const log_execute = false;
 | 
			
		||||
 | 
			
		||||
pub fn workspace_path() Error!void {
 | 
			
		||||
    const fn_name = @src().fn_name;
 | 
			
		||||
    try git(.{ "rev-parse", "--show-toplevel" }, struct {
 | 
			
		||||
        fn result(parent: tp.pid_ref, output: []const u8) void {
 | 
			
		||||
            var it = std.mem.splitScalar(u8, output, '\n');
 | 
			
		||||
            while (it.next()) |branch| if (branch.len > 0)
 | 
			
		||||
                parent.send(.{ module_name, fn_name, branch }) catch {};
 | 
			
		||||
        }
 | 
			
		||||
    }.result, exit_null_on_error(fn_name));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn current_branch() Error!void {
 | 
			
		||||
    const fn_name = @src().fn_name;
 | 
			
		||||
    try git(.{ "rev-parse", "--abbrev-ref", "HEAD" }, struct {
 | 
			
		||||
        fn result(parent: tp.pid_ref, output: []const u8) void {
 | 
			
		||||
            var it = std.mem.splitScalar(u8, output, '\n');
 | 
			
		||||
            while (it.next()) |branch| if (branch.len > 0)
 | 
			
		||||
                parent.send(.{ module_name, fn_name, branch }) catch {};
 | 
			
		||||
        }
 | 
			
		||||
    }.result, exit_null_on_error(fn_name));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn git(
 | 
			
		||||
    cmd: anytype,
 | 
			
		||||
    out: OutputHandler,
 | 
			
		||||
    exit: ExitHandler,
 | 
			
		||||
) Error!void {
 | 
			
		||||
    return git_err(cmd, out, noop, exit);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn git_err(
 | 
			
		||||
    cmd: anytype,
 | 
			
		||||
    out: OutputHandler,
 | 
			
		||||
    err: OutputHandler,
 | 
			
		||||
    exit: ExitHandler,
 | 
			
		||||
) Error!void {
 | 
			
		||||
    const cbor = @import("cbor");
 | 
			
		||||
    const git_binary = get_git() orelse return error.GitNotFound;
 | 
			
		||||
    var buf: std.ArrayListUnmanaged(u8) = .empty;
 | 
			
		||||
    const writer = buf.writer(allocator);
 | 
			
		||||
    switch (@typeInfo(@TypeOf(cmd))) {
 | 
			
		||||
        .@"struct" => |info| if (info.is_tuple) {
 | 
			
		||||
            try cbor.writeArrayHeader(writer, info.fields.len + 1);
 | 
			
		||||
            try cbor.writeValue(writer, git_binary);
 | 
			
		||||
            inline for (info.fields) |f|
 | 
			
		||||
                try cbor.writeValue(writer, @field(cmd, f.name));
 | 
			
		||||
            return shell.execute(allocator, .{ .buf = buf.items }, .{
 | 
			
		||||
                .out = to_shell_output_handler(out),
 | 
			
		||||
                .err = to_shell_output_handler(err),
 | 
			
		||||
                .exit = exit,
 | 
			
		||||
                .log_execute = log_execute,
 | 
			
		||||
            }) catch error.GitCallFailed;
 | 
			
		||||
        },
 | 
			
		||||
        else => {},
 | 
			
		||||
    }
 | 
			
		||||
    @compileError("git command should be a tuple: " ++ @typeName(@TypeOf(cmd)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn exit_null_on_error(comptime tag: []const u8) shell.ExitHandler {
 | 
			
		||||
    return struct {
 | 
			
		||||
        fn exit(_: usize, parent: tp.pid_ref, _: []const u8, _: []const u8, exit_code: i64) void {
 | 
			
		||||
            if (exit_code > 0)
 | 
			
		||||
                parent.send(.{ module_name, tag, null }) catch {};
 | 
			
		||||
        }
 | 
			
		||||
    }.exit;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const OutputHandler = fn (parent: tp.pid_ref, output: []const u8) void;
 | 
			
		||||
const ExitHandler = shell.ExitHandler;
 | 
			
		||||
 | 
			
		||||
fn to_shell_output_handler(handler: anytype) shell.OutputHandler {
 | 
			
		||||
    return struct {
 | 
			
		||||
        fn out(_: usize, parent: tp.pid_ref, _: []const u8, output: []const u8) void {
 | 
			
		||||
            handler(parent, output);
 | 
			
		||||
        }
 | 
			
		||||
    }.out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn noop(_: tp.pid_ref, _: []const u8) void {}
 | 
			
		||||
 | 
			
		||||
var git_path: ?struct {
 | 
			
		||||
    path: ?[:0]const u8 = null,
 | 
			
		||||
} = null;
 | 
			
		||||
 | 
			
		||||
const allocator = std.heap.c_allocator;
 | 
			
		||||
 | 
			
		||||
fn get_git() ?[]const u8 {
 | 
			
		||||
    if (git_path) |p| return p.path;
 | 
			
		||||
    const path = bin_path.find_binary_in_path(std.heap.c_allocator, "git") catch null;
 | 
			
		||||
    const path = bin_path.find_binary_in_path(allocator, module_name) catch null;
 | 
			
		||||
    git_path = .{ .path = path };
 | 
			
		||||
    return path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn get_current_branch(allocator: std.mem.Allocator) !void {
 | 
			
		||||
    const git_binary = get_git() orelse return error.GitBinaryNotFound;
 | 
			
		||||
    const git_current_branch_cmd = tp.message.fmt(.{ git_binary, "rev-parse", "--abbrev-ref", "HEAD" });
 | 
			
		||||
    const handlers = struct {
 | 
			
		||||
        fn out(_: usize, parent: tp.pid_ref, _: []const u8, output: []const u8) void {
 | 
			
		||||
            var it = std.mem.splitScalar(u8, output, '\n');
 | 
			
		||||
            while (it.next()) |branch| if (branch.len > 0)
 | 
			
		||||
                parent.send(.{ "git", "current_branch", branch }) catch {};
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    try shell.execute(allocator, git_current_branch_cmd, .{
 | 
			
		||||
        .out = handlers.out,
 | 
			
		||||
        .err = shell.log_err_handler,
 | 
			
		||||
        .exit = shell.log_exit_err_handler,
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
const module_name = @typeName(@This());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue