summaryrefslogtreecommitdiffstats
path: root/modules/git/repo_attribute.go
diff options
context:
space:
mode:
authorwxiaoguang <wxiaoguang@gmail.com>2021-09-21 03:46:51 +0800
committerGitHub <noreply@github.com>2021-09-20 20:46:51 +0100
commitb231d0deabf8c5e5def785e65d4d62d9355fbcd4 (patch)
tree9f88080296bf87e2d639b6c24d4503e0ab045d75 /modules/git/repo_attribute.go
parent5ac857f4d43a8452089e22c820bd1f0ddb001b7a (diff)
downloadgitea-b231d0deabf8c5e5def785e65d4d62d9355fbcd4.tar.gz
gitea-b231d0deabf8c5e5def785e65d4d62d9355fbcd4.zip
Ignore Sync errors on pipes when doing `CheckAttributeReader.CheckPath`, fix the hang of `git cat-file` (#17096)
* Ignore Sync errors on pipes when doing `CheckAttributeReader.CheckPath` * apply env patch * Drop the Sync and fix a number of issues with the Close function Signed-off-by: Andrew Thornton <art27@cantab.net> * add logs for DBIndexer and CheckPath * Fix some more closing bugs Signed-off-by: Andrew Thornton <art27@cantab.net> * Add test case for language_stats Signed-off-by: Andrew Thornton <art27@cantab.net> * Update modules/indexer/stats/db.go Co-authored-by: Lauris BH <lauris@nix.lv> Co-authored-by: Andrew Thornton <art27@cantab.net> Co-authored-by: Lauris BH <lauris@nix.lv> Co-authored-by: 6543 <6543@obermui.de>
Diffstat (limited to 'modules/git/repo_attribute.go')
-rw-r--r--modules/git/repo_attribute.go74
1 files changed, 52 insertions, 22 deletions
diff --git a/modules/git/repo_attribute.go b/modules/git/repo_attribute.go
index 0bd7d7e49c..aace644253 100644
--- a/modules/git/repo_attribute.go
+++ b/modules/git/repo_attribute.go
@@ -12,6 +12,8 @@ import (
"os"
"strconv"
"strings"
+
+ "code.gitea.io/gitea/modules/log"
)
// CheckAttributeOpts represents the possible options to CheckAttribute
@@ -112,42 +114,48 @@ func (c *CheckAttributeReader) Init(ctx context.Context) error {
if len(c.IndexFile) > 0 && CheckGitVersionAtLeast("1.7.8") == nil {
cmdArgs = append(cmdArgs, "--cached")
- c.env = []string{"GIT_INDEX_FILE=" + c.IndexFile}
+ c.env = append(c.env, "GIT_INDEX_FILE="+c.IndexFile)
}
if len(c.WorkTree) > 0 && CheckGitVersionAtLeast("1.7.8") == nil {
- c.env = []string{"GIT_WORK_TREE=" + c.WorkTree}
+ c.env = append(c.env, "GIT_WORK_TREE="+c.WorkTree)
}
- if len(c.Attributes) > 0 {
- cmdArgs = append(cmdArgs, c.Attributes...)
- cmdArgs = append(cmdArgs, "--")
- } else {
+ c.env = append(c.env, "GIT_FLUSH=1")
+
+ 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")
}
+ cmdArgs = append(cmdArgs, c.Attributes...)
+ cmdArgs = append(cmdArgs, "--")
+
c.ctx, c.cancel = context.WithCancel(ctx)
c.cmd = NewCommandContext(c.ctx, cmdArgs...)
+
var err error
+
c.stdinReader, c.stdinWriter, err = os.Pipe()
if err != nil {
+ c.cancel()
return err
}
if CheckGitVersionAtLeast("1.8.5") == nil {
lw := new(nulSeparatedAttributeWriter)
lw.attributes = make(chan attributeTriple, 5)
-
+ lw.closed = make(chan struct{})
c.stdOut = lw
} else {
lw := new(lineSeparatedAttributeWriter)
lw.attributes = make(chan attributeTriple, 5)
-
+ lw.closed = make(chan struct{})
c.stdOut = lw
}
return nil
@@ -155,13 +163,14 @@ func (c *CheckAttributeReader) Init(ctx context.Context) error {
// Run run cmd
func (c *CheckAttributeReader) Run() error {
+ defer func() {
+ _ = c.Close()
+ }()
stdErr := new(bytes.Buffer)
err := c.cmd.RunInDirTimeoutEnvFullPipelineFunc(c.env, -1, c.Repo.Path, c.stdOut, stdErr, c.stdinReader, func(_ context.Context, _ context.CancelFunc) error {
close(c.running)
return nil
})
- defer c.cancel()
- _ = c.stdOut.Close()
if err != nil && c.ctx.Err() != nil && err.Error() != "signal: killed" {
return fmt.Errorf("failed to run attr-check. Error: %w\nStderr: %s", err, stdErr.String())
}
@@ -170,27 +179,31 @@ func (c *CheckAttributeReader) Run() error {
}
// CheckPath check attr for given path
-func (c *CheckAttributeReader) CheckPath(path string) (map[string]string, error) {
+func (c *CheckAttributeReader) CheckPath(path string) (rs map[string]string, err error) {
+ defer func() {
+ if err != nil {
+ log.Error("CheckPath returns error: %v", err)
+ }
+ }()
+
select {
case <-c.ctx.Done():
return nil, c.ctx.Err()
case <-c.running:
}
- if _, err := c.stdinWriter.Write([]byte(path + "\x00")); err != nil {
- defer c.cancel()
+ if _, err = c.stdinWriter.Write([]byte(path + "\x00")); err != nil {
+ defer c.Close()
return nil, err
}
- if err := c.stdinWriter.Sync(); err != nil {
- defer c.cancel()
- return nil, err
- }
-
- rs := make(map[string]string)
+ rs = make(map[string]string)
for range c.Attributes {
select {
- case attr := <-c.stdOut.ReadAttribute():
+ 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()
@@ -201,13 +214,16 @@ func (c *CheckAttributeReader) CheckPath(path string) (map[string]string, error)
// Close close pip after use
func (c *CheckAttributeReader) Close() error {
+ err := c.stdinWriter.Close()
+ _ = c.stdinReader.Close()
+ _ = c.stdOut.Close()
+ c.cancel()
select {
case <-c.running:
default:
close(c.running)
}
- defer c.cancel()
- return c.stdinWriter.Close()
+ return err
}
type attributeWriter interface {
@@ -224,6 +240,7 @@ type attributeTriple struct {
type nulSeparatedAttributeWriter struct {
tmp []byte
attributes chan attributeTriple
+ closed chan struct{}
working attributeTriple
pos int
}
@@ -267,13 +284,20 @@ func (wr *nulSeparatedAttributeWriter) ReadAttribute() <-chan attributeTriple {
}
func (wr *nulSeparatedAttributeWriter) Close() error {
+ select {
+ case <-wr.closed:
+ return nil
+ default:
+ }
close(wr.attributes)
+ close(wr.closed)
return nil
}
type lineSeparatedAttributeWriter struct {
tmp []byte
attributes chan attributeTriple
+ closed chan struct{}
}
func (wr *lineSeparatedAttributeWriter) Write(p []byte) (n int, err error) {
@@ -356,6 +380,12 @@ func (wr *lineSeparatedAttributeWriter) ReadAttribute() <-chan attributeTriple {
}
func (wr *lineSeparatedAttributeWriter) Close() error {
+ select {
+ case <-wr.closed:
+ return nil
+ default:
+ }
close(wr.attributes)
+ close(wr.closed)
return nil
}