depp

No frills static page generator for Git repositories

git clone https://git.8pit.net/depp.git

  1package gitweb
  2
  3import (
  4	git "github.com/libgit2/git2go/v34"
  5
  6	"errors"
  7	"net/url"
  8	"os"
  9	"path/filepath"
 10	"strings"
 11)
 12
 13// Repo represents information required per repository.
 14type Repo struct {
 15	git        *git.Repository
 16	maxCommits uint
 17
 18	Path  string
 19	Title string
 20	URL   string
 21}
 22
 23// File name of the git description file.
 24const descFn = "description"
 25
 26func NewRepo(fp string, gitServer *url.URL, commits uint) (*Repo, error) {
 27	var err error
 28
 29	absFp, err := filepath.Abs(fp)
 30	if err != nil {
 31		return nil, err
 32	}
 33	r := &Repo{Path: absFp}
 34
 35	r.git, err = git.OpenRepository(absFp)
 36	if err != nil {
 37		return nil, err
 38	}
 39
 40	r.Title = filepath.Base(absFp)
 41	if gitServer != nil {
 42		r.URL = gitServer.String()
 43	}
 44
 45	ext := strings.LastIndex(r.Title, ".git")
 46	if ext > 0 {
 47		r.Title = r.Title[0:ext]
 48	}
 49
 50	r.maxCommits = commits
 51	return r, nil
 52}
 53
 54func (r *Repo) Tip() (*git.Commit, error) {
 55	head, err := r.git.Head()
 56	if err != nil {
 57		return nil, err
 58	}
 59
 60	oid := head.Target()
 61	commit, err := r.git.LookupCommit(oid)
 62	if err != nil {
 63		return nil, err
 64	}
 65
 66	return commit, nil
 67}
 68
 69func (r *Repo) Walk(fn func(*RepoPage) error) error {
 70	head, err := r.git.Head()
 71	if err != nil {
 72		return err
 73	}
 74
 75	indexPage, err := r.Page(head, "")
 76	if err != nil {
 77		return err
 78	}
 79
 80	// . is not included by tree.Walk()
 81	err = fn(indexPage)
 82	if err != nil {
 83		return err
 84	}
 85
 86	return indexPage.tree.Walk(func(root string, e *git.TreeEntry) error {
 87		fp := filepath.Join(root, e.Name)
 88		page, err := r.Page(head, fp)
 89		if err != nil {
 90			return err
 91		}
 92
 93		err = fn(page)
 94		if err != nil {
 95			return err
 96		}
 97
 98		return nil
 99	})
100}
101
102func (r *Repo) Page(ref *git.Reference, fp string) (*RepoPage, error) {
103	var err error
104	page := &RepoPage{Repo: *r}
105
106	oid := ref.Target()
107	page.commit, err = r.git.LookupCommit(oid)
108	if err != nil {
109		return nil, err
110	}
111
112	page.tree, err = page.commit.Tree()
113	if err != nil {
114		return nil, err
115	}
116
117	// TODO: Find out how to retrieve the TreeEntry for /
118	page.CurrentFile = RepoFile{Path: filepath.ToSlash(fp)}
119	if page.CurrentFile.Path != "" {
120		entry, err := page.tree.EntryByPath(fp)
121		if err != nil {
122			return nil, err
123		}
124		page.CurrentFile.Type = entry.Type
125
126		if page.CurrentFile.IsDir() {
127			page.tree, err = r.git.LookupTree(entry.Id)
128			if err != nil {
129				panic(err)
130				return nil, err
131			}
132		}
133	} else {
134		page.CurrentFile.Type = git.ObjectTree
135	}
136
137	return page, nil
138}
139
140func (r *Repo) Description() (string, error) {
141	fp := filepath.Join(r.Path, descFn)
142
143	desc, err := os.ReadFile(fp)
144	if errors.Is(err, os.ErrNotExist) {
145		return "", nil
146	} else if err != nil {
147		return "", err
148	}
149
150	descText := string(desc)
151	return strings.TrimSpace(descText), nil
152}