Read files from captured Git commits
This commit is contained in:
72
internal/validation/tree.go
Normal file
72
internal/validation/tree.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package validation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"gitea.maximumdirect.net/eric/ReleaseKit/internal/git"
|
||||
)
|
||||
|
||||
// CandidateTree is an inventory of one captured commit with blob contents
|
||||
// loaded lazily by object ID.
|
||||
type CandidateTree struct {
|
||||
repositoryDir string
|
||||
entries []git.TreeEntry
|
||||
byPath map[string]int
|
||||
blobs map[string][]byte
|
||||
}
|
||||
|
||||
// ReadCandidateTree enumerates the captured commit without reading from the
|
||||
// worktree.
|
||||
func ReadCandidateTree(ctx context.Context, repositoryDir, commit string) (*CandidateTree, error) {
|
||||
entries, err := git.ReadTree(ctx, repositoryDir, commit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tree := &CandidateTree{
|
||||
repositoryDir: repositoryDir,
|
||||
entries: entries,
|
||||
byPath: make(map[string]int, len(entries)),
|
||||
blobs: make(map[string][]byte),
|
||||
}
|
||||
for index, entry := range entries {
|
||||
tree.byPath[entry.Path] = index
|
||||
}
|
||||
return tree, nil
|
||||
}
|
||||
|
||||
// Entries returns the committed tree metadata in Git's tree order.
|
||||
func (tree *CandidateTree) Entries() []git.TreeEntry {
|
||||
return append([]git.TreeEntry(nil), tree.entries...)
|
||||
}
|
||||
|
||||
// ReadFile returns the committed blob bytes for path. Contents are cached by
|
||||
// object ID for later reads from this tree.
|
||||
func (tree *CandidateTree) ReadFile(ctx context.Context, path string) ([]byte, error) {
|
||||
index, ok := tree.byPath[path]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("committed path %q does not exist", path)
|
||||
}
|
||||
entry := tree.entries[index]
|
||||
if entry.Type != "blob" {
|
||||
return nil, fmt.Errorf("committed path %q is a %s entry, not a blob", path, entry.Type)
|
||||
}
|
||||
if contents, ok := tree.blobs[entry.ObjectID]; ok {
|
||||
return append([]byte(nil), contents...), nil
|
||||
}
|
||||
contents, err := git.ReadBlob(ctx, tree.repositoryDir, entry.ObjectID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read committed path %q: %w", path, err)
|
||||
}
|
||||
tree.blobs[entry.ObjectID] = append([]byte(nil), contents...)
|
||||
return contents, nil
|
||||
}
|
||||
|
||||
// Entry returns the committed metadata for path when present.
|
||||
func (tree *CandidateTree) Entry(path string) (git.TreeEntry, bool) {
|
||||
index, ok := tree.byPath[path]
|
||||
if !ok {
|
||||
return git.TreeEntry{}, false
|
||||
}
|
||||
return tree.entries[index], true
|
||||
}
|
||||
Reference in New Issue
Block a user