summaryrefslogtreecommitdiff
path: root/internal/storage/git_cmd_adapter.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/storage/git_cmd_adapter.go')
-rw-r--r--internal/storage/git_cmd_adapter.go42
1 files changed, 33 insertions, 9 deletions
diff --git a/internal/storage/git_cmd_adapter.go b/internal/storage/git_cmd_adapter.go
index e27fa5f..2710cb1 100644
--- a/internal/storage/git_cmd_adapter.go
+++ b/internal/storage/git_cmd_adapter.go
@@ -1,6 +1,7 @@
package storage
import (
+ "compress/zlib"
"context"
"fmt"
"io"
@@ -36,31 +37,54 @@ func (g *GitCmdAdapter) Cleanup() {
os.RemoveAll(g.tempDir)
}
-// GetObject gets a Git object using git cat-file
+// GetObject gets a Git object using git cat-file consistently
func (g *GitCmdAdapter) GetObject(ctx context.Context, repo, objectID string) ([]byte, error) {
+ log.Printf("GitCmdAdapter: Getting object %s from repo %s", objectID, repo)
repoPath, err := g.ensureRepository(ctx, repo)
if err != nil {
+ log.Printf("GitCmdAdapter: Failed to ensure repository %s: %v", repo, err)
return nil, err
}
- // Get object type first
+ // Use git cat-file to get the raw object content consistently
+ // This works for both loose objects and pack files
+ contentCmd := exec.CommandContext(ctx, "git", "--git-dir", repoPath, "cat-file", "-p", objectID)
+ content, err := contentCmd.Output()
+ if err != nil {
+ log.Printf("GitCmdAdapter: git cat-file -p failed for %s: %v", objectID, err)
+ return nil, fmt.Errorf("git cat-file -p failed for %s: %w", objectID, err)
+ }
+
+ // Get object type
typeCmd := exec.CommandContext(ctx, "git", "--git-dir", repoPath, "cat-file", "-t", objectID)
typeOutput, err := typeCmd.Output()
if err != nil {
+ log.Printf("GitCmdAdapter: git cat-file -t failed for %s: %v", objectID, err)
return nil, fmt.Errorf("git cat-file -t failed for %s: %w", objectID, err)
}
objType := strings.TrimSpace(string(typeOutput))
- // Get raw object content using type and objectID
- contentCmd := exec.CommandContext(ctx, "git", "--git-dir", repoPath, "cat-file", objType, objectID)
- content, err := contentCmd.Output()
+ // Format as Git internal object: "type size\0content"
+ header := fmt.Sprintf("%s %d\x00", objType, len(content))
+ result := append([]byte(header), content...)
+ log.Printf("GitCmdAdapter: Successfully retrieved object %s, type %s, size %d", objectID, objType, len(result))
+ return result, nil
+}
+
+// decompressObject decompresses a zlib-compressed Git object
+func (g *GitCmdAdapter) decompressObject(compressed []byte) ([]byte, error) {
+ reader, err := zlib.NewReader(strings.NewReader(string(compressed)))
+ if err != nil {
+ return nil, fmt.Errorf("failed to create zlib reader: %w", err)
+ }
+ defer reader.Close()
+
+ decompressed, err := io.ReadAll(reader)
if err != nil {
- return nil, fmt.Errorf("git cat-file failed for %s: %w", objectID, err)
+ return nil, fmt.Errorf("failed to decompress object: %w", err)
}
- // Format as Git object: "type size\0content"
- result := fmt.Sprintf("%s %d\x00", objType, len(content))
- return append([]byte(result), content...), nil
+ return decompressed, nil
}
// GetReachableObjects returns all objects reachable from the given commits