Lindenii Project Forge
Login
Commit info
ID7491c424a00f0824f1d45b33d3b3f55fb0a7c4d8
AuthorRunxi Yu<me@runxiyu.org>
Author dateTue, 11 Feb 2025 20:50:17 +0800
CommitterRunxi Yu<me@runxiyu.org>
Committer dateTue, 11 Feb 2025 20:50:17 +0800
Actions
Get patch
repo_commit: Show chunks
package main

import (
	"net/http"

	"github.com/go-git/go-git/v5/plumbing"
	"github.com/go-git/go-git/v5/plumbing/format/diff"
)

type usable_file_patch struct {
	From   diff.File
	To     diff.File
	Chunks []diff.Chunk
}

func handle_repo_commit(w http.ResponseWriter, r *http.Request) {
	data := make(map[string]any)
	// TODO: Sanitize path values
	group_name, repo_name, commit_id_string := r.PathValue("group_name"), r.PathValue("repo_name"), r.PathValue("commit_id")
	data["group_name"], data["repo_name"], data["commit_id"] = group_name, repo_name, commit_id_string
	repo, err := open_git_repo(group_name, repo_name)
	if err != nil {
		_, _ = w.Write([]byte("Error opening repo: " + err.Error()))
		return
	}
	commit_id := plumbing.NewHash(commit_id_string)
	commit_object, err := repo.CommitObject(commit_id)
	if err != nil {
		_, _ = w.Write([]byte("Error getting commit object: " + err.Error()))
		return
	}
	data["commit_object"] = commit_object

	parent_commit_object, err := commit_object.Parent(0)
	if err != nil {
		_, _ = w.Write([]byte("Error getting parent commit object: " + err.Error()))
		return
	}
	data["parent_commit_object"] = parent_commit_object

	patch, err := parent_commit_object.Patch(commit_object)
	if err != nil {
		_, _ = w.Write([]byte("Error getting patch of commit: " + err.Error()))
		return
	}
	data["patch"] = patch

	/*
		for _, file_patch := range patch.FilePatches() {
			for _, chunk := range file_patch.Chunks() {
			}
	usable_file_patches := make([]usable_file_patch, 0)
	for _, file_patch := range patch.FilePatches() {
		from, to := file_patch.Files()
		usable_file_patch := usable_file_patch{
			Chunks: file_patch.Chunks(),
			From:   from,
			To:     to,
		}
	*/
		usable_file_patches = append(usable_file_patches, usable_file_patch)
	}
	data["file_patches"] = usable_file_patches

	err = templates.ExecuteTemplate(w, "repo_commit", data)
	if err != nil {
		_, _ = w.Write([]byte("Error rendering template: " + err.Error()))
		return
	}
}
html {
	font-family: sans-serif;
	background-color: var(--background-color);
	color: var(--text-color);
	--background-color: hsl(0, 0%, 100%);
	--text-color: hsl(0, 0%, 0%);
	--link-color: hsl(320, 50%, 36%);
	--light-text-color: hsl(0, 0%, 45%);
	--darker-border-color: hsl(0, 0%, 72%);
	--lighter-border-color: hsl(0, 0%, 85%);
	--text-decoration-color: hsl(0, 0%, 72%);
	--darker-box-background-color: hsl(0, 0%, 92%);
	--lighter-box-background-color: hsl(0, 0%, 95%);
}
@media (prefers-color-scheme: dark) {
	html {
		--background-color: hsl(0, 0%, 0%);
		--text-color: hsl(0, 0%, 100%);
		--link-color: hsl(320, 50%, 76%);
		--light-text-color: hsl(0, 0%, 78%);
		--darker-border-color: hsl(0, 0%, 35%);
		--lighter-border-color: hsl(0, 0%, 25%);
		--text-decoration-color: hsl(0, 0%, 30%);
		--darker-box-background-color: hsl(0, 0%, 20%);
		--lighter-box-background-color: hsl(0, 0%, 15%);
	}
}
html, code, pre {
	font-size: 1rem; /* TODO: Not always correct */
}
footer {
	margin-top: 1rem;
	margin-left: auto;
	margin-right: auto;
	display: block;
	padding: 0 5px;
	width: fit-content;
	text-align: center;
	color: var(--light-text-color);
}
footer a:link, footer a:visited {
	color: inherit;
}
.padding-wrapper {
	margin: 1rem auto;
	max-width: 60rem;
	padding: 0 5px;
}
a:link, a:visited {
	text-decoration-color: var(--text-decoration-color);
	color: var(--link-color);
}
code:not(pre > code) {
	background-color: var(--lighter-box-background-color);
	border-radius: 2px;
	padding: 2px;
}
table {
	border: var(--lighter-border-color) solid 1px;
	border-spacing: 0px;
	border-collapse: collapse;
}
table.wide {
	width: 100%;
}
td, th {
	padding: 3px 5px;
	border: var(--lighter-border-color) solid 1px;
}
th {
	background-color: var(--lighter-box-background-color);
}
th[scope=row] {
	text-align: left;
}
tr.title-row > th {
	background-color: var(--darker-box-background-color);
}
td > pre {
	margin: 0;
}
td#readme > *:last-child {
	margin-bottom: 0;
}
td#readme > *:first-child {
	margin-top: 0;
}
.commit-id {
	font-family: monospace;
}
pre, .scroll {
.scroll {
	overflow-x: auto;
}
.toggle-table-off, .toggle-table-on {
	display: none;
}
.toggle-table-off + table > thead > tr > th, .toggle-table-on + table > thead > tr > th {
	padding: 0;
}
.toggle-table-off + table > thead > tr > th > label, .toggle-table-on + table > thead > tr > th > label {
	width: 100%;
	display: inline-block;
	padding: 3px 1px;
	cursor: pointer;
}
.toggle-table-off:checked + table > tbody {
	display: none;
}
.toggle-table-on + table > tbody {
	display: none;
}
.toggle-table-on:checked + table > tbody {
	display: table-row-group;
}
.chunk-unchanged {
	color: grey;
}
.chunk-addition {
	color: green;
}
.chunk-deletion {
	color: red;
}
.chunk-unknown {
	color: yellow;
}
{{- define "repo_commit" -}}
<!DOCTYPE html>
<html lang="en">
	<head>
		{{ template "head_common" . }}
		<title>{{ .group_name }}/repos/{{ .repo_name }} &ndash; Lindenii Forge</title>
	</head>
	<body class="repo-commit">
		<div class="padding-wrapper scroll">
			<table id="commit-info-table">
				<thead>
					<tr class="title-row">
						<th colspan="2">Commit Info</th>
					</tr>
				</thead>
				<tbody>
					<tr>
						<th scope="row">ID</th>
						<td>{{ .commit_id }}</td>
					</tr>
					<tr>
						<th scope="row">Author</th>
						<td>{{ .commit_object.Author.Name }} &lt;<a href="mailto:{{ .commit_object.Author.Email }}">{{ .commit_object.Author.Email }}</a>&gt;</td>
					</tr>
					<tr>
						<th scope="row">Author Date</th>
						<td>{{ .commit_object.Author.When.Format "Mon, 02 Jan 2006 15:04:05 -0700" }}</td>
					</tr>
					<tr>
						<th scope="row">Committer</th>
						<td>{{ .commit_object.Committer.Name }} &lt;<a href="mailto:{{ .commit_object.Committer.Email }}">{{ .commit_object.Committer.Email }}</a>&gt;</td>
					</tr>
					<tr>
						<th scope="row">Committer Date</th>
						<td>{{ .commit_object.Committer.When.Format "Mon, 02 Jan 2006 15:04:05 -0700" }}</td>
					</tr>
					<tr>
						<th scope="row">Message</th>
						<td><pre>{{ .commit_object.Message }}</pre></td>
					</tr>
				</tbody>
			</table>
		</div>
		<div class="padding-wrapper scroll">
			<pre>{{ .patch }}</pre>
			<p>
			</p>
			{{ range .file_patches }}
				<div class="file-patch">
					{{ .From.Path }} {{ .From.Mode }} &rarr; {{ .To.Path }} {{ .To.Mode }}
					{{ range .Chunks }}
						{{ if eq .Type 0 }}
							<pre class="chunk chunk-unchanged">{{ .Content }}</pre>
						{{ else if eq .Type 1 }}
							<pre class="chunk chunk-addition">{{ .Content }}</pre>
						{{ else if eq .Type 2 }}
							<pre class="chunk chunk-deletion">{{ .Content }}</pre>
						{{ else }}
							<pre class="chunk chunk-unknown">{{ .Content }}</pre>
						{{ end }}
					{{ end }}
				</div>
			{{ end }}
		</div>
		<footer>
			{{ template "footer" . }}
		</footer>
	</body>
</html>
{{- end -}}