github.com/gitbundle/modules@v0.0.0-20231025071548-85b91c5c3b01/git/blob_nogogit.go (about) 1 // Copyright 2023 The GitBundle Inc. All rights reserved. 2 // Copyright 2017 The Gitea Authors. All rights reserved. 3 // Use of this source code is governed by a MIT-style 4 // license that can be found in the LICENSE file. 5 6 //go:build !gogit 7 8 package git 9 10 import ( 11 "bufio" 12 "bytes" 13 "io" 14 "math" 15 16 "github.com/gitbundle/modules/log" 17 ) 18 19 // Blob represents a Git object. 20 type Blob struct { 21 ID SHA1 22 23 gotSize bool 24 size int64 25 name string 26 repo *Repository 27 } 28 29 // DataAsync gets a ReadCloser for the contents of a blob without reading it all. 30 // Calling the Close function on the result will discard all unread output. 31 func (b *Blob) DataAsync() (io.ReadCloser, error) { 32 wr, rd, cancel := b.repo.CatFileBatch(b.repo.Ctx) 33 34 _, err := wr.Write([]byte(b.ID.String() + "\n")) 35 if err != nil { 36 cancel() 37 return nil, err 38 } 39 _, _, size, err := ReadBatchLine(rd) 40 if err != nil { 41 cancel() 42 return nil, err 43 } 44 b.gotSize = true 45 b.size = size 46 47 if size < 4096 { 48 bs, err := io.ReadAll(io.LimitReader(rd, size)) 49 defer cancel() 50 if err != nil { 51 return nil, err 52 } 53 _, err = rd.Discard(1) 54 return io.NopCloser(bytes.NewReader(bs)), err 55 } 56 57 return &blobReader{ 58 rd: rd, 59 n: size, 60 cancel: cancel, 61 }, nil 62 } 63 64 // Size returns the uncompressed size of the blob 65 func (b *Blob) Size() int64 { 66 if b.gotSize { 67 return b.size 68 } 69 70 wr, rd, cancel := b.repo.CatFileBatchCheck(b.repo.Ctx) 71 defer cancel() 72 _, err := wr.Write([]byte(b.ID.String() + "\n")) 73 if err != nil { 74 log.Debug("error whilst reading size for %s in %s. Error: %v", b.ID.String(), b.repo.Path, err) 75 return 0 76 } 77 _, _, b.size, err = ReadBatchLine(rd) 78 if err != nil { 79 log.Debug("error whilst reading size for %s in %s. Error: %v", b.ID.String(), b.repo.Path, err) 80 return 0 81 } 82 83 b.gotSize = true 84 85 return b.size 86 } 87 88 type blobReader struct { 89 rd *bufio.Reader 90 n int64 91 cancel func() 92 } 93 94 func (b *blobReader) Read(p []byte) (n int, err error) { 95 if b.n <= 0 { 96 return 0, io.EOF 97 } 98 if int64(len(p)) > b.n { 99 p = p[0:b.n] 100 } 101 n, err = b.rd.Read(p) 102 b.n -= int64(n) 103 return 104 } 105 106 // Close implements io.Closer 107 func (b *blobReader) Close() error { 108 defer b.cancel() 109 if b.n > 0 { 110 for b.n > math.MaxInt32 { 111 n, err := b.rd.Discard(math.MaxInt32) 112 b.n -= int64(n) 113 if err != nil { 114 return err 115 } 116 b.n -= math.MaxInt32 117 } 118 n, err := b.rd.Discard(int(b.n)) 119 b.n -= int64(n) 120 if err != nil { 121 return err 122 } 123 } 124 if b.n == 0 { 125 _, err := b.rd.Discard(1) 126 b.n-- 127 return err 128 } 129 return nil 130 }