Keep candidate object inspection offline
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -95,11 +96,11 @@ func ReadTree(ctx context.Context, repositoryDir, commit string) ([]TreeEntry, e
|
||||
if !validObjectID(commit) {
|
||||
return nil, fmt.Errorf("invalid commit object ID %q", commit)
|
||||
}
|
||||
output, err := run(ctx, repositoryDir, nil, "ls-tree", "-r", "-z", "--full-tree", commit)
|
||||
output, err := readLocalObjects(ctx, repositoryDir, nil, "ls-tree", "-r", "-z", "--full-tree", commit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("enumerate committed tree %s: %w", commit, err)
|
||||
}
|
||||
entries, err := parseTreeEntries([]byte(output))
|
||||
entries, err := parseTreeEntries(output)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse committed tree %s: %w", commit, err)
|
||||
}
|
||||
@@ -115,11 +116,11 @@ func ReadBlob(ctx context.Context, repositoryDir, objectID string) ([]byte, erro
|
||||
if !validObjectID(objectID) {
|
||||
return nil, fmt.Errorf("invalid blob object ID %q", objectID)
|
||||
}
|
||||
content, err := run(ctx, repositoryDir, nil, "cat-file", "blob", objectID)
|
||||
content, err := readLocalObjects(ctx, repositoryDir, nil, "cat-file", "blob", objectID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read blob %s: %w", objectID, err)
|
||||
}
|
||||
return []byte(content), nil
|
||||
return content, nil
|
||||
}
|
||||
|
||||
func parseTreeEntries(output []byte) ([]TreeEntry, error) {
|
||||
@@ -163,28 +164,21 @@ func populateBlobSizes(ctx context.Context, repositoryDir string, entries []Tree
|
||||
if len(blobIndexes) == 0 {
|
||||
return nil
|
||||
}
|
||||
var stdout, stderr bytes.Buffer
|
||||
err := process.Run(ctx, process.Invocation{
|
||||
Args: []string{"git", "cat-file", "--batch-check=%(objectname) %(objecttype) %(objectsize)"},
|
||||
Dir: repositoryDir,
|
||||
Stdin: strings.NewReader(input.String()),
|
||||
Stdout: &stdout,
|
||||
Stderr: &stderr,
|
||||
})
|
||||
output, err := readLocalObjects(ctx, repositoryDir, strings.NewReader(input.String()),
|
||||
"cat-file", "--batch-check=%(objectname) %(objecttype) %(objectsize)")
|
||||
if err != nil {
|
||||
message := strings.TrimSpace(stderr.String())
|
||||
if message != "" {
|
||||
return fmt.Errorf("git cat-file --batch-check: %s: %w", message, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
lines := strings.Split(strings.TrimSuffix(stdout.String(), "\n"), "\n")
|
||||
lines := strings.Split(strings.TrimSuffix(string(output), "\n"), "\n")
|
||||
if len(lines) != len(blobIndexes) {
|
||||
return fmt.Errorf("git returned %d blob sizes for %d blobs", len(lines), len(blobIndexes))
|
||||
}
|
||||
for index, line := range lines {
|
||||
fields := strings.Fields(line)
|
||||
entry := &entries[blobIndexes[index]]
|
||||
if len(fields) == 2 && fields[0] == entry.ObjectID && fields[1] == "missing" {
|
||||
return fmt.Errorf("committed blob %s is unavailable locally", entry.ObjectID)
|
||||
}
|
||||
if len(fields) != 3 || fields[0] != entry.ObjectID || fields[1] != "blob" {
|
||||
return fmt.Errorf("unexpected blob size record %q", line)
|
||||
}
|
||||
@@ -197,3 +191,24 @@ func populateBlobSizes(ctx context.Context, repositoryDir string, entries []Tree
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// readLocalObjects keeps source inspection separate from network preparation.
|
||||
func readLocalObjects(ctx context.Context, repositoryDir string, input io.Reader, args ...string) ([]byte, error) {
|
||||
var stdout, stderr bytes.Buffer
|
||||
err := process.Run(ctx, process.Invocation{
|
||||
Args: append([]string{"git"}, args...),
|
||||
Dir: repositoryDir,
|
||||
// Disable transports as well for Git versions predating lazy-fetch control.
|
||||
Env: map[string]string{"GIT_NO_LAZY_FETCH": "1", "GIT_ALLOW_PROTOCOL": ""},
|
||||
Stdin: input,
|
||||
Stdout: &stdout,
|
||||
Stderr: &stderr,
|
||||
})
|
||||
if err != nil {
|
||||
if message := strings.TrimSpace(stderr.String()); message != "" {
|
||||
return nil, fmt.Errorf("read local Git objects: %s: %w", message, err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return stdout.Bytes(), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user