wyag

Write yourself a git
Log | Files | Refs | README

commit 1611a21542fc27cd4f0b0cb3bee668a730d31c64
parent 6ec49e90ef1b2a051c73cc185fa0fdbf77c3eb00
Author: Martin Ashby <martin@ashbysoft.com>
Date:   Sat,  7 Sep 2024 15:46:34 +0100

Launch an editor to write a tag message

Diffstat:
Msrc/root.zig | 53++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 48 insertions(+), 5 deletions(-)

diff --git a/src/root.zig b/src/root.zig @@ -160,6 +160,9 @@ fn doAddTag(a: std.mem.Allocator, dir: std.fs.Dir, tagname: []const u8, maybe_re var ref_str = std.fmt.bytesToHex(ref, .lower); if (create_tag_obj) { + const f = try runEditor(a, repo); + defer f.close(); + var al = std.ArrayList(u8).init(a); defer al.deinit(); const writer = al.writer(); @@ -167,7 +170,9 @@ fn doAddTag(a: std.mem.Allocator, dir: std.fs.Dir, tagname: []const u8, maybe_re try std.fmt.format(writer, "type commit\n", .{}); try std.fmt.format(writer, "tag {s}\n", .{tagname}); try std.fmt.format(writer, "tagger \"Martin Ashby\"\n", .{}); - try std.fmt.format(writer, "\n{s}\n", .{"Foo Message"}); + try writer.writeByte('\n'); + try pump(f.reader(), writer); + try writer.writeByte('\n'); var fbs = std.io.fixedBufferStream(al.items); const res = try repo.write_object(a, al.items.len, fbs.reader(), .tag, true); defer a.free(res); @@ -183,6 +188,37 @@ fn doAddTag(a: std.mem.Allocator, dir: std.fs.Dir, tagname: []const u8, maybe_re try wtr.writeByte('\n'); } +// Caller must close the file +fn runEditor(a: std.mem.Allocator, repo: GitRepository) !std.fs.File { + const tempfilepath = try repo.makeTempFilePath(a); + defer a.free(tempfilepath); + // check the config, then the EDITOR + const editor = if (repo.conf.get("core.editor")) |ed| ed else if (std.posix.getenv("EDITOR")) |ed2| ed2 else "nano"; + const args: []const []const u8 = &.{ editor, tempfilepath }; + var env = try std.process.getEnvMap(a); + defer env.deinit(); + std.log.warn("Launching {s}", .{args}); + var child = std.process.Child.init(args, a); + child.stdin_behavior = .Inherit; + child.stdout_behavior = .Inherit; + child.stderr_behavior = .Inherit; + child.cwd_dir = repo.gitdir; + child.env_map = &env; + try child.spawn(); + const term = try child.wait(); + switch (term) { + .Exited => |code| { + if (code != 0) { + return error.SubprocessError; + } + }, + else => { + return error.SubprocessError; + }, + } + return try repo.gitdir.openFile(tempfilepath, .{}); +} + fn doShowRef(a: std.mem.Allocator, dir: std.fs.Dir, writer: anytype) !void { var repo = try repo_find(a, dir); defer repo.deinit(); @@ -501,17 +537,24 @@ pub const GitRepository = struct { }; } + // Caller must free the result + pub fn makeTempFilePath(self: GitRepository, a: std.mem.Allocator) ![]const u8 { + try self.gitdir.makePath("tmp"); + var rndm = prng.random(); + const tmpfilename = try std.fmt.allocPrint(a, "wyag-{}", .{rndm.int(u16)}); + defer a.free(tmpfilename); + return try std.fs.path.join(a, &.{ "tmp", tmpfilename }); + } + // Caller owns the response pub fn write_object(self: GitRepository, ca: std.mem.Allocator, len: u64, reader: anytype, kind: ObjectKind, write: bool) ![]const u8 { var aa = std.heap.ArenaAllocator.init(ca); // 3 lines saves many little 'free' calls through this function. defer aa.deinit(); const a = aa.allocator(); // Write the stuff to a temporary file and calculate the hash - try self.gitdir.makePath("tmp"); var sha1 = std.crypto.hash.Sha1.init(.{}); - var rndm = prng.random(); - const tmpfilename = try std.fmt.allocPrint(a, "wyag-{}", .{rndm.int(u16)}); - const tmpfilepath = try std.fs.path.join(a, &.{ "tmp", tmpfilename }); + const tmpfilepath = try self.makeTempFilePath(a); + defer a.free(tmpfilepath); defer self.gitdir.deleteFile(tmpfilepath) catch {}; // not much we can do about this. { var tmpfile = try self.gitdir.createFile(tmpfilepath, .{});