From 5a8dd96b33ac6e91a5c40fc4ef867625ca6ec88e Mon Sep 17 00:00:00 2001
From: zeripath <art27@cantab.net>
Date: Wed, 13 Oct 2021 20:47:02 +0100
Subject: [PATCH] Ensure that git daemon export ok is created for mirrors
 (#17243)

* Ensure that git daemon export ok is created for mirrors

There is an issue with #16508 where it appears that create repo requires that the
repo does not exist. This causes #17241 where an error is reported because of this.

This PR fixes this and also runs update-server-info for mirrors and generated repos.

Fix #17241

Signed-off-by: Andrew Thornton <art27@cantab.net>
---
 models/db/context.go           |  8 +++++
 models/repo.go                 | 59 +++++++++++++++++++---------------
 modules/repository/adopt.go    |  3 ++
 modules/repository/create.go   |  6 +++-
 modules/repository/fork.go     |  8 +++--
 modules/repository/generate.go | 11 +++++++
 modules/repository/repo.go     | 15 +++++++++
 7 files changed, 81 insertions(+), 29 deletions(-)

diff --git a/models/db/context.go b/models/db/context.go
index 0037bb198d..62b77bc72f 100644
--- a/models/db/context.go
+++ b/models/db/context.go
@@ -31,6 +31,14 @@ type Context struct {
 	e Engine
 }
 
+// WithEngine returns a db.Context from a context.Context and db.Engine
+func WithEngine(ctx context.Context, e Engine) *Context {
+	return &Context{
+		Context: ctx,
+		e:       e,
+	}
+}
+
 // Engine returns db engine
 func (ctx *Context) Engine() Engine {
 	return ctx.e
diff --git a/models/repo.go b/models/repo.go
index efd78c6042..25b1e65206 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -1146,16 +1146,6 @@ func CreateRepository(ctx context.Context, doer, u *User, repo *Repository, over
 		return fmt.Errorf("recalculateAccesses: %v", err)
 	}
 
-	if u.Visibility == api.VisibleTypePublic && !repo.IsPrivate {
-		// Create/Remove git-daemon-export-ok for git-daemon...
-		daemonExportFile := path.Join(repo.RepoPath(), `git-daemon-export-ok`)
-		if f, err := os.Create(daemonExportFile); err != nil {
-			log.Error("Failed to create %s: %v", daemonExportFile, err)
-		} else {
-			f.Close()
-		}
-	}
-
 	if setting.Service.AutoWatchNewRepos {
 		if err = watchRepo(db.GetEngine(ctx), doer.ID, repo.ID, true); err != nil {
 			return fmt.Errorf("watchRepo: %v", err)
@@ -1169,6 +1159,38 @@ func CreateRepository(ctx context.Context, doer, u *User, repo *Repository, over
 	return nil
 }
 
+// CheckDaemonExportOK creates/removes git-daemon-export-ok for git-daemon...
+func (repo *Repository) CheckDaemonExportOK(ctx context.Context) error {
+	e := db.GetEngine(ctx)
+	if err := repo.getOwner(e); err != nil {
+		return err
+	}
+
+	// Create/Remove git-daemon-export-ok for git-daemon...
+	daemonExportFile := path.Join(repo.RepoPath(), `git-daemon-export-ok`)
+
+	isExist, err := util.IsExist(daemonExportFile)
+	if err != nil {
+		log.Error("Unable to check if %s exists. Error: %v", daemonExportFile, err)
+		return err
+	}
+
+	isPublic := !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePublic
+	if !isPublic && isExist {
+		if err = util.Remove(daemonExportFile); err != nil {
+			log.Error("Failed to remove %s: %v", daemonExportFile, err)
+		}
+	} else if isPublic && !isExist {
+		if f, err := os.Create(daemonExportFile); err != nil {
+			log.Error("Failed to create %s: %v", daemonExportFile, err)
+		} else {
+			f.Close()
+		}
+	}
+
+	return nil
+}
+
 func countRepositories(userID int64, private bool) int64 {
 	sess := db.GetEngine(db.DefaultContext).Where("id > 0")
 
@@ -1318,24 +1340,9 @@ func updateRepository(e db.Engine, repo *Repository, visibilityChanged bool) (er
 		}
 
 		// Create/Remove git-daemon-export-ok for git-daemon...
-		daemonExportFile := path.Join(repo.RepoPath(), `git-daemon-export-ok`)
-		isExist, err := util.IsExist(daemonExportFile)
-		isPublic := !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePublic
-		if err != nil {
-			log.Error("Unable to check if %s exists. Error: %v", daemonExportFile, err)
+		if err := repo.CheckDaemonExportOK(db.WithEngine(db.DefaultContext, e)); err != nil {
 			return err
 		}
-		if !isPublic && isExist {
-			if err = util.Remove(daemonExportFile); err != nil {
-				log.Error("Failed to remove %s: %v", daemonExportFile, err)
-			}
-		} else if isPublic && !isExist {
-			if f, err := os.Create(daemonExportFile); err != nil {
-				log.Error("Failed to create %s: %v", daemonExportFile, err)
-			} else {
-				f.Close()
-			}
-		}
 
 		forkRepos, err := getRepositoriesByForkID(e, repo.ID)
 		if err != nil {
diff --git a/modules/repository/adopt.go b/modules/repository/adopt.go
index c5c059f471..21477ab7d7 100644
--- a/modules/repository/adopt.go
+++ b/modules/repository/adopt.go
@@ -68,6 +68,9 @@ func AdoptRepository(doer, u *models.User, opts models.CreateRepoOptions) (*mode
 		if err := adoptRepository(ctx, repoPath, doer, repo, opts); err != nil {
 			return fmt.Errorf("createDelegateHooks: %v", err)
 		}
+		if err := repo.CheckDaemonExportOK(ctx); err != nil {
+			return fmt.Errorf("checkDaemonExportOK: %v", err)
+		}
 
 		// Initialize Issue Labels if selected
 		if len(opts.IssueLabels) > 0 {
diff --git a/modules/repository/create.go b/modules/repository/create.go
index 0e91a73b83..64d92eeb2d 100644
--- a/modules/repository/create.go
+++ b/modules/repository/create.go
@@ -105,7 +105,11 @@ func CreateRepository(doer, u *models.User, opts models.CreateRepoOptions) (*mod
 			}
 		}
 
-		if stdout, err := git.NewCommand("update-server-info").
+		if err := repo.CheckDaemonExportOK(ctx); err != nil {
+			return fmt.Errorf("checkDaemonExportOK: %v", err)
+		}
+
+		if stdout, err := git.NewCommandContext(ctx, "update-server-info").
 			SetDescription(fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath)).
 			RunInDir(repoPath); err != nil {
 			log.Error("CreateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err)
diff --git a/modules/repository/fork.go b/modules/repository/fork.go
index 59c07271a6..df1dccc596 100644
--- a/modules/repository/fork.go
+++ b/modules/repository/fork.go
@@ -97,7 +97,7 @@ func ForkRepository(doer, owner *models.User, opts models.ForkRepoOptions) (_ *m
 		needsRollback = true
 
 		repoPath := models.RepoPath(owner.Name, repo.Name)
-		if stdout, err := git.NewCommand(
+		if stdout, err := git.NewCommandContext(ctx,
 			"clone", "--bare", oldRepoPath, repoPath).
 			SetDescription(fmt.Sprintf("ForkRepository(git clone): %s to %s", opts.BaseRepo.FullName(), repo.FullName())).
 			RunInDirTimeout(10*time.Minute, ""); err != nil {
@@ -105,7 +105,11 @@ func ForkRepository(doer, owner *models.User, opts models.ForkRepoOptions) (_ *m
 			return fmt.Errorf("git clone: %v", err)
 		}
 
-		if stdout, err := git.NewCommand("update-server-info").
+		if err := repo.CheckDaemonExportOK(ctx); err != nil {
+			return fmt.Errorf("checkDaemonExportOK: %v", err)
+		}
+
+		if stdout, err := git.NewCommandContext(ctx, "update-server-info").
 			SetDescription(fmt.Sprintf("ForkRepository(git update-server-info): %s", repo.FullName())).
 			RunInDir(repoPath); err != nil {
 			log.Error("Fork Repository (git update-server-info) failed for %v:\nStdout: %s\nError: %v", repo, stdout, err)
diff --git a/modules/repository/generate.go b/modules/repository/generate.go
index 4fcebc06dc..f6b76b14af 100644
--- a/modules/repository/generate.go
+++ b/modules/repository/generate.go
@@ -275,5 +275,16 @@ func GenerateRepository(ctx context.Context, doer, owner *models.User, templateR
 		return generateRepo, err
 	}
 
+	if err = generateRepo.CheckDaemonExportOK(ctx); err != nil {
+		return generateRepo, fmt.Errorf("checkDaemonExportOK: %v", err)
+	}
+
+	if stdout, err := git.NewCommandContext(ctx, "update-server-info").
+		SetDescription(fmt.Sprintf("GenerateRepository(git update-server-info): %s", repoPath)).
+		RunInDir(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): %v", err)
+	}
+
 	return generateRepo, nil
 }
diff --git a/modules/repository/repo.go b/modules/repository/repo.go
index 6b40a894fb..05306218de 100644
--- a/modules/repository/repo.go
+++ b/modules/repository/repo.go
@@ -96,6 +96,21 @@ func MigrateRepositoryGitData(ctx context.Context, u *models.User, repo *models.
 		}
 	}
 
+	if repo.OwnerID == u.ID {
+		repo.Owner = u
+	}
+
+	if err = repo.CheckDaemonExportOK(ctx); err != nil {
+		return repo, fmt.Errorf("checkDaemonExportOK: %v", err)
+	}
+
+	if stdout, err := git.NewCommandContext(ctx, "update-server-info").
+		SetDescription(fmt.Sprintf("MigrateRepositoryGitData(git update-server-info): %s", repoPath)).
+		RunInDir(repoPath); err != nil {
+		log.Error("MigrateRepositoryGitData(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err)
+		return repo, fmt.Errorf("error in MigrateRepositoryGitData(git update-server-info): %v", err)
+	}
+
 	gitRepo, err := git.OpenRepository(repoPath)
 	if err != nil {
 		return repo, fmt.Errorf("OpenRepository: %v", err)