aboutsummaryrefslogtreecommitdiffstats
path: root/modules/git/repo_attribute.go
diff options
context:
space:
mode:
Diffstat (limited to 'modules/git/repo_attribute.go')
-rw-r--r--modules/git/repo_attribute.go340
1 files changed, 0 insertions, 340 deletions
diff --git a/modules/git/repo_attribute.go b/modules/git/repo_attribute.go
deleted file mode 100644
index 89101e5af3..0000000000
--- a/modules/git/repo_attribute.go
+++ /dev/null
@@ -1,340 +0,0 @@
-// Copyright 2019 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package git
-
-import (
- "bytes"
- "context"
- "fmt"
- "io"
- "os"
- "path/filepath"
- "time"
-
- "code.gitea.io/gitea/modules/log"
-)
-
-// CheckAttributeOpts represents the possible options to CheckAttribute
-type CheckAttributeOpts struct {
- CachedOnly bool
- AllAttributes bool
- Attributes []string
- Filenames []string
- IndexFile string
- WorkTree string
-}
-
-// CheckAttribute return the Blame object of file
-func (repo *Repository) CheckAttribute(opts CheckAttributeOpts) (map[string]map[string]string, error) {
- env := []string{}
-
- if len(opts.IndexFile) > 0 {
- env = append(env, "GIT_INDEX_FILE="+opts.IndexFile)
- }
- if len(opts.WorkTree) > 0 {
- env = append(env, "GIT_WORK_TREE="+opts.WorkTree)
- }
-
- if len(env) > 0 {
- env = append(os.Environ(), env...)
- }
-
- stdOut := new(bytes.Buffer)
- stdErr := new(bytes.Buffer)
-
- cmd := NewCommand("check-attr", "-z")
-
- if opts.AllAttributes {
- cmd.AddArguments("-a")
- } else {
- for _, attribute := range opts.Attributes {
- if attribute != "" {
- cmd.AddDynamicArguments(attribute)
- }
- }
- }
-
- if opts.CachedOnly {
- cmd.AddArguments("--cached")
- }
-
- cmd.AddDashesAndList(opts.Filenames...)
-
- if err := cmd.Run(repo.Ctx, &RunOpts{
- Env: env,
- Dir: repo.Path,
- Stdout: stdOut,
- Stderr: stdErr,
- }); err != nil {
- return nil, fmt.Errorf("failed to run check-attr: %w\n%s\n%s", err, stdOut.String(), stdErr.String())
- }
-
- // FIXME: This is incorrect on versions < 1.8.5
- fields := bytes.Split(stdOut.Bytes(), []byte{'\000'})
-
- if len(fields)%3 != 1 {
- return nil, fmt.Errorf("wrong number of fields in return from check-attr")
- }
-
- name2attribute2info := make(map[string]map[string]string)
-
- for i := 0; i < (len(fields) / 3); i++ {
- filename := string(fields[3*i])
- attribute := string(fields[3*i+1])
- info := string(fields[3*i+2])
- attribute2info := name2attribute2info[filename]
- if attribute2info == nil {
- attribute2info = make(map[string]string)
- }
- attribute2info[attribute] = info
- name2attribute2info[filename] = attribute2info
- }
-
- return name2attribute2info, nil
-}
-
-// CheckAttributeReader provides a reader for check-attribute content that can be long running
-type CheckAttributeReader struct {
- // params
- Attributes []string
- Repo *Repository
- IndexFile string
- WorkTree string
-
- stdinReader io.ReadCloser
- stdinWriter *os.File
- stdOut *nulSeparatedAttributeWriter
- cmd *Command
- env []string
- ctx context.Context
- cancel context.CancelFunc
-}
-
-// Init initializes the CheckAttributeReader
-func (c *CheckAttributeReader) Init(ctx context.Context) error {
- if len(c.Attributes) == 0 {
- lw := new(nulSeparatedAttributeWriter)
- lw.attributes = make(chan attributeTriple)
- lw.closed = make(chan struct{})
-
- c.stdOut = lw
- c.stdOut.Close()
- return fmt.Errorf("no provided Attributes to check")
- }
-
- c.ctx, c.cancel = context.WithCancel(ctx)
- c.cmd = NewCommand("check-attr", "--stdin", "-z")
-
- if len(c.IndexFile) > 0 {
- c.cmd.AddArguments("--cached")
- c.env = append(c.env, "GIT_INDEX_FILE="+c.IndexFile)
- }
-
- if len(c.WorkTree) > 0 {
- c.env = append(c.env, "GIT_WORK_TREE="+c.WorkTree)
- }
-
- c.env = append(c.env, "GIT_FLUSH=1")
-
- c.cmd.AddDynamicArguments(c.Attributes...)
-
- var err error
-
- c.stdinReader, c.stdinWriter, err = os.Pipe()
- if err != nil {
- c.cancel()
- return err
- }
-
- lw := new(nulSeparatedAttributeWriter)
- lw.attributes = make(chan attributeTriple, 5)
- lw.closed = make(chan struct{})
- c.stdOut = lw
- return nil
-}
-
-func (c *CheckAttributeReader) Run() error {
- defer func() {
- _ = c.stdinReader.Close()
- _ = c.stdOut.Close()
- }()
- stdErr := new(bytes.Buffer)
- err := c.cmd.Run(c.ctx, &RunOpts{
- Env: c.env,
- Dir: c.Repo.Path,
- Stdin: c.stdinReader,
- Stdout: c.stdOut,
- Stderr: stdErr,
- })
- if err != nil && !IsErrCanceledOrKilled(err) {
- return fmt.Errorf("failed to run attr-check. Error: %w\nStderr: %s", err, stdErr.String())
- }
- return nil
-}
-
-// CheckPath check attr for given path
-func (c *CheckAttributeReader) CheckPath(path string) (rs map[string]string, err error) {
- defer func() {
- if err != nil && err != c.ctx.Err() {
- log.Error("Unexpected error when checking path %s in %s, error: %v", path, filepath.Base(c.Repo.Path), err)
- }
- }()
-
- select {
- case <-c.ctx.Done():
- return nil, c.ctx.Err()
- default:
- }
-
- if _, err = c.stdinWriter.Write([]byte(path + "\x00")); err != nil {
- defer c.Close()
- return nil, err
- }
-
- reportTimeout := func() error {
- stdOutClosed := false
- select {
- case <-c.stdOut.closed:
- stdOutClosed = true
- default:
- }
- debugMsg := fmt.Sprintf("check path %q in repo %q", path, filepath.Base(c.Repo.Path))
- debugMsg += fmt.Sprintf(", stdOut: tmp=%q, pos=%d, closed=%v", string(c.stdOut.tmp), c.stdOut.pos, stdOutClosed)
- if c.cmd.cmd != nil {
- debugMsg += fmt.Sprintf(", process state: %q", c.cmd.cmd.ProcessState.String())
- }
- _ = c.Close()
- return fmt.Errorf("CheckPath timeout: %s", debugMsg)
- }
-
- rs = make(map[string]string)
- for range c.Attributes {
- select {
- case <-time.After(5 * time.Second):
- // There is a strange "hang" problem in gitdiff.GetDiff -> CheckPath
- // So add a timeout here to mitigate the problem, and output more logs for debug purpose
- // In real world, if CheckPath runs long than seconds, it blocks the end user's operation,
- // and at the moment the CheckPath result is not so important, so we can just ignore it.
- return nil, reportTimeout()
- case attr, ok := <-c.stdOut.ReadAttribute():
- if !ok {
- return nil, c.ctx.Err()
- }
- rs[attr.Attribute] = attr.Value
- case <-c.ctx.Done():
- return nil, c.ctx.Err()
- }
- }
- return rs, nil
-}
-
-func (c *CheckAttributeReader) Close() error {
- c.cancel()
- err := c.stdinWriter.Close()
- return err
-}
-
-type attributeTriple struct {
- Filename string
- Attribute string
- Value string
-}
-
-type nulSeparatedAttributeWriter struct {
- tmp []byte
- attributes chan attributeTriple
- closed chan struct{}
- working attributeTriple
- pos int
-}
-
-func (wr *nulSeparatedAttributeWriter) Write(p []byte) (n int, err error) {
- l, read := len(p), 0
-
- nulIdx := bytes.IndexByte(p, '\x00')
- for nulIdx >= 0 {
- wr.tmp = append(wr.tmp, p[:nulIdx]...)
- switch wr.pos {
- case 0:
- wr.working = attributeTriple{
- Filename: string(wr.tmp),
- }
- case 1:
- wr.working.Attribute = string(wr.tmp)
- case 2:
- wr.working.Value = string(wr.tmp)
- }
- wr.tmp = wr.tmp[:0]
- wr.pos++
- if wr.pos > 2 {
- wr.attributes <- wr.working
- wr.pos = 0
- }
- read += nulIdx + 1
- if l > read {
- p = p[nulIdx+1:]
- nulIdx = bytes.IndexByte(p, '\x00')
- } else {
- return l, nil
- }
- }
- wr.tmp = append(wr.tmp, p...)
- return len(p), nil
-}
-
-func (wr *nulSeparatedAttributeWriter) ReadAttribute() <-chan attributeTriple {
- return wr.attributes
-}
-
-func (wr *nulSeparatedAttributeWriter) Close() error {
- select {
- case <-wr.closed:
- return nil
- default:
- }
- close(wr.attributes)
- close(wr.closed)
- return nil
-}
-
-// CheckAttributeReader creates a check attribute reader for the current repository and provided commit ID
-func (repo *Repository) CheckAttributeReader(commitID string) (*CheckAttributeReader, context.CancelFunc) {
- indexFilename, worktree, deleteTemporaryFile, err := repo.ReadTreeToTemporaryIndex(commitID)
- if err != nil {
- return nil, func() {}
- }
-
- checker := &CheckAttributeReader{
- Attributes: []string{
- AttributeLinguistVendored,
- AttributeLinguistGenerated,
- AttributeLinguistDocumentation,
- AttributeLinguistDetectable,
- AttributeLinguistLanguage,
- AttributeGitlabLanguage,
- },
- Repo: repo,
- IndexFile: indexFilename,
- WorkTree: worktree,
- }
- ctx, cancel := context.WithCancel(repo.Ctx)
- if err := checker.Init(ctx); err != nil {
- log.Error("Unable to open attribute checker for commit %s, error: %v", commitID, err)
- } else {
- go func() {
- err := checker.Run()
- if err != nil && !IsErrCanceledOrKilled(err) {
- log.Error("Attribute checker for commit %s exits with error: %v", commitID, err)
- }
- cancel()
- }()
- }
- deferrable := func() {
- _ = checker.Close()
- cancel()
- deleteTemporaryFile()
- }
-
- return checker, deferrable
-}