mirror of https://github.com/harness/drone.git
183 lines
4.5 KiB
Go
183 lines
4.5 KiB
Go
package gitrpc
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
|
|
"github.com/harness/gitness/internal/gitrpc/rpc"
|
|
)
|
|
|
|
type repositoryService struct {
|
|
rpc.UnimplementedRepositoryServiceServer
|
|
adapter gitAdapter
|
|
store UploadStore
|
|
}
|
|
|
|
//nolint:funlen,gocognit // needs to refactor this code
|
|
func (s repositoryService) CreateRepository(stream rpc.RepositoryService_CreateRepositoryServer) error {
|
|
repoRoot := getRepoRoot()
|
|
// first get repo params from stream
|
|
req, err := stream.Recv()
|
|
if err != nil {
|
|
return status.Errorf(codes.Unknown, "cannot receive create repository data")
|
|
}
|
|
|
|
repo := req.GetRepository()
|
|
log.Info().Msgf("receive an create repository request %v", repo)
|
|
targetPath := filepath.Join(repoRoot, repo.Name)
|
|
if _, err = os.Stat(targetPath); !os.IsNotExist(err) {
|
|
return fmt.Errorf("repository exists already: %v", targetPath)
|
|
}
|
|
|
|
// create repository in repos folder
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
err = s.adapter.InitRepository(ctx, targetPath, true)
|
|
if err != nil {
|
|
// on error cleanup repo dir
|
|
defer func(path string) {
|
|
_ = os.RemoveAll(path)
|
|
}(targetPath)
|
|
return fmt.Errorf("CreateRepository error: %w", err)
|
|
}
|
|
|
|
// we need temp dir for cloning
|
|
tempDir, err := os.MkdirTemp("", "*-"+repo.Name)
|
|
if err != nil {
|
|
return fmt.Errorf("error creating temp dir for repo %s: %w", repo.Name, err)
|
|
}
|
|
defer func(path string) {
|
|
// when repo is successfully created remove temp dir
|
|
_ = os.RemoveAll(path)
|
|
}(tempDir)
|
|
|
|
// Clone repository to temp dir
|
|
if err = s.adapter.Clone(ctx, targetPath, tempDir, cloneRepoOption{}); err != nil {
|
|
return err
|
|
}
|
|
|
|
// logic for receiving the files
|
|
files := make([]string, 0, 16)
|
|
for {
|
|
log.Info().Msg("waiting to receive filepath data")
|
|
req, err = stream.Recv()
|
|
if errors.Is(err, io.EOF) {
|
|
log.Info().Msg("EOF found")
|
|
break
|
|
}
|
|
// get file path message
|
|
filePath := req.GetFilepath()
|
|
log.Info().Msgf("receiving file %s", filePath)
|
|
// work with file content chunks
|
|
fileData := bytes.Buffer{}
|
|
fileSize := 0
|
|
for {
|
|
log.Info().Msg("waiting to receive more data")
|
|
|
|
req, err = stream.Recv()
|
|
if errors.Is(err, io.EOF) {
|
|
log.Print("no more data")
|
|
break
|
|
}
|
|
|
|
chunk := req.GetChunkData()
|
|
size := len(chunk)
|
|
|
|
if len("EOF") == size && chunk[0] == 'E' && chunk[1] == 'O' && chunk[2] == 'F' {
|
|
break
|
|
}
|
|
|
|
log.Printf("received a chunk with size: %d", size)
|
|
fileSize += size
|
|
if fileSize > maxImageSize {
|
|
return status.Errorf(codes.InvalidArgument, "file is too large: %d > %d", fileSize, maxImageSize)
|
|
}
|
|
_, err = fileData.Write(chunk)
|
|
if err != nil {
|
|
return status.Errorf(codes.Internal, "cannot write chunk data: %v", err)
|
|
}
|
|
}
|
|
log.Info().Msgf("saving file %s in repo path %s", filePath, tempDir)
|
|
fullPath := filepath.Join(tempDir, filePath)
|
|
_, err = s.store.Save(fullPath, fileData)
|
|
if err != nil {
|
|
return status.Errorf(codes.Internal, "cannot save file to the store: %v", err)
|
|
}
|
|
files = append(files, filePath)
|
|
}
|
|
res := &rpc.CreateRepositoryResponse{
|
|
TempPath: tempDir,
|
|
}
|
|
|
|
if len(files) > 0 {
|
|
if _, err = s.AddFilesAndPush(ctx, &rpc.AddFilesAndPushRequest{
|
|
RepoPath: res.GetTempPath(),
|
|
Message: "initial commit",
|
|
Files: files,
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
err = stream.SendAndClose(res)
|
|
if err != nil {
|
|
return status.Errorf(codes.Unknown, "cannot send response: %v", err)
|
|
}
|
|
|
|
log.Info().Msgf("repository created: %s, path: %s", repo.Name, res.GetTempPath())
|
|
return nil
|
|
}
|
|
|
|
func (s repositoryService) AddFilesAndPush(
|
|
ctx context.Context,
|
|
params *rpc.AddFilesAndPushRequest,
|
|
) (*rpc.AddFilesAndPushResponse, error) {
|
|
err := s.adapter.AddFiles(params.GetRepoPath(), false, params.GetFiles()...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
now := time.Now()
|
|
err = s.adapter.Commit(params.GetRepoPath(), commitChangesOptions{
|
|
committer: &signature{
|
|
name: "enver",
|
|
email: "enver.bisevac@harness.io",
|
|
when: now,
|
|
},
|
|
author: &signature{
|
|
name: "enver",
|
|
email: "enver.bisevac@harness.io",
|
|
when: now,
|
|
},
|
|
message: params.GetMessage(),
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = s.adapter.Push(ctx, params.GetRepoPath(), pushOptions{
|
|
remote: "origin",
|
|
branch: "",
|
|
force: false,
|
|
mirror: false,
|
|
env: nil,
|
|
timeout: 0,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = os.RemoveAll(params.GetRepoPath())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &rpc.AddFilesAndPushResponse{}, nil
|
|
}
|