2020-12-17 17:00:47 +03:00
// Copyright 2020 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2020-12-17 17:00:47 +03:00
2021-08-24 19:47:09 +03:00
//go:build !gogit
2020-12-17 17:00:47 +03:00
package git
import (
"bufio"
2021-05-10 04:27:03 +03:00
"bytes"
2020-12-17 17:00:47 +03:00
"io"
2021-06-25 19:54:08 +03:00
"code.gitea.io/gitea/modules/log"
2020-12-17 17:00:47 +03:00
)
// Blob represents a Git object.
type Blob struct {
2023-12-14 00:02:00 +03:00
ID ObjectID
2020-12-17 17:00:47 +03:00
2021-05-10 04:27:03 +03:00
gotSize bool
size int64
name string
repo * Repository
2020-12-17 17:00:47 +03:00
}
// DataAsync gets a ReadCloser for the contents of a blob without reading it all.
// Calling the Close function on the result will discard all unread output.
func ( b * Blob ) DataAsync ( ) ( io . ReadCloser , error ) {
2021-11-30 23:06:32 +03:00
wr , rd , cancel := b . repo . CatFileBatch ( b . repo . Ctx )
2020-12-17 17:00:47 +03:00
2021-05-10 04:27:03 +03:00
_ , err := wr . Write ( [ ] byte ( b . ID . String ( ) + "\n" ) )
2020-12-17 17:00:47 +03:00
if err != nil {
2021-05-10 04:27:03 +03:00
cancel ( )
2020-12-17 17:00:47 +03:00
return nil , err
}
2021-05-10 04:27:03 +03:00
_ , _ , size , err := ReadBatchLine ( rd )
if err != nil {
cancel ( )
return nil , err
}
b . gotSize = true
b . size = size
2020-12-17 17:00:47 +03:00
2021-05-10 04:27:03 +03:00
if size < 4096 {
2021-09-22 08:38:34 +03:00
bs , err := io . ReadAll ( io . LimitReader ( rd , size ) )
2021-08-31 10:43:31 +03:00
defer cancel ( )
2021-05-10 04:27:03 +03:00
if err != nil {
return nil , err
}
_ , err = rd . Discard ( 1 )
2021-09-22 08:38:34 +03:00
return io . NopCloser ( bytes . NewReader ( bs ) ) , err
2021-05-10 04:27:03 +03:00
}
return & blobReader {
rd : rd ,
n : size ,
cancel : cancel ,
2021-02-04 00:36:38 +03:00
} , nil
2020-12-17 17:00:47 +03:00
}
// Size returns the uncompressed size of the blob
func ( b * Blob ) Size ( ) int64 {
if b . gotSize {
return b . size
}
2021-11-30 23:06:32 +03:00
wr , rd , cancel := b . repo . CatFileBatchCheck ( b . repo . Ctx )
2021-05-10 04:27:03 +03:00
defer cancel ( )
_ , err := wr . Write ( [ ] byte ( b . ID . String ( ) + "\n" ) )
2020-12-17 17:00:47 +03:00
if err != nil {
2021-06-25 19:54:08 +03:00
log . Debug ( "error whilst reading size for %s in %s. Error: %v" , b . ID . String ( ) , b . repo . Path , err )
2020-12-17 17:00:47 +03:00
return 0
}
2021-05-10 04:27:03 +03:00
_ , _ , b . size , err = ReadBatchLine ( rd )
2020-12-17 17:00:47 +03:00
if err != nil {
2021-06-25 19:54:08 +03:00
log . Debug ( "error whilst reading size for %s in %s. Error: %v" , b . ID . String ( ) , b . repo . Path , err )
2020-12-17 17:00:47 +03:00
return 0
}
2021-05-10 04:27:03 +03:00
2020-12-17 17:00:47 +03:00
b . gotSize = true
return b . size
}
2021-05-10 04:27:03 +03:00
type blobReader struct {
rd * bufio . Reader
n int64
cancel func ( )
}
func ( b * blobReader ) Read ( p [ ] byte ) ( n int , err error ) {
if b . n <= 0 {
return 0 , io . EOF
}
if int64 ( len ( p ) ) > b . n {
p = p [ 0 : b . n ]
}
n , err = b . rd . Read ( p )
b . n -= int64 ( n )
2022-06-20 13:02:49 +03:00
return n , err
2021-05-10 04:27:03 +03:00
}
// Close implements io.Closer
func ( b * blobReader ) Close ( ) error {
2024-02-24 14:45:59 +03:00
if b . rd == nil {
return nil
}
2021-08-31 10:43:31 +03:00
defer b . cancel ( )
2024-02-22 06:48:19 +03:00
2024-02-24 14:45:59 +03:00
if err := DiscardFull ( b . rd , b . n + 1 ) ; err != nil {
return err
}
b . rd = nil
return nil
2021-05-10 04:27:03 +03:00
}