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:
M | src/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, .{});