Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
113 lines
3.2 KiB
113 lines
3.2 KiB
// Copyright 2021 The Gitea Authors. All rights reserved. |
|
// Use of this source code is governed by a MIT-style |
|
// license that can be found in the LICENSE file. |
|
|
|
//go:build !gogit |
|
// +build !gogit |
|
|
|
package lfs |
|
|
|
import ( |
|
"bufio" |
|
"context" |
|
"io" |
|
"strconv" |
|
"strings" |
|
"sync" |
|
|
|
"code.gitea.io/gitea/modules/git" |
|
"code.gitea.io/gitea/modules/git/pipeline" |
|
) |
|
|
|
// SearchPointerBlobs scans the whole repository for LFS pointer files |
|
func SearchPointerBlobs(ctx context.Context, repo *git.Repository, pointerChan chan<- PointerBlob, errChan chan<- error) { |
|
basePath := repo.Path |
|
|
|
catFileCheckReader, catFileCheckWriter := io.Pipe() |
|
shasToBatchReader, shasToBatchWriter := io.Pipe() |
|
catFileBatchReader, catFileBatchWriter := io.Pipe() |
|
|
|
wg := sync.WaitGroup{} |
|
wg.Add(4) |
|
|
|
// Create the go-routines in reverse order. |
|
|
|
// 4. Take the output of cat-file --batch and check if each file in turn |
|
// to see if they're pointers to files in the LFS store |
|
go createPointerResultsFromCatFileBatch(ctx, catFileBatchReader, &wg, pointerChan) |
|
|
|
// 3. Take the shas of the blobs and batch read them |
|
go pipeline.CatFileBatch(shasToBatchReader, catFileBatchWriter, &wg, basePath) |
|
|
|
// 2. From the provided objects restrict to blobs <=1k |
|
go pipeline.BlobsLessThan1024FromCatFileBatchCheck(catFileCheckReader, shasToBatchWriter, &wg) |
|
|
|
// 1. Run batch-check on all objects in the repository |
|
if git.CheckGitVersionAtLeast("2.6.0") != nil { |
|
revListReader, revListWriter := io.Pipe() |
|
shasToCheckReader, shasToCheckWriter := io.Pipe() |
|
wg.Add(2) |
|
go pipeline.CatFileBatchCheck(shasToCheckReader, catFileCheckWriter, &wg, basePath) |
|
go pipeline.BlobsFromRevListObjects(revListReader, shasToCheckWriter, &wg) |
|
go pipeline.RevListAllObjects(revListWriter, &wg, basePath, errChan) |
|
} else { |
|
go pipeline.CatFileBatchCheckAllObjects(catFileCheckWriter, &wg, basePath, errChan) |
|
} |
|
wg.Wait() |
|
|
|
close(pointerChan) |
|
close(errChan) |
|
} |
|
|
|
func createPointerResultsFromCatFileBatch(ctx context.Context, catFileBatchReader *io.PipeReader, wg *sync.WaitGroup, pointerChan chan<- PointerBlob) { |
|
defer wg.Done() |
|
defer catFileBatchReader.Close() |
|
|
|
bufferedReader := bufio.NewReader(catFileBatchReader) |
|
buf := make([]byte, 1025) |
|
|
|
loop: |
|
for { |
|
select { |
|
case <-ctx.Done(): |
|
break loop |
|
default: |
|
} |
|
|
|
// File descriptor line: sha |
|
sha, err := bufferedReader.ReadString(' ') |
|
if err != nil { |
|
_ = catFileBatchReader.CloseWithError(err) |
|
break |
|
} |
|
sha = strings.TrimSpace(sha) |
|
// Throw away the blob |
|
if _, err := bufferedReader.ReadString(' '); err != nil { |
|
_ = catFileBatchReader.CloseWithError(err) |
|
break |
|
} |
|
sizeStr, err := bufferedReader.ReadString('\n') |
|
if err != nil { |
|
_ = catFileBatchReader.CloseWithError(err) |
|
break |
|
} |
|
size, err := strconv.Atoi(sizeStr[:len(sizeStr)-1]) |
|
if err != nil { |
|
_ = catFileBatchReader.CloseWithError(err) |
|
break |
|
} |
|
pointerBuf := buf[:size+1] |
|
if _, err := io.ReadFull(bufferedReader, pointerBuf); err != nil { |
|
_ = catFileBatchReader.CloseWithError(err) |
|
break |
|
} |
|
pointerBuf = pointerBuf[:size] |
|
// Now we need to check if the pointerBuf is an LFS pointer |
|
pointer, _ := ReadPointerFromBuffer(pointerBuf) |
|
if !pointer.IsValid() { |
|
continue |
|
} |
|
|
|
pointerChan <- PointerBlob{Hash: sha, Pointer: pointer} |
|
} |
|
}
|
|
|