code.gitea.io/gitea@v1.22.3/modules/git/blob_nogogit.go (about) 1 // Copyright 2020 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 //go:build !gogit 5 6 package git 7 8 import ( 9 "bufio" 10 "bytes" 11 "io" 12 13 "code.gitea.io/gitea/modules/log" 14 ) 15 16 // Blob represents a Git object. 17 type Blob struct { 18 ID ObjectID 19 20 gotSize bool 21 size int64 22 name string 23 repo *Repository 24 } 25 26 // DataAsync gets a ReadCloser for the contents of a blob without reading it all. 27 // Calling the Close function on the result will discard all unread output. 28 func (b *Blob) DataAsync() (io.ReadCloser, error) { 29 wr, rd, cancel, err := b.repo.CatFileBatch(b.repo.Ctx) 30 if err != nil { 31 return nil, err 32 } 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, err := b.repo.CatFileBatchCheck(b.repo.Ctx) 71 if err != nil { 72 log.Debug("error whilst reading size for %s in %s. Error: %v", b.ID.String(), b.repo.Path, err) 73 return 0 74 } 75 defer cancel() 76 _, err = wr.Write([]byte(b.ID.String() + "\n")) 77 if err != nil { 78 log.Debug("error whilst reading size for %s in %s. Error: %v", b.ID.String(), b.repo.Path, err) 79 return 0 80 } 81 _, _, b.size, err = ReadBatchLine(rd) 82 if err != nil { 83 log.Debug("error whilst reading size for %s in %s. Error: %v", b.ID.String(), b.repo.Path, err) 84 return 0 85 } 86 87 b.gotSize = true 88 89 return b.size 90 } 91 92 type blobReader struct { 93 rd *bufio.Reader 94 n int64 95 cancel func() 96 } 97 98 func (b *blobReader) Read(p []byte) (n int, err error) { 99 if b.n <= 0 { 100 return 0, io.EOF 101 } 102 if int64(len(p)) > b.n { 103 p = p[0:b.n] 104 } 105 n, err = b.rd.Read(p) 106 b.n -= int64(n) 107 return n, err 108 } 109 110 // Close implements io.Closer 111 func (b *blobReader) Close() error { 112 if b.rd == nil { 113 return nil 114 } 115 116 defer b.cancel() 117 118 if err := DiscardFull(b.rd, b.n+1); err != nil { 119 return err 120 } 121 122 b.rd = nil 123 124 return nil 125 }