This repository has no description
1.4 kB
80 lines
1// Copyright 2021 The Gitea Authors. All rights reserved.
2// SPDX-License-Identifier: MIT
3
4package gitea
5
6import (
7 "bufio"
8 "bytes"
9 "context"
10 "io"
11
12 "github.com/go-git/go-git/v5/plumbing"
13)
14
15// ReadBlob returns blob size and [io.ReadCloser] of that blob.
16func ReadBlob(ctx context.Context, repoPath string, hash plumbing.Hash) (int64, io.ReadCloser, error) {
17 wr, rd, cancel := CatFileBatch(ctx, repoPath)
18
19 _, err := wr.Write([]byte(hash.String() + "\n"))
20 if err != nil {
21 cancel()
22 return 0, nil, err
23 }
24 _, _, size, err := ReadBatchLine(rd)
25 if err != nil {
26 cancel()
27 return 0, nil, err
28 }
29
30 if size < 4096 {
31 bs, err := io.ReadAll(io.LimitReader(rd, size))
32 defer cancel()
33 if err != nil {
34 return 0, nil, err
35 }
36 _, err = rd.Discard(1)
37 return size, io.NopCloser(bytes.NewReader(bs)), err
38 }
39
40 return size, &blobReader{
41 rd: rd,
42 n: size,
43 cancel: cancel,
44 }, nil
45}
46
47type blobReader struct {
48 rd *bufio.Reader
49 n int64
50 cancel func()
51}
52
53func (b *blobReader) Read(p []byte) (n int, err error) {
54 if b.n <= 0 {
55 return 0, io.EOF
56 }
57 if int64(len(p)) > b.n {
58 p = p[0:b.n]
59 }
60 n, err = b.rd.Read(p)
61 b.n -= int64(n)
62 return n, err
63}
64
65// Close implements io.Closer
66func (b *blobReader) Close() error {
67 if b.rd == nil {
68 return nil
69 }
70
71 defer b.cancel()
72
73 if err := DiscardFull(b.rd, b.n+1); err != nil {
74 return err
75 }
76
77 b.rd = nil
78
79 return nil
80}