mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-10-30 22:11:07 +00:00 
			
		
		
		
	Refactor repository check and sync functions (#9854)
Move more general repository functions out of models/repo.go
This commit is contained in:
		
					parent
					
						
							
								27c6b8fc07
							
						
					
				
			
			
				commit
				
					
						d92781bf94
					
				
			
		
					 12 changed files with 313 additions and 210 deletions
				
			
		|  | @ -14,9 +14,10 @@ import ( | ||||||
| 	"code.gitea.io/gitea/models" | 	"code.gitea.io/gitea/models" | ||||||
| 	"code.gitea.io/gitea/modules/auth/oauth2" | 	"code.gitea.io/gitea/modules/auth/oauth2" | ||||||
| 	"code.gitea.io/gitea/modules/git" | 	"code.gitea.io/gitea/modules/git" | ||||||
|  | 	"code.gitea.io/gitea/modules/graceful" | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	pwd "code.gitea.io/gitea/modules/password" | 	pwd "code.gitea.io/gitea/modules/password" | ||||||
| 	"code.gitea.io/gitea/modules/repository" | 	repo_module "code.gitea.io/gitea/modules/repository" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 
 | 
 | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli" | ||||||
|  | @ -375,7 +376,7 @@ func runRepoSyncReleases(c *cli.Context) error { | ||||||
| 			} | 			} | ||||||
| 			log.Trace(" currentNumReleases is %d, running SyncReleasesWithTags", oldnum) | 			log.Trace(" currentNumReleases is %d, running SyncReleasesWithTags", oldnum) | ||||||
| 
 | 
 | ||||||
| 			if err = repository.SyncReleasesWithTags(repo, gitRepo); err != nil { | 			if err = repo_module.SyncReleasesWithTags(repo, gitRepo); err != nil { | ||||||
| 				log.Warn(" SyncReleasesWithTags: %v", err) | 				log.Warn(" SyncReleasesWithTags: %v", err) | ||||||
| 				gitRepo.Close() | 				gitRepo.Close() | ||||||
| 				continue | 				continue | ||||||
|  | @ -410,7 +411,7 @@ func runRegenerateHooks(c *cli.Context) error { | ||||||
| 	if err := initDB(); err != nil { | 	if err := initDB(); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	return models.SyncRepositoryHooks() | 	return repo_module.SyncRepositoryHooks(graceful.GetManager().ShutdownContext()) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func runRegenerateKeys(c *cli.Context) error { | func runRegenerateKeys(c *cli.Context) error { | ||||||
|  |  | ||||||
|  | @ -4,6 +4,12 @@ | ||||||
| 
 | 
 | ||||||
| package models | package models | ||||||
| 
 | 
 | ||||||
|  | import ( | ||||||
|  | 	"code.gitea.io/gitea/modules/setting" | ||||||
|  | 
 | ||||||
|  | 	"xorm.io/builder" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
| // DBContext represents a db context | // DBContext represents a db context | ||||||
| type DBContext struct { | type DBContext struct { | ||||||
| 	e Engine | 	e Engine | ||||||
|  | @ -53,3 +59,10 @@ func WithTx(f func(ctx DBContext) error) error { | ||||||
| 	sess.Close() | 	sess.Close() | ||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // Iterate iterates the databases and doing something | ||||||
|  | func Iterate(ctx DBContext, tableBean interface{}, cond builder.Cond, fun func(idx int, bean interface{}) error) error { | ||||||
|  | 	return ctx.e.Where(cond). | ||||||
|  | 		BufferSize(setting.Database.IterateBufferSize). | ||||||
|  | 		Iterate(tableBean, fun) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -5,11 +5,12 @@ | ||||||
| package migrations | package migrations | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"code.gitea.io/gitea/models" | 	"code.gitea.io/gitea/modules/graceful" | ||||||
|  | 	repo_module "code.gitea.io/gitea/modules/repository" | ||||||
| 
 | 
 | ||||||
| 	"xorm.io/xorm" | 	"xorm.io/xorm" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func regenerateGitHooks36(x *xorm.Engine) (err error) { | func regenerateGitHooks36(x *xorm.Engine) (err error) { | ||||||
| 	return models.SyncRepositoryHooks() | 	return repo_module.SyncRepositoryHooks(graceful.GetManager().ShutdownContext()) | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										189
									
								
								models/repo.go
									
										
									
									
									
								
							
							
						
						
									
										189
									
								
								models/repo.go
									
										
									
									
									
								
							|  | @ -26,12 +26,10 @@ import ( | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"code.gitea.io/gitea/modules/avatar" | 	"code.gitea.io/gitea/modules/avatar" | ||||||
| 	"code.gitea.io/gitea/modules/git" |  | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/markup" | 	"code.gitea.io/gitea/modules/markup" | ||||||
| 	"code.gitea.io/gitea/modules/options" | 	"code.gitea.io/gitea/modules/options" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 	"code.gitea.io/gitea/modules/structs" |  | ||||||
| 	api "code.gitea.io/gitea/modules/structs" | 	api "code.gitea.io/gitea/modules/structs" | ||||||
| 	"code.gitea.io/gitea/modules/timeutil" | 	"code.gitea.io/gitea/modules/timeutil" | ||||||
| 	"code.gitea.io/gitea/modules/util" | 	"code.gitea.io/gitea/modules/util" | ||||||
|  | @ -152,7 +150,7 @@ type Repository struct { | ||||||
| 	Name                string             `xorm:"INDEX NOT NULL"` | 	Name                string             `xorm:"INDEX NOT NULL"` | ||||||
| 	Description         string             `xorm:"TEXT"` | 	Description         string             `xorm:"TEXT"` | ||||||
| 	Website             string             `xorm:"VARCHAR(2048)"` | 	Website             string             `xorm:"VARCHAR(2048)"` | ||||||
| 	OriginalServiceType structs.GitServiceType `xorm:"index"` | 	OriginalServiceType api.GitServiceType `xorm:"index"` | ||||||
| 	OriginalURL         string             `xorm:"VARCHAR(2048)"` | 	OriginalURL         string             `xorm:"VARCHAR(2048)"` | ||||||
| 	DefaultBranch       string | 	DefaultBranch       string | ||||||
| 
 | 
 | ||||||
|  | @ -911,63 +909,12 @@ func CheckCreateRepository(doer, u *User, name string) error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // CreateDelegateHooks creates all the hooks scripts for the repo |  | ||||||
| func CreateDelegateHooks(repoPath string) error { |  | ||||||
| 	return createDelegateHooks(repoPath) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // createDelegateHooks creates all the hooks scripts for the repo |  | ||||||
| func createDelegateHooks(repoPath string) (err error) { |  | ||||||
| 
 |  | ||||||
| 	var ( |  | ||||||
| 		hookNames = []string{"pre-receive", "update", "post-receive"} |  | ||||||
| 		hookTpls  = []string{ |  | ||||||
| 			fmt.Sprintf("#!/usr/bin/env %s\ndata=$(cat)\nexitcodes=\"\"\nhookname=$(basename $0)\nGIT_DIR=${GIT_DIR:-$(dirname $0)}\n\nfor hook in ${GIT_DIR}/hooks/${hookname}.d/*; do\ntest -x \"${hook}\" || continue\necho \"${data}\" | \"${hook}\"\nexitcodes=\"${exitcodes} $?\"\ndone\n\nfor i in ${exitcodes}; do\n[ ${i} -eq 0 ] || exit ${i}\ndone\n", setting.ScriptType), |  | ||||||
| 			fmt.Sprintf("#!/usr/bin/env %s\nexitcodes=\"\"\nhookname=$(basename $0)\nGIT_DIR=${GIT_DIR:-$(dirname $0)}\n\nfor hook in ${GIT_DIR}/hooks/${hookname}.d/*; do\ntest -x \"${hook}\" || continue\n\"${hook}\" $1 $2 $3\nexitcodes=\"${exitcodes} $?\"\ndone\n\nfor i in ${exitcodes}; do\n[ ${i} -eq 0 ] || exit ${i}\ndone\n", setting.ScriptType), |  | ||||||
| 			fmt.Sprintf("#!/usr/bin/env %s\ndata=$(cat)\nexitcodes=\"\"\nhookname=$(basename $0)\nGIT_DIR=${GIT_DIR:-$(dirname $0)}\n\nfor hook in ${GIT_DIR}/hooks/${hookname}.d/*; do\ntest -x \"${hook}\" || continue\necho \"${data}\" | \"${hook}\"\nexitcodes=\"${exitcodes} $?\"\ndone\n\nfor i in ${exitcodes}; do\n[ ${i} -eq 0 ] || exit ${i}\ndone\n", setting.ScriptType), |  | ||||||
| 		} |  | ||||||
| 		giteaHookTpls = []string{ |  | ||||||
| 			fmt.Sprintf("#!/usr/bin/env %s\n\"%s\" hook --config='%s' pre-receive\n", setting.ScriptType, setting.AppPath, setting.CustomConf), |  | ||||||
| 			fmt.Sprintf("#!/usr/bin/env %s\n\"%s\" hook --config='%s' update $1 $2 $3\n", setting.ScriptType, setting.AppPath, setting.CustomConf), |  | ||||||
| 			fmt.Sprintf("#!/usr/bin/env %s\n\"%s\" hook --config='%s' post-receive\n", setting.ScriptType, setting.AppPath, setting.CustomConf), |  | ||||||
| 		} |  | ||||||
| 	) |  | ||||||
| 
 |  | ||||||
| 	hookDir := filepath.Join(repoPath, "hooks") |  | ||||||
| 
 |  | ||||||
| 	for i, hookName := range hookNames { |  | ||||||
| 		oldHookPath := filepath.Join(hookDir, hookName) |  | ||||||
| 		newHookPath := filepath.Join(hookDir, hookName+".d", "gitea") |  | ||||||
| 
 |  | ||||||
| 		if err := os.MkdirAll(filepath.Join(hookDir, hookName+".d"), os.ModePerm); err != nil { |  | ||||||
| 			return fmt.Errorf("create hooks dir '%s': %v", filepath.Join(hookDir, hookName+".d"), err) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		// WARNING: This will override all old server-side hooks |  | ||||||
| 		if err = os.Remove(oldHookPath); err != nil && !os.IsNotExist(err) { |  | ||||||
| 			return fmt.Errorf("unable to pre-remove old hook file '%s' prior to rewriting: %v ", oldHookPath, err) |  | ||||||
| 		} |  | ||||||
| 		if err = ioutil.WriteFile(oldHookPath, []byte(hookTpls[i]), 0777); err != nil { |  | ||||||
| 			return fmt.Errorf("write old hook file '%s': %v", oldHookPath, err) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if err = os.Remove(newHookPath); err != nil && !os.IsNotExist(err) { |  | ||||||
| 			return fmt.Errorf("unable to pre-remove new hook file '%s' prior to rewriting: %v", newHookPath, err) |  | ||||||
| 		} |  | ||||||
| 		if err = ioutil.WriteFile(newHookPath, []byte(giteaHookTpls[i]), 0777); err != nil { |  | ||||||
| 			return fmt.Errorf("write new hook file '%s': %v", newHookPath, err) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // CreateRepoOptions contains the create repository options | // CreateRepoOptions contains the create repository options | ||||||
| type CreateRepoOptions struct { | type CreateRepoOptions struct { | ||||||
| 	Name           string | 	Name           string | ||||||
| 	Description    string | 	Description    string | ||||||
| 	OriginalURL    string | 	OriginalURL    string | ||||||
| 	GitServiceType structs.GitServiceType | 	GitServiceType api.GitServiceType | ||||||
| 	Gitignores     string | 	Gitignores     string | ||||||
| 	IssueLabels    string | 	IssueLabels    string | ||||||
| 	License        string | 	License        string | ||||||
|  | @ -1883,138 +1830,6 @@ func deleteOldRepositoryArchives(ctx context.Context, idx int, bean interface{}) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func gatherMissingRepoRecords() ([]*Repository, error) { |  | ||||||
| 	repos := make([]*Repository, 0, 10) |  | ||||||
| 	if err := x. |  | ||||||
| 		Where("id > 0"). |  | ||||||
| 		Iterate(new(Repository), |  | ||||||
| 			func(idx int, bean interface{}) error { |  | ||||||
| 				repo := bean.(*Repository) |  | ||||||
| 				if !com.IsDir(repo.RepoPath()) { |  | ||||||
| 					repos = append(repos, repo) |  | ||||||
| 				} |  | ||||||
| 				return nil |  | ||||||
| 			}); err != nil { |  | ||||||
| 		if err2 := CreateRepositoryNotice(fmt.Sprintf("gatherMissingRepoRecords: %v", err)); err2 != nil { |  | ||||||
| 			return nil, fmt.Errorf("CreateRepositoryNotice: %v", err) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return repos, nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // DeleteMissingRepositories deletes all repository records that lost Git files. |  | ||||||
| func DeleteMissingRepositories(doer *User) error { |  | ||||||
| 	repos, err := gatherMissingRepoRecords() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return fmt.Errorf("gatherMissingRepoRecords: %v", err) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if len(repos) == 0 { |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	for _, repo := range repos { |  | ||||||
| 		log.Trace("Deleting %d/%d...", repo.OwnerID, repo.ID) |  | ||||||
| 		if err := DeleteRepository(doer, repo.OwnerID, repo.ID); err != nil { |  | ||||||
| 			if err2 := CreateRepositoryNotice(fmt.Sprintf("DeleteRepository [%d]: %v", repo.ID, err)); err2 != nil { |  | ||||||
| 				return fmt.Errorf("CreateRepositoryNotice: %v", err) |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // ReinitMissingRepositories reinitializes all repository records that lost Git files. |  | ||||||
| func ReinitMissingRepositories() error { |  | ||||||
| 	repos, err := gatherMissingRepoRecords() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return fmt.Errorf("gatherMissingRepoRecords: %v", err) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if len(repos) == 0 { |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	for _, repo := range repos { |  | ||||||
| 		log.Trace("Initializing %d/%d...", repo.OwnerID, repo.ID) |  | ||||||
| 		if err := git.InitRepository(repo.RepoPath(), true); err != nil { |  | ||||||
| 			if err2 := CreateRepositoryNotice(fmt.Sprintf("InitRepository [%d]: %v", repo.ID, err)); err2 != nil { |  | ||||||
| 				return fmt.Errorf("CreateRepositoryNotice: %v", err) |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // SyncRepositoryHooks rewrites all repositories' pre-receive, update and post-receive hooks |  | ||||||
| // to make sure the binary and custom conf path are up-to-date. |  | ||||||
| func SyncRepositoryHooks() error { |  | ||||||
| 	return x.Cols("owner_id", "name").Where("id > 0").Iterate(new(Repository), |  | ||||||
| 		func(idx int, bean interface{}) error { |  | ||||||
| 			if err := createDelegateHooks(bean.(*Repository).RepoPath()); err != nil { |  | ||||||
| 				return fmt.Errorf("SyncRepositoryHook: %v", err) |  | ||||||
| 			} |  | ||||||
| 			if bean.(*Repository).HasWiki() { |  | ||||||
| 				if err := createDelegateHooks(bean.(*Repository).WikiPath()); err != nil { |  | ||||||
| 					return fmt.Errorf("SyncRepositoryHook: %v", err) |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 			return nil |  | ||||||
| 		}) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // GitFsck calls 'git fsck' to check repository health. |  | ||||||
| func GitFsck(ctx context.Context) { |  | ||||||
| 	log.Trace("Doing: GitFsck") |  | ||||||
| 	if err := x. |  | ||||||
| 		Where("id>0 AND is_fsck_enabled=?", true).BufferSize(setting.Database.IterateBufferSize). |  | ||||||
| 		Iterate(new(Repository), |  | ||||||
| 			func(idx int, bean interface{}) error { |  | ||||||
| 				select { |  | ||||||
| 				case <-ctx.Done(): |  | ||||||
| 					return fmt.Errorf("Aborted due to shutdown") |  | ||||||
| 				default: |  | ||||||
| 				} |  | ||||||
| 				repo := bean.(*Repository) |  | ||||||
| 				repoPath := repo.RepoPath() |  | ||||||
| 				log.Trace("Running health check on repository %s", repoPath) |  | ||||||
| 				if err := git.Fsck(repoPath, setting.Cron.RepoHealthCheck.Timeout, setting.Cron.RepoHealthCheck.Args...); err != nil { |  | ||||||
| 					desc := fmt.Sprintf("Failed to health check repository (%s): %v", repoPath, err) |  | ||||||
| 					log.Warn(desc) |  | ||||||
| 					if err = CreateRepositoryNotice(desc); err != nil { |  | ||||||
| 						log.Error("CreateRepositoryNotice: %v", err) |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 				return nil |  | ||||||
| 			}); err != nil { |  | ||||||
| 		log.Error("GitFsck: %v", err) |  | ||||||
| 	} |  | ||||||
| 	log.Trace("Finished: GitFsck") |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // GitGcRepos calls 'git gc' to remove unnecessary files and optimize the local repository |  | ||||||
| func GitGcRepos() error { |  | ||||||
| 	args := append([]string{"gc"}, setting.Git.GCArgs...) |  | ||||||
| 	return x. |  | ||||||
| 		Where("id > 0").BufferSize(setting.Database.IterateBufferSize). |  | ||||||
| 		Iterate(new(Repository), |  | ||||||
| 			func(idx int, bean interface{}) error { |  | ||||||
| 				repo := bean.(*Repository) |  | ||||||
| 				if err := repo.GetOwner(); err != nil { |  | ||||||
| 					return err |  | ||||||
| 				} |  | ||||||
| 				if stdout, err := git.NewCommand(args...). |  | ||||||
| 					SetDescription(fmt.Sprintf("Repository Garbage Collection: %s", repo.FullName())). |  | ||||||
| 					RunInDirTimeout( |  | ||||||
| 						time.Duration(setting.Git.Timeout.GC)*time.Second, |  | ||||||
| 						repo.RepoPath()); err != nil { |  | ||||||
| 					log.Error("Repository garbage collection failed for %v. Stdout: %s\nError: %v", repo, stdout, err) |  | ||||||
| 					return fmt.Errorf("Repository garbage collection failed: Error: %v", err) |  | ||||||
| 				} |  | ||||||
| 				return nil |  | ||||||
| 			}) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type repoChecker struct { | type repoChecker struct { | ||||||
| 	querySQL, correctSQL string | 	querySQL, correctSQL string | ||||||
| 	desc                 string | 	desc                 string | ||||||
|  |  | ||||||
|  | @ -13,6 +13,7 @@ import ( | ||||||
| 	"code.gitea.io/gitea/modules/graceful" | 	"code.gitea.io/gitea/modules/graceful" | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/migrations" | 	"code.gitea.io/gitea/modules/migrations" | ||||||
|  | 	repo_module "code.gitea.io/gitea/modules/repository" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 	"code.gitea.io/gitea/modules/sync" | 	"code.gitea.io/gitea/modules/sync" | ||||||
| 	mirror_service "code.gitea.io/gitea/services/mirror" | 	mirror_service "code.gitea.io/gitea/services/mirror" | ||||||
|  | @ -69,14 +70,22 @@ func NewContext() { | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	if setting.Cron.RepoHealthCheck.Enabled { | 	if setting.Cron.RepoHealthCheck.Enabled { | ||||||
| 		entry, err = c.AddFunc("Repository health check", setting.Cron.RepoHealthCheck.Schedule, WithUnique(gitFsck, models.GitFsck)) | 		entry, err = c.AddFunc("Repository health check", setting.Cron.RepoHealthCheck.Schedule, WithUnique(gitFsck, func(ctx context.Context) { | ||||||
|  | 			if err := repo_module.GitFsck(ctx); err != nil { | ||||||
|  | 				log.Error("GitFsck: %s", err) | ||||||
|  | 			} | ||||||
|  | 		})) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			log.Fatal("Cron[Repository health check]: %v", err) | 			log.Fatal("Cron[Repository health check]: %v", err) | ||||||
| 		} | 		} | ||||||
| 		if setting.Cron.RepoHealthCheck.RunAtStart { | 		if setting.Cron.RepoHealthCheck.RunAtStart { | ||||||
| 			entry.Prev = time.Now() | 			entry.Prev = time.Now() | ||||||
| 			entry.ExecTimes++ | 			entry.ExecTimes++ | ||||||
| 			go WithUnique(gitFsck, models.GitFsck)() | 			go WithUnique(gitFsck, func(ctx context.Context) { | ||||||
|  | 				if err := repo_module.GitFsck(ctx); err != nil { | ||||||
|  | 					log.Error("GitFsck: %s", err) | ||||||
|  | 				} | ||||||
|  | 			})() | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	if setting.Cron.CheckRepoStats.Enabled { | 	if setting.Cron.CheckRepoStats.Enabled { | ||||||
|  |  | ||||||
							
								
								
									
										156
									
								
								modules/repository/check.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								modules/repository/check.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,156 @@ | ||||||
|  | // Copyright 2020 The Gitea Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a MIT-style | ||||||
|  | // license that can be found in the LICENSE file. | ||||||
|  | 
 | ||||||
|  | package repository | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"fmt" | ||||||
|  | 	"time" | ||||||
|  | 
 | ||||||
|  | 	"code.gitea.io/gitea/models" | ||||||
|  | 	"code.gitea.io/gitea/modules/git" | ||||||
|  | 	"code.gitea.io/gitea/modules/log" | ||||||
|  | 	"code.gitea.io/gitea/modules/setting" | ||||||
|  | 
 | ||||||
|  | 	"github.com/unknwon/com" | ||||||
|  | 	"xorm.io/builder" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // GitFsck calls 'git fsck' to check repository health. | ||||||
|  | func GitFsck(ctx context.Context) error { | ||||||
|  | 	log.Trace("Doing: GitFsck") | ||||||
|  | 
 | ||||||
|  | 	if err := models.Iterate( | ||||||
|  | 		models.DefaultDBContext(), | ||||||
|  | 		new(models.Repository), | ||||||
|  | 		builder.Expr("id>0 AND is_fsck_enabled=?", true), | ||||||
|  | 		func(idx int, bean interface{}) error { | ||||||
|  | 			select { | ||||||
|  | 			case <-ctx.Done(): | ||||||
|  | 				return fmt.Errorf("Aborted due to shutdown") | ||||||
|  | 			default: | ||||||
|  | 			} | ||||||
|  | 			repo := bean.(*models.Repository) | ||||||
|  | 			repoPath := repo.RepoPath() | ||||||
|  | 			log.Trace("Running health check on repository %s", repoPath) | ||||||
|  | 			if err := git.Fsck(repoPath, setting.Cron.RepoHealthCheck.Timeout, setting.Cron.RepoHealthCheck.Args...); err != nil { | ||||||
|  | 				desc := fmt.Sprintf("Failed to health check repository (%s): %v", repoPath, err) | ||||||
|  | 				log.Warn(desc) | ||||||
|  | 				if err = models.CreateRepositoryNotice(desc); err != nil { | ||||||
|  | 					log.Error("CreateRepositoryNotice: %v", err) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			return nil | ||||||
|  | 		}, | ||||||
|  | 	); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	log.Trace("Finished: GitFsck") | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GitGcRepos calls 'git gc' to remove unnecessary files and optimize the local repository | ||||||
|  | func GitGcRepos(ctx context.Context) error { | ||||||
|  | 	log.Trace("Doing: GitGcRepos") | ||||||
|  | 	args := append([]string{"gc"}, setting.Git.GCArgs...) | ||||||
|  | 
 | ||||||
|  | 	if err := models.Iterate( | ||||||
|  | 		models.DefaultDBContext(), | ||||||
|  | 		new(models.Repository), | ||||||
|  | 		builder.Gt{"id": 0}, | ||||||
|  | 		func(idx int, bean interface{}) error { | ||||||
|  | 			select { | ||||||
|  | 			case <-ctx.Done(): | ||||||
|  | 				return fmt.Errorf("Aborted due to shutdown") | ||||||
|  | 			default: | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			repo := bean.(*models.Repository) | ||||||
|  | 			if err := repo.GetOwner(); err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 			if stdout, err := git.NewCommand(args...). | ||||||
|  | 				SetDescription(fmt.Sprintf("Repository Garbage Collection: %s", repo.FullName())). | ||||||
|  | 				RunInDirTimeout( | ||||||
|  | 					time.Duration(setting.Git.Timeout.GC)*time.Second, | ||||||
|  | 					repo.RepoPath()); err != nil { | ||||||
|  | 				log.Error("Repository garbage collection failed for %v. Stdout: %s\nError: %v", repo, stdout, err) | ||||||
|  | 				return fmt.Errorf("Repository garbage collection failed: Error: %v", err) | ||||||
|  | 			} | ||||||
|  | 			return nil | ||||||
|  | 		}, | ||||||
|  | 	); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	log.Trace("Finished: GitGcRepos") | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func gatherMissingRepoRecords() ([]*models.Repository, error) { | ||||||
|  | 	repos := make([]*models.Repository, 0, 10) | ||||||
|  | 	if err := models.Iterate( | ||||||
|  | 		models.DefaultDBContext(), | ||||||
|  | 		new(models.Repository), | ||||||
|  | 		builder.Gt{"id": 0}, | ||||||
|  | 		func(idx int, bean interface{}) error { | ||||||
|  | 			repo := bean.(*models.Repository) | ||||||
|  | 			if !com.IsDir(repo.RepoPath()) { | ||||||
|  | 				repos = append(repos, repo) | ||||||
|  | 			} | ||||||
|  | 			return nil | ||||||
|  | 		}, | ||||||
|  | 	); err != nil { | ||||||
|  | 		if err2 := models.CreateRepositoryNotice(fmt.Sprintf("gatherMissingRepoRecords: %v", err)); err2 != nil { | ||||||
|  | 			return nil, fmt.Errorf("CreateRepositoryNotice: %v", err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return repos, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DeleteMissingRepositories deletes all repository records that lost Git files. | ||||||
|  | func DeleteMissingRepositories(doer *models.User) error { | ||||||
|  | 	repos, err := gatherMissingRepoRecords() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("gatherMissingRepoRecords: %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if len(repos) == 0 { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, repo := range repos { | ||||||
|  | 		log.Trace("Deleting %d/%d...", repo.OwnerID, repo.ID) | ||||||
|  | 		if err := models.DeleteRepository(doer, repo.OwnerID, repo.ID); err != nil { | ||||||
|  | 			if err2 := models.CreateRepositoryNotice(fmt.Sprintf("DeleteRepository [%d]: %v", repo.ID, err)); err2 != nil { | ||||||
|  | 				return fmt.Errorf("CreateRepositoryNotice: %v", err) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ReinitMissingRepositories reinitializes all repository records that lost Git files. | ||||||
|  | func ReinitMissingRepositories() error { | ||||||
|  | 	repos, err := gatherMissingRepoRecords() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("gatherMissingRepoRecords: %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if len(repos) == 0 { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, repo := range repos { | ||||||
|  | 		log.Trace("Initializing %d/%d...", repo.OwnerID, repo.ID) | ||||||
|  | 		if err := git.InitRepository(repo.RepoPath(), true); err != nil { | ||||||
|  | 			if err2 := models.CreateRepositoryNotice(fmt.Sprintf("InitRepository [%d]: %v", repo.ID, err)); err2 != nil { | ||||||
|  | 				return fmt.Errorf("CreateRepositoryNotice: %v", err) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | @ -69,7 +69,7 @@ func ForkRepository(doer, owner *models.User, oldRepo *models.Repository, name, | ||||||
| 			return fmt.Errorf("git update-server-info: %v", err) | 			return fmt.Errorf("git update-server-info: %v", err) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if err = models.CreateDelegateHooks(repoPath); err != nil { | 		if err = createDelegateHooks(repoPath); err != nil { | ||||||
| 			return fmt.Errorf("createDelegateHooks: %v", err) | 			return fmt.Errorf("createDelegateHooks: %v", err) | ||||||
| 		} | 		} | ||||||
| 		return nil | 		return nil | ||||||
|  |  | ||||||
							
								
								
									
										104
									
								
								modules/repository/hooks.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								modules/repository/hooks.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,104 @@ | ||||||
|  | // Copyright 2020 The Gitea Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a MIT-style | ||||||
|  | // license that can be found in the LICENSE file. | ||||||
|  | 
 | ||||||
|  | package repository | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io/ioutil" | ||||||
|  | 	"os" | ||||||
|  | 	"path/filepath" | ||||||
|  | 
 | ||||||
|  | 	"code.gitea.io/gitea/models" | ||||||
|  | 	"code.gitea.io/gitea/modules/log" | ||||||
|  | 	"code.gitea.io/gitea/modules/setting" | ||||||
|  | 
 | ||||||
|  | 	"xorm.io/builder" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // CreateDelegateHooks creates all the hooks scripts for the repo | ||||||
|  | func CreateDelegateHooks(repoPath string) error { | ||||||
|  | 	return createDelegateHooks(repoPath) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // createDelegateHooks creates all the hooks scripts for the repo | ||||||
|  | func createDelegateHooks(repoPath string) (err error) { | ||||||
|  | 
 | ||||||
|  | 	var ( | ||||||
|  | 		hookNames = []string{"pre-receive", "update", "post-receive"} | ||||||
|  | 		hookTpls  = []string{ | ||||||
|  | 			fmt.Sprintf("#!/usr/bin/env %s\ndata=$(cat)\nexitcodes=\"\"\nhookname=$(basename $0)\nGIT_DIR=${GIT_DIR:-$(dirname $0)}\n\nfor hook in ${GIT_DIR}/hooks/${hookname}.d/*; do\ntest -x \"${hook}\" || continue\necho \"${data}\" | \"${hook}\"\nexitcodes=\"${exitcodes} $?\"\ndone\n\nfor i in ${exitcodes}; do\n[ ${i} -eq 0 ] || exit ${i}\ndone\n", setting.ScriptType), | ||||||
|  | 			fmt.Sprintf("#!/usr/bin/env %s\nexitcodes=\"\"\nhookname=$(basename $0)\nGIT_DIR=${GIT_DIR:-$(dirname $0)}\n\nfor hook in ${GIT_DIR}/hooks/${hookname}.d/*; do\ntest -x \"${hook}\" || continue\n\"${hook}\" $1 $2 $3\nexitcodes=\"${exitcodes} $?\"\ndone\n\nfor i in ${exitcodes}; do\n[ ${i} -eq 0 ] || exit ${i}\ndone\n", setting.ScriptType), | ||||||
|  | 			fmt.Sprintf("#!/usr/bin/env %s\ndata=$(cat)\nexitcodes=\"\"\nhookname=$(basename $0)\nGIT_DIR=${GIT_DIR:-$(dirname $0)}\n\nfor hook in ${GIT_DIR}/hooks/${hookname}.d/*; do\ntest -x \"${hook}\" || continue\necho \"${data}\" | \"${hook}\"\nexitcodes=\"${exitcodes} $?\"\ndone\n\nfor i in ${exitcodes}; do\n[ ${i} -eq 0 ] || exit ${i}\ndone\n", setting.ScriptType), | ||||||
|  | 		} | ||||||
|  | 		giteaHookTpls = []string{ | ||||||
|  | 			fmt.Sprintf("#!/usr/bin/env %s\n\"%s\" hook --config='%s' pre-receive\n", setting.ScriptType, setting.AppPath, setting.CustomConf), | ||||||
|  | 			fmt.Sprintf("#!/usr/bin/env %s\n\"%s\" hook --config='%s' update $1 $2 $3\n", setting.ScriptType, setting.AppPath, setting.CustomConf), | ||||||
|  | 			fmt.Sprintf("#!/usr/bin/env %s\n\"%s\" hook --config='%s' post-receive\n", setting.ScriptType, setting.AppPath, setting.CustomConf), | ||||||
|  | 		} | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | 	hookDir := filepath.Join(repoPath, "hooks") | ||||||
|  | 
 | ||||||
|  | 	for i, hookName := range hookNames { | ||||||
|  | 		oldHookPath := filepath.Join(hookDir, hookName) | ||||||
|  | 		newHookPath := filepath.Join(hookDir, hookName+".d", "gitea") | ||||||
|  | 
 | ||||||
|  | 		if err := os.MkdirAll(filepath.Join(hookDir, hookName+".d"), os.ModePerm); err != nil { | ||||||
|  | 			return fmt.Errorf("create hooks dir '%s': %v", filepath.Join(hookDir, hookName+".d"), err) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// WARNING: This will override all old server-side hooks | ||||||
|  | 		if err = os.Remove(oldHookPath); err != nil && !os.IsNotExist(err) { | ||||||
|  | 			return fmt.Errorf("unable to pre-remove old hook file '%s' prior to rewriting: %v ", oldHookPath, err) | ||||||
|  | 		} | ||||||
|  | 		if err = ioutil.WriteFile(oldHookPath, []byte(hookTpls[i]), 0777); err != nil { | ||||||
|  | 			return fmt.Errorf("write old hook file '%s': %v", oldHookPath, err) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if err = os.Remove(newHookPath); err != nil && !os.IsNotExist(err) { | ||||||
|  | 			return fmt.Errorf("unable to pre-remove new hook file '%s' prior to rewriting: %v", newHookPath, err) | ||||||
|  | 		} | ||||||
|  | 		if err = ioutil.WriteFile(newHookPath, []byte(giteaHookTpls[i]), 0777); err != nil { | ||||||
|  | 			return fmt.Errorf("write new hook file '%s': %v", newHookPath, err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SyncRepositoryHooks rewrites all repositories' pre-receive, update and post-receive hooks | ||||||
|  | // to make sure the binary and custom conf path are up-to-date. | ||||||
|  | func SyncRepositoryHooks(ctx context.Context) error { | ||||||
|  | 	log.Trace("Doing: SyncRepositoryHooks") | ||||||
|  | 
 | ||||||
|  | 	if err := models.Iterate( | ||||||
|  | 		models.DefaultDBContext(), | ||||||
|  | 		new(models.Repository), | ||||||
|  | 		builder.Gt{"id": 0}, | ||||||
|  | 		func(idx int, bean interface{}) error { | ||||||
|  | 			select { | ||||||
|  | 			case <-ctx.Done(): | ||||||
|  | 				return fmt.Errorf("Aborted due to shutdown") | ||||||
|  | 			default: | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if err := createDelegateHooks(bean.(*models.Repository).RepoPath()); err != nil { | ||||||
|  | 				return fmt.Errorf("SyncRepositoryHook: %v", err) | ||||||
|  | 			} | ||||||
|  | 			if bean.(*models.Repository).HasWiki() { | ||||||
|  | 				if err := createDelegateHooks(bean.(*models.Repository).WikiPath()); err != nil { | ||||||
|  | 					return fmt.Errorf("SyncRepositoryHook: %v", err) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			return nil | ||||||
|  | 		}, | ||||||
|  | 	); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	log.Trace("Finished: SyncRepositoryHooks") | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | @ -164,7 +164,7 @@ func checkInitRepository(repoPath string) (err error) { | ||||||
| 	// Init git bare new repository. | 	// Init git bare new repository. | ||||||
| 	if err = git.InitRepository(repoPath, true); err != nil { | 	if err = git.InitRepository(repoPath, true); err != nil { | ||||||
| 		return fmt.Errorf("git.InitRepository: %v", err) | 		return fmt.Errorf("git.InitRepository: %v", err) | ||||||
| 	} else if err = models.CreateDelegateHooks(repoPath); err != nil { | 	} else if err = createDelegateHooks(repoPath); err != nil { | ||||||
| 		return fmt.Errorf("createDelegateHooks: %v", err) | 		return fmt.Errorf("createDelegateHooks: %v", err) | ||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
|  |  | ||||||
|  | @ -17,6 +17,7 @@ import ( | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 	api "code.gitea.io/gitea/modules/structs" | 	api "code.gitea.io/gitea/modules/structs" | ||||||
| 	"code.gitea.io/gitea/modules/timeutil" | 	"code.gitea.io/gitea/modules/timeutil" | ||||||
|  | 
 | ||||||
| 	"gopkg.in/ini.v1" | 	"gopkg.in/ini.v1" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | @ -156,11 +157,11 @@ func cleanUpMigrateGitConfig(configPath string) error { | ||||||
| // CleanUpMigrateInfo finishes migrating repository and/or wiki with things that don't need to be done for mirrors. | // CleanUpMigrateInfo finishes migrating repository and/or wiki with things that don't need to be done for mirrors. | ||||||
| func CleanUpMigrateInfo(repo *models.Repository) (*models.Repository, error) { | func CleanUpMigrateInfo(repo *models.Repository) (*models.Repository, error) { | ||||||
| 	repoPath := repo.RepoPath() | 	repoPath := repo.RepoPath() | ||||||
| 	if err := models.CreateDelegateHooks(repoPath); err != nil { | 	if err := createDelegateHooks(repoPath); err != nil { | ||||||
| 		return repo, fmt.Errorf("createDelegateHooks: %v", err) | 		return repo, fmt.Errorf("createDelegateHooks: %v", err) | ||||||
| 	} | 	} | ||||||
| 	if repo.HasWiki() { | 	if repo.HasWiki() { | ||||||
| 		if err := models.CreateDelegateHooks(repo.WikiPath()); err != nil { | 		if err := createDelegateHooks(repo.WikiPath()); err != nil { | ||||||
| 			return repo, fmt.Errorf("createDelegateHooks.(wiki): %v", err) | 			return repo, fmt.Errorf("createDelegateHooks.(wiki): %v", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -24,6 +24,7 @@ import ( | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/process" | 	"code.gitea.io/gitea/modules/process" | ||||||
| 	"code.gitea.io/gitea/modules/queue" | 	"code.gitea.io/gitea/modules/queue" | ||||||
|  | 	repo_module "code.gitea.io/gitea/modules/repository" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 	"code.gitea.io/gitea/modules/timeutil" | 	"code.gitea.io/gitea/modules/timeutil" | ||||||
| 	"code.gitea.io/gitea/services/mailer" | 	"code.gitea.io/gitea/services/mailer" | ||||||
|  | @ -150,6 +151,7 @@ func Dashboard(ctx *context.Context) { | ||||||
| 	if op > 0 { | 	if op > 0 { | ||||||
| 		var err error | 		var err error | ||||||
| 		var success string | 		var success string | ||||||
|  | 		shutdownCtx := graceful.GetManager().ShutdownContext() | ||||||
| 
 | 
 | ||||||
| 		switch Operation(op) { | 		switch Operation(op) { | ||||||
| 		case cleanInactivateUser: | 		case cleanInactivateUser: | ||||||
|  | @ -160,25 +162,25 @@ func Dashboard(ctx *context.Context) { | ||||||
| 			err = models.DeleteRepositoryArchives() | 			err = models.DeleteRepositoryArchives() | ||||||
| 		case cleanMissingRepos: | 		case cleanMissingRepos: | ||||||
| 			success = ctx.Tr("admin.dashboard.delete_missing_repos_success") | 			success = ctx.Tr("admin.dashboard.delete_missing_repos_success") | ||||||
| 			err = models.DeleteMissingRepositories(ctx.User) | 			err = repo_module.DeleteMissingRepositories(ctx.User) | ||||||
| 		case gitGCRepos: | 		case gitGCRepos: | ||||||
| 			success = ctx.Tr("admin.dashboard.git_gc_repos_success") | 			success = ctx.Tr("admin.dashboard.git_gc_repos_success") | ||||||
| 			err = models.GitGcRepos() | 			err = repo_module.GitGcRepos(shutdownCtx) | ||||||
| 		case syncSSHAuthorizedKey: | 		case syncSSHAuthorizedKey: | ||||||
| 			success = ctx.Tr("admin.dashboard.resync_all_sshkeys_success") | 			success = ctx.Tr("admin.dashboard.resync_all_sshkeys_success") | ||||||
| 			err = models.RewriteAllPublicKeys() | 			err = models.RewriteAllPublicKeys() | ||||||
| 		case syncRepositoryUpdateHook: | 		case syncRepositoryUpdateHook: | ||||||
| 			success = ctx.Tr("admin.dashboard.resync_all_hooks_success") | 			success = ctx.Tr("admin.dashboard.resync_all_hooks_success") | ||||||
| 			err = models.SyncRepositoryHooks() | 			err = repo_module.SyncRepositoryHooks(shutdownCtx) | ||||||
| 		case reinitMissingRepository: | 		case reinitMissingRepository: | ||||||
| 			success = ctx.Tr("admin.dashboard.reinit_missing_repos_success") | 			success = ctx.Tr("admin.dashboard.reinit_missing_repos_success") | ||||||
| 			err = models.ReinitMissingRepositories() | 			err = repo_module.ReinitMissingRepositories() | ||||||
| 		case syncExternalUsers: | 		case syncExternalUsers: | ||||||
| 			success = ctx.Tr("admin.dashboard.sync_external_users_started") | 			success = ctx.Tr("admin.dashboard.sync_external_users_started") | ||||||
| 			go graceful.GetManager().RunWithShutdownContext(models.SyncExternalUsers) | 			go graceful.GetManager().RunWithShutdownContext(models.SyncExternalUsers) | ||||||
| 		case gitFsck: | 		case gitFsck: | ||||||
| 			success = ctx.Tr("admin.dashboard.git_fsck_started") | 			success = ctx.Tr("admin.dashboard.git_fsck_started") | ||||||
| 			go graceful.GetManager().RunWithShutdownContext(models.GitFsck) | 			err = repo_module.GitFsck(shutdownCtx) | ||||||
| 		case deleteGeneratedRepositoryAvatars: | 		case deleteGeneratedRepositoryAvatars: | ||||||
| 			success = ctx.Tr("admin.dashboard.delete_generated_repository_avatars_success") | 			success = ctx.Tr("admin.dashboard.delete_generated_repository_avatars_success") | ||||||
| 			err = models.RemoveRandomAvatars() | 			err = models.RemoveRandomAvatars() | ||||||
|  |  | ||||||
|  | @ -14,6 +14,7 @@ import ( | ||||||
| 	"code.gitea.io/gitea/models" | 	"code.gitea.io/gitea/models" | ||||||
| 	"code.gitea.io/gitea/modules/git" | 	"code.gitea.io/gitea/modules/git" | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
|  | 	repo_module "code.gitea.io/gitea/modules/repository" | ||||||
| 	"code.gitea.io/gitea/modules/sync" | 	"code.gitea.io/gitea/modules/sync" | ||||||
| 	"code.gitea.io/gitea/modules/util" | 	"code.gitea.io/gitea/modules/util" | ||||||
| 
 | 
 | ||||||
|  | @ -74,7 +75,7 @@ func InitWiki(repo *models.Repository) error { | ||||||
| 
 | 
 | ||||||
| 	if err := git.InitRepository(repo.WikiPath(), true); err != nil { | 	if err := git.InitRepository(repo.WikiPath(), true); err != nil { | ||||||
| 		return fmt.Errorf("InitRepository: %v", err) | 		return fmt.Errorf("InitRepository: %v", err) | ||||||
| 	} else if err = models.CreateDelegateHooks(repo.WikiPath()); err != nil { | 	} else if err = repo_module.CreateDelegateHooks(repo.WikiPath()); err != nil { | ||||||
| 		return fmt.Errorf("createDelegateHooks: %v", err) | 		return fmt.Errorf("createDelegateHooks: %v", err) | ||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue