refactor: use WithRepo instead of WithDir for most git operations, clean up model migrations (#38555)

by the way, remove some unnecessary "models" imports from model
migration package, fix migration test model init bug
(modelmigration/migrationtest/tests.go)
This commit is contained in:
wxiaoguang
2026-07-21 12:18:00 +00:00
committed by GitHub
parent 8731ea4bbb
commit 91eb14c944
45 changed files with 211 additions and 217 deletions
+13
View File
@@ -0,0 +1,13 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package base
import (
repo_model "gitea.dev/models/repo"
"gitea.dev/modules/git/gitcmd"
)
func LocalCodeGitRepo(ownerName, repoName string) gitcmd.RepositoryFacade {
return repo_model.CodeRepoByName(ownerName, repoName)
}
+4
View File
@@ -58,7 +58,11 @@ func PrepareTestEnv(t *testing.T, skip int, syncModels ...any) (base.EngineMigra
} }
} }
db.ResetModels()
if len(syncModels) > 0 { if len(syncModels) > 0 {
for _, syncModel := range syncModels {
db.RegisterModel(syncModel)
}
if err := x.Sync(syncModels...); err != nil { if err := x.Sync(syncModels...); err != nil {
t.Errorf("error during sync: %v", err) t.Errorf("error during sync: %v", err)
return x, deferFn return x, deferFn
+5 -7
View File
@@ -7,7 +7,6 @@ import (
"context" "context"
"fmt" "fmt"
"math" "math"
"path/filepath"
"strings" "strings"
"time" "time"
@@ -76,24 +75,23 @@ func FixMergeBase(ctx context.Context, x base.EngineMigration) error {
log.Error("Missing base repo with id %d for PR ID %d", pr.BaseRepoID, pr.ID) log.Error("Missing base repo with id %d for PR ID %d", pr.BaseRepoID, pr.ID)
continue continue
} }
userPath := filepath.Join(setting.RepoRootPath, strings.ToLower(baseRepo.OwnerName))
repoPath := filepath.Join(userPath, strings.ToLower(baseRepo.Name)+".git")
gitRepo := base.LocalCodeGitRepo(baseRepo.OwnerName, baseRepo.Name)
gitRefName := fmt.Sprintf("refs/pull/%d/head", pr.Index) gitRefName := fmt.Sprintf("refs/pull/%d/head", pr.Index)
if !pr.HasMerged { if !pr.HasMerged {
var err error var err error
pr.MergeBase, _, err = gitcmd.NewCommand("merge-base").AddDashesAndList(pr.BaseBranch, gitRefName).WithDir(repoPath).RunStdString(ctx) pr.MergeBase, _, err = gitcmd.NewCommand("merge-base").AddDashesAndList(pr.BaseBranch, gitRefName).WithRepo(gitRepo).RunStdString(ctx)
if err != nil { if err != nil {
var err2 error var err2 error
pr.MergeBase, _, err2 = gitcmd.NewCommand("rev-parse").AddDynamicArguments(git.BranchPrefix + pr.BaseBranch).WithDir(repoPath).RunStdString(ctx) pr.MergeBase, _, err2 = gitcmd.NewCommand("rev-parse").AddDynamicArguments(git.BranchPrefix + pr.BaseBranch).WithRepo(gitRepo).RunStdString(ctx)
if err2 != nil { if err2 != nil {
log.Error("Unable to get merge base for PR ID %d, Index %d in %s/%s. Error: %v & %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err, err2) log.Error("Unable to get merge base for PR ID %d, Index %d in %s/%s. Error: %v & %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err, err2)
continue continue
} }
} }
} else { } else {
parentsString, _, err := gitcmd.NewCommand("rev-list", "--parents", "-n", "1").AddDynamicArguments(pr.MergedCommitID).WithDir(repoPath).RunStdString(ctx) parentsString, _, err := gitcmd.NewCommand("rev-list", "--parents", "-n", "1").AddDynamicArguments(pr.MergedCommitID).WithRepo(gitRepo).RunStdString(ctx)
if err != nil { if err != nil {
log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err) log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
continue continue
@@ -107,7 +105,7 @@ func FixMergeBase(ctx context.Context, x base.EngineMigration) error {
refs = append(refs, gitRefName) refs = append(refs, gitRefName)
cmd := gitcmd.NewCommand("merge-base").AddDashesAndList(refs...) cmd := gitcmd.NewCommand("merge-base").AddDashesAndList(refs...)
pr.MergeBase, _, err = cmd.WithDir(repoPath).RunStdString(ctx) pr.MergeBase, _, err = cmd.WithRepo(gitRepo).RunStdString(ctx)
if err != nil { if err != nil {
log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err) log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
continue continue
+3 -5
View File
@@ -7,7 +7,6 @@ import (
"context" "context"
"fmt" "fmt"
"math" "math"
"path/filepath"
"strings" "strings"
"time" "time"
@@ -74,12 +73,11 @@ func RefixMergeBase(ctx context.Context, x base.EngineMigration) error {
log.Error("Missing base repo with id %d for PR ID %d", pr.BaseRepoID, pr.ID) log.Error("Missing base repo with id %d for PR ID %d", pr.BaseRepoID, pr.ID)
continue continue
} }
userPath := filepath.Join(setting.RepoRootPath, strings.ToLower(baseRepo.OwnerName))
repoPath := filepath.Join(userPath, strings.ToLower(baseRepo.Name)+".git")
gitRepo := base.LocalCodeGitRepo(baseRepo.OwnerName, baseRepo.Name)
gitRefName := fmt.Sprintf("refs/pull/%d/head", pr.Index) gitRefName := fmt.Sprintf("refs/pull/%d/head", pr.Index)
parentsString, _, err := gitcmd.NewCommand("rev-list", "--parents", "-n", "1").AddDynamicArguments(pr.MergedCommitID).WithDir(repoPath).RunStdString(ctx) parentsString, _, err := gitcmd.NewCommand("rev-list", "--parents", "-n", "1").AddDynamicArguments(pr.MergedCommitID).WithRepo(gitRepo).RunStdString(ctx)
if err != nil { if err != nil {
log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err) log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
continue continue
@@ -94,7 +92,7 @@ func RefixMergeBase(ctx context.Context, x base.EngineMigration) error {
refs = append(refs, gitRefName) refs = append(refs, gitRefName)
cmd := gitcmd.NewCommand("merge-base").AddDashesAndList(refs...) cmd := gitcmd.NewCommand("merge-base").AddDashesAndList(refs...)
pr.MergeBase, _, err = cmd.WithDir(repoPath).RunStdString(ctx) pr.MergeBase, _, err = cmd.WithRepo(gitRepo).RunStdString(ctx)
if err != nil { if err != nil {
log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err) log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
continue continue
+1 -2
View File
@@ -9,7 +9,6 @@ import (
"time" "time"
"gitea.dev/modelmigration/base" "gitea.dev/modelmigration/base"
repo_model "gitea.dev/models/repo"
"gitea.dev/modules/git" "gitea.dev/modules/git"
"gitea.dev/modules/graceful" "gitea.dev/modules/graceful"
"gitea.dev/modules/log" "gitea.dev/modules/log"
@@ -83,7 +82,7 @@ func AddCommitDivergenceToPulls(x base.EngineMigration) error {
log.Error("Missing base repo with id %d for PR ID %d", pr.BaseRepoID, pr.ID) log.Error("Missing base repo with id %d for PR ID %d", pr.BaseRepoID, pr.ID)
continue continue
} }
repoStore := repo_model.CodeRepoByName(baseRepo.OwnerName, baseRepo.Name) repoStore := base.LocalCodeGitRepo(baseRepo.OwnerName, baseRepo.Name)
gitRefName := fmt.Sprintf("refs/pull/%d/head", pr.Index) gitRefName := fmt.Sprintf("refs/pull/%d/head", pr.Index)
divergence, err := git.GetDivergingCommits(graceful.GetManager().HammerContext(), repoStore, pr.BaseBranch, gitRefName) divergence, err := git.GetDivergingCommits(graceful.GetManager().HammerContext(), repoStore, pr.BaseBranch, gitRefName)
if err != nil { if err != nil {
+1 -2
View File
@@ -9,7 +9,6 @@ import (
"strings" "strings"
"gitea.dev/modelmigration/base" "gitea.dev/modelmigration/base"
repo_model "gitea.dev/models/repo"
"gitea.dev/modules/git" "gitea.dev/modules/git"
"gitea.dev/modules/log" "gitea.dev/modules/log"
) )
@@ -98,7 +97,7 @@ func FixPublisherIDforTagReleases(ctx context.Context, x base.EngineMigration) e
return err return err
} }
} }
gitRepo, err = git.OpenRepository(repo_model.CodeRepoByName(repo.OwnerName, repo.Name)) gitRepo, err = git.OpenRepository(base.LocalCodeGitRepo(repo.OwnerName, repo.Name))
if err != nil { if err != nil {
log.Error("Error whilst opening git repo for [%d]%s/%s. Error: %v", repo.ID, repo.OwnerName, repo.Name, err) log.Error("Error whilst opening git repo for [%d]%s/%s. Error: %v", repo.ID, repo.OwnerName, repo.Name, err)
return err return err
+6 -7
View File
@@ -5,18 +5,17 @@ package v1_17
import ( import (
"gitea.dev/modelmigration/base" "gitea.dev/modelmigration/base"
"gitea.dev/models/pull"
"gitea.dev/modules/timeutil" "gitea.dev/modules/timeutil"
) )
func AddReviewViewedFiles(x base.EngineMigration) error { func AddReviewViewedFiles(x base.EngineMigration) error {
type ReviewState struct { type ReviewState struct {
ID int64 `xorm:"pk autoincr"` ID int64 `xorm:"pk autoincr"`
UserID int64 `xorm:"NOT NULL UNIQUE(pull_commit_user)"` UserID int64 `xorm:"NOT NULL UNIQUE(pull_commit_user)"`
PullID int64 `xorm:"NOT NULL INDEX UNIQUE(pull_commit_user) DEFAULT 0"` PullID int64 `xorm:"NOT NULL INDEX UNIQUE(pull_commit_user) DEFAULT 0"`
CommitSHA string `xorm:"NOT NULL VARCHAR(40) UNIQUE(pull_commit_user)"` CommitSHA string `xorm:"NOT NULL VARCHAR(40) UNIQUE(pull_commit_user)"`
UpdatedFiles map[string]pull.ViewedState `xorm:"NOT NULL LONGTEXT JSON"` UpdatedFiles map[string]uint8 `xorm:"NOT NULL LONGTEXT JSON"`
UpdatedUnix timeutil.TimeStamp `xorm:"updated"` UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
} }
return x.Sync(new(ReviewState)) return x.Sync(new(ReviewState))
+2 -4
View File
@@ -7,15 +7,13 @@ import (
"time" "time"
"gitea.dev/modelmigration/base" "gitea.dev/modelmigration/base"
"gitea.dev/models/repo"
"gitea.dev/modules/timeutil" "gitea.dev/modules/timeutil"
) )
func AddSyncOnCommitColForPushMirror(x base.EngineMigration) error { func AddSyncOnCommitColForPushMirror(x base.EngineMigration) error {
type PushMirror struct { type PushMirror struct {
ID int64 `xorm:"pk autoincr"` ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"INDEX"` RepoID int64 `xorm:"INDEX"`
Repo *repo.Repository `xorm:"-"`
RemoteName string RemoteName string
SyncOnCommit bool `xorm:"NOT NULL DEFAULT true"` SyncOnCommit bool `xorm:"NOT NULL DEFAULT true"`
+1 -2
View File
@@ -7,7 +7,6 @@ import (
"context" "context"
"gitea.dev/modelmigration/base" "gitea.dev/modelmigration/base"
repo_model "gitea.dev/models/repo"
"gitea.dev/modules/git" "gitea.dev/modules/git"
"gitea.dev/modules/setting" "gitea.dev/modules/setting"
) )
@@ -159,7 +158,7 @@ func migratePushMirrors(x base.EngineMigration) error {
func getRemoteAddress(ownerName, repoName, remoteName string) (string, error) { func getRemoteAddress(ownerName, repoName, remoteName string) (string, error) {
ctx := context.Background() ctx := context.Background()
repo := repo_model.CodeRepoByName(ownerName, repoName) repo := base.LocalCodeGitRepo(ownerName, repoName)
if exist, _ := git.IsRepositoryExist(ctx, repo); !exist { if exist, _ := git.IsRepositoryExist(ctx, repo); !exist {
return "", nil return "", nil
} }
+1 -2
View File
@@ -5,12 +5,11 @@ package v1_22
import ( import (
"gitea.dev/modelmigration/base" "gitea.dev/modelmigration/base"
"gitea.dev/models/perm"
) )
func AddRepoUnitEveryoneAccessMode(x base.EngineMigration) error { func AddRepoUnitEveryoneAccessMode(x base.EngineMigration) error {
type RepoUnit struct { //revive:disable-line:exported type RepoUnit struct { //revive:disable-line:exported
EveryoneAccessMode perm.AccessMode `xorm:"NOT NULL DEFAULT 0"` EveryoneAccessMode int `xorm:"NOT NULL DEFAULT 0"`
} }
return x.Sync(&RepoUnit{}) return x.Sync(&RepoUnit{})
} }
+1 -2
View File
@@ -5,14 +5,13 @@ package v1_24
import ( import (
"gitea.dev/modelmigration/base" "gitea.dev/modelmigration/base"
"gitea.dev/models/perm"
"xorm.io/xorm" "xorm.io/xorm"
) )
func AddRepoUnitAnonymousAccessMode(x base.EngineMigration) error { func AddRepoUnitAnonymousAccessMode(x base.EngineMigration) error {
type RepoUnit struct { //revive:disable-line:exported type RepoUnit struct { //revive:disable-line:exported
AnonymousAccessMode perm.AccessMode `xorm:"NOT NULL DEFAULT 0"` AnonymousAccessMode int `xorm:"NOT NULL DEFAULT 0"`
} }
_, err := x.SyncWithOptions(xorm.SyncOptions{ _, err := x.SyncWithOptions(xorm.SyncOptions{
IgnoreConstrains: true, IgnoreConstrains: true,
-4
View File
@@ -11,10 +11,6 @@ import (
"gitea.dev/modules/setting" "gitea.dev/modules/setting"
"gitea.dev/modules/test" "gitea.dev/modules/test"
_ "gitea.dev/models/actions"
_ "gitea.dev/models/git"
_ "gitea.dev/models/repo"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
+1 -2
View File
@@ -8,7 +8,6 @@ import (
"fmt" "fmt"
"gitea.dev/modelmigration/base" "gitea.dev/modelmigration/base"
repo_model "gitea.dev/models/repo"
"gitea.dev/modules/git" "gitea.dev/modules/git"
) )
@@ -86,7 +85,7 @@ func FixReleaseSha1OnReleaseTable(ctx context.Context, x base.EngineMigration) e
userCache[repo.OwnerID] = user userCache[repo.OwnerID] = user
} }
gitRepo, err = git.OpenRepository(repo_model.CodeRepoByName(user.Name, repo.Name)) gitRepo, err = git.OpenRepository(base.LocalCodeGitRepo(user.Name, repo.Name))
if err != nil { if err != nil {
return err return err
} }
+4
View File
@@ -116,6 +116,10 @@ func RegisterModel(bean any, initFunc ...func() error) {
} }
} }
func ResetModels() {
registeredModels, registeredInitFuncs = nil, nil
}
// SyncAllTables sync the schemas of all tables, is required by unit test code // SyncAllTables sync the schemas of all tables, is required by unit test code
func SyncAllTables() error { func SyncAllTables() error {
_, err := xormEngine.StoreEngine("InnoDB").SyncWithOptions(xorm.SyncOptions{ _, err := xormEngine.StoreEngine("InnoDB").SyncWithOptions(xorm.SyncOptions{
+15
View File
@@ -0,0 +1,15 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package models
import (
"context"
"gitea.dev/models/unit"
)
// Init initialize model
func Init(ctx context.Context) error {
return unit.LoadUnitConfig()
}
@@ -1,7 +1,7 @@
// Copyright 2020 The Gitea Authors. All rights reserved. // Copyright 2020 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
package models package repostats
import ( import (
"testing" "testing"
+1 -7
View File
@@ -2,7 +2,7 @@
// Copyright 2017 The Gitea Authors. All rights reserved. // Copyright 2017 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
package models package repostats
import ( import (
"context" "context"
@@ -12,7 +12,6 @@ import (
"gitea.dev/models/db" "gitea.dev/models/db"
issues_model "gitea.dev/models/issues" issues_model "gitea.dev/models/issues"
repo_model "gitea.dev/models/repo" repo_model "gitea.dev/models/repo"
"gitea.dev/models/unit"
user_model "gitea.dev/models/user" user_model "gitea.dev/models/user"
"gitea.dev/modules/log" "gitea.dev/modules/log"
@@ -21,11 +20,6 @@ import (
"xorm.io/builder" "xorm.io/builder"
) )
// Init initialize model
func Init(ctx context.Context) error {
return unit.LoadUnitConfig()
}
type repoChecker struct { type repoChecker struct {
querySQL func(ctx context.Context) ([]int64, error) querySQL func(ctx context.Context) ([]int64, error)
correctSQL func(ctx context.Context, id int64) error correctSQL func(ctx context.Context, id int64) error
@@ -1,7 +1,7 @@
// Copyright 2017 The Gitea Authors. All rights reserved. // Copyright 2017 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
package models package repostats
import ( import (
"testing" "testing"
+10 -6
View File
@@ -42,30 +42,34 @@ func CreateBundle(ctx context.Context, repo RepositoryFacade, commit string, out
// git update-ref refs/bundle/temp-{timestamp} {commit} // git update-ref refs/bundle/temp-{timestamp} {commit}
// git bundle create - refs/bundle/temp-{timestamp} // git bundle create - refs/bundle/temp-{timestamp}
// git update-ref -d refs/bundle/temp-{timestamp} // git update-ref -d refs/bundle/temp-{timestamp}
tmp, cleanup, err := setting.AppDataTempDir("git-repo-content").MkdirTempRandom("gitea-bundle") tmpDir, cleanup, err := setting.AppDataTempDir("git-repo-content").MkdirTempRandom("gitea-bundle")
if err != nil { if err != nil {
return err return err
} }
defer cleanup() defer cleanup()
env := append(os.Environ(), "GIT_OBJECT_DIRECTORY="+filepath.Join(gitcmd.RepoLocalPath(repo), "objects")) env := append(os.Environ(), "GIT_OBJECT_DIRECTORY="+filepath.Join(gitcmd.RepoLocalPath(repo), "objects"))
_, _, err = gitcmd.NewCommand("init", "--bare").WithDir(tmp).WithEnv(env).RunStdString(ctx) gitTmpCmd := func() *gitcmd.Command {
return gitcmd.NewCommand().WithDir(tmpDir).WithEnv(env)
}
_, _, err = gitTmpCmd().AddArguments("init", "--bare").RunStdString(ctx)
if err != nil { if err != nil {
return err return err
} }
_, _, err = gitcmd.NewCommand("reset", "--soft").AddDynamicArguments(commit).WithDir(tmp).WithEnv(env).RunStdString(ctx) _, _, err = gitTmpCmd().AddArguments("reset", "--soft").AddDynamicArguments(commit).RunStdString(ctx)
if err != nil { if err != nil {
return err return err
} }
_, _, err = gitcmd.NewCommand("branch", "-m", "bundle").WithDir(tmp).WithEnv(env).RunStdString(ctx) _, _, err = gitTmpCmd().AddArguments("branch", "-m", "bundle").RunStdString(ctx)
if err != nil { if err != nil {
return err return err
} }
tmpFile := filepath.Join(tmp, "bundle") tmpFile := filepath.Join(tmpDir, "bundle")
_, _, err = gitcmd.NewCommand("bundle", "create").AddDynamicArguments(tmpFile, "bundle", "HEAD").WithDir(tmp).WithEnv(env).RunStdString(ctx) _, _, err = gitTmpCmd().AddArguments("bundle", "create").AddDynamicArguments(tmpFile, "bundle", "HEAD").RunStdString(ctx)
if err != nil { if err != nil {
return err return err
} }
+8 -3
View File
@@ -6,8 +6,10 @@ package git
import ( import (
"context" "context"
"io" "io"
"os"
"gitea.dev/modules/git/gitcmd" "gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/util"
) )
type BufferedReader interface { type BufferedReader interface {
@@ -49,8 +51,11 @@ type CatFileBatchCloser interface {
// The CatFileBatch and the readers create by it should only be used in the same goroutine. // The CatFileBatch and the readers create by it should only be used in the same goroutine.
func NewBatch(ctx context.Context, repo RepositoryFacade) (CatFileBatchCloser, error) { func NewBatch(ctx context.Context, repo RepositoryFacade) (CatFileBatchCloser, error) {
repoPath := gitcmd.RepoLocalPath(repo) repoPath := gitcmd.RepoLocalPath(repo)
if DefaultFeatures().SupportCatFileBatchCommand { if _, err := os.Stat(repoPath); err != nil {
return newCatFileBatchCommand(ctx, repoPath) return nil, util.NewNotExistErrorf("repo %q doesn't exist", repo.LogString())
} }
return newCatFileBatchLegacy(ctx, repoPath) if DefaultFeatures().SupportCatFileBatchCommand {
return newCatFileBatchCommand(ctx, repo), nil
}
return newCatFileBatchLegacy(ctx, repo), nil
} }
+6 -12
View File
@@ -5,38 +5,32 @@ package git
import ( import (
"context" "context"
"os"
"path/filepath"
"strings" "strings"
"gitea.dev/modules/git/gitcmd" "gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/setting" "gitea.dev/modules/setting"
"gitea.dev/modules/util"
) )
// catFileBatchCommand implements the CatFileBatch interface using the "cat-file --batch-command" command // catFileBatchCommand implements the CatFileBatch interface using the "cat-file --batch-command" command
// for git version >= 2.36 // for git version >= 2.36
// ref: https://git-scm.com/docs/git-cat-file#Documentation/git-cat-file.txt---batch-command // ref: https://git-scm.com/docs/git-cat-file#Documentation/git-cat-file.txt---batch-command
type catFileBatchCommand struct { type catFileBatchCommand struct {
ctx context.Context ctx context.Context
repoPath string repo RepositoryFacade
batch *catFileBatchCommunicator batch *catFileBatchCommunicator
} }
var _ CatFileBatch = (*catFileBatchCommand)(nil) var _ CatFileBatch = (*catFileBatchCommand)(nil)
func newCatFileBatchCommand(ctx context.Context, repoPath string) (*catFileBatchCommand, error) { func newCatFileBatchCommand(ctx context.Context, repo RepositoryFacade) *catFileBatchCommand {
if _, err := os.Stat(repoPath); err != nil { return &catFileBatchCommand{ctx: ctx, repo: repo}
return nil, util.NewNotExistErrorf("repo %q doesn't exist", filepath.Base(repoPath))
}
return &catFileBatchCommand{ctx: ctx, repoPath: repoPath}, nil
} }
func (b *catFileBatchCommand) getBatch() *catFileBatchCommunicator { func (b *catFileBatchCommand) getBatch() *catFileBatchCommunicator {
if b.batch != nil { if b.batch != nil {
return b.batch return b.batch
} }
b.batch = newCatFileBatch(b.ctx, b.repoPath, gitcmd.NewCommand("cat-file", "--batch-command")) b.batch = newCatFileBatch(b.ctx, b.repo, gitcmd.NewCommand("cat-file", "--batch-command"))
return b.batch return b.batch
} }
+5 -11
View File
@@ -6,13 +6,10 @@ package git
import ( import (
"context" "context"
"io" "io"
"os"
"path/filepath"
"strings" "strings"
"gitea.dev/modules/git/gitcmd" "gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/setting" "gitea.dev/modules/setting"
"gitea.dev/modules/util"
) )
// catFileBatchLegacy implements the CatFileBatch interface using the "cat-file --batch" command and "cat-file --batch-check" command // catFileBatchLegacy implements the CatFileBatch interface using the "cat-file --batch" command and "cat-file --batch-check" command
@@ -21,25 +18,22 @@ import (
// ref: https://git-scm.com/docs/git-cat-file#Documentation/git-cat-file.txt---batch // ref: https://git-scm.com/docs/git-cat-file#Documentation/git-cat-file.txt---batch
type catFileBatchLegacy struct { type catFileBatchLegacy struct {
ctx context.Context ctx context.Context
repoPath string repo RepositoryFacade
batchContent *catFileBatchCommunicator batchContent *catFileBatchCommunicator
batchCheck *catFileBatchCommunicator batchCheck *catFileBatchCommunicator
} }
var _ CatFileBatchCloser = (*catFileBatchLegacy)(nil) var _ CatFileBatchCloser = (*catFileBatchLegacy)(nil)
func newCatFileBatchLegacy(ctx context.Context, repoPath string) (*catFileBatchLegacy, error) { func newCatFileBatchLegacy(ctx context.Context, repo RepositoryFacade) *catFileBatchLegacy {
if _, err := os.Stat(repoPath); err != nil { return &catFileBatchLegacy{ctx: ctx, repo: repo}
return nil, util.NewNotExistErrorf("repo %q doesn't exist", filepath.Base(repoPath))
}
return &catFileBatchLegacy{ctx: ctx, repoPath: repoPath}, nil
} }
func (b *catFileBatchLegacy) getBatchContent() *catFileBatchCommunicator { func (b *catFileBatchLegacy) getBatchContent() *catFileBatchCommunicator {
if b.batchContent != nil { if b.batchContent != nil {
return b.batchContent return b.batchContent
} }
b.batchContent = newCatFileBatch(b.ctx, b.repoPath, gitcmd.NewCommand("cat-file", "--batch")) b.batchContent = newCatFileBatch(b.ctx, b.repo, gitcmd.NewCommand("cat-file", "--batch"))
return b.batchContent return b.batchContent
} }
@@ -47,7 +41,7 @@ func (b *catFileBatchLegacy) getBatchCheck() *catFileBatchCommunicator {
if b.batchCheck != nil { if b.batchCheck != nil {
return b.batchCheck return b.batchCheck
} }
b.batchCheck = newCatFileBatch(b.ctx, b.repoPath, gitcmd.NewCommand("cat-file", "--batch-check")) b.batchCheck = newCatFileBatch(b.ctx, b.repo, gitcmd.NewCommand("cat-file", "--batch-check"))
return b.batchCheck return b.batchCheck
} }
+3 -3
View File
@@ -34,7 +34,7 @@ func (b *catFileBatchCommunicator) Close(err ...error) {
} }
// newCatFileBatch opens git cat-file --batch/--batch-check/--batch-command command and prepares the stdin/stdout pipes for communication. // newCatFileBatch opens git cat-file --batch/--batch-check/--batch-command command and prepares the stdin/stdout pipes for communication.
func newCatFileBatch(ctx context.Context, repoPath string, cmdCatFile *gitcmd.Command) *catFileBatchCommunicator { func newCatFileBatch(ctx context.Context, repo RepositoryFacade, cmdCatFile *gitcmd.Command) *catFileBatchCommunicator {
ctx, ctxCancel := context.WithCancelCause(ctx) ctx, ctxCancel := context.WithCancelCause(ctx)
stdinWriter, stdoutReader, stdPipeClose := cmdCatFile.MakeStdinStdoutPipe() stdinWriter, stdoutReader, stdPipeClose := cmdCatFile.MakeStdinStdoutPipe()
ret := &catFileBatchCommunicator{ ret := &catFileBatchCommunicator{
@@ -47,7 +47,7 @@ func newCatFileBatch(ctx context.Context, repoPath string, cmdCatFile *gitcmd.Co
stdPipeClose() stdPipeClose()
})) }))
err := cmdCatFile.WithDir(repoPath).StartWithStderr(ctx) err := cmdCatFile.WithRepo(repo).StartWithStderr(ctx)
if err != nil { if err != nil {
log.Error("Unable to start git command %v: %v", cmdCatFile.LogString(), err) log.Error("Unable to start git command %v: %v", cmdCatFile.LogString(), err)
// ideally here it should return the error, but it would require refactoring all callers // ideally here it should return the error, but it would require refactoring all callers
@@ -59,7 +59,7 @@ func newCatFileBatch(ctx context.Context, repoPath string, cmdCatFile *gitcmd.Co
go func() { go func() {
err := cmdCatFile.WaitWithStderr() err := cmdCatFile.WaitWithStderr()
if err != nil && !errors.Is(err, context.Canceled) { if err != nil && !errors.Is(err, context.Canceled) {
log.Error("cat-file --batch command failed in repo %s, error: %v", repoPath, err) log.Error("cat-file --batch command failed in repo %s, error: %v", repo.LogString(), err)
} }
ret.Close(err) ret.Close(err)
}() }()
+25 -30
View File
@@ -35,7 +35,14 @@ type Command struct {
args []string args []string
preErrors []error preErrors []error
configArgs []string configArgs []string
opts runOpts
// Dir is the working dir for the git command, however:
// FIXME: this could be incorrect in many cases, for example:
// * /some/path/.git
// * /some/path/.git/gitea-data/data/repositories/user/repo.git
// If "user/repo.git" is invalid/broken, then running git command in it will use "/some/path/.git", and produce unexpected results
// The correct approach is to use `--git-dir" global argument or "GIT_DIR=..." environment variable.
gitDir string
cmd *exec.Cmd cmd *exec.Cmd
@@ -44,10 +51,15 @@ type Command struct {
cmdFinished process.FinishedFunc cmdFinished process.FinishedFunc
cmdStartTime time.Time cmdStartTime time.Time
pipelineFunc func(Context) error
parentPipeFiles []*os.File parentPipeFiles []*os.File
parentPipeReaders []*os.File parentPipeReaders []*os.File
childrenPipeFiles []*os.File childrenPipeFiles []*os.File
cmdEnv []string
cmdTimeout time.Duration
// only os.Pipe and in-memory buffers can work with Stdin safely, see https://github.com/golang/go/issues/77227 if the command would exit unexpectedly // only os.Pipe and in-memory buffers can work with Stdin safely, see https://github.com/golang/go/issues/77227 if the command would exit unexpectedly
cmdStdin io.Reader cmdStdin io.Reader
cmdStdout io.Writer cmdStdout io.Writer
@@ -204,23 +216,6 @@ func ToTrustedCmdArgs(args []string) TrustedCmdArgs {
return ret return ret
} }
type runOpts struct {
// TODO: this struct should be removed, the fields can be just merged into the command
Env []string
Timeout time.Duration
// Dir is the working dir for the git command, however:
// FIXME: this could be incorrect in many cases, for example:
// * /some/path/.git
// * /some/path/.git/gitea-data/data/repositories/user/repo.git
// If "user/repo.git" is invalid/broken, then running git command in it will use "/some/path/.git", and produce unexpected results
// The correct approach is to use `--git-dir" global argument or "GIT_DIR=..." environment variable.
Dir string
PipelineFunc func(Context) error
}
func commonBaseEnvs() []string { func commonBaseEnvs() []string {
envs := []string{ envs := []string{
// Make Gitea use internal git config only, to prevent conflicts with user's git config // Make Gitea use internal git config only, to prevent conflicts with user's git config
@@ -262,17 +257,17 @@ func CommonCmdServEnvs() []string {
var ErrBrokenCommand = errors.New("git command is broken") var ErrBrokenCommand = errors.New("git command is broken")
func (c *Command) WithDir(dir string) *Command { func (c *Command) WithDir(dir string) *Command {
c.opts.Dir = dir c.gitDir = dir
return c return c
} }
func (c *Command) WithEnv(env []string) *Command { func (c *Command) WithEnv(env []string) *Command {
c.opts.Env = env c.cmdEnv = env
return c return c
} }
func (c *Command) WithTimeout(timeout time.Duration) *Command { func (c *Command) WithTimeout(timeout time.Duration) *Command {
c.opts.Timeout = timeout c.cmdTimeout = timeout
return c return c
} }
@@ -361,7 +356,7 @@ func (c *Command) WithStdoutCopy(w io.Writer) *Command {
// The returned error of Run / Wait can be joined errors from the pipeline function, context cause, and command exit error. // The returned error of Run / Wait can be joined errors from the pipeline function, context cause, and command exit error.
// Caller can get the pipeline function's error (if any) by UnwrapPipelineError. // Caller can get the pipeline function's error (if any) by UnwrapPipelineError.
func (c *Command) WithPipelineFunc(f func(ctx Context) error) *Command { func (c *Command) WithPipelineFunc(f func(ctx Context) error) *Command {
c.opts.PipelineFunc = f c.pipelineFunc = f
return c return c
} }
@@ -418,7 +413,7 @@ func (c *Command) Start(ctx context.Context) (retErr error) {
c.WithParentCallerInfo() c.WithParentCallerInfo()
} }
// these logs are for debugging purposes only, so no guarantee of correctness or stability // these logs are for debugging purposes only, so no guarantee of correctness or stability
desc := fmt.Sprintf("git.Run(by:%s, repo:%s): %s", c.callerInfo, logArgSanitize(c.opts.Dir), cmdLogString) desc := fmt.Sprintf("git.Run(by:%s, repo:%s): %s", c.callerInfo, logArgSanitize(c.gitDir), cmdLogString)
log.Debug("git.Command: %s", desc) log.Debug("git.Command: %s", desc)
_, span := gtprof.GetTracer().Start(ctx, gtprof.TraceSpanGitRun) _, span := gtprof.GetTracer().Start(ctx, gtprof.TraceSpanGitRun)
@@ -426,24 +421,24 @@ func (c *Command) Start(ctx context.Context) (retErr error) {
span.SetAttributeString(gtprof.TraceAttrFuncCaller, c.callerInfo) span.SetAttributeString(gtprof.TraceAttrFuncCaller, c.callerInfo)
span.SetAttributeString(gtprof.TraceAttrGitCommand, cmdLogString) span.SetAttributeString(gtprof.TraceAttrGitCommand, cmdLogString)
if c.opts.Timeout <= 0 { if c.cmdTimeout <= 0 {
c.cmdCtx, c.cmdCancel, c.cmdFinished = process.GetManager().AddContext(ctx, desc) c.cmdCtx, c.cmdCancel, c.cmdFinished = process.GetManager().AddContext(ctx, desc)
} else { } else {
c.cmdCtx, c.cmdCancel, c.cmdFinished = process.GetManager().AddContextTimeout(ctx, c.opts.Timeout, desc) c.cmdCtx, c.cmdCancel, c.cmdFinished = process.GetManager().AddContextTimeout(ctx, c.cmdTimeout, desc)
} }
c.cmdStartTime = time.Now() c.cmdStartTime = time.Now()
c.cmd = exec.CommandContext(c.cmdCtx, c.prog, append(c.configArgs, c.args...)...) c.cmd = exec.CommandContext(c.cmdCtx, c.prog, append(c.configArgs, c.args...)...)
if c.opts.Env == nil { if c.cmdEnv == nil {
c.cmd.Env = os.Environ() c.cmd.Env = os.Environ()
} else { } else {
c.cmd.Env = c.opts.Env c.cmd.Env = c.cmdEnv
} }
process.SetSysProcAttribute(c.cmd) process.SetSysProcAttribute(c.cmd)
c.cmd.Env = append(c.cmd.Env, CommonGitCmdEnvs()...) c.cmd.Env = append(c.cmd.Env, CommonGitCmdEnvs()...)
c.cmd.Dir = c.opts.Dir c.cmd.Dir = c.gitDir
c.cmd.Stdout = c.cmdStdout c.cmd.Stdout = c.cmdStdout
c.cmd.Stdin = c.cmdStdin c.cmd.Stdin = c.cmdStdin
c.cmd.Stderr = c.cmdStderr c.cmd.Stderr = c.cmdStderr
@@ -481,8 +476,8 @@ func (c *Command) Wait() error {
c.cmdFinished() c.cmdFinished()
}() }()
if c.opts.PipelineFunc != nil { if c.pipelineFunc != nil {
errPipeline := c.opts.PipelineFunc(&cmdContext{Context: c.cmdCtx, cmd: c}) errPipeline := c.pipelineFunc(&cmdContext{Context: c.cmdCtx, cmd: c})
if context.Cause(c.cmdCtx) == nil { if context.Cause(c.cmdCtx) == nil {
// if the context is not canceled explicitly, we need to discard the unread data, // if the context is not canceled explicitly, we need to discard the unread data,
+1 -1
View File
@@ -25,7 +25,7 @@ type RepositoryFacade interface {
} }
func (c *Command) WithRepo(repo RepositoryFacade) *Command { func (c *Command) WithRepo(repo RepositoryFacade) *Command {
c.opts.Dir = RepoLocalPath(repo) c.gitDir = RepoLocalPath(repo)
return c return c
} }
+6 -6
View File
@@ -15,19 +15,19 @@ import (
) )
// CatFileBatchCheck runs cat-file with --batch-check // CatFileBatchCheck runs cat-file with --batch-check
func CatFileBatchCheck(ctx context.Context, cmd *gitcmd.Command, tmpBasePath string) error { func CatFileBatchCheck(ctx context.Context, cmd *gitcmd.Command, repo git.RepositoryFacade) error {
cmd.AddArguments("cat-file", "--batch-check") cmd.AddArguments("cat-file", "--batch-check")
return cmd.WithDir(tmpBasePath).RunWithStderr(ctx) return cmd.WithRepo(repo).RunWithStderr(ctx)
} }
// CatFileBatchCheckAllObjects runs cat-file with --batch-check --batch-all // CatFileBatchCheckAllObjects runs cat-file with --batch-check --batch-all
func CatFileBatchCheckAllObjects(ctx context.Context, cmd *gitcmd.Command, gitRepo *git.Repository) error { func CatFileBatchCheckAllObjects(ctx context.Context, cmd *gitcmd.Command, repo git.RepositoryFacade) error {
return cmd.AddArguments("cat-file", "--batch-check", "--batch-all-objects").WithRepo(gitRepo).RunWithStderr(ctx) return cmd.AddArguments("cat-file", "--batch-check", "--batch-all-objects").WithRepo(repo).RunWithStderr(ctx)
} }
// CatFileBatch runs cat-file --batch // CatFileBatch runs cat-file --batch
func CatFileBatch(ctx context.Context, cmd *gitcmd.Command, gitRepo git.RepositoryFacade) error { func CatFileBatch(ctx context.Context, cmd *gitcmd.Command, repo git.RepositoryFacade) error {
return cmd.AddArguments("cat-file", "--batch").WithRepo(gitRepo).RunWithStderr(ctx) return cmd.AddArguments("cat-file", "--batch").WithRepo(repo).RunWithStderr(ctx)
} }
// BlobsLessThan1024FromCatFileBatchCheck reads a pipeline from cat-file --batch-check and returns the blobs <1024 in size // BlobsLessThan1024FromCatFileBatchCheck reads a pipeline from cat-file --batch-check and returns the blobs <1024 in size
+3 -2
View File
@@ -9,16 +9,17 @@ import (
"io" "io"
"strings" "strings"
"gitea.dev/modules/git"
"gitea.dev/modules/git/gitcmd" "gitea.dev/modules/git/gitcmd"
) )
// RevListObjects run rev-list --objects from headSHA to baseSHA // RevListObjects run rev-list --objects from headSHA to baseSHA
func RevListObjects(ctx context.Context, cmd *gitcmd.Command, tmpBasePath, headSHA, baseSHA string) error { func RevListObjects(ctx context.Context, cmd *gitcmd.Command, repo git.RepositoryFacade, headSHA, baseSHA string) error {
cmd.AddArguments("rev-list", "--objects").AddDynamicArguments(headSHA) cmd.AddArguments("rev-list", "--objects").AddDynamicArguments(headSHA)
if baseSHA != "" { if baseSHA != "" {
cmd = cmd.AddArguments("--not").AddDynamicArguments(baseSHA) cmd = cmd.AddArguments("--not").AddDynamicArguments(baseSHA)
} }
return cmd.WithDir(tmpBasePath).RunWithStderr(ctx) return cmd.WithRepo(repo).RunWithStderr(ctx)
} }
// BlobsFromRevListObjects reads a RevListAllObjects and only selects blobs // BlobsFromRevListObjects reads a RevListAllObjects and only selects blobs
+5 -5
View File
@@ -105,8 +105,8 @@ func IsRepoURLAccessible(ctx context.Context, url string) bool {
} }
// InitRepositoryLocal initializes a new Git repository. // InitRepositoryLocal initializes a new Git repository.
func InitRepositoryLocal(ctx context.Context, repoPath string, bare bool, objectFormatName string) error { func InitRepositoryLocal(ctx context.Context, localRepoPath string, bare bool, objectFormatName string) error {
err := os.MkdirAll(repoPath, os.ModePerm) err := os.MkdirAll(localRepoPath, os.ModePerm)
if err != nil { if err != nil {
return err return err
} }
@@ -123,7 +123,7 @@ func InitRepositoryLocal(ctx context.Context, repoPath string, bare bool, object
if bare { if bare {
cmd.AddArguments("--bare") cmd.AddArguments("--bare")
} }
_, _, err = cmd.WithDir(repoPath).RunStdString(ctx) _, _, err = cmd.WithDir(localRepoPath).RunStdString(ctx)
return err return err
} }
@@ -234,7 +234,7 @@ type PushOptions struct {
} }
// Push pushs local commits to given remote branch. // Push pushs local commits to given remote branch.
func Push(ctx context.Context, repoPath string, opts PushOptions) error { func Push(ctx context.Context, localRepoPath string, opts PushOptions) error {
cmd := gitcmd.NewCommand("push") cmd := gitcmd.NewCommand("push")
if opts.ForceWithLease != "" { if opts.ForceWithLease != "" {
cmd.AddOptionFormat("--force-with-lease=%s", opts.ForceWithLease) cmd.AddOptionFormat("--force-with-lease=%s", opts.ForceWithLease)
@@ -256,7 +256,7 @@ func Push(ctx context.Context, repoPath string, opts PushOptions) error {
} }
cmd.AddDashesAndList(remoteBranchArgs...) cmd.AddDashesAndList(remoteBranchArgs...)
stdout, stderr, err := cmd.WithEnv(opts.Env).WithTimeout(opts.Timeout).WithDir(repoPath).RunStdString(ctx) stdout, stderr, err := cmd.WithEnv(opts.Env).WithTimeout(opts.Timeout).WithDir(localRepoPath).RunStdString(ctx)
if err != nil { if err != nil {
if strings.Contains(stderr, "non-fast-forward") { if strings.Contains(stderr, "non-fast-forward") {
return &ErrPushOutOfDate{StdOut: stdout, StdErr: stderr, Err: err} return &ErrPushOutOfDate{StdOut: stdout, StdErr: stderr, Err: err}
+5 -5
View File
@@ -19,11 +19,11 @@ type TemplateSubmoduleCommit struct {
// GetTemplateSubmoduleCommits returns a list of submodules paths and their commits from a repository // GetTemplateSubmoduleCommits returns a list of submodules paths and their commits from a repository
// This function is only for generating new repos based on existing template, the template couldn't be too large. // This function is only for generating new repos based on existing template, the template couldn't be too large.
func GetTemplateSubmoduleCommits(ctx context.Context, repoPath string) (submoduleCommits []TemplateSubmoduleCommit, _ error) { func GetTemplateSubmoduleCommits(ctx context.Context, repo gitcmd.RepositoryFacade) (submoduleCommits []TemplateSubmoduleCommit, _ error) {
cmd := gitcmd.NewCommand("ls-tree", "-r", "--", "HEAD") cmd := gitcmd.NewCommand("ls-tree", "-r", "--", "HEAD")
stdoutReader, stdoutReaderClose := cmd.MakeStdoutPipe() stdoutReader, stdoutReaderClose := cmd.MakeStdoutPipe()
defer stdoutReaderClose() defer stdoutReaderClose()
err := cmd.WithDir(repoPath). err := cmd.WithRepo(repo).
WithPipelineFunc(func(ctx gitcmd.Context) error { WithPipelineFunc(func(ctx gitcmd.Context) error {
scanner := bufio.NewScanner(stdoutReader) scanner := bufio.NewScanner(stdoutReader)
for scanner.Scan() { for scanner.Scan() {
@@ -46,11 +46,11 @@ func GetTemplateSubmoduleCommits(ctx context.Context, repoPath string) (submodul
// AddTemplateSubmoduleIndexes Adds the given submodules to the git index. // AddTemplateSubmoduleIndexes Adds the given submodules to the git index.
// It is only for generating new repos based on existing template, requires the .gitmodules file to be already present in the work dir. // It is only for generating new repos based on existing template, requires the .gitmodules file to be already present in the work dir.
func AddTemplateSubmoduleIndexes(ctx context.Context, repoPath string, submodules []TemplateSubmoduleCommit) error { func AddTemplateSubmoduleIndexes(ctx context.Context, tmpRepoPath string, submodules []TemplateSubmoduleCommit) error {
for _, submodule := range submodules { for _, submodule := range submodules {
cmd := gitcmd.NewCommand("update-index", "--add", "--cacheinfo", "160000").AddDynamicArguments(submodule.Commit, submodule.Path) cmd := gitcmd.NewCommand("update-index", "--add", "--cacheinfo", "160000").AddDynamicArguments(submodule.Commit, submodule.Path)
if stdout, _, err := cmd.WithDir(repoPath).RunStdString(ctx); err != nil { if stdout, _, err := cmd.WithDir(tmpRepoPath).RunStdString(ctx); err != nil {
log.Error("Unable to add %s as submodule to repo %s: stdout %s\nError: %v", submodule.Path, repoPath, stdout, err) log.Error("Unable to add %s as submodule to repo %s: stdout %s\nError: %v", submodule.Path, tmpRepoPath, stdout, err)
return err return err
} }
} }
+2 -2
View File
@@ -15,7 +15,7 @@ import (
) )
func TestGetTemplateSubmoduleCommits(t *testing.T) { func TestGetTemplateSubmoduleCommits(t *testing.T) {
testRepoPath := filepath.Join(testReposDir, "repo4_submodules") testRepoPath := mockRepository("repo4_submodules")
submodules, err := GetTemplateSubmoduleCommits(t.Context(), testRepoPath) submodules, err := GetTemplateSubmoduleCommits(t.Context(), testRepoPath)
require.NoError(t, err) require.NoError(t, err)
@@ -41,7 +41,7 @@ func TestAddTemplateSubmoduleIndexes(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
_, _, err = gitcmd.NewCommand("-c", "user.name=a", "-c", "user.email=b", "commit", "-m=test").WithDir(tmpDir).RunStdString(ctx) _, _, err = gitcmd.NewCommand("-c", "user.name=a", "-c", "user.email=b", "commit", "-m=test").WithDir(tmpDir).RunStdString(ctx)
require.NoError(t, err) require.NoError(t, err)
submodules, err := GetTemplateSubmoduleCommits(t.Context(), tmpDir) submodules, err := GetTemplateSubmoduleCommits(t.Context(), mockRepository(tmpDir))
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, submodules, 1) assert.Len(t, submodules, 1)
assert.Equal(t, "new-dir", submodules[0].Path) assert.Equal(t, "new-dir", submodules[0].Path)
+3 -3
View File
@@ -265,20 +265,20 @@ var (
func dummyInfoRefs(ctx *context.Context) { func dummyInfoRefs(ctx *context.Context) {
infoRefsOnce.Do(func() { infoRefsOnce.Do(func() {
tmpDir, cleanup, err := setting.AppDataTempDir("git-repo-content").MkdirTempRandom("gitea-info-refs-cache") tmpEmptyRepoDir, cleanup, err := setting.AppDataTempDir("git-repo-content").MkdirTempRandom("gitea-info-refs-cache")
if err != nil { if err != nil {
log.Error("Failed to create temp dir for git-receive-pack cache: %v", err) log.Error("Failed to create temp dir for git-receive-pack cache: %v", err)
return return
} }
defer cleanup() defer cleanup()
if err := git.InitRepositoryLocal(ctx, tmpDir, true, git.Sha1ObjectFormat.Name()); err != nil { if err := git.InitRepositoryLocal(ctx, tmpEmptyRepoDir, true, git.Sha1ObjectFormat.Name()); err != nil {
log.Error("Failed to init bare repo for git-receive-pack cache: %v", err) log.Error("Failed to init bare repo for git-receive-pack cache: %v", err)
return return
} }
refs, _, err := gitcmd.NewCommand("receive-pack", "--stateless-rpc", "--advertise-refs", "."). refs, _, err := gitcmd.NewCommand("receive-pack", "--stateless-rpc", "--advertise-refs", ".").
WithDir(tmpDir). WithDir(tmpEmptyRepoDir).
RunStdBytes(ctx) RunStdBytes(ctx)
if err != nil { if err != nil {
log.Error(fmt.Sprintf("%v - %s", err, string(refs))) log.Error(fmt.Sprintf("%v - %s", err, string(refs)))
+2 -2
View File
@@ -7,8 +7,8 @@ import (
"context" "context"
"time" "time"
"gitea.dev/models"
git_model "gitea.dev/models/git" git_model "gitea.dev/models/git"
"gitea.dev/models/repostats"
user_model "gitea.dev/models/user" user_model "gitea.dev/models/user"
"gitea.dev/models/webhook" "gitea.dev/models/webhook"
"gitea.dev/modules/git/gitcmd" "gitea.dev/modules/git/gitcmd"
@@ -69,7 +69,7 @@ func registerCheckRepoStats() {
RunAtStart: true, RunAtStart: true,
Schedule: "@midnight", Schedule: "@midnight",
}, func(ctx context.Context, _ *user_model.User, _ Config) error { }, func(ctx context.Context, _ *user_model.User, _ Config) error {
return models.CheckRepoStats(ctx) return repostats.CheckRepoStats(ctx)
}) })
} }
+2 -2
View File
@@ -7,9 +7,9 @@ import (
"context" "context"
"fmt" "fmt"
"gitea.dev/models"
"gitea.dev/models/db" "gitea.dev/models/db"
repo_model "gitea.dev/models/repo" repo_model "gitea.dev/models/repo"
"gitea.dev/models/repostats"
user_model "gitea.dev/models/user" user_model "gitea.dev/models/user"
"gitea.dev/modules/git" "gitea.dev/modules/git"
"gitea.dev/modules/log" "gitea.dev/modules/log"
@@ -57,7 +57,7 @@ func checkHooks(ctx context.Context, logger log.Logger, autofix bool) error {
func checkUserStarNum(ctx context.Context, logger log.Logger, autofix bool) error { func checkUserStarNum(ctx context.Context, logger log.Logger, autofix bool) error {
if autofix { if autofix {
if err := models.DoctorUserStarNum(ctx); err != nil { if err := repostats.DoctorUserStarNum(ctx); err != nil {
logger.Critical("Unable update User Stars numbers") logger.Critical("Unable update User Stars numbers")
return err return err
} }
+2 -2
View File
@@ -13,10 +13,10 @@ import (
"strings" "strings"
"time" "time"
"gitea.dev/models"
"gitea.dev/models/db" "gitea.dev/models/db"
issues_model "gitea.dev/models/issues" issues_model "gitea.dev/models/issues"
repo_model "gitea.dev/models/repo" repo_model "gitea.dev/models/repo"
"gitea.dev/models/repostats"
user_model "gitea.dev/models/user" user_model "gitea.dev/models/user"
"gitea.dev/modules/git" "gitea.dev/modules/git"
"gitea.dev/modules/git/gitcmd" "gitea.dev/modules/git/gitcmd"
@@ -965,7 +965,7 @@ func (g *GiteaLocalUploader) Finish(ctx context.Context) error {
return err return err
} }
if err := models.UpdateRepoStats(ctx, g.repo.ID); err != nil { if err := repostats.UpdateRepoStats(ctx, g.repo.ID); err != nil {
return err return err
} }
+2 -2
View File
@@ -64,7 +64,7 @@ func LFSPush(ctx context.Context, tmpBasePath string, tmpRepo git.RepositoryFaca
// 3. Run batch-check on the objects retrieved from rev-list // 3. Run batch-check on the objects retrieved from rev-list
wg.Go(func() error { wg.Go(func() error {
return pipeline.CatFileBatchCheck(ctx, cmd3BathCheck, tmpBasePath) return pipeline.CatFileBatchCheck(ctx, cmd3BathCheck, tmpRepo)
}) })
// 2. Check each object retrieved rejecting those without names as they will be commits or trees // 2. Check each object retrieved rejecting those without names as they will be commits or trees
@@ -74,7 +74,7 @@ func LFSPush(ctx context.Context, tmpBasePath string, tmpRepo git.RepositoryFaca
// 1. Run rev-list objects from mergeHead to mergeBase // 1. Run rev-list objects from mergeHead to mergeBase
wg.Go(func() error { wg.Go(func() error {
return pipeline.RevListObjects(ctx, cmd1RevList, tmpBasePath, mergeHeadSHA, mergeBaseSHA) return pipeline.RevListObjects(ctx, cmd1RevList, tmpRepo, mergeHeadSHA, mergeBaseSHA)
}) })
return wg.Wait() return wg.Wait()
+6 -6
View File
@@ -38,7 +38,7 @@ type mergeContext struct {
func (ctx *mergeContext) PrepareGitCmd(cmd *gitcmd.Command) *gitcmd.Command { func (ctx *mergeContext) PrepareGitCmd(cmd *gitcmd.Command) *gitcmd.Command {
ctx.outbuf.Reset() ctx.outbuf.Reset()
return cmd.WithEnv(ctx.env). return cmd.WithEnv(ctx.env).
WithDir(ctx.tmpBasePath). WithRepo(ctx.tmpRepo).
WithParentCallerInfo(). WithParentCallerInfo().
WithStdoutBuffer(ctx.outbuf) WithStdoutBuffer(ctx.outbuf)
} }
@@ -77,7 +77,7 @@ func createTemporaryRepoForMerge(ctx context.Context, pr *issues_model.PullReque
trackingCommitID, _, err := gitcmd.NewCommand("show-ref", "--hash"). trackingCommitID, _, err := gitcmd.NewCommand("show-ref", "--hash").
AddDynamicArguments(git.BranchPrefix + tmpRepoTrackingBranch). AddDynamicArguments(git.BranchPrefix + tmpRepoTrackingBranch).
WithEnv(mergeCtx.env). WithEnv(mergeCtx.env).
WithDir(mergeCtx.tmpBasePath). WithRepo(mergeCtx.tmpRepo).
RunStdString(ctx) RunStdString(ctx)
if err != nil { if err != nil {
defer cancel() defer cancel()
@@ -154,7 +154,7 @@ func prepareTemporaryRepoForMerge(ctx *mergeContext) error {
} }
defer sparseCheckoutListFile.Close() // we will close it earlier but we need to ensure it is closed if there is an error defer sparseCheckoutListFile.Close() // we will close it earlier but we need to ensure it is closed if there is an error
if err := getDiffTree(ctx, ctx.tmpBasePath, tmpRepoBaseBranch, tmpRepoTrackingBranch, sparseCheckoutListFile); err != nil { if err := getDiffTree(ctx, ctx.tmpRepo, tmpRepoBaseBranch, tmpRepoTrackingBranch, sparseCheckoutListFile); err != nil {
log.Error("%-v getDiffTree(%s, %s, %s): %v", ctx.pr, ctx.tmpBasePath, tmpRepoBaseBranch, tmpRepoTrackingBranch, err) log.Error("%-v getDiffTree(%s, %s, %s): %v", ctx.pr, ctx.tmpBasePath, tmpRepoBaseBranch, tmpRepoTrackingBranch, err)
return fmt.Errorf("getDiffTree: %w", err) return fmt.Errorf("getDiffTree: %w", err)
} }
@@ -206,13 +206,13 @@ func prepareTemporaryRepoForMerge(ctx *mergeContext) error {
} }
// getDiffTree returns a string containing all the files that were changed between headBranch and baseBranch // getDiffTree returns a string containing all the files that were changed between headBranch and baseBranch
// the filenames are escaped so as to fit the format required for .git/info/sparse-checkout // the filenames are escaped to fit the format required for .git/info/sparse-checkout
func getDiffTree(ctx context.Context, repoPath, baseBranch, headBranch string, out io.Writer) error { func getDiffTree(ctx context.Context, repo git.RepositoryFacade, baseBranch, headBranch string, out io.Writer) error {
cmd := gitcmd.NewCommand("diff-tree", "--no-commit-id", "--name-only", "-r", "-r", "-z", "--root") cmd := gitcmd.NewCommand("diff-tree", "--no-commit-id", "--name-only", "-r", "-r", "-z", "--root")
diffOutReader, diffOutReaderClose := cmd.MakeStdoutPipe() diffOutReader, diffOutReaderClose := cmd.MakeStdoutPipe()
defer diffOutReaderClose() defer diffOutReaderClose()
err := cmd.AddDynamicArguments(baseBranch, headBranch). err := cmd.AddDynamicArguments(baseBranch, headBranch).
WithDir(repoPath). WithRepo(repo).
WithPipelineFunc(func(ctx gitcmd.Context) error { WithPipelineFunc(func(ctx gitcmd.Context) error {
// Now scan the output from the command // Now scan the output from the command
scanner := bufio.NewScanner(diffOutReader) scanner := bufio.NewScanner(diffOutReader)
+2 -2
View File
@@ -16,7 +16,7 @@ import (
// getRebaseAmendMessage composes the message to amend commits in rebase merge of a pull request. // getRebaseAmendMessage composes the message to amend commits in rebase merge of a pull request.
func getRebaseAmendMessage(ctx *mergeContext, baseGitRepo *git.Repository) (message string, err error) { func getRebaseAmendMessage(ctx *mergeContext, baseGitRepo *git.Repository) (message string, err error) {
// Get existing commit message. // Get existing commit message.
commitMessage, _, err := gitcmd.NewCommand("show", "--format=%B", "-s").WithDir(ctx.tmpBasePath).RunStdString(ctx) commitMessage, _, err := gitcmd.NewCommand("show", "--format=%B", "-s").WithRepo(ctx.tmpRepo).RunStdString(ctx)
if err != nil { if err != nil {
return "", err return "", err
} }
@@ -76,7 +76,7 @@ func doMergeRebaseFastForward(ctx *mergeContext) error {
cmdCommit := gitcmd.NewCommand("commit", "--amend"). cmdCommit := gitcmd.NewCommand("commit", "--amend").
AddOptionFormat("--message=%s", newMessage) AddOptionFormat("--message=%s", newMessage)
addCommitSigningOptions(cmdCommit, ctx.signKey) addCommitSigningOptions(cmdCommit, ctx.signKey)
if err := cmdCommit.WithDir(ctx.tmpBasePath).Run(ctx); err != nil { if err := cmdCommit.WithRepo(ctx.tmpRepo).Run(ctx); err != nil {
log.Error("Unable to amend commit message: %v", err) log.Error("Unable to amend commit message: %v", err)
return err return err
} }
+25 -25
View File
@@ -73,23 +73,23 @@ func checkPullRequestMergeableByTmpRepo(ctx context.Context, pr *issues_model.Pu
} }
defer cancel() defer cancel()
gitRepo, err := git.OpenRepositoryLocal(prCtx.tmpBasePath) tmpGitRepo, err := git.OpenRepositoryLocal(prCtx.tmpBasePath)
if err != nil { if err != nil {
return fmt.Errorf("OpenRepository: %w", err) return fmt.Errorf("OpenRepository: %w", err)
} }
defer gitRepo.Close() defer tmpGitRepo.Close()
// 1. update merge base // 1. update merge base
pr.MergeBase, _, err = gitcmd.NewCommand("merge-base", "--", tmpRepoBaseBranch, tmpRepoTrackingBranch).WithDir(prCtx.tmpBasePath).RunStdString(ctx) pr.MergeBase, _, err = gitcmd.NewCommand("merge-base", "--", tmpRepoBaseBranch, tmpRepoTrackingBranch).WithRepo(prCtx.tmpRepo).RunStdString(ctx)
if err != nil { if err != nil {
var err2 error var err2 error
pr.MergeBase, err2 = gitRepo.GetRefCommitID(ctx, git.BranchPrefix+tmpRepoBaseBranch) pr.MergeBase, err2 = tmpGitRepo.GetRefCommitID(ctx, git.BranchPrefix+tmpRepoBaseBranch)
if err2 != nil { if err2 != nil {
return fmt.Errorf("GetMergeBase: %v and can't find commit ID for base: %w", err, err2) return fmt.Errorf("GetMergeBase: %v and can't find commit ID for base: %w", err, err2)
} }
} }
pr.MergeBase = strings.TrimSpace(pr.MergeBase) pr.MergeBase = strings.TrimSpace(pr.MergeBase)
if pr.HeadCommitID, err = gitRepo.GetRefCommitID(ctx, git.BranchPrefix+tmpRepoTrackingBranch); err != nil { if pr.HeadCommitID, err = tmpGitRepo.GetRefCommitID(ctx, git.BranchPrefix+tmpRepoTrackingBranch); err != nil {
return fmt.Errorf("GetBranchCommitID: can't find commit ID for head: %w", err) return fmt.Errorf("GetBranchCommitID: can't find commit ID for head: %w", err)
} }
@@ -99,7 +99,7 @@ func checkPullRequestMergeableByTmpRepo(ctx context.Context, pr *issues_model.Pu
} }
// 2. Check for conflicts // 2. Check for conflicts
conflicts, err := checkConflictsByTmpRepo(ctx, pr, gitRepo, prCtx.tmpBasePath) conflicts, err := checkConflictsByTmpRepo(ctx, pr, tmpGitRepo, prCtx.tmpBasePath)
if err != nil { if err != nil {
return err return err
} }
@@ -110,7 +110,7 @@ func checkPullRequestMergeableByTmpRepo(ctx context.Context, pr *issues_model.Pu
} }
// 3. Check for protected files changes // 3. Check for protected files changes
if err = checkPullFilesProtection(ctx, pr, gitRepo, tmpRepoTrackingBranch); err != nil { if err = checkPullFilesProtection(ctx, pr, tmpGitRepo, tmpRepoTrackingBranch); err != nil {
return fmt.Errorf("pr.CheckPullFilesProtection(): %w", err) return fmt.Errorf("pr.CheckPullFilesProtection(): %w", err)
} }
@@ -127,7 +127,7 @@ func (e *errMergeConflict) Error() string {
return "conflict detected at: " + e.filename return "conflict detected at: " + e.filename
} }
func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, filesToRemove *[]string, filesToAdd *[]git.IndexObjectInfo) error { func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, tmpGitRepo *git.Repository, filesToRemove *[]string, filesToAdd *[]git.IndexObjectInfo) error {
log.Trace("Attempt to merge:\n%v", file) log.Trace("Attempt to merge:\n%v", file)
switch { switch {
@@ -182,7 +182,7 @@ func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, f
} }
// Need to get the objects from the object db to attempt to merge // Need to get the objects from the object db to attempt to merge
root, _, err := gitcmd.NewCommand("unpack-file").AddDynamicArguments(file.stage1.sha).WithDir(tmpBasePath).RunStdString(ctx) root, _, err := gitcmd.NewCommand("unpack-file").AddDynamicArguments(file.stage1.sha).WithRepo(tmpGitRepo).RunStdString(ctx)
if err != nil { if err != nil {
return fmt.Errorf("unable to get root object: %s at path: %s for merging. Error: %w", file.stage1.sha, file.stage1.path, err) return fmt.Errorf("unable to get root object: %s at path: %s for merging. Error: %w", file.stage1.sha, file.stage1.path, err)
} }
@@ -191,7 +191,7 @@ func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, f
_ = util.Remove(filepath.Join(tmpBasePath, root)) _ = util.Remove(filepath.Join(tmpBasePath, root))
}() }()
base, _, err := gitcmd.NewCommand("unpack-file").AddDynamicArguments(file.stage2.sha).WithDir(tmpBasePath).RunStdString(ctx) base, _, err := gitcmd.NewCommand("unpack-file").AddDynamicArguments(file.stage2.sha).WithRepo(tmpGitRepo).RunStdString(ctx)
if err != nil { if err != nil {
return fmt.Errorf("unable to get base object: %s at path: %s for merging. Error: %w", file.stage2.sha, file.stage2.path, err) return fmt.Errorf("unable to get base object: %s at path: %s for merging. Error: %w", file.stage2.sha, file.stage2.path, err)
} }
@@ -199,7 +199,7 @@ func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, f
defer func() { defer func() {
_ = util.Remove(base) _ = util.Remove(base)
}() }()
head, _, err := gitcmd.NewCommand("unpack-file").AddDynamicArguments(file.stage3.sha).WithDir(tmpBasePath).RunStdString(ctx) head, _, err := gitcmd.NewCommand("unpack-file").AddDynamicArguments(file.stage3.sha).WithRepo(tmpGitRepo).RunStdString(ctx)
if err != nil { if err != nil {
return fmt.Errorf("unable to get head object:%s at path: %s for merging. Error: %w", file.stage3.sha, file.stage3.path, err) return fmt.Errorf("unable to get head object:%s at path: %s for merging. Error: %w", file.stage3.sha, file.stage3.path, err)
} }
@@ -209,13 +209,13 @@ func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, f
}() }()
// now git merge-file annoyingly takes a different order to the merge-tree ... // now git merge-file annoyingly takes a different order to the merge-tree ...
_, _, conflictErr := gitcmd.NewCommand("merge-file").AddDynamicArguments(base, root, head).WithDir(tmpBasePath).RunStdString(ctx) _, _, conflictErr := gitcmd.NewCommand("merge-file").AddDynamicArguments(base, root, head).WithRepo(tmpGitRepo).RunStdString(ctx)
if conflictErr != nil { if conflictErr != nil {
return &errMergeConflict{file.stage2.path} return &errMergeConflict{file.stage2.path}
} }
// base now contains the merged data // base now contains the merged data
hash, _, err := gitcmd.NewCommand("hash-object", "-w", "--path").AddDynamicArguments(file.stage2.path, base).WithDir(tmpBasePath).RunStdString(ctx) hash, _, err := gitcmd.NewCommand("hash-object", "-w", "--path").AddDynamicArguments(file.stage2.path, base).WithRepo(tmpGitRepo).RunStdString(ctx)
if err != nil { if err != nil {
return err return err
} }
@@ -240,7 +240,7 @@ func AttemptThreeWayMerge(ctx context.Context, gitPath string, gitRepo *git.Repo
defer cancel() defer cancel()
// First we use read-tree to do a simple three-way merge // First we use read-tree to do a simple three-way merge
if err := gitcmd.NewCommand("read-tree", "-m").AddDynamicArguments(base, ours, theirs).WithDir(gitPath).RunWithStderr(ctx); err != nil { if err := gitcmd.NewCommand("read-tree", "-m").AddDynamicArguments(base, ours, theirs).WithRepo(gitRepo).RunWithStderr(ctx); err != nil {
log.Error("Unable to run read-tree -m! Error: %v", err) log.Error("Unable to run read-tree -m! Error: %v", err)
return false, nil, fmt.Errorf("unable to run read-tree -m! Error: %w", err) return false, nil, fmt.Errorf("unable to run read-tree -m! Error: %w", err)
} }
@@ -250,7 +250,7 @@ func AttemptThreeWayMerge(ctx context.Context, gitPath string, gitRepo *git.Repo
// Then we use git ls-files -u to list the unmerged files and collate the triples in unmergedfiles // Then we use git ls-files -u to list the unmerged files and collate the triples in unmergedfiles
unmerged := make(chan *unmergedFile) unmerged := make(chan *unmergedFile)
go unmergedFiles(ctx, gitPath, unmerged) go unmergedFiles(ctx, gitRepo, unmerged)
defer func() { defer func() {
cancel() cancel()
@@ -273,7 +273,7 @@ func AttemptThreeWayMerge(ctx context.Context, gitPath string, gitRepo *git.Repo
} }
// OK now we have the unmerged file triplet attempt to merge it // OK now we have the unmerged file triplet attempt to merge it
if err := attemptMerge(ctx, file, gitPath, &filesToRemove, &filesToAdd); err != nil { if err := attemptMerge(ctx, file, gitPath, gitRepo, &filesToRemove, &filesToAdd); err != nil {
if conflictErr, ok := err.(*errMergeConflict); ok { if conflictErr, ok := err.(*errMergeConflict); ok {
log.Trace("Conflict: %s in %s", conflictErr.filename, description) log.Trace("Conflict: %s in %s", conflictErr.filename, description)
conflict = true conflict = true
@@ -298,14 +298,14 @@ func AttemptThreeWayMerge(ctx context.Context, gitPath string, gitRepo *git.Repo
return conflict, conflictedFiles, nil return conflict, conflictedFiles, nil
} }
func checkConflictsByTmpRepo(ctx context.Context, pr *issues_model.PullRequest, gitRepo *git.Repository, tmpBasePath string) (bool, error) { func checkConflictsByTmpRepo(ctx context.Context, pr *issues_model.PullRequest, tmpGitRepo *git.Repository, tmpBasePath string) (bool, error) {
// 1. checkConflictsByTmpRepo resets the conflict status - therefore - reset the conflict status // 1. checkConflictsByTmpRepo resets the conflict status - therefore - reset the conflict status
pr.ConflictedFiles = nil pr.ConflictedFiles = nil
// 2. AttemptThreeWayMerge first - this is much quicker than plain patch to base // 2. AttemptThreeWayMerge first - this is much quicker than plain patch to base
description := fmt.Sprintf("PR[%d] %s/%s#%d", pr.ID, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, pr.Index) description := fmt.Sprintf("PR[%d] %s/%s#%d", pr.ID, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, pr.Index)
conflict, conflictFiles, err := AttemptThreeWayMerge(ctx, conflict, conflictFiles, err := AttemptThreeWayMerge(ctx,
tmpBasePath, gitRepo, pr.MergeBase, tmpRepoBaseBranch, tmpRepoTrackingBranch, description) tmpBasePath, tmpGitRepo, pr.MergeBase, tmpRepoBaseBranch, tmpRepoTrackingBranch, description)
if err != nil { if err != nil {
return false, err return false, err
} }
@@ -314,13 +314,13 @@ func checkConflictsByTmpRepo(ctx context.Context, pr *issues_model.PullRequest,
// No conflicts detected so we need to check if the patch is empty... // No conflicts detected so we need to check if the patch is empty...
// a. Write the newly merged tree and check the new tree-hash // a. Write the newly merged tree and check the new tree-hash
var treeHash string var treeHash string
treeHash, _, err = gitcmd.NewCommand("write-tree").WithDir(tmpBasePath).RunStdString(ctx) treeHash, _, err = gitcmd.NewCommand("write-tree").WithRepo(tmpGitRepo).RunStdString(ctx)
if err != nil { if err != nil {
lsfiles, _, _ := gitcmd.NewCommand("ls-files", "-u").WithDir(tmpBasePath).RunStdString(ctx) lsfiles, _, _ := gitcmd.NewCommand("ls-files", "-u").WithRepo(tmpGitRepo).RunStdString(ctx)
return false, fmt.Errorf("unable to write unconflicted tree: %w\n`git ls-files -u`:\n%s", err, lsfiles) return false, fmt.Errorf("unable to write unconflicted tree: %w\n`git ls-files -u`:\n%s", err, lsfiles)
} }
treeHash = strings.TrimSpace(treeHash) treeHash = strings.TrimSpace(treeHash)
baseTree, err := gitRepo.GetTree(ctx, tmpRepoBaseBranch) baseTree, err := tmpGitRepo.GetTree(ctx, tmpRepoBaseBranch)
if err != nil { if err != nil {
return false, err return false, err
} }
@@ -365,11 +365,11 @@ func (err ErrFilePathProtected) Unwrap() error {
} }
// CheckFileProtection check file Protection // CheckFileProtection check file Protection
func CheckFileProtection(ctx context.Context, repo *git.Repository, branchName, oldCommitID, newCommitID string, patterns []glob.Glob, limit int, env []string) ([]string, error) { func CheckFileProtection(ctx context.Context, gitRepo *git.Repository, branchName, oldCommitID, newCommitID string, patterns []glob.Glob, limit int, env []string) ([]string, error) {
if len(patterns) == 0 { if len(patterns) == 0 {
return nil, nil return nil, nil
} }
affectedFiles, err := git.GetAffectedFiles(ctx, repo, branchName, oldCommitID, newCommitID, env) affectedFiles, err := git.GetAffectedFiles(ctx, gitRepo, branchName, oldCommitID, newCommitID, env)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -395,11 +395,11 @@ func CheckFileProtection(ctx context.Context, repo *git.Repository, branchName,
} }
// CheckUnprotectedFiles check if the commit only touches unprotected files // CheckUnprotectedFiles check if the commit only touches unprotected files
func CheckUnprotectedFiles(ctx context.Context, repo *git.Repository, branchName, oldCommitID, newCommitID string, patterns []glob.Glob, env []string) (bool, error) { func CheckUnprotectedFiles(ctx context.Context, gitRepo *git.Repository, branchName, oldCommitID, newCommitID string, patterns []glob.Glob, env []string) (bool, error) {
if len(patterns) == 0 { if len(patterns) == 0 {
return false, nil return false, nil
} }
affectedFiles, err := git.GetAffectedFiles(ctx, repo, branchName, oldCommitID, newCommitID, env) affectedFiles, err := git.GetAffectedFiles(ctx, gitRepo, branchName, oldCommitID, newCommitID, env)
if err != nil { if err != nil {
return false, err return false, err
} }
+5 -4
View File
@@ -12,6 +12,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"gitea.dev/modules/git"
"gitea.dev/modules/git/gitcmd" "gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/log" "gitea.dev/modules/log"
) )
@@ -53,7 +54,7 @@ func (line *lsFileLine) String() string {
// readUnmergedLsFileLines calls git ls-files -u -z and parses the lines into mode-sha-stage-path quadruplets // readUnmergedLsFileLines calls git ls-files -u -z and parses the lines into mode-sha-stage-path quadruplets
// it will push these to the provided channel closing it at the end // it will push these to the provided channel closing it at the end
func readUnmergedLsFileLines(ctx context.Context, tmpBasePath string, outputChan chan *lsFileLine) { func readUnmergedLsFileLines(ctx context.Context, tmpRepo git.RepositoryFacade, outputChan chan *lsFileLine) {
defer func() { defer func() {
// Always close the outputChan at the end of this function // Always close the outputChan at the end of this function
close(outputChan) close(outputChan)
@@ -62,7 +63,7 @@ func readUnmergedLsFileLines(ctx context.Context, tmpBasePath string, outputChan
cmd := gitcmd.NewCommand("ls-files", "-u", "-z") cmd := gitcmd.NewCommand("ls-files", "-u", "-z")
lsFilesReader, lsFilesReaderClose := cmd.MakeStdoutPipe() lsFilesReader, lsFilesReaderClose := cmd.MakeStdoutPipe()
defer lsFilesReaderClose() defer lsFilesReaderClose()
err := cmd.WithDir(tmpBasePath). err := cmd.WithRepo(tmpRepo).
WithPipelineFunc(func(gitcmd.Context) error { WithPipelineFunc(func(gitcmd.Context) error {
bufferedReader := bufio.NewReader(lsFilesReader) bufferedReader := bufio.NewReader(lsFilesReader)
@@ -123,7 +124,7 @@ func (u *unmergedFile) String() string {
// unmergedFiles will collate the output from readUnstagedLsFileLines in to file triplets and send them // unmergedFiles will collate the output from readUnstagedLsFileLines in to file triplets and send them
// to the provided channel, closing at the end. // to the provided channel, closing at the end.
func unmergedFiles(ctx context.Context, tmpBasePath string, unmerged chan *unmergedFile) { func unmergedFiles(ctx context.Context, tmpGitRepo git.RepositoryFacade, unmerged chan *unmergedFile) {
defer func() { defer func() {
// Always close the channel // Always close the channel
close(unmerged) close(unmerged)
@@ -131,7 +132,7 @@ func unmergedFiles(ctx context.Context, tmpBasePath string, unmerged chan *unmer
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
lsFileLineChan := make(chan *lsFileLine, 10) // give lsFileLineChan a buffer lsFileLineChan := make(chan *lsFileLine, 10) // give lsFileLineChan a buffer
go readUnmergedLsFileLines(ctx, tmpBasePath, lsFileLineChan) go readUnmergedLsFileLines(ctx, tmpGitRepo, lsFileLineChan)
defer func() { defer func() {
cancel() cancel()
for range lsFileLineChan { for range lsFileLineChan {
+1 -1
View File
@@ -536,7 +536,7 @@ func checkIfPRContentChanged(ctx context.Context, pr *issues_model.PullRequest,
stdoutReader, stdoutReaderClose := cmd.MakeStdoutPipe() stdoutReader, stdoutReaderClose := cmd.MakeStdoutPipe()
defer stdoutReaderClose() defer stdoutReaderClose()
if err := cmd.WithDir(prCtx.tmpBasePath). if err := cmd.WithRepo(prCtx.tmpRepo).
WithPipelineFunc(func(ctx gitcmd.Context) error { WithPipelineFunc(func(ctx gitcmd.Context) error {
return util.IsEmptyReader(stdoutReader) return util.IsEmptyReader(stdoutReader)
}). }).
+1 -1
View File
@@ -40,7 +40,7 @@ type prTmpRepoContext struct {
// Do NOT use it with gitcmd.RunStd*() functions, otherwise it will panic // Do NOT use it with gitcmd.RunStd*() functions, otherwise it will panic
func (ctx *prTmpRepoContext) PrepareGitCmd(cmd *gitcmd.Command) *gitcmd.Command { func (ctx *prTmpRepoContext) PrepareGitCmd(cmd *gitcmd.Command) *gitcmd.Command {
ctx.outbuf.Reset() ctx.outbuf.Reset()
return cmd.WithDir(ctx.tmpBasePath).WithStdoutBuffer(ctx.outbuf) return cmd.WithRepo(ctx.tmpRepo).WithStdoutBuffer(ctx.outbuf)
} }
// createTemporaryRepoForPR creates a temporary repo with "base" for pr.BaseBranch and "tracking" for pr.HeadBranch // createTemporaryRepoForPR creates a temporary repo with "base" for pr.BaseBranch and "tracking" for pr.HeadBranch
+2 -2
View File
@@ -29,7 +29,7 @@ func updateHeadByRebaseOnToBase(ctx context.Context, pr *issues_model.PullReques
// Determine the old merge-base before the rebase - we use this for LFS push later on // Determine the old merge-base before the rebase - we use this for LFS push later on
oldMergeBase, _, _ := gitcmd.NewCommand("merge-base").AddDashesAndList(tmpRepoBaseBranch, tmpRepoTrackingBranch). oldMergeBase, _, _ := gitcmd.NewCommand("merge-base").AddDashesAndList(tmpRepoBaseBranch, tmpRepoTrackingBranch).
WithDir(mergeCtx.tmpBasePath).RunStdString(ctx) WithRepo(mergeCtx.tmpRepo).RunStdString(ctx)
oldMergeBase = strings.TrimSpace(oldMergeBase) oldMergeBase = strings.TrimSpace(oldMergeBase)
// Rebase the tracking branch on to the base as the staging branch // Rebase the tracking branch on to the base as the staging branch
@@ -81,7 +81,7 @@ func updateHeadByRebaseOnToBase(ctx context.Context, pr *issues_model.PullReques
pr.ID, pr.ID,
pr.Index, pr.Index,
)). )).
WithDir(mergeCtx.tmpBasePath). WithRepo(mergeCtx.tmpRepo).
WithStdoutBuffer(mergeCtx.outbuf). WithStdoutBuffer(mergeCtx.outbuf).
RunWithStderr(ctx); err != nil { RunWithStderr(ctx); err != nil {
if strings.Contains(err.Stderr(), "non-fast-forward") { if strings.Contains(err.Stderr(), "non-fast-forward") {
+1 -1
View File
@@ -168,7 +168,7 @@ func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user
cmdApply.AddArguments("-3") cmdApply.AddArguments("-3")
} }
if err := cmdApply.WithDir(t.basePath). if err := cmdApply.WithRepo(t.gitRepo).
WithStdinBytes([]byte(opts.Content)). WithStdinBytes([]byte(opts.Content)).
RunWithStderr(ctx); err != nil { RunWithStderr(ctx); err != nil {
return nil, fmt.Errorf("git apply error: %w", err) return nil, fmt.Errorf("git apply error: %w", err)
+16 -29
View File
@@ -6,7 +6,6 @@ package files
import ( import (
"bytes" "bytes"
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
"os" "os"
@@ -18,7 +17,6 @@ import (
user_model "gitea.dev/models/user" user_model "gitea.dev/models/user"
"gitea.dev/modules/git" "gitea.dev/modules/git"
"gitea.dev/modules/git/gitcmd" "gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/log"
repo_module "gitea.dev/modules/repository" repo_module "gitea.dev/modules/repository"
"gitea.dev/modules/setting" "gitea.dev/modules/setting"
"gitea.dev/modules/util" "gitea.dev/modules/util"
@@ -76,7 +74,7 @@ func (t *TemporaryUploadRepository) Clone(ctx context.Context, branch string, ba
Name: t.repo.Name, Name: t.repo.Name,
} }
} }
return fmt.Errorf("Clone: %w %s", err, stderr) return fmt.Errorf("temp repo clone error: %w, %s", err, stderr)
} }
gitRepo, err := git.OpenRepositoryLocal(t.basePath) gitRepo, err := git.OpenRepositoryLocal(t.basePath)
if err != nil { if err != nil {
@@ -101,7 +99,7 @@ func (t *TemporaryUploadRepository) Init(ctx context.Context, objectFormatName s
// SetDefaultIndex sets the git index to our HEAD // SetDefaultIndex sets the git index to our HEAD
func (t *TemporaryUploadRepository) SetDefaultIndex(ctx context.Context) error { func (t *TemporaryUploadRepository) SetDefaultIndex(ctx context.Context) error {
if err := gitcmd.NewCommand("read-tree", "HEAD").WithDir(t.basePath).RunWithStderr(ctx); err != nil { if err := gitcmd.NewCommand("read-tree", "HEAD").WithRepo(t.gitRepo).RunWithStderr(ctx); err != nil {
return fmt.Errorf("SetDefaultIndex: %w", err) return fmt.Errorf("SetDefaultIndex: %w", err)
} }
return nil return nil
@@ -109,7 +107,7 @@ func (t *TemporaryUploadRepository) SetDefaultIndex(ctx context.Context) error {
// RefreshIndex looks at the current index and checks to see if merges or updates are needed by checking stat() information. // RefreshIndex looks at the current index and checks to see if merges or updates are needed by checking stat() information.
func (t *TemporaryUploadRepository) RefreshIndex(ctx context.Context) error { func (t *TemporaryUploadRepository) RefreshIndex(ctx context.Context) error {
if err := gitcmd.NewCommand("update-index", "--refresh").WithDir(t.basePath).RunWithStderr(ctx); err != nil { if err := gitcmd.NewCommand("update-index", "--refresh").WithRepo(t.gitRepo).RunWithStderr(ctx); err != nil {
return fmt.Errorf("RefreshIndex: %w", err) return fmt.Errorf("RefreshIndex: %w", err)
} }
return nil return nil
@@ -119,7 +117,7 @@ func (t *TemporaryUploadRepository) RefreshIndex(ctx context.Context) error {
func (t *TemporaryUploadRepository) LsFiles(ctx context.Context, filenames ...string) ([]string, error) { func (t *TemporaryUploadRepository) LsFiles(ctx context.Context, filenames ...string) ([]string, error) {
stdOut := new(bytes.Buffer) stdOut := new(bytes.Buffer)
if err := gitcmd.NewCommand("ls-files", "-z").AddDashesAndList(filenames...). if err := gitcmd.NewCommand("ls-files", "-z").AddDashesAndList(filenames...).
WithDir(t.basePath). WithRepo(t.gitRepo).
WithStdoutBuffer(stdOut). WithStdoutBuffer(stdOut).
RunWithStderr(ctx); err != nil { RunWithStderr(ctx); err != nil {
return nil, fmt.Errorf("unable to run git ls-files for temporary repo of: %s, error: %w", t.repo.FullName(), err) return nil, fmt.Errorf("unable to run git ls-files for temporary repo of: %s, error: %w", t.repo.FullName(), err)
@@ -136,7 +134,7 @@ func (t *TemporaryUploadRepository) LsFiles(ctx context.Context, filenames ...st
func (t *TemporaryUploadRepository) RemoveRecursivelyFromIndex(ctx context.Context, path string) error { func (t *TemporaryUploadRepository) RemoveRecursivelyFromIndex(ctx context.Context, path string) error {
_, _, err := gitcmd.NewCommand("rm", "--cached", "-r"). _, _, err := gitcmd.NewCommand("rm", "--cached", "-r").
AddDynamicArguments(path). AddDynamicArguments(path).
WithDir(t.basePath). WithRepo(t.gitRepo).
RunStdBytes(ctx) RunStdBytes(ctx)
return err return err
} }
@@ -157,7 +155,7 @@ func (t *TemporaryUploadRepository) RemoveFilesFromIndex(ctx context.Context, fi
} }
if err := gitcmd.NewCommand("update-index", "--remove", "-z", "--index-info"). if err := gitcmd.NewCommand("update-index", "--remove", "-z", "--index-info").
WithDir(t.basePath). WithRepo(t.gitRepo).
WithStdinBytes(stdIn.Bytes()). WithStdinBytes(stdIn.Bytes()).
RunWithStderr(ctx); err != nil { RunWithStderr(ctx); err != nil {
return fmt.Errorf("unable to update-index for temporary repo: %q, error: %w", t.repo.FullName(), err) return fmt.Errorf("unable to update-index for temporary repo: %q, error: %w", t.repo.FullName(), err)
@@ -169,7 +167,7 @@ func (t *TemporaryUploadRepository) RemoveFilesFromIndex(ctx context.Context, fi
func (t *TemporaryUploadRepository) HashObjectAndWrite(ctx context.Context, content io.Reader) (string, error) { func (t *TemporaryUploadRepository) HashObjectAndWrite(ctx context.Context, content io.Reader) (string, error) {
stdOut := new(bytes.Buffer) stdOut := new(bytes.Buffer)
if err := gitcmd.NewCommand("hash-object", "-w", "--stdin"). if err := gitcmd.NewCommand("hash-object", "-w", "--stdin").
WithDir(t.basePath). WithRepo(t.gitRepo).
WithStdoutBuffer(stdOut). WithStdoutBuffer(stdOut).
WithStdinCopy(content). WithStdinCopy(content).
RunWithStderr(ctx); err != nil { RunWithStderr(ctx); err != nil {
@@ -182,7 +180,7 @@ func (t *TemporaryUploadRepository) HashObjectAndWrite(ctx context.Context, cont
// AddObjectToIndex adds the provided object hash to the index with the provided mode and path // AddObjectToIndex adds the provided object hash to the index with the provided mode and path
func (t *TemporaryUploadRepository) AddObjectToIndex(ctx context.Context, mode, objectHash, objectPath string) error { func (t *TemporaryUploadRepository) AddObjectToIndex(ctx context.Context, mode, objectHash, objectPath string) error {
cmd := gitcmd.NewCommand("update-index", "--add", "--replace", "--cacheinfo"). cmd := gitcmd.NewCommand("update-index", "--add", "--replace", "--cacheinfo").
AddDynamicArguments(mode + "," + objectHash + "," + objectPath).WithDir(t.basePath) AddDynamicArguments(mode + "," + objectHash + "," + objectPath).WithRepo(t.gitRepo)
if err := cmd.RunWithStderr(ctx); err != nil { if err := cmd.RunWithStderr(ctx); err != nil {
if matched, _ := regexp.MatchString(".*Invalid path '.*", err.Stderr()); matched { if matched, _ := regexp.MatchString(".*Invalid path '.*", err.Stderr()); matched {
return ErrFilePathInvalid{ return ErrFilePathInvalid{
@@ -197,10 +195,9 @@ func (t *TemporaryUploadRepository) AddObjectToIndex(ctx context.Context, mode,
// WriteTree writes the current index as a tree to the object db and returns its hash // WriteTree writes the current index as a tree to the object db and returns its hash
func (t *TemporaryUploadRepository) WriteTree(ctx context.Context) (string, error) { func (t *TemporaryUploadRepository) WriteTree(ctx context.Context) (string, error) {
stdout, _, err := gitcmd.NewCommand("write-tree").WithDir(t.basePath).RunStdString(ctx) stdout, _, err := gitcmd.NewCommand("write-tree").WithRepo(t.gitRepo).RunStdString(ctx)
if err != nil { if err != nil {
log.Error("Unable to write tree in temporary repo: %s(%s): Error: %v", t.repo.FullName(), t.basePath, err) return "", fmt.Errorf("unable to write-tree in temporary repo for %s, error: %w", t.repo.FullName(), err)
return "", fmt.Errorf("Unable to write-tree in temporary repo for: %s Error: %w", t.repo.FullName(), err)
} }
return strings.TrimSpace(stdout), nil return strings.TrimSpace(stdout), nil
} }
@@ -215,10 +212,9 @@ func (t *TemporaryUploadRepository) GetLastCommitByRef(ctx context.Context, ref
if ref == "" { if ref == "" {
ref = "HEAD" ref = "HEAD"
} }
stdout, _, err := gitcmd.NewCommand("rev-parse").AddDynamicArguments(ref).WithDir(t.basePath).RunStdString(ctx) stdout, _, err := gitcmd.NewCommand("rev-parse").AddDynamicArguments(ref).WithRepo(t.gitRepo).RunStdString(ctx)
if err != nil { if err != nil {
log.Error("Unable to get last ref for %s in temporary repo: %s(%s): Error: %v", ref, t.repo.FullName(), t.basePath, err) return "", fmt.Errorf("unable to rev-parse ref %s in temporary repo for: %s, error: %w", ref, t.repo.FullName(), err)
return "", fmt.Errorf("Unable to rev-parse %s in temporary repo for: %s Error: %w", ref, t.repo.FullName(), err)
} }
return strings.TrimSpace(stdout), nil return strings.TrimSpace(stdout), nil
} }
@@ -328,11 +324,11 @@ func (t *TemporaryUploadRepository) CommitTree(ctx context.Context, opts *Commit
stdout := new(bytes.Buffer) stdout := new(bytes.Buffer)
if err := cmdCommitTree. if err := cmdCommitTree.
WithEnv(env). WithEnv(env).
WithDir(t.basePath). WithRepo(t.gitRepo).
WithStdoutBuffer(stdout). WithStdoutBuffer(stdout).
WithStdinBytes(messageBytes.Bytes()). WithStdinBytes(messageBytes.Bytes()).
RunWithStderr(ctx); err != nil { RunWithStderr(ctx); err != nil {
return "", fmt.Errorf("unable to commit-tree in temporary repo: %s Error: %w", t.repo.FullName(), err) return "", fmt.Errorf("unable to commit-tree in temporary repo: %s, error: %w", t.repo.FullName(), err)
} }
return strings.TrimSpace(stdout.String()), nil return strings.TrimSpace(stdout.String()), nil
} }
@@ -351,10 +347,7 @@ func (t *TemporaryUploadRepository) Push(ctx context.Context, doer *user_model.U
} else if git.IsErrPushRejected(err) { } else if git.IsErrPushRejected(err) {
return err return err
} }
log.Error("Unable to push back to repo from temporary repo: %s (%s)\nError: %v", return fmt.Errorf("unable to push back to repo %s from temporary repo, error: %w", t.repo.FullName(), err)
t.repo.FullName(), t.basePath, err)
return fmt.Errorf("Unable to push back to repo from temporary repo: %s (%s) Error: %v",
t.repo.FullName(), t.basePath, err)
} }
return nil return nil
} }
@@ -367,7 +360,7 @@ func (t *TemporaryUploadRepository) DiffIndex(ctx context.Context, oldContent, n
defer stdoutReaderClose() defer stdoutReaderClose()
err := cmd.WithTimeout(30 * time.Second). err := cmd.WithTimeout(30 * time.Second).
WithDir(t.basePath). WithRepo(t.gitRepo).
WithPipelineFunc(func(ctx gitcmd.Context) error { WithPipelineFunc(func(ctx gitcmd.Context) error {
var diffErr error var diffErr error
diff, diffErr = gitdiff.ParsePatch(ctx, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, stdoutReader, "") diff, diffErr = gitdiff.ParsePatch(ctx, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, stdoutReader, "")
@@ -390,16 +383,10 @@ func (t *TemporaryUploadRepository) DiffIndex(ctx context.Context, oldContent, n
// GetBranchCommit Gets the commit object of the given branch // GetBranchCommit Gets the commit object of the given branch
func (t *TemporaryUploadRepository) GetBranchCommit(ctx context.Context, branch string) (*git.Commit, error) { func (t *TemporaryUploadRepository) GetBranchCommit(ctx context.Context, branch string) (*git.Commit, error) {
if t.gitRepo == nil {
return nil, errors.New("repository has not been cloned")
}
return t.gitRepo.GetBranchCommit(ctx, branch) return t.gitRepo.GetBranchCommit(ctx, branch)
} }
// GetCommit Gets the commit object of the given commit ID // GetCommit Gets the commit object of the given commit ID
func (t *TemporaryUploadRepository) GetCommit(ctx context.Context, commitID string) (*git.Commit, error) { func (t *TemporaryUploadRepository) GetCommit(ctx context.Context, commitID string) (*git.Commit, error) {
if t.gitRepo == nil {
return nil, errors.New("repository has not been cloned")
}
return t.gitRepo.GetCommit(ctx, commitID) return t.gitRepo.GetCommit(ctx, commitID)
} }
+1 -1
View File
@@ -218,7 +218,7 @@ func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *r
} }
// Get active submodules from the template // Get active submodules from the template
submodules, err := git.GetTemplateSubmoduleCommits(ctx, tmpDir) submodules, err := git.GetTemplateSubmoduleCommits(ctx, templateRepo)
if err != nil { if err != nil {
return fmt.Errorf("GetTemplateSubmoduleCommits: %w", err) return fmt.Errorf("GetTemplateSubmoduleCommits: %w", err)
} }