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  }