srctree

Gregory Mullen parent 5d1feeb6 c2c099a7
list remotes on diff page

src/endpoints/repos/diffs.zig added: 119, removed: 13, total 106
@@ -6,6 +6,8 @@ const Commits = @import("commits.zig");
 
const Repo = @import("../repos.zig");
 
const Git = @import("../../git.zig");
const RepoUtil = @import("../../repos.zig");
const Bleach = @import("../../bleach.zig");
const CURL = @import("../../curl.zig");
const Context = @import("../../context.zig");
@@ -69,10 +71,32 @@ fn new(ctx: *Context) Error!void {
const udata = post.validate(DiffCreateChangeReq) catch return error.BadData;
 
if (udata.from_network) |_| {
const rd = Repo.RouteData.make(&ctx.uri) orelse return error.Unrouteable;
var cwd = std.fs.cwd();
const filename = try allocPrint(ctx.alloc, "./repos/{s}", .{rd.name});
const dir = cwd.openDir(filename, .{}) catch return error.Unknown;
const repo = Git.Repo.init(dir) catch return error.Unrouteable;
 
const remotes = repo.listRemotes(ctx.alloc) catch return error.Unknown;
defer {
for (remotes) |r| {
ctx.alloc.free(r.name);
if (r.url) |url| ctx.alloc.free(url);
if (r.fetch) |fetch| ctx.alloc.free(fetch);
}
ctx.alloc.free(remotes);
}
 
const network_remotes = try ctx.alloc.alloc(S.Remotes, remotes.len);
for (remotes, network_remotes) |src, *dst| {
dst.* = .{
.value = src.name,
.name = try allocPrint(ctx.alloc, "{diff}", .{src}),
};
}
 
network = .{
.remotes = &.{
.{ .value = "upstream", .name = "upstream network thingy" },
},
.remotes = network_remotes,
.branches = &.{
.{ .value = "main", .name = "main" },
.{ .value = "develop", .name = "develop" },
 
src/git.zig added: 119, removed: 13, total 106
@@ -11,12 +11,15 @@ const parseInt = std.fmt.parseInt;
const allocPrint = std.fmt.allocPrint;
const AnyReader = std.io.AnyReader;
 
const Ini = @import("ini.zig");
 
pub const Actor = @import("git/actor.zig");
pub const Agent = @import("git/agent.zig");
pub const Blob = @import("git/blob.zig");
pub const Commit = @import("git/commit.zig");
pub const Pack = @import("git/pack.zig");
pub const Tree = @import("git/tree.zig");
pub const Remote = @import("git/remote.zig");
 
pub const Error = error{
ReadError,
@@ -122,6 +125,7 @@ pub const Repo = struct {
repo.dir = d;
if (d.openFile("./HEAD", .{})) |file| {
file.close();
repo.bare = true;
} else |_| {
if (d.openDir("./.git", .{})) |full| {
if (full.openFile("./HEAD", .{})) |file| {
@@ -168,6 +172,24 @@ pub const Repo = struct {
_ = try self.HEAD(a);
}
 
pub fn listRemotes(self: Repo, a: Allocator) ![]Remote {
var list = std.ArrayList(Remote).init(a);
errdefer list.clearAndFree();
const config_data = try self.dir.readFileAlloc(a, "config", 0xffff);
const cfg = try Ini.initOwned(a, config_data);
defer cfg.raze();
for (0..cfg.ns.len) |i| {
const ns = cfg.filter("remote", i) orelse break;
try list.append(.{
.name = try a.dupe(u8, std.mem.trim(u8, ns.name[6..], "' \t\n\"")),
.url = if (ns.get("url")) |url| try a.dupe(u8, url) else null,
.fetch = if (ns.get("fetch")) |fetch| try a.dupe(u8, fetch) else null,
});
}
 
return try list.toOwnedSlice();
}
 
fn loadFile(self: Repo, a: Allocator, sha: SHA) !Object {
var fb = [_]u8{0} ** 2048;
const grouped = try bufPrint(&fb, "./objects/{s}/{s}", .{ sha.hex[0..2], sha.hex[2..] });
@@ -1304,3 +1326,20 @@ test "updated at" {
_ = oldest;
//std.debug.print("{}\n", .{oldest});
}
 
test "list remotes" {
const a = std.testing.allocator;
 
const cwd = try std.fs.cwd().openDir(".", .{});
var repo = try Repo.init(cwd);
const remotes = try repo.listRemotes(a);
try std.testing.expect(remotes.len == 2);
try std.testing.expectEqualStrings("github", remotes[0].name);
try std.testing.expectEqualStrings("gr.ht", remotes[1].name);
for (remotes) |rm| {
a.free(rm.name);
if (rm.url) |url| a.free(url);
if (rm.fetch) |fetch| a.free(fetch);
}
a.free(remotes);
}
 
filename was Deleted added: 119, removed: 13, total 106
@@ -0,0 +1,37 @@
const std = @import("std");
const eql = std.mem.eql;
const startsWith = std.mem.startsWith;
const endsWith = std.mem.endsWith;
 
pub const Remote = @This();
 
name: []const u8,
url: ?[]const u8,
fetch: ?[]const u8,
 
pub fn format(r: Remote, comptime fmt: []const u8, _: std.fmt.FormatOptions, out: anytype) !void {
if (std.mem.eql(u8, fmt, "diff")) {
if (r.url) |url| {
var printable = url;
if (startsWith(u8, printable, "https://")) {
printable = printable[8..];
} else if (startsWith(u8, printable, "git@")) {
printable = printable[4..];
}
if (endsWith(u8, printable, ".git")) {
printable = printable[0 .. printable.len - 4];
}
try out.writeAll(printable);
try out.writeAll(" [");
try out.writeAll(r.name);
try out.writeAll("]");
}
}
}
 
/// Half supported alloc function
pub fn raze(r: Remote, a: std.mem.Allocator) void {
a.free(r.name);
if (r.url) |url| a.free(url);
if (r.fetch) |fetch| a.free(fetch);
}
 
src/ini.zig added: 119, removed: 13, total 106
@@ -1,4 +1,5 @@
const std = @import("std");
const eql = std.mem.eql;
 
const Allocator = std.mem.Allocator;
 
@@ -74,9 +75,9 @@ pub const Namespace = struct {
if (set.len > 5) return null;
var buffer: [6]u8 = undefined;
const check = std.ascii.lowerString(buffer[0..], set);
if (eql(check, "false") or eql(check, "0") or eql(check, "f")) {
if (eql(u8, check, "false") or eql(u8, check, "0") or eql(u8, check, "f")) {
return false;
} else if (eql(check, "true") or eql(check, "1") or eql(check, "t")) {
} else if (eql(u8, check, "true") or eql(u8, check, "1") or eql(u8, check, "t")) {
return true;
} else return null;
}
@@ -162,15 +163,20 @@ pub fn init(a: Allocator, data: []const u8) !Config {
};
}
 
/// I'm not happy with this API. I think I deleted it once already... deleted
/// twice incoming!
pub fn initOwned(a: Allocator, data: []u8) !Config {
var c =
try init(a, data);
c.owned = data;
return c;
}
 
pub fn fromFile(a: Allocator, file: std.fs.File) !Config {
const data = try file.readToEndAlloc(a, 1 <<| 18);
return try init(a, data);
}
 
fn eql(left: []const u8, right: []const u8) bool {
return std.mem.eql(u8, left, right);
}
 
test "default" {
const a = std.testing.allocator;
const expected = Config{