This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / knotmirror / xrpc / gitea / blob.go
2.6 kB 122 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 "github.com/go-git/go-git/v5/plumbing/filemode" 14 "github.com/go-git/go-git/v5/plumbing/object" 15 "github.com/samber/lo" 16) 17 18func GetBlobSize(ctx context.Context, repoPath string, hash plumbing.Hash) (int64, error) { 19 wr, rd, cancel := CatFileBatchCheck(ctx, repoPath) 20 defer cancel() 21 if _, err := wr.Write([]byte(hash.String() + "\n")); err != nil { 22 return 0, err 23 } 24 _, _, size, err := ReadBatchLine(rd) 25 return size, err 26} 27 28func EntrySizes(ctx context.Context, repoPath string, entries []object.TreeEntry) ([]int64, error) { 29 sizes := make([]int64, len(entries)) 30 blobs := lo.Filter(lo.Range(len(entries)), func(i int, _ int) bool { 31 return isBlobMode(entries[i].Mode) 32 }) 33 if len(blobs) == 0 { 34 return sizes, nil 35 } 36 wr, rd, cancel := CatFileBatchCheck(ctx, repoPath) 37 defer cancel() 38 for _, i := range blobs { 39 if _, err := wr.Write([]byte(entries[i].Hash.String() + "\n")); err != nil { 40 return sizes, err 41 } 42 _, typ, size, err := ReadBatchLine(rd) 43 if err != nil { 44 return sizes, err 45 } 46 if typ == "blob" { 47 sizes[i] = size 48 } 49 } 50 return sizes, nil 51} 52 53func isBlobMode(mode filemode.FileMode) bool { 54 return mode == filemode.Regular || mode == filemode.Executable || mode == filemode.Symlink 55} 56 57// ReadBlob returns blob size and [io.ReadCloser] of that blob. 58func ReadBlob(ctx context.Context, repoPath string, hash plumbing.Hash) (int64, io.ReadCloser, error) { 59 wr, rd, cancel := CatFileBatch(ctx, repoPath) 60 61 _, err := wr.Write([]byte(hash.String() + "\n")) 62 if err != nil { 63 cancel() 64 return 0, nil, err 65 } 66 _, _, size, err := ReadBatchLine(rd) 67 if err != nil { 68 cancel() 69 return 0, nil, err 70 } 71 72 if size < 4096 { 73 bs, err := io.ReadAll(io.LimitReader(rd, size)) 74 defer cancel() 75 if err != nil { 76 return 0, nil, err 77 } 78 _, err = rd.Discard(1) 79 return size, io.NopCloser(bytes.NewReader(bs)), err 80 } 81 82 return size, &blobReader{ 83 rd: rd, 84 n: size, 85 cancel: cancel, 86 }, nil 87} 88 89type blobReader struct { 90 rd *bufio.Reader 91 n int64 92 cancel func() 93} 94 95func (b *blobReader) Read(p []byte) (n int, err error) { 96 if b.n <= 0 { 97 return 0, io.EOF 98 } 99 if int64(len(p)) > b.n { 100 p = p[0:b.n] 101 } 102 n, err = b.rd.Read(p) 103 b.n -= int64(n) 104 return n, err 105} 106 107// Close implements io.Closer 108func (b *blobReader) Close() error { 109 if b.rd == nil { 110 return nil 111 } 112 113 defer b.cancel() 114 115 if err := DiscardFull(b.rd, b.n+1); err != nil { 116 return err 117 } 118 119 b.rd = nil 120 121 return nil 122}