Blog/Models/GitRepositories.cs 5.6 K · 148 lines · raw · history

1 namespace Blog.Models;
2
3 /// <summary>
4 /// A name, an address and a time — git's author and committer lines, flattened out of libgit2's
5 /// handles so a page can still read them after the repository has been closed.
6 /// </summary>
7 public sealed record GitSignature(string Name, string Email, DateTimeOffset When);
8
9 /// <summary>One repository under the repository root, as the index lists it.</summary>
10 /// <param name="Name">The directory name, which is also the route segment: <c>blog.git</c>.</param>
11 /// <param name="DisplayName">The same without the suffix, for headings: <c>blog</c>.</param>
12 /// <param name="Description">
13 /// The <c>description</c> file, unless it still holds the placeholder <c>git init</c> writes.
14 /// </param>
15 /// <param name="Owner"><c>gitweb.owner</c> from the repository config, which is what cgit reads.</param>
16 /// <param name="Head">The branch HEAD points at, or null when it is unborn.</param>
17 /// <param name="Tip">The commit on that branch, and when it landed.</param>
18 public sealed record GitRepoSummary(
19 string Name,
20 string DisplayName,
21 string? Description,
22 string? Owner,
23 string? Head,
24 GitCommitInfo? Tip);
25
26 /// <summary>A commit, with everything a page shows about it.</summary>
27 /// <param name="Refs">
28 /// The branch and tag names whose tips are this commit. Filled in on the log, where the badges
29 /// mark where each branch has got to; empty everywhere else.
30 /// </param>
31 public sealed record GitCommitInfo(
32 string Sha,
33 string Summary,
34 string Body,
35 GitSignature Author,
36 GitSignature Committer,
37 IReadOnlyList<string> Parents,
38 IReadOnlyList<string> Refs)
39 {
40 /// <summary>Enough of the hash to be unambiguous, and short enough to sit in a table.</summary>
41 public string ShortSha => Sha.Length >= 10 ? Sha[..10] : Sha;
42
43 /// <summary>A commit with two or more parents is diffed against the first, as git does.</summary>
44 public bool IsMerge => Parents.Count > 1;
45 }
46
47 /// <summary>A page of history, and whether there is another one behind it.</summary>
48 public sealed record GitLogPage(IReadOnlyList<GitCommitInfo> Commits, bool HasMore);
49
50 /// <summary>What a tree entry is, as far as the listing cares.</summary>
51 public enum GitEntryKind
52 {
53 Directory,
54 File,
55
56 /// <summary>Mode 100755. Worth marking: it is the difference between a script and a text file.</summary>
57 Executable,
58
59 Symlink,
60
61 /// <summary>Another repository, pinned at a commit. There is nothing here to browse into.</summary>
62 Submodule
63 }
64
65 /// <param name="Path">Full path from the repository root, which is what the tree links carry.</param>
66 public sealed record GitTreeEntry(string Name, string Path, GitEntryKind Kind, long Size, string Sha);
67
68 /// <param name="IsBinary">
69 /// Decided the way git decides it: a NUL byte anywhere in the first few kilobytes. Binary blobs
70 /// are linked to the raw endpoint instead of being printed.
71 /// </param>
72 /// <param name="Lines">The blob's text split for numbering, or null when it is not shown.</param>
73 public sealed record GitBlob(
74 string Path,
75 string Sha,
76 long Size,
77 bool IsBinary,
78 bool TooLarge,
79 IReadOnlyList<string>? Lines);
80
81 /// <summary>
82 /// One path in one revision: a directory listing, or a file. Which of the two is set says which
83 /// the path turned out to be.
84 /// </summary>
85 /// <param name="Reference">The revision as it was asked for, for links that stay on this branch.</param>
86 public sealed record GitPathView(
87 GitCommitInfo Commit,
88 string Reference,
89 string Path,
90 IReadOnlyList<GitTreeEntry>? Entries,
91 GitBlob? Blob);
92
93 public enum GitChange
94 {
95 Added,
96 Deleted,
97 Modified,
98 Renamed,
99 Copied,
100 TypeChanged
101 }
102
103 /// <param name="Origin">
104 /// <c>' '</c> context, <c>'+'</c> added, <c>'-'</c> removed, <c>'\'</c> for git's
105 /// "No newline at end of file" note.
106 /// </param>
107 public sealed record GitDiffLine(char Origin, int? OldNumber, int? NewNumber, string Text);
108
109 /// <param name="Header">The <c>@@ -a,b +c,d @@</c> line, section heading and all.</param>
110 public sealed record GitDiffHunk(string Header, IReadOnlyList<GitDiffLine> Lines);
111
112 /// <param name="Hunks">Empty for a binary file, and for one dropped to keep the page finite.</param>
113 public sealed record GitDiffFile(
114 string Path,
115 string? OldPath,
116 GitChange Change,
117 int Added,
118 int Deleted,
119 bool IsBinary,
120 bool Skipped,
121 IReadOnlyList<GitDiffHunk> Hunks);
122
123 /// <param name="Truncated">
124 /// Set when the diff ran past the line budget and the rest of the files kept their stats but lost
125 /// their hunks. A commit that vendors a 4 MB file should not render 4 MB of green.
126 /// </param>
127 public sealed record GitDiff(IReadOnlyList<GitDiffFile> Files, int Added, int Deleted, bool Truncated);
128
129 /// <summary>
130 /// One file's bytes at one revision, for the raw endpoint. <paramref name="IsBinary"/> decides
131 /// whether it is handed over as text or as a download.
132 /// </summary>
133 public sealed record GitRawBlob(byte[] Bytes, bool IsBinary, string Name);
134
135 /// <summary>A commit and the diff that goes with it — everything the commit page renders.</summary>
136 public sealed record GitCommitView(GitCommitInfo Commit, GitDiff Diff);
137
138 /// <summary>A branch or a tag, with the commit it points at.</summary>
139 /// <param name="Message">An annotated tag's own message. Null for branches and lightweight tags.</param>
140 public sealed record GitRef(
141 string Name,
142 bool IsTag,
143 string Sha,
144 GitCommitInfo? Tip,
145 string? Message);
146
147 /// <summary>Every ref in a repository, branches and tags kept apart as the refs page shows them.</summary>
148 public sealed record GitRefsView(IReadOnlyList<GitRef> Branches, IReadOnlyList<GitRef> Tags);