docs: code comments

Signed-off-by: jolheiser <john.olheiser@gmail.com>
ffdhall
jolheiser 2024-01-18 22:41:16 -06:00
parent 5f408c1fb1
commit 22cdff623a
Signed by: jolheiser
GPG Key ID: B853ADA5DA7BBF7A
9 changed files with 57 additions and 21 deletions

View File

@ -51,6 +51,7 @@ func PathExists(path string) (bool, error) {
return true, err return true, err
} }
// Tree returns the git tree at a given ref/rev
func (r Repo) Tree(ref string) (*object.Tree, error) { func (r Repo) Tree(ref string) (*object.Tree, error) {
g, err := r.Git() g, err := r.Git()
if err != nil { if err != nil {
@ -70,6 +71,7 @@ func (r Repo) Tree(ref string) (*object.Tree, error) {
return c.Tree() return c.Tree()
} }
// FileInfo is the information for a file in a tree
type FileInfo struct { type FileInfo struct {
Path string Path string
IsDir bool IsDir bool
@ -77,10 +79,13 @@ type FileInfo struct {
Size string Size string
} }
// Name returns the last part of the FileInfo.Path
func (f FileInfo) Name() string { func (f FileInfo) Name() string {
return filepath.Base(f.Path) return filepath.Base(f.Path)
} }
// Dir returns the given dirpath in the given ref as a slice of FileInfo
// Sorted alphabetically, dirs first
func (r Repo) Dir(ref, path string) ([]FileInfo, error) { func (r Repo) Dir(ref, path string) ([]FileInfo, error) {
t, err := r.Tree(ref) t, err := r.Tree(ref)
if err != nil { if err != nil {
@ -119,6 +124,7 @@ func (r Repo) Dir(ref, path string) ([]FileInfo, error) {
return fis, nil return fis, nil
} }
// FileContent returns the content of a file in the git tree at a given ref/rev
func (r Repo) FileContent(ref, file string) (string, error) { func (r Repo) FileContent(ref, file string) (string, error) {
t, err := r.Tree(ref) t, err := r.Tree(ref)
if err != nil { if err != nil {

View File

@ -8,11 +8,13 @@ import (
"path/filepath" "path/filepath"
) )
// RepoMeta is the meta information a Repo can have
type RepoMeta struct { type RepoMeta struct {
Description string `json:"description"` Description string `json:"description"`
Private bool `json:"private"` Private bool `json:"private"`
} }
// Update updates meta given another RepoMeta
func (m *RepoMeta) Update(meta RepoMeta) error { func (m *RepoMeta) Update(meta RepoMeta) error {
data, err := json.Marshal(meta) data, err := json.Marshal(meta)
if err != nil { if err != nil {
@ -25,13 +27,14 @@ func (r Repo) metaPath() string {
return filepath.Join(r.path, "ugit.json") return filepath.Join(r.path, "ugit.json")
} }
// SaveMeta saves the meta info of a Repo
func (r Repo) SaveMeta() error { func (r Repo) SaveMeta() error {
// Compatibility with gitweb, because why not // Compatibility with gitweb, because why not
// Ignoring the error because it's not technically detrimental to ugit // Ignoring the error because it's not technically detrimental to ugit
desc, err := os.Create(filepath.Join(r.path, "description")) desc, err := os.Create(filepath.Join(r.path, "description"))
if err == nil { if err == nil {
defer desc.Close() defer desc.Close()
desc.WriteString(r.Meta.Description) _, _ = desc.WriteString(r.Meta.Description)
} }
fi, err := os.Create(r.metaPath()) fi, err := os.Create(r.metaPath())

View File

@ -20,16 +20,19 @@ import (
"github.com/go-git/go-git/v5/utils/ioutil" "github.com/go-git/go-git/v5/utils/ioutil"
) )
// ReadWriteContexter is the interface required to operate on git protocols
type ReadWriteContexter interface { type ReadWriteContexter interface {
io.ReadWriteCloser io.ReadWriteCloser
Context() context.Context Context() context.Context
} }
// Protocol handles the endpoint and server of the git protocols
type Protocol struct { type Protocol struct {
endpoint *transport.Endpoint endpoint *transport.Endpoint
server transport.Transport server transport.Transport
} }
// NewProtocol constructs a Protocol for a given repo
func NewProtocol(repoPath string) (Protocol, error) { func NewProtocol(repoPath string) (Protocol, error) {
endpoint, err := transport.NewEndpoint("/") endpoint, err := transport.NewEndpoint("/")
if err != nil { if err != nil {
@ -44,6 +47,7 @@ func NewProtocol(repoPath string) (Protocol, error) {
}, nil }, nil
} }
// HTTPInfoRefs handles the inforef part of the HTTP protocol
func (p Protocol) HTTPInfoRefs(rwc ReadWriteContexter) error { func (p Protocol) HTTPInfoRefs(rwc ReadWriteContexter) error {
session, err := p.server.NewUploadPackSession(p.endpoint, nil) session, err := p.server.NewUploadPackSession(p.endpoint, nil)
if err != nil { if err != nil {
@ -73,10 +77,12 @@ func (p Protocol) infoRefs(rwc ReadWriteContexter, session transport.UploadPackS
return nil return nil
} }
// HTTPUploadPack handles the upload-pack process for HTTP
func (p Protocol) HTTPUploadPack(rwc ReadWriteContexter) error { func (p Protocol) HTTPUploadPack(rwc ReadWriteContexter) error {
return p.uploadPack(rwc, false) return p.uploadPack(rwc, false)
} }
// SSHUploadPack handles the upload-pack process for SSH
func (p Protocol) SSHUploadPack(rwc ReadWriteContexter) error { func (p Protocol) SSHUploadPack(rwc ReadWriteContexter) error {
return p.uploadPack(rwc, true) return p.uploadPack(rwc, true)
} }
@ -112,6 +118,7 @@ func (p Protocol) uploadPack(rwc ReadWriteContexter, ssh bool) error {
return nil return nil
} }
// SSHReceivePack handles the receive-pack process for SSH
func (p Protocol) SSHReceivePack(rwc ReadWriteContexter, repo *Repo) error { func (p Protocol) SSHReceivePack(rwc ReadWriteContexter, repo *Repo) error {
buf := bufio.NewReader(rwc) buf := bufio.NewReader(rwc)
@ -213,6 +220,7 @@ func handlePushOptions(repo *Repo, opts []*packp.Option) error {
return nil return nil
} }
// UpdateServerInfo handles updating server info for the git repo
func UpdateServerInfo(repo string) error { func UpdateServerInfo(repo string) error {
r, err := git.PlainOpen(repo) r, err := git.PlainOpen(repo)
if err != nil { if err != nil {

View File

@ -15,15 +15,18 @@ import (
"github.com/go-git/go-git/v5/plumbing/object" "github.com/go-git/go-git/v5/plumbing/object"
) )
// Repo is a git repository
type Repo struct { type Repo struct {
path string path string
Meta RepoMeta Meta RepoMeta
} }
// Name returns the human-friendly name, the dir name without the .git suffix
func (r Repo) Name() string { func (r Repo) Name() string {
return strings.TrimSuffix(filepath.Base(r.path), ".git") return strings.TrimSuffix(filepath.Base(r.path), ".git")
} }
// NewRepo constructs a Repo given a dir and name
func NewRepo(dir, name string) (*Repo, error) { func NewRepo(dir, name string) (*Repo, error) {
if !strings.HasSuffix(name, ".git") { if !strings.HasSuffix(name, ".git") {
name += ".git" name += ".git"
@ -98,6 +101,7 @@ type Commit struct {
Author string Author string
Email string Email string
When time.Time When time.Time
// Extra // Extra
Stats CommitStats Stats CommitStats
Patch string Patch string
@ -125,19 +129,22 @@ type CommitFileEntry struct {
Commit string Commit string
} }
// Short returns the first eight characters of the SHA
func (c Commit) Short() string { func (c Commit) Short() string {
return c.SHA[:8] return c.SHA[:8]
} }
// Summary returns the first line of the commit, suitable for a <summary>
func (c Commit) Summary() string { func (c Commit) Summary() string {
return strings.Split(c.Message, "\n")[0] return strings.Split(c.Message, "\n")[0]
} }
// Details returns all lines *after* the first, suitable for <details>
func (c Commit) Details() string { func (c Commit) Details() string {
return strings.Join(strings.Split(c.Message, "\n")[1:], "\n") return strings.Join(strings.Split(c.Message, "\n")[1:], "\n")
} }
// Commit gets a specific commit by SHA // Commit gets a specific commit by SHA, including all commit information
func (r Repo) Commit(sha string) (Commit, error) { func (r Repo) Commit(sha string) (Commit, error) {
repo, err := r.Git() repo, err := r.Git()
if err != nil { if err != nil {
@ -147,7 +154,7 @@ func (r Repo) Commit(sha string) (Commit, error) {
return commit(repo, sha, true) return commit(repo, sha, true)
} }
// LastCommit returns the last commit of the repo // LastCommit returns the last commit of the repo without any extra information
func (r Repo) LastCommit() (Commit, error) { func (r Repo) LastCommit() (Commit, error) {
repo, err := r.Git() repo, err := r.Git()
if err != nil { if err != nil {
@ -313,15 +320,8 @@ func (r Repo) Tags() ([]Tag, error) {
var tags []Tag var tags []Tag
if err := tgs.ForEach(func(tag *plumbing.Reference) error { if err := tgs.ForEach(func(tag *plumbing.Reference) error {
obj, err := repo.TagObject(tag.Hash()) obj, err := repo.TagObject(tag.Hash())
switch err { switch {
case nil: case errors.Is(err, plumbing.ErrObjectNotFound):
tags = append(tags, Tag{
Name: obj.Name,
Annotation: obj.Message,
Signature: obj.PGPSignature,
When: obj.Tagger.When,
})
case plumbing.ErrObjectNotFound:
commit, err := repo.CommitObject(tag.Hash()) commit, err := repo.CommitObject(tag.Hash())
if err != nil { if err != nil {
return err return err
@ -332,6 +332,13 @@ func (r Repo) Tags() ([]Tag, error) {
Signature: commit.PGPSignature, Signature: commit.PGPSignature,
When: commit.Author.When, When: commit.Author.When,
}) })
case err == nil:
tags = append(tags, Tag{
Name: obj.Name,
Annotation: obj.Message,
Signature: obj.PGPSignature,
When: obj.Tagger.When,
})
default: default:
return err return err
} }

View File

@ -6,12 +6,11 @@ import (
"bytes" "bytes"
_ "embed" _ "embed"
"fmt" "fmt"
"go.jolheiser.com/ugit/internal/html/markup"
"go/format" "go/format"
"os" "os"
"os/exec" "os/exec"
"go.jolheiser.com/ugit/internal/html"
"github.com/alecthomas/chroma/v2/styles" "github.com/alecthomas/chroma/v2/styles"
) )
@ -33,6 +32,7 @@ func main() {
} }
} }
// Generate tailwind code from templ templates and combine with other misc CSS
func tailwind() error { func tailwind() error {
fmt.Println("generating tailwind...") fmt.Println("generating tailwind...")
@ -48,13 +48,13 @@ func tailwind() error {
fmt.Println("generating chroma styles...") fmt.Println("generating chroma styles...")
latte := styles.Get("catppuccin-latte") latte := styles.Get("catppuccin-latte")
if err := html.Formatter.WriteCSS(tmp, latte); err != nil { if err := markup.Formatter.WriteCSS(tmp, latte); err != nil {
return err return err
} }
tmp.WriteString("@media (prefers-color-scheme: dark) {") tmp.WriteString("@media (prefers-color-scheme: dark) {")
mocha := styles.Get("catppuccin-mocha") mocha := styles.Get("catppuccin-mocha")
if err := html.Formatter.WriteCSS(tmp, mocha); err != nil { if err := markup.Formatter.WriteCSS(tmp, mocha); err != nil {
return err return err
} }
tmp.WriteString("}") tmp.WriteString("}")

View File

@ -1,4 +1,4 @@
package html package markup
import ( import (
"io" "io"
@ -10,6 +10,7 @@ import (
) )
var ( var (
// Formatter is the default formatter
Formatter = html.New( Formatter = html.New(
html.WithLineNumbers(true), html.WithLineNumbers(true),
html.WithLinkableLineNumbers(true, "L"), html.WithLinkableLineNumbers(true, "L"),
@ -19,6 +20,7 @@ var (
basicFormatter = html.New( basicFormatter = html.New(
html.WithClasses(true), html.WithClasses(true),
) )
// Code is the entrypoint for formatting
Code = code{} Code = code{}
) )
@ -44,6 +46,7 @@ func (c code) setup(source []byte, fileName string) (chroma.Iterator, *chroma.St
return iter, style, nil return iter, style, nil
} }
// Basic formats code without any extras
func (c code) Basic(source []byte, fileName string, writer io.Writer) error { func (c code) Basic(source []byte, fileName string, writer io.Writer) error {
iter, style, err := c.setup(source, fileName) iter, style, err := c.setup(source, fileName)
if err != nil { if err != nil {
@ -52,6 +55,7 @@ func (c code) Basic(source []byte, fileName string, writer io.Writer) error {
return basicFormatter.Format(writer, style, iter) return basicFormatter.Format(writer, style, iter)
} }
// Convert formats code with line numbers, links, etc.
func (c code) Convert(source []byte, fileName string, writer io.Writer) error { func (c code) Convert(source []byte, fileName string, writer io.Writer) error {
iter, style, err := c.setup(source, fileName) iter, style, err := c.setup(source, fileName)
if err != nil { if err != nil {

View File

@ -1,4 +1,4 @@
package html package markup
import ( import (
"bytes" "bytes"
@ -48,6 +48,7 @@ var markdown = goldmark.New(
), ),
) )
// Readme transforms a readme, potentially from markdown, into HTML
func Readme(repo *git.Repo, ref, path string) (string, error) { func Readme(repo *git.Repo, ref, path string) (string, error) {
var readme string var readme string
var err error var err error
@ -98,6 +99,9 @@ type markdownContext struct {
type astTransformer struct{} type astTransformer struct{}
// Transform does two main things
// 1. Changes images to work relative to the source and wraps them in links
// 2. Changes links to work relative to the source
func (a astTransformer) Transform(node *ast.Document, _ text.Reader, pc parser.Context) { func (a astTransformer) Transform(node *ast.Document, _ text.Reader, pc parser.Context) {
_ = ast.Walk(node, func(n ast.Node, entering bool) (ast.WalkStatus, error) { _ = ast.Walk(node, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering { if !entering {

View File

@ -20,14 +20,17 @@ func (h httpError) Unwrap() error {
return h.err return h.err
} }
// Error returns a generic 500 error
func Error(err error) httpError { func Error(err error) httpError {
return Status(err, http.StatusInternalServerError) return Status(err, http.StatusInternalServerError)
} }
// Status returns a set status with the error
func Status(err error, status int) httpError { func Status(err error, status int) httpError {
return httpError{err: err, status: status} return httpError{err: err, status: status}
} }
// Handler transforms an http handler + error into a stdlib handler
func Handler(fn func(w http.ResponseWriter, r *http.Request) error) http.HandlerFunc { func Handler(fn func(w http.ResponseWriter, r *http.Request) error) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
if err := fn(w, r); err != nil { if err := fn(w, r); err != nil {

View File

@ -3,6 +3,7 @@ package http
import ( import (
"bytes" "bytes"
"errors" "errors"
"go.jolheiser.com/ugit/internal/html/markup"
"io/fs" "io/fs"
"mime" "mime"
"net/http" "net/http"
@ -46,7 +47,7 @@ func (rh repoHandler) repoTree(ref, path string) http.HandlerFunc {
return httperr.Error(err) return httperr.Error(err)
} }
readmeContent, err := html.Readme(repo, ref, path) readmeContent, err := markup.Readme(repo, ref, path)
if err != nil { if err != nil {
return httperr.Error(err) return httperr.Error(err)
} }
@ -92,7 +93,7 @@ func (rh repoHandler) repoFile(w http.ResponseWriter, r *http.Request, repo *git
} }
var buf bytes.Buffer var buf bytes.Buffer
if err := html.Code.Convert([]byte(content), filepath.Base(path), &buf); err != nil { if err := markup.Code.Convert([]byte(content), filepath.Base(path), &buf); err != nil {
return httperr.Error(err) return httperr.Error(err)
} }
@ -195,7 +196,7 @@ func (rh repoHandler) repoCommit(w http.ResponseWriter, r *http.Request) error {
for idx, p := range commit.Files { for idx, p := range commit.Files {
var patch bytes.Buffer var patch bytes.Buffer
if err := html.Code.Basic([]byte(p.Patch), "commit.patch", &patch); err != nil { if err := markup.Code.Basic([]byte(p.Patch), "commit.patch", &patch); err != nil {
return httperr.Error(err) return httperr.Error(err)
} }
commit.Files[idx].Patch = patch.String() commit.Files[idx].Patch = patch.String()