wyag

Write yourself a git
Log | Files | Refs | README

commit 871ebbae8d66341336b5e29535300d7c284d0fa1
parent 040307b324692a6146ddcb903f190879547dea7a
Author: Martin Ashby <martin@ashbysoft.com>
Date:   Tue, 27 Aug 2024 22:01:09 +0100

Implement tag listing
Rename GitTree -> Tree to be more consistent

Diffstat:
Msrc/root.zig | 177+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
1 file changed, 110 insertions(+), 67 deletions(-)

diff --git a/src/root.zig b/src/root.zig @@ -53,6 +53,15 @@ pub fn doMain() !void { var show_ref: argparse.Subcommand = .{ .parent = &ap, .description = "List references in a local repository", .name = "show-ref" }; try ap.addSubcommand(&show_ref); + var tag: argparse.Subcommand = .{ .parent = &ap, .description = "Manage tags", .name = "tag" }; + try ap.addSubcommand(&tag); + var tag_name: argparse.Positional = .{ .name = "name", .description = "name for the new tag" }; + try tag.addPositional(&tag_name); + var tag_object: argparse.Positional = .{ .name = "object", .description = "the object to add a tag for" }; + try tag.addPositional(&tag_object); + var tag_kind: argparse.Flag = .{ .long = "add", .short = "a", .description = "whether to create a tag object", .hasarg = false }; + try tag.addFlag(&tag_kind); + if (!try ap.parseOrHelp()) { return; } @@ -107,6 +116,12 @@ pub fn doMain() !void { } } else if (show_ref.wasExecuted) { try doShowRef(a, std.fs.cwd(), std.io.getStdOut().writer()); + } else if (tag.wasExecuted) { + if (tag_name.value) |tagname| { + try doAddTag(a, std.fs.cwd(), std.io.getStdOut().writer(), tagname, tag_object.value); + } else { + try doListTags(a, std.fs.cwd(), std.io.getStdOut().writer()); + } } else { if (ap.excess.items.len > 0) { std.log.err("Unsupported sub-command {s}, have you tried implementing it yourself?", .{ap.excess.items[0]}); @@ -117,6 +132,33 @@ pub fn doMain() !void { } } +fn doListTags(a: std.mem.Allocator, dir: std.fs.Dir, writer: anytype) !void { + var repo = try repo_find(a, dir); + defer repo.deinit(); + var refs = try repo.ref_list(a); + defer { + // TODO could do with a more convenient wrapper probably, maybe even an arena + for (refs.keys()) |k| a.free(k); + refs.deinit(); + } + for (refs.keys()) |k| { + // tags/ + const tags_prefix = "tags/"; + if (std.mem.startsWith(u8, k, tags_prefix)) { + try std.fmt.format(writer, "{s}\n", .{k[tags_prefix.len..]}); + } + } +} + +fn doAddTag(a: std.mem.Allocator, dir: std.fs.Dir, writer: anytype, tagname: []const u8, tagobj: ?[]const u8) !void { + _ = a; + _ = dir; + _ = writer; + _ = tagname; + _ = tagobj; + return error.Unimplemented; +} + fn doShowRef(a: std.mem.Allocator, dir: std.fs.Dir, writer: anytype) !void { var repo = try repo_find(a, dir); defer repo.deinit(); @@ -154,7 +196,7 @@ fn doCheckout(a: std.mem.Allocator, dir: std.fs.Dir, commit_ref: []const u8, che fn doCheckoutInternal(a: std.mem.Allocator, repo: *GitRepository, go: *GitObject, dir: std.fs.Dir) !void { if (go.kind != .tree) return error.NotATree; - var gt = try GitTree.parse(a, go.reader()); + var gt = try Tree.parse(a, go.reader()); defer gt.deinit(); for (gt.leaves.items) |leaf| { var go2 = try repo.read_object_sha(a, leaf.sha); @@ -199,7 +241,7 @@ fn lsTree(a: std.mem.Allocator, dir: Dir, ref: []const u8, writer: anytype, recu fn lsTreeInternal(a: std.mem.Allocator, repo: *GitRepository, go: *GitObject, writer: anytype, recurse: bool, path_prefix: []const u8) !void { if (go.kind != .tree) return error.NotATree; - var gt = try GitTree.parse(a, go.reader()); + var gt = try Tree.parse(a, go.reader()); defer gt.deinit(); for (gt.leaves.items) |leaf| { const filetype_str = switch (leaf.filetype) { @@ -512,7 +554,6 @@ pub const GitRepository = struct { try res.put(key, ref); } } - //`fn lessThan(ctx: @TypeOf(ctx), a_index: usize, b_index: usize) bool` const Srt = struct { map: std.StringArrayHashMap([20]u8), pub fn lessThan(slf: *@This(), ai: usize, bi: usize) bool { @@ -588,65 +629,6 @@ const ObjectKind = enum { blob, }; -const Commit = struct { - _kvlm: Kvlm, - tree: []const u8, - parents: std.ArrayListUnmanaged([]const u8), - author: []const u8, - committer: ?[]const u8, - gpgsig: ?[]const u8, - message: []const u8, - - pub fn parse(a: std.mem.Allocator, z_reader: anytype) !Commit { - var kvlm = try Kvlm.parse(a, z_reader); - errdefer kvlm.deinit(a); - return .{ - ._kvlm = kvlm, - .tree = if (kvlm.headers.get("tree")) |tree| tree.items[0] else return error.InvalidCommit, - .parents = kvlm.headers.get("parent") orelse .{}, - .author = if (kvlm.headers.get("author")) |tree| tree.items[0] else return error.InvalidCommit, - .committer = if (kvlm.headers.get("committer")) |tree| tree.items[0] else null, - .gpgsig = if (kvlm.headers.get("gpgsig")) |tree| tree.items[0] else null, - .message = kvlm.message, - }; - } - - pub fn deinit(self: *Commit, a: std.mem.Allocator) void { - self._kvlm.deinit(a); - } -}; - -test "parse commit" { - const commit_str = - \\tree 29ff16c9c14e2652b22f8b78bb08a5a07930c147 - \\parent 206941306e8a8af65b66eaaaea388a7ae24d49a0 - \\author Thibault Polge <thibault@thb.lt> 1527025023 +0200 - \\committer Thibault Polge <thibault@thb.lt> 1527025044 +0200 - \\gpgsig -----BEGIN PGP SIGNATURE----- - \\ - \\ iQIzBAABCAAdFiEExwXquOM8bWb4Q2zVGxM2FxoLkGQFAlsEjZQACgkQGxM2FxoL - \\ kGQdcBAAqPP+ln4nGDd2gETXjvOpOxLzIMEw4A9gU6CzWzm+oB8mEIKyaH0UFIPh - \\ rNUZ1j7/ZGFNeBDtT55LPdPIQw4KKlcf6kC8MPWP3qSu3xHqx12C5zyai2duFZUU - \\ wqOt9iCFCscFQYqKs3xsHI+ncQb+PGjVZA8+jPw7nrPIkeSXQV2aZb1E68wa2YIL - \\ 3eYgTUKz34cB6tAq9YwHnZpyPx8UJCZGkshpJmgtZ3mCbtQaO17LoihnqPn4UOMr - \\ V75R/7FjSuPLS8NaZF4wfi52btXMSxO/u7GuoJkzJscP3p4qtwe6Rl9dc1XC8P7k - \\ NIbGZ5Yg5cEPcfmhgXFOhQZkD0yxcJqBUcoFpnp2vu5XJl2E5I/quIyVxUXi6O6c - \\ /obspcvace4wy8uO0bdVhc4nJ+Rla4InVSJaUaBeiHTW8kReSFYyMmDCzLjGIu1q - \\ doU61OM3Zv1ptsLu3gUE6GU27iWYj2RWN3e3HE4Sbd89IFwLXNdSuM0ifDLZk7AQ - \\ WBhRhipCCgZhkj9g2NEk7jRVslti1NdN5zoQLaJNqSwO1MtxTmJ15Ksk3QP6kfLB - \\ Q52UWybBzpaP9HEd4XnR+HuQ4k2K0ns2KgNImsNvIyFwbpMUyUWLMPimaV1DWUXo - \\ 5SBjDB/V/W2JBFR+XKHFJeFwYhj7DD/ocsGr4ZMx/lgc8rjIBkI= - \\ =lgTX - \\ -----END PGP SIGNATURE----- - \\ - \\Create first draft - ; - var fbs = std.io.fixedBufferStream(commit_str); - const rdr = fbs.reader(); - var commit = try Commit.parse(std.testing.allocator, rdr); - defer commit.deinit(std.testing.allocator); -} - const Kvlm = struct { headers: std.StringArrayHashMapUnmanaged(std.ArrayListUnmanaged([]const u8)), message: []const u8, @@ -733,7 +715,68 @@ const Kvlm = struct { } }; -pub const GitTree = struct { +const Commit = struct { + _kvlm: Kvlm, + tree: []const u8, + parents: std.ArrayListUnmanaged([]const u8), + author: []const u8, + committer: ?[]const u8, + gpgsig: ?[]const u8, + message: []const u8, + + pub fn parse(a: std.mem.Allocator, z_reader: anytype) !Commit { + var kvlm = try Kvlm.parse(a, z_reader); + errdefer kvlm.deinit(a); + return .{ + ._kvlm = kvlm, + .tree = if (kvlm.headers.get("tree")) |tree| tree.items[0] else return error.InvalidCommit, + .parents = kvlm.headers.get("parent") orelse .{}, + .author = if (kvlm.headers.get("author")) |tree| tree.items[0] else return error.InvalidCommit, + .committer = if (kvlm.headers.get("committer")) |tree| tree.items[0] else null, + .gpgsig = if (kvlm.headers.get("gpgsig")) |tree| tree.items[0] else null, + .message = kvlm.message, + }; + } + + pub fn deinit(self: *Commit, a: std.mem.Allocator) void { + self._kvlm.deinit(a); + } +}; + +const Tag = Commit; // same structure and everything + +test "parse commit" { + const commit_str = + \\tree 29ff16c9c14e2652b22f8b78bb08a5a07930c147 + \\parent 206941306e8a8af65b66eaaaea388a7ae24d49a0 + \\author Thibault Polge <thibault@thb.lt> 1527025023 +0200 + \\committer Thibault Polge <thibault@thb.lt> 1527025044 +0200 + \\gpgsig -----BEGIN PGP SIGNATURE----- + \\ + \\ iQIzBAABCAAdFiEExwXquOM8bWb4Q2zVGxM2FxoLkGQFAlsEjZQACgkQGxM2FxoL + \\ kGQdcBAAqPP+ln4nGDd2gETXjvOpOxLzIMEw4A9gU6CzWzm+oB8mEIKyaH0UFIPh + \\ rNUZ1j7/ZGFNeBDtT55LPdPIQw4KKlcf6kC8MPWP3qSu3xHqx12C5zyai2duFZUU + \\ wqOt9iCFCscFQYqKs3xsHI+ncQb+PGjVZA8+jPw7nrPIkeSXQV2aZb1E68wa2YIL + \\ 3eYgTUKz34cB6tAq9YwHnZpyPx8UJCZGkshpJmgtZ3mCbtQaO17LoihnqPn4UOMr + \\ V75R/7FjSuPLS8NaZF4wfi52btXMSxO/u7GuoJkzJscP3p4qtwe6Rl9dc1XC8P7k + \\ NIbGZ5Yg5cEPcfmhgXFOhQZkD0yxcJqBUcoFpnp2vu5XJl2E5I/quIyVxUXi6O6c + \\ /obspcvace4wy8uO0bdVhc4nJ+Rla4InVSJaUaBeiHTW8kReSFYyMmDCzLjGIu1q + \\ doU61OM3Zv1ptsLu3gUE6GU27iWYj2RWN3e3HE4Sbd89IFwLXNdSuM0ifDLZk7AQ + \\ WBhRhipCCgZhkj9g2NEk7jRVslti1NdN5zoQLaJNqSwO1MtxTmJ15Ksk3QP6kfLB + \\ Q52UWybBzpaP9HEd4XnR+HuQ4k2K0ns2KgNImsNvIyFwbpMUyUWLMPimaV1DWUXo + \\ 5SBjDB/V/W2JBFR+XKHFJeFwYhj7DD/ocsGr4ZMx/lgc8rjIBkI= + \\ =lgTX + \\ -----END PGP SIGNATURE----- + \\ + \\Create first draft + ; + var fbs = std.io.fixedBufferStream(commit_str); + const rdr = fbs.reader(); + var commit = try Commit.parse(std.testing.allocator, rdr); + defer commit.deinit(std.testing.allocator); +} + +pub const Tree = struct { pub const Leaf = struct { pub const FileType = enum { file, @@ -761,8 +804,8 @@ pub const GitTree = struct { aa: std.heap.ArenaAllocator, leaves: std.ArrayListUnmanaged(Leaf) = .{}, - pub fn parse(ca: std.mem.Allocator, reader: anytype) !GitTree { - var result: GitTree = .{ + pub fn parse(ca: std.mem.Allocator, reader: anytype) !Tree { + var result: Tree = .{ .aa = std.heap.ArenaAllocator.init(ca), }; errdefer result.aa.deinit(); @@ -787,7 +830,7 @@ pub const GitTree = struct { return result; } - pub fn deinit(self: *GitTree) void { + pub fn deinit(self: *Tree) void { self.aa.deinit(); } }; @@ -795,7 +838,7 @@ pub const GitTree = struct { test "parse tree" { const a = std.testing.allocator; var fbs = std.io.fixedBufferStream(@embedFile("sample.tree")); - var tree = try GitTree.parse(a, fbs.reader()); + var tree = try Tree.parse(a, fbs.reader()); defer tree.deinit(); }