Lindenii Project Forge
Login
Commit info
IDb63917094e6a69c8c01f9e7df8716f3d5fc42385
AuthorRunxi Yu<me@runxiyu.org>
Author dateFri, 07 Mar 2025 19:20:54 +0800
CommitterRunxi Yu<me@runxiyu.org>
Committer dateFri, 07 Mar 2025 19:20:54 +0800
Actions
Get patch
repo/index: Display repo info only, when commits/files unavailable
// SPDX-License-Identifier: AGPL-3.0-only
// SPDX-FileContributor: Runxi Yu <https://runxiyu.org>

package main

import (
	"net/http"

	"github.com/go-git/go-git/v5"
	"github.com/go-git/go-git/v5/plumbing"
	"github.com/go-git/go-git/v5/plumbing/object"
)

func handle_repo_index(w http.ResponseWriter, r *http.Request, params map[string]any) {
	var repo *git.Repository
	var repo_name string
	var group_path []string
	var ref_hash plumbing.Hash
	var err error
	var recent_commits []*object.Commit
	var commit_object *object.Commit
	var tree *object.Tree

	repo, repo_name, group_path = params["repo"].(*git.Repository), params["repo_name"].(string), params["group_path"].([]string)

	if ref_hash, err = get_ref_hash_from_type_and_name(repo, params["ref_type"].(string), params["ref_name"].(string)); err != nil {
		http.Error(w, "Error getting ref hash: "+err.Error(), http.StatusInternalServerError)
		return
	ref_hash, err = get_ref_hash_from_type_and_name(repo, params["ref_type"].(string), params["ref_name"].(string))
	if err != nil {
		goto no_ref
	}

	if recent_commits, err = get_recent_commits(repo, ref_hash, 3); err != nil {
		http.Error(w, "Error getting recent commits: "+err.Error(), http.StatusInternalServerError)
		return
		goto no_ref
	}
	params["commits"] = recent_commits
	commit_object, err = repo.CommitObject(ref_hash)
	if err != nil {
		http.Error(w, "Error getting commit object: "+err.Error(), http.StatusInternalServerError)
		return

	if commit_object, err = repo.CommitObject(ref_hash); err != nil {
		goto no_ref
	}
	tree, err = commit_object.Tree()
	if err != nil {
		http.Error(w, "Error getting file tree: "+err.Error(), http.StatusInternalServerError)
		return

	if tree, err = commit_object.Tree(); err != nil {
		goto no_ref
	}

	params["readme_filename"], params["readme"] = render_readme_at_tree(tree)
	params["files"] = build_display_git_tree(tree)
	params["readme_filename"], params["readme"] = render_readme_at_tree(tree)

no_ref:

	params["http_clone_url"] = generate_http_remote_url(group_path, repo_name)
	params["ssh_clone_url"] = generate_ssh_remote_url(group_path, repo_name)

	render_template(w, "repo_index", params)
}
// SPDX-License-Identifier: AGPL-3.0-only
// SPDX-FileContributor: Runxi Yu <https://runxiyu.org>

package main

import (
	"net/url"
	"path"
	"strings"
	"net/url"
)

func first_line(s string) string {
	before, _, _ := strings.Cut(s, "\n")
	return before
}

func base_name(s string) string {
	return path.Base(s)
}

func path_escape(s string) string {
	return url.PathEscape(s)
}

func query_escape(s string) string {
	return url.QueryEscape(s)
}
// SPDX-License-Identifier: AGPL-3.0-only
// SPDX-FileContributor: Runxi Yu <https://runxiyu.org>

package main

import (
	"embed"
	"html/template"
	"io/fs"
	"net/http"
)

// We embed all source for easy AGPL compliance.
//
//go:embed .gitignore .gitattributes
//go:embed LICENSE README.md
//go:embed *.go go.mod go.sum
//go:embed *.scfg
//go:embed Makefile
//go:embed static/* templates/* scripts/* sql/*
//go:embed git_hooks_client/*.c
//go:embed vendor/*
var source_fs embed.FS

var source_handler = http.StripPrefix(
	"/:/source/",
	http.FileServer(http.FS(source_fs)),
)

//go:embed templates/* static/* git_hooks_client/git_hooks_client
var resources_fs embed.FS

var templates *template.Template

func load_templates() (err error) {
	templates, err = template.New("templates").Funcs(template.FuncMap{
		"first_line": first_line,
		"base_name":  base_name,
		"path_escape": path_escape,
		"first_line":   first_line,
		"base_name":    base_name,
		"path_escape":  path_escape,
		"query_escape": query_escape,
	}).ParseFS(resources_fs, "templates/*")
	return err
}

var static_handler http.Handler

func init() {
	static_fs, err := fs.Sub(resources_fs, "static")
	if err != nil {
		panic(err)
	}
	static_handler = http.StripPrefix("/:/static/", http.FileServer(http.FS(static_fs)))
}
{{/*
	SPDX-License-Identifier: AGPL-3.0-only
	SPDX-FileContributor: Runxi Yu <https://runxiyu.org>
*/}}
{{- define "repo_index" -}}
<!DOCTYPE html>
<html lang="en">
	<head>
		{{ template "head_common" . }}
		<title>{{ .repo_name }} &ndash; {{ template "group_path_plain" .group_path }} &ndash; {{ .global.forge_title }}</title>
	</head>
	<body class="repo-index">
		{{ template "header" . }}
		<div class="padding-wrapper">
			<table id="repo-info-table">
				<thead>
					<tr class="title-row">
						<th colspan="2">Repo info</th>
					</tr>
				</thead>
				<tbody>
					<tr>
						<th scope="row">Name</th>
						<td>{{ .repo_name }}</td>
					</tr>
					{{ if .repo_description }}
						<tr>
							<th scope="row">Description</th>
							<td>{{ .repo_description }}</td>
						</tr>
					{{ end }}
					<tr>
						<th scope="row">SSH remote</th>
						<td><code>{{ .ssh_clone_url }}</code></td>
					</tr>
				</tbody>
			</table>
		</div>
		<div class="padding-wrapper">
			<p>
				<a href="contrib/" class="btn-normal">Merge requests</a>
			</p>
		</div>
		<div class="padding-wrapper scroll">
			<table id="recent-commits" class="wide">
				<thead>
					<tr class="title-row">
						<th colspan="3">Recent commits (<a href="log/{{ if .ref_type }}?{{ .ref_type }}={{ .ref_name }}{{ end }}">see all</a>)</th>
					</tr>
					<tr>
						<th scope="col">Title</th>
						<th scope="col">Author</th>
						<th scope="col">Author Date</th>
					</tr>
				</thead>
				<tbody>
					{{- range .commits }}
		{{ if .commits }}
			<div class="padding-wrapper scroll">
				<table id="recent-commits" class="wide">
					<thead>
						<tr class="title-row">
							<th colspan="3">Recent commits (<a href="log/{{ if .ref_type }}?{{ .ref_type }}={{ .ref_name }}{{ end }}">see all</a>)</th>
						</tr>
						<tr>
							<td class="commit-title"><a href="commit/{{ .ID }}">{{ .Message | first_line }}</a></td>
							<td class="commit-author">
								<a class="email-name" href="mailto:{{ .Author.Email }}">{{ .Author.Name }}</a>
							</td>
							<td class="commit-time">
								{{ .Author.When.Format "2006-01-02 15:04:05 -0700" }}
							</td>
							<th scope="col">Title</th>
							<th scope="col">Author</th>
							<th scope="col">Author Date</th>
						</tr>
					{{- end }}
				</tbody>
			</table>
		</div>
		<div class="padding-wrapper scroll">
			<table id="file-tree" class="wide">
				<thead>
					<tr class="title-row">
						<th colspan="3">/{{ if .ref_name }} on {{ .ref_name }}{{ end }}</th>
					</tr>
					<tr>
						<th scope="col">Mode</th>
						<th scope="col">Filename</th>
						<th scope="col">Size</th>
					</tr>
				</thead>
				<tbody>
					{{- $ref_type := .ref_type }}
					{{- $ref := .ref_name }}
					{{- range .files }}
					</thead>
					<tbody>
						{{- range .commits }}
							<tr>
								<td class="commit-title"><a href="commit/{{ .ID }}">{{ .Message | first_line }}</a></td>
								<td class="commit-author">
									<a class="email-name" href="mailto:{{ .Author.Email }}">{{ .Author.Name }}</a>
								</td>
								<td class="commit-time">
									{{ .Author.When.Format "2006-01-02 15:04:05 -0700" }}
								</td>
							</tr>
						{{- end }}
					</tbody>
				</table>
			</div>
		{{ end }}
		{{ if .files }}
			<div class="padding-wrapper scroll">
				<table id="file-tree" class="wide">
					<thead>
						<tr class="title-row">
							<th colspan="3">/{{ if .ref_name }} on {{ .ref_name }}{{ end }}</th>
						</tr>
						<tr>
							<td class="file-mode">{{ .Mode }}</td>
							<td class="file-name"><a href="tree/{{ .Name }}{{ if not .Is_file }}/{{ end }}{{ if $ref_type }}?{{ $ref_type }}={{ $ref }}{{ end }}">{{ .Name }}</a>{{ if not .Is_file }}/{{ end }}</td>
							<td class="file-size">{{ .Size }}</td>
							<th scope="col">Mode</th>
							<th scope="col">Filename</th>
							<th scope="col">Size</th>
						</tr>
					{{- end }}
				</tbody>
			</table>
		</div>
		<div class="padding-wrapper" id="readme">
			{{ .readme }}
		</div>
					</thead>
					<tbody>
						{{- $ref_type := .ref_type }}
						{{- $ref := .ref_name }}
						{{- range .files }}
							<tr>
								<td class="file-mode">{{ .Mode }}</td>
								<td class="file-name"><a href="tree/{{ .Name }}{{ if not .Is_file }}/{{ end }}{{ if $ref_type }}?{{ $ref_type }}={{ $ref }}{{ end }}">{{ .Name }}</a>{{ if not .Is_file }}/{{ end }}</td>
								<td class="file-size">{{ .Size }}</td>
							</tr>
						{{- end }}
					</tbody>
				</table>
			</div>
		{{ end }}
		{{ if .readme }}
			<div class="padding-wrapper" id="readme">
				{{ .readme }}
			</div>
		{{ end }}
		<footer>
			{{ template "footer" . }}
		</footer>
	</body>
</html>
{{- end -}}