Welcome to mirror list, hosted at ThFree Co, Russian Federation.

info_attributes.go « repository « service « gitaly « internal - gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 9f8f54a24b1298e80bef10ae9cd8e1f9c9d7dc18 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package repository

import (
	"bufio"
	"errors"
	"io"
	"os"
	"strings"

	"gitlab.com/gitlab-org/gitaly/v16/internal/git"
	"gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
	"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
	"gitlab.com/gitlab-org/gitaly/v16/streamio"
)

func (s *server) GetInfoAttributes(in *gitalypb.GetInfoAttributesRequest, stream gitalypb.RepositoryService_GetInfoAttributesServer) (returnedErr error) {
	repository := in.GetRepository()
	if err := s.locator.ValidateRepository(repository); err != nil {
		return structerr.NewInvalidArgument("%w", err)
	}
	repoPath, err := s.locator.GetRepoPath(repository)
	if err != nil {
		return err
	}

	// In git 2.43.0+, gitattributes supports reading from HEAD:.gitattributes,
	// so info/attributes is no longer needed. To make sure info/attributes file is cleaned up,
	// we delete it if it exists when reading from HEAD:.gitattributes is called.
	// This logic can be removed when ApplyGitattributes and GetInfoAttributes PRC are totally removed from
	// the code base.
	deletionErr := deleteInfoAttributesFile(repoPath)
	if !os.IsNotExist(deletionErr) {
		s.logger.WithError(deletionErr).Error("failed to delete info/gitattributes file at " + repoPath)
	}

	repo := s.localrepo(in.GetRepository())
	ctx := stream.Context()
	var stderr strings.Builder
	// Call cat-file -p HEAD:.gitattributes instead of cat info/attributes
	catFileCmd, err := repo.Exec(ctx, git.Command{
		Name: "cat-file",
		Flags: []git.Option{
			git.Flag{Name: "-p"},
		},
		Args: []string{"HEAD:.gitattributes"},
	},
		git.WithSetupStdout(),
		git.WithStderr(&stderr),
	)
	if err != nil {
		return structerr.NewInternal("failure to read HEAD:.gitattributes: %w", err)
	}
	defer func() {
		if err := catFileCmd.Wait(); err != nil {
			s.logger.Error("git cat-file command error: " + stderr.String())
			if returnedErr != nil {
				returnedErr = structerr.NewInternal("failure to read HEAD:.gitattributes: %w", err)
			}
		}
	}()

	buf := bufio.NewReader(catFileCmd)
	_, err = buf.Peek(1)
	if errors.Is(err, io.EOF) {
		return stream.Send(&gitalypb.GetInfoAttributesResponse{})
	}

	sw := streamio.NewWriter(func(p []byte) error {
		return stream.Send(&gitalypb.GetInfoAttributesResponse{
			Attributes: p,
		})
	})
	_, err = io.Copy(sw, buf)

	return err
}