Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cmd/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ func runRepoSyncReleases(ctx context.Context, _ *cli.Command) error {
}
log.Trace("Processing next %d repos of %d", len(repos), count)
for _, repo := range repos {
log.Trace("Synchronizing repo %s with path %s", repo.FullName(), repo.RepoPath())
log.Trace("Synchronizing repo %s with path %s", repo.FullName(), repo.RelativePath())
gitRepo, err := gitrepo.OpenRepository(ctx, repo)
if err != nil {
log.Warn("OpenRepository: %v", err)
Expand All @@ -147,7 +147,7 @@ func runRepoSyncReleases(ctx context.Context, _ *cli.Command) error {
continue
}

log.Trace(" repo %s releases synchronized to tags: from %d to %d",
log.Trace("repo %s releases synchronized to tags: from %d to %d",
repo.FullName(), oldnum, count)
gitRepo.Close()
}
Expand Down
27 changes: 15 additions & 12 deletions modules/git/gitcmd/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,11 @@ type RunOpts struct {
Stdin io.Reader

PipelineFunc func(context.Context, context.CancelFunc) error

// for debugging purpose only, it indicates how many stack frames to skip to find the caller info
// it's mainly used to find the caller function name for logging
// it should be 0 when the caller is the direct caller of Run/RunStdString/RunStdBytes
LogSkip int
}

func commonBaseEnvs() []string {
Expand Down Expand Up @@ -265,10 +270,6 @@ var ErrBrokenCommand = errors.New("git command is broken")

// Run runs the command with the RunOpts
func (c *Command) Run(ctx context.Context, opts *RunOpts) error {
return c.run(ctx, 1, opts)
}

func (c *Command) run(ctx context.Context, skip int, opts *RunOpts) error {
if len(c.brokenArgs) != 0 {
log.Error("git command is broken: %s, broken args: %s", c.LogString(), strings.Join(c.brokenArgs, " "))
return ErrBrokenCommand
Expand All @@ -284,13 +285,13 @@ func (c *Command) run(ctx context.Context, skip int, opts *RunOpts) error {
}

cmdLogString := c.LogString()
callerInfo := util.CallerFuncName(1 /* util */ + 1 /* this */ + skip /* parent */)
callerInfo := util.CallerFuncName(1 /* util */ + 1 /* this */ + opts.LogSkip /* parent */)
if pos := strings.LastIndex(callerInfo, "/"); pos >= 0 {
callerInfo = callerInfo[pos+1:]
}
// these logs are for debugging purposes only, so no guarantee of correctness or stability
desc := fmt.Sprintf("git.Run(by:%s, repo:%s): %s", callerInfo, logArgSanitize(opts.Dir), cmdLogString)
log.Debug("git.Command: %s", desc)
log.DebugWithSkip(opts.LogSkip+1, "git.Command: %s", desc)

_, span := gtprof.GetTracer().Start(ctx, gtprof.TraceSpanGitRun)
defer span.End()
Expand Down Expand Up @@ -399,7 +400,11 @@ func IsErrorExitCode(err error, code int) bool {

// RunStdString runs the command with options and returns stdout/stderr as string. and store stderr to returned error (err combined with stderr).
func (c *Command) RunStdString(ctx context.Context, opts *RunOpts) (stdout, stderr string, runErr RunStdError) {
stdoutBytes, stderrBytes, err := c.runStdBytes(ctx, opts)
if opts == nil {
opts = &RunOpts{}
}
opts.LogSkip++
stdoutBytes, stderrBytes, err := c.RunStdBytes(ctx, opts)
stdout = util.UnsafeBytesToString(stdoutBytes)
stderr = util.UnsafeBytesToString(stderrBytes)
if err != nil {
Expand All @@ -411,13 +416,10 @@ func (c *Command) RunStdString(ctx context.Context, opts *RunOpts) (stdout, stde

// RunStdBytes runs the command with options and returns stdout/stderr as bytes. and store stderr to returned error (err combined with stderr).
func (c *Command) RunStdBytes(ctx context.Context, opts *RunOpts) (stdout, stderr []byte, runErr RunStdError) {
return c.runStdBytes(ctx, opts)
}

func (c *Command) runStdBytes(ctx context.Context, opts *RunOpts) (stdout, stderr []byte, runErr RunStdError) {
if opts == nil {
opts = &RunOpts{}
}
opts.LogSkip++
if opts.Stdout != nil || opts.Stderr != nil {
// we must panic here, otherwise there would be bugs if developers set Stdin/Stderr by mistake, and it would be very difficult to debug
panic("stdout and stderr field must be nil when using RunStdBytes")
Expand All @@ -435,9 +437,10 @@ func (c *Command) runStdBytes(ctx context.Context, opts *RunOpts) (stdout, stder
Stderr: stderrBuf,
Stdin: opts.Stdin,
PipelineFunc: opts.PipelineFunc,
LogSkip: opts.LogSkip,
}

err := c.run(ctx, 2, newOpts)
err := c.Run(ctx, newOpts)
stderr = stderrBuf.Bytes()
if err != nil {
return nil, stderr, &runStdError{err: err, stderr: util.UnsafeBytesToString(stderr)}
Expand Down
2 changes: 1 addition & 1 deletion modules/gitrepo/blame.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

func LineBlame(ctx context.Context, repo Repository, revision, file string, line uint) (string, error) {
return runCmdString(ctx, repo,
return RunCmdString(ctx, repo,
gitcmd.NewCommand("blame").
AddOptionFormat("-L %d,%d", line, line).
AddOptionValues("-p", revision).
Expand Down
12 changes: 6 additions & 6 deletions modules/gitrepo/branch.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ func GetBranchCommitID(ctx context.Context, repo Repository, branch string) (str

// SetDefaultBranch sets default branch of repository.
func SetDefaultBranch(ctx context.Context, repo Repository, name string) error {
_, err := runCmdString(ctx, repo, gitcmd.NewCommand("symbolic-ref", "HEAD").
_, err := RunCmdString(ctx, repo, gitcmd.NewCommand("symbolic-ref", "HEAD").
AddDynamicArguments(git.BranchPrefix+name))
return err
}

// GetDefaultBranch gets default branch of repository.
func GetDefaultBranch(ctx context.Context, repo Repository) (string, error) {
stdout, err := runCmdString(ctx, repo, gitcmd.NewCommand("symbolic-ref", "HEAD"))
stdout, err := RunCmdString(ctx, repo, gitcmd.NewCommand("symbolic-ref", "HEAD"))
if err != nil {
return "", err
}
Expand All @@ -56,7 +56,7 @@ func GetDefaultBranch(ctx context.Context, repo Repository) (string, error) {

// IsReferenceExist returns true if given reference exists in the repository.
func IsReferenceExist(ctx context.Context, repo Repository, name string) bool {
_, err := runCmdString(ctx, repo, gitcmd.NewCommand("show-ref", "--verify").AddDashesAndList(name))
_, err := RunCmdString(ctx, repo, gitcmd.NewCommand("show-ref", "--verify").AddDashesAndList(name))
return err == nil
}

Expand All @@ -76,7 +76,7 @@ func DeleteBranch(ctx context.Context, repo Repository, name string, force bool)
}

cmd.AddDashesAndList(name)
_, err := runCmdString(ctx, repo, cmd)
_, err := RunCmdString(ctx, repo, cmd)
return err
}

Expand All @@ -85,12 +85,12 @@ func CreateBranch(ctx context.Context, repo Repository, branch, oldbranchOrCommi
cmd := gitcmd.NewCommand("branch")
cmd.AddDashesAndList(branch, oldbranchOrCommit)

_, err := runCmdString(ctx, repo, cmd)
_, err := RunCmdString(ctx, repo, cmd)
return err
}

// RenameBranch rename a branch
func RenameBranch(ctx context.Context, repo Repository, from, to string) error {
_, err := runCmdString(ctx, repo, gitcmd.NewCommand("branch", "-m").AddDynamicArguments(from, to))
_, err := RunCmdString(ctx, repo, gitcmd.NewCommand("branch", "-m").AddDynamicArguments(from, to))
return err
}
22 changes: 20 additions & 2 deletions modules/gitrepo/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,25 @@ import (
"code.gitea.io/gitea/modules/git/gitcmd"
)

func runCmdString(ctx context.Context, repo Repository, cmd *gitcmd.Command) (string, error) {
res, _, err := cmd.RunStdString(ctx, &gitcmd.RunOpts{Dir: repoPath(repo)})
type CmdOption struct {
Env []string
}

func WithEnv(env []string) func(opt *CmdOption) {
return func(opt *CmdOption) {
opt.Env = env
}
}

func RunCmdString(ctx context.Context, repo Repository, cmd *gitcmd.Command, opts ...func(opt *CmdOption)) (string, error) {
var opt CmdOption
for _, o := range opts {
o(&opt)
}
res, _, err := cmd.RunStdString(ctx, &gitcmd.RunOpts{
Dir: repoPath(repo),
Env: opt.Env,
LogSkip: 1,
})
return res, err
}
6 changes: 3 additions & 3 deletions modules/gitrepo/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
)

func GitConfigGet(ctx context.Context, repo Repository, key string) (string, error) {
result, err := runCmdString(ctx, repo, gitcmd.NewCommand("config", "--get").
result, err := RunCmdString(ctx, repo, gitcmd.NewCommand("config", "--get").
AddDynamicArguments(key))
if err != nil {
return "", err
Expand All @@ -27,7 +27,7 @@ func getRepoConfigLockKey(repoStoragePath string) string {
// GitConfigAdd add a git configuration key to a specific value for the given repository.
func GitConfigAdd(ctx context.Context, repo Repository, key, value string) error {
return globallock.LockAndDo(ctx, getRepoConfigLockKey(repo.RelativePath()), func(ctx context.Context) error {
_, err := runCmdString(ctx, repo, gitcmd.NewCommand("config", "--add").
_, err := RunCmdString(ctx, repo, gitcmd.NewCommand("config", "--add").
AddDynamicArguments(key, value))
return err
})
Expand All @@ -38,7 +38,7 @@ func GitConfigAdd(ctx context.Context, repo Repository, key, value string) error
// If the key exists, it will be updated to the new value.
func GitConfigSet(ctx context.Context, repo Repository, key, value string) error {
return globallock.LockAndDo(ctx, getRepoConfigLockKey(repo.RelativePath()), func(ctx context.Context) error {
_, err := runCmdString(ctx, repo, gitcmd.NewCommand("config").
_, err := RunCmdString(ctx, repo, gitcmd.NewCommand("config").
AddDynamicArguments(key, value))
return err
})
Expand Down
2 changes: 1 addition & 1 deletion modules/gitrepo/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func GetDiffShortStatByCmdArgs(ctx context.Context, repo Repository, trustedArgs
// we get:
// " 9902 files changed, 2034198 insertions(+), 298800 deletions(-)\n"
cmd := gitcmd.NewCommand("diff", "--shortstat").AddArguments(trustedArgs...).AddDynamicArguments(dynamicArgs...)
stdout, err := runCmdString(ctx, repo, cmd)
stdout, err := RunCmdString(ctx, repo, cmd)
if err != nil {
return 0, 0, 0, err
}
Expand Down
4 changes: 2 additions & 2 deletions modules/gitrepo/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@ func GitRemoteAdd(ctx context.Context, repo Repository, remoteName, remoteURL st
return errors.New("unknown remote option: " + string(options[0]))
}
}
_, err := runCmdString(ctx, repo, cmd.AddDynamicArguments(remoteName, remoteURL))
_, err := RunCmdString(ctx, repo, cmd.AddDynamicArguments(remoteName, remoteURL))
return err
})
}

func GitRemoteRemove(ctx context.Context, repo Repository, remoteName string) error {
return globallock.LockAndDo(ctx, getRepoConfigLockKey(repo.RelativePath()), func(ctx context.Context) error {
cmd := gitcmd.NewCommand("remote", "rm").AddDynamicArguments(remoteName)
_, err := runCmdString(ctx, repo, cmd)
_, err := RunCmdString(ctx, repo, cmd)
return err
})
}
Expand Down
37 changes: 37 additions & 0 deletions modules/gitrepo/size.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package gitrepo

import (
"os"
"path/filepath"
)

const notRegularFileMode = os.ModeSymlink | os.ModeNamedPipe | os.ModeSocket | os.ModeDevice | os.ModeCharDevice | os.ModeIrregular

// CalcRepositorySize returns the disk consumption for a given path
func CalcRepositorySize(repo Repository) (int64, error) {
var size int64
err := filepath.WalkDir(repoPath(repo), func(_ string, entry os.DirEntry, err error) error {
if os.IsNotExist(err) { // ignore the error because some files (like temp/lock file) may be deleted during traversing.
return nil
} else if err != nil {
return err
}
if entry.IsDir() {
return nil
}
info, err := entry.Info()
if os.IsNotExist(err) { // ignore the error as above
return nil
} else if err != nil {
return err
}
if (info.Mode() & notRegularFileMode) == 0 {
size += info.Size()
}
return nil
})
return size, err
}
3 changes: 2 additions & 1 deletion modules/indexer/code/bleve/bleve.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"code.gitea.io/gitea/modules/charset"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/git/gitcmd"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/indexer"
path_filter "code.gitea.io/gitea/modules/indexer/code/bleve/token/path"
"code.gitea.io/gitea/modules/indexer/code/internal"
Expand Down Expand Up @@ -163,7 +164,7 @@ func (b *Indexer) addUpdate(ctx context.Context, batchWriter git.WriteCloserErro
var err error
if !update.Sized {
var stdout string
stdout, _, err = gitcmd.NewCommand("cat-file", "-s").AddDynamicArguments(update.BlobSha).RunStdString(ctx, &gitcmd.RunOpts{Dir: repo.RepoPath()})
stdout, err = gitrepo.RunCmdString(ctx, repo, gitcmd.NewCommand("cat-file", "-s").AddDynamicArguments(update.BlobSha))
if err != nil {
return err
}
Expand Down
3 changes: 2 additions & 1 deletion modules/indexer/code/elasticsearch/elasticsearch.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/charset"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/git/gitcmd"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/indexer"
"code.gitea.io/gitea/modules/indexer/code/internal"
indexer_internal "code.gitea.io/gitea/modules/indexer/internal"
Expand Down Expand Up @@ -148,7 +149,7 @@ func (b *Indexer) addUpdate(ctx context.Context, batchWriter git.WriteCloserErro
var err error
if !update.Sized {
var stdout string
stdout, _, err = gitcmd.NewCommand("cat-file", "-s").AddDynamicArguments(update.BlobSha).RunStdString(ctx, &gitcmd.RunOpts{Dir: repo.RepoPath()})
stdout, err = gitrepo.RunCmdString(ctx, repo, gitcmd.NewCommand("cat-file", "-s").AddDynamicArguments(update.BlobSha))
if err != nil {
return nil, err
}
Expand Down
7 changes: 4 additions & 3 deletions modules/indexer/code/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/git/gitcmd"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/indexer/code/internal"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
)

func getDefaultBranchSha(ctx context.Context, repo *repo_model.Repository) (string, error) {
stdout, _, err := gitcmd.NewCommand("show-ref", "-s").AddDynamicArguments(git.BranchPrefix+repo.DefaultBranch).RunStdString(ctx, &gitcmd.RunOpts{Dir: repo.RepoPath()})
stdout, err := gitrepo.RunCmdString(ctx, repo, gitcmd.NewCommand("show-ref", "-s").AddDynamicArguments(git.BranchPrefix+repo.DefaultBranch))
if err != nil {
return "", err
}
Expand All @@ -34,7 +35,7 @@ func getRepoChanges(ctx context.Context, repo *repo_model.Repository, revision s
needGenesis := len(status.CommitSha) == 0
if !needGenesis {
hasAncestorCmd := gitcmd.NewCommand("merge-base").AddDynamicArguments(status.CommitSha, revision)
stdout, _, _ := hasAncestorCmd.RunStdString(ctx, &gitcmd.RunOpts{Dir: repo.RepoPath()})
stdout, _ := gitrepo.RunCmdString(ctx, repo, hasAncestorCmd)
needGenesis = len(stdout) == 0
}

Expand Down Expand Up @@ -100,7 +101,7 @@ func genesisChanges(ctx context.Context, repo *repo_model.Repository, revision s
// nonGenesisChanges get changes since the previous indexer update
func nonGenesisChanges(ctx context.Context, repo *repo_model.Repository, revision string) (*internal.RepoChanges, error) {
diffCmd := gitcmd.NewCommand("diff", "--name-status").AddDynamicArguments(repo.CodeIndexerStatus.CommitSha, revision)
stdout, _, runErr := diffCmd.RunStdString(ctx, &gitcmd.RunOpts{Dir: repo.RepoPath()})
stdout, runErr := gitrepo.RunCmdString(ctx, repo, diffCmd)
if runErr != nil {
// previous commit sha may have been removed by a force push, so
// try rebuilding from scratch
Expand Down
4 changes: 4 additions & 0 deletions modules/log/logger_global.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ func Debug(format string, v ...any) {
Log(1, DEBUG, format, v...)
}

func DebugWithSkip(skip int, format string, v ...any) {
Log(skip+1, DEBUG, format, v...)
}

func IsDebug() bool {
return GetLevel() <= DEBUG
}
Expand Down
Loading