Release validation source bytes after checks
This commit is contained in:
@@ -13,14 +13,14 @@ import (
|
||||
// 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
|
||||
directories map[string]struct{}
|
||||
blobs map[string][]byte
|
||||
blobReader *git.BlobReader
|
||||
closed bool
|
||||
closeErr error
|
||||
repositoryDir string
|
||||
entries []git.TreeEntry
|
||||
byPath map[string]int
|
||||
directories map[string]struct{}
|
||||
blobReader *git.BlobReader
|
||||
symlinkTargets map[string]string
|
||||
closed bool
|
||||
closeErr error
|
||||
}
|
||||
|
||||
// ReadCandidateTree enumerates the captured commit without reading from the
|
||||
@@ -31,11 +31,11 @@ func ReadCandidateTree(ctx context.Context, repositoryDir, commit string) (*Cand
|
||||
return nil, err
|
||||
}
|
||||
tree := &CandidateTree{
|
||||
repositoryDir: repositoryDir,
|
||||
entries: entries,
|
||||
byPath: make(map[string]int, len(entries)),
|
||||
directories: make(map[string]struct{}),
|
||||
blobs: make(map[string][]byte),
|
||||
repositoryDir: repositoryDir,
|
||||
entries: entries,
|
||||
byPath: make(map[string]int, len(entries)),
|
||||
directories: make(map[string]struct{}),
|
||||
symlinkTargets: make(map[string]string),
|
||||
}
|
||||
tree.directories["."] = struct{}{}
|
||||
for index, entry := range entries {
|
||||
@@ -52,8 +52,9 @@ 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.
|
||||
// ReadFile returns newly allocated, caller-owned bytes for a committed blob.
|
||||
// Regular-file content is not cached, so repeated reads request the object
|
||||
// again through the tree's scoped blob reader.
|
||||
func (tree *CandidateTree) ReadFile(ctx context.Context, path string) ([]byte, error) {
|
||||
if tree.closed {
|
||||
return nil, fmt.Errorf("read committed path %q: candidate tree is closed", path)
|
||||
@@ -66,8 +67,41 @@ func (tree *CandidateTree) ReadFile(ctx context.Context, path string) ([]byte, e
|
||||
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
|
||||
if entry.Mode == "120000" {
|
||||
target, err := tree.readSymlinkTarget(ctx, entry)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []byte(target), nil
|
||||
}
|
||||
return tree.readBlob(ctx, entry)
|
||||
}
|
||||
|
||||
func (tree *CandidateTree) readSymlinkTarget(ctx context.Context, entry git.TreeEntry) (string, error) {
|
||||
if tree.closed {
|
||||
return "", fmt.Errorf("read committed path %q: candidate tree is closed", entry.Path)
|
||||
}
|
||||
if entry.Type != "blob" || entry.Mode != "120000" {
|
||||
return "", fmt.Errorf("committed path %q is not a symlink blob", entry.Path)
|
||||
}
|
||||
if target, ok := tree.symlinkTargets[entry.ObjectID]; ok {
|
||||
return target, nil
|
||||
}
|
||||
contents, err := tree.readBlob(ctx, entry)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
target := string(contents)
|
||||
if tree.symlinkTargets == nil {
|
||||
tree.symlinkTargets = make(map[string]string)
|
||||
}
|
||||
tree.symlinkTargets[entry.ObjectID] = target
|
||||
return target, nil
|
||||
}
|
||||
|
||||
func (tree *CandidateTree) readBlob(ctx context.Context, entry git.TreeEntry) ([]byte, error) {
|
||||
if tree.closed {
|
||||
return nil, fmt.Errorf("read committed path %q: candidate tree is closed", entry.Path)
|
||||
}
|
||||
if tree.blobReader == nil {
|
||||
// The reader belongs to the tree and can outlive an individual read
|
||||
@@ -77,12 +111,8 @@ func (tree *CandidateTree) ReadFile(ctx context.Context, path string) ([]byte, e
|
||||
}
|
||||
contents, err := tree.blobReader.Read(ctx, entry.ObjectID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read committed path %q: %w", path, err)
|
||||
return nil, fmt.Errorf("read committed path %q: %w", entry.Path, err)
|
||||
}
|
||||
if tree.blobs == nil {
|
||||
tree.blobs = make(map[string][]byte)
|
||||
}
|
||||
tree.blobs[entry.ObjectID] = append([]byte(nil), contents...)
|
||||
return contents, nil
|
||||
}
|
||||
|
||||
@@ -179,11 +209,12 @@ func (tree *CandidateTree) resolveDestination(ctx context.Context, directory str
|
||||
if active[partial] {
|
||||
return Destination{Kind: DestinationSymlinkCycle, Path: partial}, nil
|
||||
}
|
||||
linkText, err := tree.ReadFile(ctx, partial)
|
||||
entry, _ := tree.Entry(partial)
|
||||
linkText, err := tree.readSymlinkTarget(ctx, entry)
|
||||
if err != nil {
|
||||
return Destination{}, fmt.Errorf("read committed symlink %q: %w", partial, err)
|
||||
}
|
||||
target := string(linkText)
|
||||
target := linkText
|
||||
targetDirectory := directory
|
||||
if path.IsAbs(target) {
|
||||
relative, inside, err := tree.relativeAbsoluteDestination(target)
|
||||
|
||||
Reference in New Issue
Block a user