-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgit.zig
More file actions
106 lines (99 loc) · 3.12 KB
/
git.zig
File metadata and controls
106 lines (99 loc) · 3.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
const std = @import("std");
var is_installed: ?bool = null;
pub fn isInstalled(gpa: std.mem.Allocator, io: std.Io) bool {
if (is_installed) |v| {
return v;
}
var arena = std.heap.ArenaAllocator.init(gpa);
defer arena.deinit();
const run = std.process.run(arena.allocator(), io, .{
.argv = &.{ "git", "--version" },
}) catch {
is_installed = false;
return is_installed.?;
};
is_installed = switch (run.term) {
.exited => |v| v == 0,
else => false,
};
return is_installed.?;
}
pub fn currentCommit(gpa: std.mem.Allocator, io: std.Io) ![]const u8 {
if (!isInstalled(gpa, io)) return error.GitNotInstalled;
var arena = std.heap.ArenaAllocator.init(gpa);
defer arena.deinit();
const run = try std.process.run(arena.allocator(), io, .{
.argv = &.{ "git", "rev-parse", "HEAD" },
});
return try gpa.dupe(u8, run.stdout[0..8]);
}
pub fn getLinesChanged(
gpa: std.mem.Allocator,
io: std.Io,
login: []const u8,
token: []const u8,
repo: []const u8,
emails: []const []const u8,
) !u32 {
if (!isInstalled(gpa, io)) return error.GitNotInstalled;
var arena = std.heap.ArenaAllocator.init(gpa);
defer arena.deinit();
const allocator = arena.allocator();
const repo_path = try std.mem.replaceOwned(u8, allocator, repo, "/", "_");
const repo_url = try std.fmt.allocPrint(
allocator,
"https://{s}:{s}@github.com/{s}.git",
.{ login, token, repo },
);
const clone = try std.process.run(allocator, io, .{
.argv = &.{
"git",
"clone",
"--bare",
"--filter=blob:limit=1m",
"--no-tags",
"--single-branch",
repo_url,
repo_path,
},
});
switch (clone.term) {
.exited => |v| if (v != 0) return error.CloneFailed,
else => return error.CloneFailed,
}
defer std.Io.Dir.cwd().deleteTree(io, repo_path) catch {};
const email_args = try allocator.alloc([]const u8, emails.len * 2);
for (emails, 0..) |email, i| {
email_args[i * 2] = "--author";
email_args[i * 2 + 1] = email;
}
const log_args = try std.mem.concat(allocator, []const u8, &.{
&.{
"git",
"-C",
repo_path,
"log",
"--all",
"--numstat",
"--pretty=tformat:",
},
email_args,
});
const log = try std.process.run(allocator, io, .{ .argv = log_args });
switch (log.term) {
.exited => |v| if (v != 0) return error.LogFailed,
else => return error.LogFailed,
}
var lines_changed: u32 = 0;
var lines = std.mem.tokenizeScalar(u8, log.stdout, '\n');
while (lines.next()) |line| {
if (line.len == 0) continue;
var parts = std.mem.tokenizeAny(u8, line, " \t");
const additions =
std.fmt.parseUnsigned(u32, parts.next().?, 10) catch 0;
const deletions =
std.fmt.parseUnsigned(u32, parts.next().?, 10) catch 0;
lines_changed += additions + deletions;
}
return lines_changed;
}