knotserver: last commit for each file
This is a super trivial implementation last commit for each file. It's slow and inefficient despite using ristretto for in-memory caching.
We should move this to storing in sqlite in the future.
MODIFIED
go.mod
MODIFIED
go.mod
@@ -11,6 +11,7 @@ github.com/bluesky-social/indigo v0.0.0-20250123072624-9e3b84fdbb20github.com/bluesky-social/jetstream v0.0.0-20241210005130-ea96859b93d1github.com/casbin/casbin/v2 v2.103.0github.com/cyphar/filepath-securejoin v0.3.3+ github.com/dgraph-io/ristretto v0.2.0github.com/dustin/go-humanize v1.0.1github.com/gliderlabs/ssh v0.3.5github.com/go-chi/chi/v5 v5.2.0@@ -81,6 +82,7 @@ github.com/multiformats/go-multihash v0.2.3 // indirectgithub.com/multiformats/go-varint v0.0.7 // indirectgithub.com/opentracing/opentracing-go v1.2.0 // indirectgithub.com/pjbgf/sha1cd v0.3.0 // indirect+ github.com/pkg/errors v0.9.1 // indirectgithub.com/pmezard/go-difflib v1.0.0 // indirectgithub.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f // indirectgithub.com/prometheus/client_golang v1.19.1 // indirect
MODIFIED
go.sum
MODIFIED
go.sum
@@ -50,6 +50,10 @@ github.com/cyphar/filepath-securejoin v0.3.3/go.mod h1:8s/MCNJREmFK0H02MF6Ihv1nakJe4L/w3WZLHNkvlYM=github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=+github.com/dgraph-io/ristretto v0.2.0 h1:XAfl+7cmoUDWW/2Lx8TGZQjjxIQ2Ley9DSf52dru4WE=+github.com/dgraph-io/ristretto v0.2.0/go.mod h1:8uBHCU/PBV4Ag0CJrP47b9Ofby5dqWNh4FicAdoqFNU=+github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y=+github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
MODIFIED
knotserver/git/git.go
MODIFIED
knotserver/git/git.go
@@ -7,12 +7,28 @@ "io""io/fs""path""sort"+ "sync""time"+ "github.com/dgraph-io/ristretto""github.com/go-git/go-git/v5""github.com/go-git/go-git/v5/plumbing""github.com/go-git/go-git/v5/plumbing/object")++var (+ commitCache *ristretto.Cache+ cacheMu sync.RWMutex+)++func init() {+ cache, _ := ristretto.NewCache(&ristretto.Config{+ NumCounters: 1e7,+ MaxCost: 1 << 30,+ BufferItems: 64,+ })+ commitCache = cache+}var (ErrBinaryFile = fmt.Errorf("binary file")@@ -277,6 +293,38 @@ }}return nil+}++func (g *GitRepo) LastCommitTime(filePath string) (*object.Commit, error) {+ cacheMu.RLock()+ if commit, exists := commitCache.Get(filePath); exists {+ cacheMu.RUnlock()+ return commit.(*object.Commit), nil+ }+ cacheMu.RUnlock()++ commitIter, err := g.r.Log(&git.LogOptions{+ From: g.h,+ PathFilter: func(s string) bool {+ return s == filePath+ },+ Order: git.LogOrderCommitterTime,+ })++ if err != nil {+ return nil, fmt.Errorf("failed to get commit log for %s: %w", filePath, err)+ }++ commit, err := commitIter.Next()+ if err != nil {+ return nil, fmt.Errorf("no commit found for %s", filePath)+ }++ cacheMu.Lock()+ commitCache.Set(filePath, commit, 1)+ cacheMu.Unlock()++ return commit, nil}func newInfoWrapper(
MODIFIED
knotserver/git/tree.go
MODIFIED
knotserver/git/tree.go
@@ -20,7 +20,7 @@ return nil, fmt.Errorf("file tree: %w", err)}if path == "" {- files = makeNiceTree(tree)+ files = g.makeNiceTree(tree)} else {o, err := tree.FindEntry(path)if err != nil {@@ -33,25 +33,33 @@ if err != nil {return nil, err}- files = makeNiceTree(subtree)+ files = g.makeNiceTree(subtree)}}return files, nil}-func makeNiceTree(t *object.Tree) []types.NiceTree {+func (g *GitRepo) makeNiceTree(t *object.Tree) []types.NiceTree {nts := []types.NiceTree{}for _, e := range t.Entries {mode, _ := e.Mode.ToOSFileMode()sz, _ := t.Size(e.Name)++ lastCommit, err := g.LastCommitTime(e.Name)+ if err != nil {+ continue+ }+nts = append(nts, types.NiceTree{- Name: e.Name,- Mode: mode.String(),- IsFile: e.Mode.IsFile(),- Size: sz,+ Name: e.Name,+ Mode: mode.String(),+ IsFile: e.Mode.IsFile(),+ Size: sz,+ LastCommit: lastCommit,})+}return nts
MODIFIED
types/tree.go
MODIFIED
types/tree.go
@@ -1,5 +1,9 @@package types+import (+ "github.com/go-git/go-git/v5/plumbing/object"+)+// A nicer git tree representation.type NiceTree struct {Name string `json:"name"`@@ -7,4 +11,6 @@ Mode string `json:"mode"`Size int64 `json:"size"`IsFile bool `json:"is_file"`IsSubtree bool `json:"is_subtree"`++ LastCommit *object.Commit `json:"last_commit,omitempty"`}