Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add abstraction layer to check if the repository exists on disk #33874

Merged
merged 6 commits into from
Mar 14, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 5 additions & 0 deletions modules/gitrepo/gitrepo.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,8 @@ func RepositoryFromRequestContextOrOpen(ctx reqctx.RequestContext, repo Reposito
ctx.SetContextValue(ck, gitRepo)
return gitRepo, nil
}

// IsRepositoryExist returns true if the repository directory exists in the disk
func IsRepositoryExist(ctx context.Context, repo Repository) (bool, error) {
return util.IsExist(repoPath(repo))
}
16 changes: 8 additions & 8 deletions modules/repository/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
issues_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/label"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/options"
Expand Down Expand Up @@ -120,25 +121,24 @@ func LoadRepoConfig() error {
return nil
}

func CheckInitRepository(ctx context.Context, owner, name, objectFormatName string) (err error) {
func CheckInitRepository(ctx context.Context, repo *repo_model.Repository) (err error) {
// Somehow the directory could exist.
repoPath := repo_model.RepoPath(owner, name)
isExist, err := util.IsExist(repoPath)
isExist, err := gitrepo.IsRepositoryExist(ctx, repo)
if err != nil {
log.Error("Unable to check if %s exists. Error: %v", repoPath, err)
log.Error("Unable to check if %s exists. Error: %v", repo.FullName(), err)
return err
}
if isExist {
return repo_model.ErrRepoFilesAlreadyExist{
Uname: owner,
Name: name,
Uname: repo.OwnerName,
Name: repo.Name,
}
}

// Init git bare new repository.
if err = git.InitRepository(ctx, repoPath, true, objectFormatName); err != nil {
if err = git.InitRepository(ctx, repo.RepoPath(), true, repo.ObjectFormatName); err != nil {
return fmt.Errorf("git.InitRepository: %w", err)
} else if err = CreateDelegateHooks(repoPath); err != nil {
} else if err = CreateDelegateHooks(repo.RepoPath()); err != nil {
return fmt.Errorf("createDelegateHooks: %w", err)
}
return nil
Expand Down
20 changes: 9 additions & 11 deletions services/repository/adopt.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,10 @@ func AdoptRepository(ctx context.Context, doer, u *user_model.User, opts CreateR
IsEmpty: !opts.AutoInit,
}

repoPath := repo_model.RepoPath(u.Name, repo.Name)

if err := db.WithTx(ctx, func(ctx context.Context) error {
isExist, err := util.IsExist(repoPath)
isExist, err := gitrepo.IsRepositoryExist(ctx, repo)
if err != nil {
log.Error("Unable to check if %s exists. Error: %v", repoPath, err)
log.Error("Unable to check if %s exists. Error: %v", repo.FullName(), err)
return err
}
if !isExist {
Expand All @@ -82,7 +80,7 @@ func AdoptRepository(ctx context.Context, doer, u *user_model.User, opts CreateR
}

if err := func() error {
if err := adoptRepository(ctx, repoPath, repo, opts.DefaultBranch); err != nil {
if err := adoptRepository(ctx, repo, opts.DefaultBranch); err != nil {
return fmt.Errorf("adoptRepository: %w", err)
}

Expand All @@ -91,7 +89,7 @@ func AdoptRepository(ctx context.Context, doer, u *user_model.User, opts CreateR
}

if stdout, _, err := git.NewCommand("update-server-info").
RunStdString(ctx, &git.RunOpts{Dir: repoPath}); err != nil {
RunStdString(ctx, &git.RunOpts{Dir: repo.RepoPath()}); err != nil {
log.Error("CreateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err)
return fmt.Errorf("CreateRepository(git update-server-info): %w", err)
}
Expand All @@ -107,17 +105,17 @@ func AdoptRepository(ctx context.Context, doer, u *user_model.User, opts CreateR
return repo, nil
}

func adoptRepository(ctx context.Context, repoPath string, repo *repo_model.Repository, defaultBranch string) (err error) {
isExist, err := util.IsExist(repoPath)
func adoptRepository(ctx context.Context, repo *repo_model.Repository, defaultBranch string) (err error) {
isExist, err := gitrepo.IsRepositoryExist(ctx, repo)
if err != nil {
log.Error("Unable to check if %s exists. Error: %v", repoPath, err)
log.Error("Unable to check if %s exists. Error: %v", repo.FullName(), err)
return err
}
if !isExist {
return fmt.Errorf("adoptRepository: path does not already exist: %s", repoPath)
return fmt.Errorf("adoptRepository: path does not already exist: %s", repo.FullName())
}

if err := repo_module.CreateDelegateHooks(repoPath); err != nil {
if err := repo_module.CreateDelegateHooks(repo.RepoPath()); err != nil {
return fmt.Errorf("createDelegateHooks: %w", err)
}

Expand Down
34 changes: 16 additions & 18 deletions services/repository/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ type CreateRepoOptions struct {
ObjectFormatName string
}

func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir, repoPath string, opts CreateRepoOptions) error {
func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir string, opts CreateRepoOptions) error {
commitTimeStr := time.Now().Format(time.RFC3339)
authorSig := repo.Owner.NewGitSig()

Expand All @@ -67,7 +67,7 @@ func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir,
)

// Clone to temporary path and do the init commit.
if stdout, _, err := git.NewCommand("clone").AddDynamicArguments(repoPath, tmpDir).
if stdout, _, err := git.NewCommand("clone").AddDynamicArguments(repo.RepoPath(), tmpDir).
RunStdString(ctx, &git.RunOpts{Dir: "", Env: env}); err != nil {
log.Error("Failed to clone from %v into %s: stdout: %s\nError: %v", repo, tmpDir, stdout, err)
return fmt.Errorf("git clone: %w", err)
Expand Down Expand Up @@ -139,24 +139,24 @@ func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir,
}

// InitRepository initializes README and .gitignore if needed.
func initRepository(ctx context.Context, repoPath string, u *user_model.User, repo *repo_model.Repository, opts CreateRepoOptions) (err error) {
if err = repo_module.CheckInitRepository(ctx, repo.OwnerName, repo.Name, opts.ObjectFormatName); err != nil {
func initRepository(ctx context.Context, u *user_model.User, repo *repo_model.Repository, opts CreateRepoOptions) (err error) {
if err = repo_module.CheckInitRepository(ctx, repo); err != nil {
return err
}

// Initialize repository according to user's choice.
if opts.AutoInit {
tmpDir, err := os.MkdirTemp(os.TempDir(), "gitea-"+repo.Name)
if err != nil {
return fmt.Errorf("Failed to create temp dir for repository %s: %w", repo.RepoPath(), err)
return fmt.Errorf("Failed to create temp dir for repository %s: %w", repo.FullName(), err)
}
defer func() {
if err := util.RemoveAll(tmpDir); err != nil {
log.Warn("Unable to remove temporary directory: %s: Error: %v", tmpDir, err)
}
}()

if err = prepareRepoCommit(ctx, repo, tmpDir, repoPath, opts); err != nil {
if err = prepareRepoCommit(ctx, repo, tmpDir, opts); err != nil {
return fmt.Errorf("prepareRepoCommit: %w", err)
}

Expand Down Expand Up @@ -256,10 +256,9 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt
return nil
}

repoPath := repo_model.RepoPath(u.Name, repo.Name)
isExist, err := util.IsExist(repoPath)
isExist, err := gitrepo.IsRepositoryExist(ctx, repo)
if err != nil {
log.Error("Unable to check if %s exists. Error: %v", repoPath, err)
log.Error("Unable to check if %s exists. Error: %v", repo.FullName(), err)
return err
}
if isExist {
Expand All @@ -270,15 +269,15 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt
//
// Previously Gitea would just delete and start afresh - this was naughty.
// So we will now fail and delegate to other functionality to adopt or delete
log.Error("Files already exist in %s and we are not going to adopt or delete.", repoPath)
log.Error("Files already exist in %s and we are not going to adopt or delete.", repo.FullName())
return repo_model.ErrRepoFilesAlreadyExist{
Uname: u.Name,
Name: repo.Name,
}
}

if err = initRepository(ctx, repoPath, doer, repo, opts); err != nil {
if err2 := util.RemoveAll(repoPath); err2 != nil {
if err = initRepository(ctx, doer, repo, opts); err != nil {
if err2 := util.RemoveAll(repo.RepoPath()); err2 != nil {
log.Error("initRepository: %v", err)
return fmt.Errorf(
"delete repo directory %s/%s failed(2): %v", u.Name, repo.Name, err2)
Expand All @@ -300,7 +299,7 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt
}

if stdout, _, err := git.NewCommand("update-server-info").
RunStdString(ctx, &git.RunOpts{Dir: repoPath}); err != nil {
RunStdString(ctx, &git.RunOpts{Dir: repo.RepoPath()}); err != nil {
log.Error("CreateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err)
rollbackRepo = repo
rollbackRepo.OwnerID = u.ID
Expand All @@ -312,7 +311,7 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt
if len(opts.License) > 0 {
licenses = append(licenses, opts.License)

stdout, _, err := git.NewCommand("rev-parse", "HEAD").RunStdString(ctx, &git.RunOpts{Dir: repoPath})
stdout, _, err := git.NewCommand("rev-parse", "HEAD").RunStdString(ctx, &git.RunOpts{Dir: repo.RepoPath()})
if err != nil {
log.Error("CreateRepository(git rev-parse HEAD) in %v: Stdout: %s\nError: %v", repo, stdout, err)
rollbackRepo = repo
Expand Down Expand Up @@ -353,14 +352,13 @@ func CreateRepositoryByExample(ctx context.Context, doer, u *user_model.User, re
}
}

repoPath := repo_model.RepoPath(u.Name, repo.Name)
isExist, err := util.IsExist(repoPath)
isExist, err := gitrepo.IsRepositoryExist(ctx, repo)
if err != nil {
log.Error("Unable to check if %s exists. Error: %v", repoPath, err)
log.Error("Unable to check if %s exists. Error: %v", repo.FullName(), err)
return err
}
if !overwriteOrAdopt && isExist {
log.Error("Files already exist in %s and we are not going to adopt or delete.", repoPath)
log.Error("Files already exist in %s and we are not going to adopt or delete.", repo.FullName())
return repo_model.ErrRepoFilesAlreadyExist{
Uname: u.Name,
Name: repo.Name,
Expand Down
6 changes: 2 additions & 4 deletions services/repository/fork.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,15 +110,13 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork
return
}

repoPath := repo_model.RepoPath(owner.Name, repo.Name)

if exists, _ := util.IsExist(repoPath); !exists {
if exists, _ := gitrepo.IsRepositoryExist(ctx, repo); !exists {
return
}

// As the transaction will be failed and hence database changes will be destroyed we only need
// to delete the related repository on the filesystem
if errDelete := util.RemoveAll(repoPath); errDelete != nil {
if errDelete := util.RemoveAll(repo.RepoPath()); errDelete != nil {
log.Error("Failed to remove fork repo")
}
}
Expand Down
11 changes: 5 additions & 6 deletions services/repository/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *r
func generateGitContent(ctx context.Context, repo, templateRepo, generateRepo *repo_model.Repository) (err error) {
tmpDir, err := os.MkdirTemp(os.TempDir(), "gitea-"+repo.Name)
if err != nil {
return fmt.Errorf("Failed to create temp dir for repository %s: %w", repo.RepoPath(), err)
return fmt.Errorf("Failed to create temp dir for repository %s: %w", repo.FullName(), err)
}

defer func() {
Expand Down Expand Up @@ -350,10 +350,9 @@ func generateRepository(ctx context.Context, doer, owner *user_model.User, templ
return nil, err
}

repoPath := generateRepo.RepoPath()
isExist, err := util.IsExist(repoPath)
isExist, err := gitrepo.IsRepositoryExist(ctx, generateRepo)
if err != nil {
log.Error("Unable to check if %s exists. Error: %v", repoPath, err)
log.Error("Unable to check if %s exists. Error: %v", generateRepo.FullName(), err)
return nil, err
}
if isExist {
Expand All @@ -363,7 +362,7 @@ func generateRepository(ctx context.Context, doer, owner *user_model.User, templ
}
}

if err = repo_module.CheckInitRepository(ctx, owner.Name, generateRepo.Name, generateRepo.ObjectFormatName); err != nil {
if err = repo_module.CheckInitRepository(ctx, generateRepo); err != nil {
return generateRepo, err
}

Expand All @@ -372,7 +371,7 @@ func generateRepository(ctx context.Context, doer, owner *user_model.User, templ
}

if stdout, _, err := git.NewCommand("update-server-info").
RunStdString(ctx, &git.RunOpts{Dir: repoPath}); err != nil {
RunStdString(ctx, &git.RunOpts{Dir: generateRepo.RepoPath()}); err != nil {
log.Error("GenerateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", generateRepo, stdout, err)
return generateRepo, fmt.Errorf("error in GenerateRepository(git update-server-info): %w", err)
}
Expand Down