Blog/Models/GitRepositories.cs 6.4 K · 163 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="Text"> |
| 73 | /// The file, newlines normalised to <c>\n</c> and the final one removed, or null when there is |
| 74 | /// nothing to print. Whole rather than split into lines: the highlighter needs the whole of it to |
| 75 | /// see that a block comment or a fenced code block carries on past the end of a line. |
| 76 | /// </param> |
| 77 | public sealed record GitBlob( |
| 78 | string Path, |
| 79 | string Sha, |
| 80 | long Size, |
| 81 | bool IsBinary, |
| 82 | bool TooLarge, |
| 83 | string? Text); |
| 84 | |
| 85 | /// <summary> |
| 86 | /// One path in one revision: a directory listing, or a file. Which of the two is set says which |
| 87 | /// the path turned out to be. |
| 88 | /// </summary> |
| 89 | /// <param name="Reference">The revision as it was asked for, for links that stay on this branch.</param> |
| 90 | public sealed record GitPathView( |
| 91 | GitCommitInfo Commit, |
| 92 | string Reference, |
| 93 | string Path, |
| 94 | IReadOnlyList<GitTreeEntry>? Entries, |
| 95 | GitBlob? Blob); |
| 96 | |
| 97 | public enum GitChange |
| 98 | { |
| 99 | Added, |
| 100 | Deleted, |
| 101 | Modified, |
| 102 | Renamed, |
| 103 | Copied, |
| 104 | TypeChanged |
| 105 | } |
| 106 | |
| 107 | /// <param name="Origin"> |
| 108 | /// <c>' '</c> context, <c>'+'</c> added, <c>'-'</c> removed, <c>'\'</c> for git's |
| 109 | /// "No newline at end of file" note. |
| 110 | /// </param> |
| 111 | public sealed record GitDiffLine(char Origin, int? OldNumber, int? NewNumber, string Text); |
| 112 | |
| 113 | /// <param name="Header">The <c>@@ -a,b +c,d @@</c> line, section heading and all.</param> |
| 114 | public sealed record GitDiffHunk(string Header, IReadOnlyList<GitDiffLine> Lines); |
| 115 | |
| 116 | /// <param name="Hunks">Empty for a binary file, and for one dropped to keep the page finite.</param> |
| 117 | public sealed record GitDiffFile( |
| 118 | string Path, |
| 119 | string? OldPath, |
| 120 | GitChange Change, |
| 121 | int Added, |
| 122 | int Deleted, |
| 123 | bool IsBinary, |
| 124 | bool Skipped, |
| 125 | IReadOnlyList<GitDiffHunk> Hunks); |
| 126 | |
| 127 | /// <param name="Truncated"> |
| 128 | /// Set when the diff ran past the line budget and the rest of the files kept their stats but lost |
| 129 | /// their hunks. A commit that vendors a 4 MB file should not render 4 MB of green. |
| 130 | /// </param> |
| 131 | public sealed record GitDiff(IReadOnlyList<GitDiffFile> Files, int Added, int Deleted, bool Truncated); |
| 132 | |
| 133 | /// <summary> |
| 134 | /// One file's bytes at one revision, for the raw endpoint. <paramref name="IsBinary"/> decides |
| 135 | /// whether it is handed over as text or as a download. |
| 136 | /// </summary> |
| 137 | public sealed record GitRawBlob(byte[] Bytes, bool IsBinary, string Name); |
| 138 | |
| 139 | /// <summary> |
| 140 | /// What the index found under the repository root, and why it found nothing when it found nothing. |
| 141 | /// </summary> |
| 142 | /// <remarks> |
| 143 | /// A failure is a value here, as it is for the drop tables and for the rvrb node. An unreadable |
| 144 | /// root is a deployment problem, and the page that says which deployment problem is worth more |
| 145 | /// than a stack trace: "there are no repositories" and "this process cannot read them" look |
| 146 | /// identical from the outside and are fixed in completely different places. |
| 147 | /// </remarks> |
| 148 | public sealed record GitIndexView(IReadOnlyList<GitRepoSummary> Repositories, string? Error); |
| 149 | |
| 150 | /// <summary>A commit and the diff that goes with it — everything the commit page renders.</summary> |
| 151 | public sealed record GitCommitView(GitCommitInfo Commit, GitDiff Diff); |
| 152 | |
| 153 | /// <summary>A branch or a tag, with the commit it points at.</summary> |
| 154 | /// <param name="Message">An annotated tag's own message. Null for branches and lightweight tags.</param> |
| 155 | public sealed record GitRef( |
| 156 | string Name, |
| 157 | bool IsTag, |
| 158 | string Sha, |
| 159 | GitCommitInfo? Tip, |
| 160 | string? Message); |
| 161 | |
| 162 | /// <summary>Every ref in a repository, branches and tags kept apart as the refs page shows them.</summary> |
| 163 | public sealed record GitRefsView(IReadOnlyList<GitRef> Branches, IReadOnlyList<GitRef> Tags); |