forked from tangled.org/core
this repo has no description

knotserver/git: cache just the commit hash and time

This should help alleviate the memory leakyness that was exhibited when
we stored the entire object.Commit in memory.

anirudh.fi 31c88431 f164a6f6

verified
Changed files
+40 -17
appview
pages
templates
knotserver
git
types
+2 -2
appview/pages/templates/repo/index.html
···
</a>
<time class="text-xs text-gray-500"
-
>{{ timeFmt .LastCommit.Author.When }}</time
>
</div>
</div>
···
</a>
<time class="text-xs text-gray-500"
-
>{{ timeFmt .LastCommit.Author.When }}</time
>
</div>
</div>
···
</a>
<time class="text-xs text-gray-500"
+
>{{ timeFmt .LastCommit.When }}</time
>
</div>
</div>
···
</a>
<time class="text-xs text-gray-500"
+
>{{ timeFmt .LastCommit.When }}</time
>
</div>
</div>
+2 -2
appview/pages/templates/repo/tree.html
···
<i class="w-3 h-3 fill-current" data-lucide="folder"></i>{{ .Name }}
</div>
</a>
-
<time class="text-xs text-gray-500">{{ timeFmt .LastCommit.Author.When }}</time>
</div>
</div>
{{ end }}
···
<i class="w-3 h-3" data-lucide="file"></i>{{ .Name }}
</div>
</a>
-
<time class="text-xs text-gray-500">{{ timeFmt .LastCommit.Author.When }}</time>
</div>
</div>
{{ end }}
···
<i class="w-3 h-3 fill-current" data-lucide="folder"></i>{{ .Name }}
</div>
</a>
+
<time class="text-xs text-gray-500">{{ timeFmt .LastCommit.When }}</time>
</div>
</div>
{{ end }}
···
<i class="w-3 h-3" data-lucide="file"></i>{{ .Name }}
</div>
</a>
+
<time class="text-xs text-gray-500">{{ timeFmt .LastCommit.When }}</time>
</div>
</div>
{{ end }}
+26 -11
knotserver/git/git.go
···
"os/exec"
"path"
"sort"
"strings"
"sync"
"time"
···
"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 (
···
return nil
}
-
func (g *GitRepo) LastCommitForPath(path string) (*object.Commit, error) {
cacheKey := fmt.Sprintf("%s:%s", g.h.String(), path)
cacheMu.RLock()
-
if commit, found := commitCache.Get(cacheKey); found {
cacheMu.RUnlock()
-
return commit.(*object.Commit), nil
}
cacheMu.RUnlock()
-
cmd := exec.Command("git", "-C", g.path, "log", "-1", "--format=%H", "--", path)
var out bytes.Buffer
cmd.Stdout = &out
···
return nil, fmt.Errorf("failed to get commit hash: %w", err)
}
-
commitHash := strings.TrimSpace(out.String())
-
if commitHash == "" {
return nil, fmt.Errorf("no commits found for path: %s", path)
}
hash := plumbing.NewHash(commitHash)
-
commit, err := g.r.CommitObject(hash)
-
if err != nil {
-
return nil, err
}
cacheMu.Lock()
-
commitCache.Set(cacheKey, commit, 1)
cacheMu.Unlock()
-
return commit, nil
}
func newInfoWrapper(
···
"os/exec"
"path"
"sort"
+
"strconv"
"strings"
"sync"
"time"
···
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
+
"github.com/sotangled/tangled/types"
)
var (
···
return nil
}
+
func (g *GitRepo) LastCommitForPath(path string) (*types.LastCommitInfo, error) {
cacheKey := fmt.Sprintf("%s:%s", g.h.String(), path)
cacheMu.RLock()
+
if commitInfo, found := commitCache.Get(cacheKey); found {
cacheMu.RUnlock()
+
return commitInfo.(*types.LastCommitInfo), nil
}
cacheMu.RUnlock()
+
cmd := exec.Command("git", "-C", g.path, "log", "-1", "--format=%H %ct", "--", path)
var out bytes.Buffer
cmd.Stdout = &out
···
return nil, fmt.Errorf("failed to get commit hash: %w", err)
}
+
output := strings.TrimSpace(out.String())
+
if output == "" {
return nil, fmt.Errorf("no commits found for path: %s", path)
}
+
parts := strings.SplitN(output, " ", 2)
+
if len(parts) < 2 {
+
return nil, fmt.Errorf("unexpected commit log format")
+
}
+
+
commitHash := parts[0]
+
commitTimeUnix, err := strconv.ParseInt(parts[1], 10, 64)
+
if err != nil {
+
return nil, fmt.Errorf("parsing commit time: %w", err)
+
}
+
commitTime := time.Unix(commitTimeUnix, 0)
+
hash := plumbing.NewHash(commitHash)
+
commitInfo := &types.LastCommitInfo{
+
Hash: hash,
+
Message: "",
+
When: commitTime,
}
cacheMu.Lock()
+
commitCache.Set(cacheKey, commitInfo, 1)
cacheMu.Unlock()
+
return commitInfo, nil
}
func newInfoWrapper(
+10 -2
types/tree.go
···
package types
import (
-
"github.com/go-git/go-git/v5/plumbing/object"
)
// A nicer git tree representation.
···
IsFile bool `json:"is_file"`
IsSubtree bool `json:"is_subtree"`
-
LastCommit *object.Commit `json:"last_commit,omitempty"`
}
···
package types
import (
+
"time"
+
+
"github.com/go-git/go-git/v5/plumbing"
)
// A nicer git tree representation.
···
IsFile bool `json:"is_file"`
IsSubtree bool `json:"is_subtree"`
+
LastCommit *LastCommitInfo `json:"last_commit,omitempty"`
+
}
+
+
type LastCommitInfo struct {
+
Hash plumbing.Hash
+
Message string
+
When time.Time
}