Lindenii Project Forge
Commit info | |
---|---|
ID | b63917094e6a69c8c01f9e7df8716f3d5fc42385 |
Author | Runxi Yu<me@runxiyu.org> |
Author date | Fri, 07 Mar 2025 19:20:54 +0800 |
Committer | Runxi Yu<me@runxiyu.org> |
Committer date | Fri, 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 }} – {{ template "group_path_plain" .group_path }} – {{ .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 -}}