mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 20:36:07 +01:00 
			
		
		
		
	Fix git error handling (#32401)
This commit is contained in:
		@@ -4,28 +4,14 @@
 | 
				
			|||||||
package git
 | 
					package git
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/modules/util"
 | 
						"code.gitea.io/gitea/modules/util"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ErrExecTimeout error when exec timed out
 | 
					 | 
				
			||||||
type ErrExecTimeout struct {
 | 
					 | 
				
			||||||
	Duration time.Duration
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// IsErrExecTimeout if some error is ErrExecTimeout
 | 
					 | 
				
			||||||
func IsErrExecTimeout(err error) bool {
 | 
					 | 
				
			||||||
	_, ok := err.(ErrExecTimeout)
 | 
					 | 
				
			||||||
	return ok
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (err ErrExecTimeout) Error() string {
 | 
					 | 
				
			||||||
	return fmt.Sprintf("execution is timeout [duration: %v]", err.Duration)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// ErrNotExist commit not exist error
 | 
					// ErrNotExist commit not exist error
 | 
				
			||||||
type ErrNotExist struct {
 | 
					type ErrNotExist struct {
 | 
				
			||||||
	ID      string
 | 
						ID      string
 | 
				
			||||||
@@ -62,21 +48,6 @@ func IsErrBadLink(err error) bool {
 | 
				
			|||||||
	return ok
 | 
						return ok
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ErrUnsupportedVersion error when required git version not matched
 | 
					 | 
				
			||||||
type ErrUnsupportedVersion struct {
 | 
					 | 
				
			||||||
	Required string
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// IsErrUnsupportedVersion if some error is ErrUnsupportedVersion
 | 
					 | 
				
			||||||
func IsErrUnsupportedVersion(err error) bool {
 | 
					 | 
				
			||||||
	_, ok := err.(ErrUnsupportedVersion)
 | 
					 | 
				
			||||||
	return ok
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (err ErrUnsupportedVersion) Error() string {
 | 
					 | 
				
			||||||
	return fmt.Sprintf("Operation requires higher version [required: %s]", err.Required)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// ErrBranchNotExist represents a "BranchNotExist" kind of error.
 | 
					// ErrBranchNotExist represents a "BranchNotExist" kind of error.
 | 
				
			||||||
type ErrBranchNotExist struct {
 | 
					type ErrBranchNotExist struct {
 | 
				
			||||||
	Name string
 | 
						Name string
 | 
				
			||||||
@@ -185,3 +156,10 @@ func IsErrMoreThanOne(err error) bool {
 | 
				
			|||||||
func (err *ErrMoreThanOne) Error() string {
 | 
					func (err *ErrMoreThanOne) Error() string {
 | 
				
			||||||
	return fmt.Sprintf("ErrMoreThanOne Error: %v: %s\n%s", err.Err, err.StdErr, err.StdOut)
 | 
						return fmt.Sprintf("ErrMoreThanOne Error: %v: %s\n%s", err.Err, err.StdErr, err.StdOut)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func IsErrCanceledOrKilled(err error) bool {
 | 
				
			||||||
 | 
						// When "cancel()" a git command's context, the returned error of "Run()" could be one of them:
 | 
				
			||||||
 | 
						// - context.Canceled
 | 
				
			||||||
 | 
						// - *exec.ExitError: "signal: killed"
 | 
				
			||||||
 | 
						return err != nil && (errors.Is(err, context.Canceled) || err.Error() == "signal: killed")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -166,9 +166,7 @@ func (c *CheckAttributeReader) Run() error {
 | 
				
			|||||||
		Stdout: c.stdOut,
 | 
							Stdout: c.stdOut,
 | 
				
			||||||
		Stderr: stdErr,
 | 
							Stderr: stdErr,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	if err != nil && //                      If there is an error we need to return but:
 | 
						if err != nil && !IsErrCanceledOrKilled(err) {
 | 
				
			||||||
		c.ctx.Err() != err && //             1. Ignore the context error if the context is cancelled or exceeds the deadline (RunWithContext could return c.ctx.Err() which is Canceled or DeadlineExceeded)
 | 
					 | 
				
			||||||
		err.Error() != "signal: killed" { // 2. We should not pass up errors due to the program being killed
 | 
					 | 
				
			||||||
		return fmt.Errorf("failed to run attr-check. Error: %w\nStderr: %s", err, stdErr.String())
 | 
							return fmt.Errorf("failed to run attr-check. Error: %w\nStderr: %s", err, stdErr.String())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,7 +21,6 @@ import (
 | 
				
			|||||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
						repo_model "code.gitea.io/gitea/models/repo"
 | 
				
			||||||
	unit_model "code.gitea.io/gitea/models/unit"
 | 
						unit_model "code.gitea.io/gitea/models/unit"
 | 
				
			||||||
	user_model "code.gitea.io/gitea/models/user"
 | 
						user_model "code.gitea.io/gitea/models/user"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/git"
 | 
					 | 
				
			||||||
	"code.gitea.io/gitea/modules/gitrepo"
 | 
						"code.gitea.io/gitea/modules/gitrepo"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/label"
 | 
						"code.gitea.io/gitea/modules/label"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/log"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
@@ -739,11 +738,9 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err
 | 
				
			|||||||
	if opts.DefaultBranch != nil && repo.DefaultBranch != *opts.DefaultBranch && (repo.IsEmpty || ctx.Repo.GitRepo.IsBranchExist(*opts.DefaultBranch)) {
 | 
						if opts.DefaultBranch != nil && repo.DefaultBranch != *opts.DefaultBranch && (repo.IsEmpty || ctx.Repo.GitRepo.IsBranchExist(*opts.DefaultBranch)) {
 | 
				
			||||||
		if !repo.IsEmpty {
 | 
							if !repo.IsEmpty {
 | 
				
			||||||
			if err := gitrepo.SetDefaultBranch(ctx, ctx.Repo.Repository, *opts.DefaultBranch); err != nil {
 | 
								if err := gitrepo.SetDefaultBranch(ctx, ctx.Repo.Repository, *opts.DefaultBranch); err != nil {
 | 
				
			||||||
				if !git.IsErrUnsupportedVersion(err) {
 | 
					 | 
				
			||||||
				ctx.Error(http.StatusInternalServerError, "SetDefaultBranch", err)
 | 
									ctx.Error(http.StatusInternalServerError, "SetDefaultBranch", err)
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			updateRepoLicense = true
 | 
								updateRepoLicense = true
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		repo.DefaultBranch = *opts.DefaultBranch
 | 
							repo.DefaultBranch = *opts.DefaultBranch
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,6 @@ import (
 | 
				
			|||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
						repo_model "code.gitea.io/gitea/models/repo"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/git"
 | 
					 | 
				
			||||||
	"code.gitea.io/gitea/modules/gitrepo"
 | 
						"code.gitea.io/gitea/modules/gitrepo"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/private"
 | 
						"code.gitea.io/gitea/modules/private"
 | 
				
			||||||
	gitea_context "code.gitea.io/gitea/services/context"
 | 
						gitea_context "code.gitea.io/gitea/services/context"
 | 
				
			||||||
@@ -23,13 +22,11 @@ func SetDefaultBranch(ctx *gitea_context.PrivateContext) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	ctx.Repo.Repository.DefaultBranch = branch
 | 
						ctx.Repo.Repository.DefaultBranch = branch
 | 
				
			||||||
	if err := gitrepo.SetDefaultBranch(ctx, ctx.Repo.Repository, ctx.Repo.Repository.DefaultBranch); err != nil {
 | 
						if err := gitrepo.SetDefaultBranch(ctx, ctx.Repo.Repository, ctx.Repo.Repository.DefaultBranch); err != nil {
 | 
				
			||||||
		if !git.IsErrUnsupportedVersion(err) {
 | 
					 | 
				
			||||||
		ctx.JSON(http.StatusInternalServerError, private.Response{
 | 
							ctx.JSON(http.StatusInternalServerError, private.Response{
 | 
				
			||||||
			Err: fmt.Sprintf("Unable to set default branch on repository: %s/%s Error: %v", ownerName, repoName, err),
 | 
								Err: fmt.Sprintf("Unable to set default branch on repository: %s/%s Error: %v", ownerName, repoName, err),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := repo_model.UpdateDefaultBranch(ctx, ctx.Repo.Repository); err != nil {
 | 
						if err := repo_model.UpdateDefaultBranch(ctx, ctx.Repo.Repository); err != nil {
 | 
				
			||||||
		ctx.JSON(http.StatusInternalServerError, private.Response{
 | 
							ctx.JSON(http.StatusInternalServerError, private.Response{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -467,7 +467,7 @@ func serviceRPC(ctx *context.Context, h *serviceHandler, service string) {
 | 
				
			|||||||
		Stderr:            &stderr,
 | 
							Stderr:            &stderr,
 | 
				
			||||||
		UseContextTimeout: true,
 | 
							UseContextTimeout: true,
 | 
				
			||||||
	}); err != nil {
 | 
						}); err != nil {
 | 
				
			||||||
		if err.Error() != "signal: killed" {
 | 
							if !git.IsErrCanceledOrKilled(err) {
 | 
				
			||||||
			log.Error("Fail to serve RPC(%s) in %s: %v - %s", service, h.getRepoDir(), err, stderr.String())
 | 
								log.Error("Fail to serve RPC(%s) in %s: %v - %s", service, h.getRepoDir(), err, stderr.String())
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1162,7 +1162,7 @@ func GetDiff(ctx context.Context, gitRepo *git.Repository, opts *DiffOptions, fi
 | 
				
			|||||||
			Dir:     repoPath,
 | 
								Dir:     repoPath,
 | 
				
			||||||
			Stdout:  writer,
 | 
								Stdout:  writer,
 | 
				
			||||||
			Stderr:  stderr,
 | 
								Stderr:  stderr,
 | 
				
			||||||
		}); err != nil && err.Error() != "signal: killed" {
 | 
							}); err != nil && !git.IsErrCanceledOrKilled(err) {
 | 
				
			||||||
			log.Error("error during GetDiff(git diff dir: %s): %v, stderr: %s", repoPath, err, stderr.String())
 | 
								log.Error("error during GetDiff(git diff dir: %s): %v, stderr: %s", repoPath, err, stderr.String())
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -613,15 +613,9 @@ func checkAndUpdateEmptyRepository(ctx context.Context, m *repo_model.Mirror, re
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		// Update the git repository default branch
 | 
							// Update the git repository default branch
 | 
				
			||||||
		if err := gitrepo.SetDefaultBranch(ctx, m.Repo, m.Repo.DefaultBranch); err != nil {
 | 
							if err := gitrepo.SetDefaultBranch(ctx, m.Repo, m.Repo.DefaultBranch); err != nil {
 | 
				
			||||||
			if !git.IsErrUnsupportedVersion(err) {
 | 
					 | 
				
			||||||
			log.Error("Failed to update default branch of underlying git repository %-v. Error: %v", m.Repo, err)
 | 
								log.Error("Failed to update default branch of underlying git repository %-v. Error: %v", m.Repo, err)
 | 
				
			||||||
				desc := fmt.Sprintf("Failed to update default branch of underlying git repository '%s': %v", m.Repo.RepoPath(), err)
 | 
					 | 
				
			||||||
				if err = system_model.CreateRepositoryNotice(desc); err != nil {
 | 
					 | 
				
			||||||
					log.Error("CreateRepositoryNotice: %v", err)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			return false
 | 
								return false
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		m.Repo.IsEmpty = false
 | 
							m.Repo.IsEmpty = false
 | 
				
			||||||
		// Update the is empty and default_branch columns
 | 
							// Update the is empty and default_branch columns
 | 
				
			||||||
		if err := repo_model.UpdateRepositoryCols(ctx, m.Repo, "default_branch", "is_empty"); err != nil {
 | 
							if err := repo_model.UpdateRepositoryCols(ctx, m.Repo, "default_branch", "is_empty"); err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -602,12 +602,7 @@ func SetRepoDefaultBranch(ctx context.Context, repo *repo_model.Repository, gitR
 | 
				
			|||||||
			log.Error("CancelPreviousJobs: %v", err)
 | 
								log.Error("CancelPreviousJobs: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := gitrepo.SetDefaultBranch(ctx, repo, newBranchName); err != nil {
 | 
							return gitrepo.SetDefaultBranch(ctx, repo, newBranchName)
 | 
				
			||||||
			if !git.IsErrUnsupportedVersion(err) {
 | 
					 | 
				
			||||||
				return err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}); err != nil {
 | 
						}); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -339,8 +339,7 @@ func (t *TemporaryUploadRepository) Push(doer *user_model.User, commitHash, bran
 | 
				
			|||||||
func (t *TemporaryUploadRepository) DiffIndex() (*gitdiff.Diff, error) {
 | 
					func (t *TemporaryUploadRepository) DiffIndex() (*gitdiff.Diff, error) {
 | 
				
			||||||
	stdoutReader, stdoutWriter, err := os.Pipe()
 | 
						stdoutReader, stdoutWriter, err := os.Pipe()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Error("Unable to open stdout pipe: %v", err)
 | 
							return nil, fmt.Errorf("unable to open stdout pipe: %w", err)
 | 
				
			||||||
		return nil, fmt.Errorf("Unable to open stdout pipe: %w", err)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer func() {
 | 
						defer func() {
 | 
				
			||||||
		_ = stdoutReader.Close()
 | 
							_ = stdoutReader.Close()
 | 
				
			||||||
@@ -348,9 +347,7 @@ func (t *TemporaryUploadRepository) DiffIndex() (*gitdiff.Diff, error) {
 | 
				
			|||||||
	}()
 | 
						}()
 | 
				
			||||||
	stderr := new(bytes.Buffer)
 | 
						stderr := new(bytes.Buffer)
 | 
				
			||||||
	var diff *gitdiff.Diff
 | 
						var diff *gitdiff.Diff
 | 
				
			||||||
	var finalErr error
 | 
						err = git.NewCommand(t.ctx, "diff-index", "--src-prefix=\\a/", "--dst-prefix=\\b/", "--cached", "-p", "HEAD").
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err := git.NewCommand(t.ctx, "diff-index", "--src-prefix=\\a/", "--dst-prefix=\\b/", "--cached", "-p", "HEAD").
 | 
					 | 
				
			||||||
		Run(&git.RunOpts{
 | 
							Run(&git.RunOpts{
 | 
				
			||||||
			Timeout: 30 * time.Second,
 | 
								Timeout: 30 * time.Second,
 | 
				
			||||||
			Dir:     t.basePath,
 | 
								Dir:     t.basePath,
 | 
				
			||||||
@@ -359,27 +356,19 @@ func (t *TemporaryUploadRepository) DiffIndex() (*gitdiff.Diff, error) {
 | 
				
			|||||||
			PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
 | 
								PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
 | 
				
			||||||
				_ = stdoutWriter.Close()
 | 
									_ = stdoutWriter.Close()
 | 
				
			||||||
				defer cancel()
 | 
									defer cancel()
 | 
				
			||||||
				diff, finalErr = gitdiff.ParsePatch(t.ctx, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, stdoutReader, "")
 | 
									var diffErr error
 | 
				
			||||||
				if finalErr != nil {
 | 
									diff, diffErr = gitdiff.ParsePatch(t.ctx, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, stdoutReader, "")
 | 
				
			||||||
					log.Error("ParsePatch: %v", finalErr)
 | 
					 | 
				
			||||||
					cancel()
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				_ = stdoutReader.Close()
 | 
									_ = stdoutReader.Close()
 | 
				
			||||||
				return finalErr
 | 
									if diffErr != nil {
 | 
				
			||||||
 | 
										// if the diffErr is not nil, it will be returned as the error of "Run()"
 | 
				
			||||||
 | 
										return fmt.Errorf("ParsePatch: %w", diffErr)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									return nil
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		}); err != nil {
 | 
							})
 | 
				
			||||||
		if finalErr != nil {
 | 
						if err != nil && !git.IsErrCanceledOrKilled(err) {
 | 
				
			||||||
			log.Error("Unable to ParsePatch in temporary repo %s (%s). Error: %v", t.repo.FullName(), t.basePath, finalErr)
 | 
							log.Error("Unable to diff-index in temporary repo %s (%s). Error: %v\nStderr: %s", t.repo.FullName(), t.basePath, err, stderr)
 | 
				
			||||||
			return nil, finalErr
 | 
							return nil, fmt.Errorf("unable to run diff-index pipeline in temporary repo: %w", err)
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// If the process exited early, don't error
 | 
					 | 
				
			||||||
		if err != context.Canceled {
 | 
					 | 
				
			||||||
			log.Error("Unable to run diff-index pipeline in temporary repo %s (%s). Error: %v\nStderr: %s",
 | 
					 | 
				
			||||||
				t.repo.FullName(), t.basePath, err, stderr)
 | 
					 | 
				
			||||||
			return nil, fmt.Errorf("Unable to run diff-index pipeline in temporary repo %s. Error: %w\nStderr: %s",
 | 
					 | 
				
			||||||
				t.repo.FullName(), err, stderr)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	diff.NumFiles, diff.TotalAddition, diff.TotalDeletion, err = git.GetDiffShortStat(t.ctx, t.basePath, git.TrustedCmdArgs{"--cached"}, "HEAD")
 | 
						diff.NumFiles, diff.TotalAddition, diff.TotalDeletion, err = git.GetDiffShortStat(t.ctx, t.basePath, git.TrustedCmdArgs{"--cached"}, "HEAD")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -183,11 +183,9 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
 | 
				
			|||||||
						repo.IsEmpty = false
 | 
											repo.IsEmpty = false
 | 
				
			||||||
						if repo.DefaultBranch != setting.Repository.DefaultBranch {
 | 
											if repo.DefaultBranch != setting.Repository.DefaultBranch {
 | 
				
			||||||
							if err := gitrepo.SetDefaultBranch(ctx, repo, repo.DefaultBranch); err != nil {
 | 
												if err := gitrepo.SetDefaultBranch(ctx, repo, repo.DefaultBranch); err != nil {
 | 
				
			||||||
								if !git.IsErrUnsupportedVersion(err) {
 | 
					 | 
				
			||||||
								return err
 | 
													return err
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
						// Update the is empty and default_branch columns
 | 
											// Update the is empty and default_branch columns
 | 
				
			||||||
						if err := repo_model.UpdateRepositoryCols(ctx, repo, "default_branch", "is_empty"); err != nil {
 | 
											if err := repo_model.UpdateRepositoryCols(ctx, repo, "default_branch", "is_empty"); err != nil {
 | 
				
			||||||
							return fmt.Errorf("UpdateRepositoryCols: %w", err)
 | 
												return fmt.Errorf("UpdateRepositoryCols: %w", err)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user