diff options
author | Lunny Xiao <xiaolunwen@gmail.com> | 2017-02-23 11:40:44 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-02-23 11:40:44 +0800 |
commit | 0e6b9ea786a77a4df4aa9fff1b96b9483bcdded5 (patch) | |
tree | 83ce2a577016f3a6fd478cce8e384f9b3118f3f6 /models | |
parent | 4f3880ff151fcbda019a1a9467bc39da621fbe07 (diff) | |
download | gitea-0e6b9ea786a77a4df4aa9fff1b96b9483bcdded5.tar.gz gitea-0e6b9ea786a77a4df4aa9fff1b96b9483bcdded5.zip |
Take back control of hooks (#1006)
* git: delegate all server-side Git hooks (#1623)
* create hooks directories
* take control hooks back
* fix lint
* bug fixed and minor changes
* fix imports style
* fix migration scripts
Diffstat (limited to 'models')
-rw-r--r-- | models/migrations/migrations.go | 2 | ||||
-rw-r--r-- | models/migrations/v18.go | 4 | ||||
-rw-r--r-- | models/migrations/v19.go | 85 | ||||
-rw-r--r-- | models/repo.go | 75 | ||||
-rw-r--r-- | models/wiki.go | 4 |
5 files changed, 146 insertions, 24 deletions
diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 2a1c70af77..5ae139cb3f 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -86,6 +86,8 @@ var migrations = []Migration{ NewMigration("set protect branches updated with created", setProtectedBranchUpdatedWithCreated), // v18 -> v19 NewMigration("add external login user", addExternalLoginUser), + // v19 -> v20 + NewMigration("generate and migrate Git hooks", generateAndMigrateGitHooks), } // Migrate database to current version diff --git a/models/migrations/v18.go b/models/migrations/v18.go index be51615341..3b3cd23ccf 100644 --- a/models/migrations/v18.go +++ b/models/migrations/v18.go @@ -13,8 +13,8 @@ import ( // ExternalLoginUser makes the connecting between some existing user and additional external login sources type ExternalLoginUser struct { ExternalID string `xorm:"NOT NULL"` - UserID int64 `xorm:"NOT NULL"` - LoginSourceID int64 `xorm:"NOT NULL"` + UserID int64 `xorm:"NOT NULL"` + LoginSourceID int64 `xorm:"NOT NULL"` } func addExternalLoginUser(x *xorm.Engine) error { diff --git a/models/migrations/v19.go b/models/migrations/v19.go new file mode 100644 index 0000000000..6e0dbedaa3 --- /dev/null +++ b/models/migrations/v19.go @@ -0,0 +1,85 @@ +// Copyright 2017 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 migrations + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "code.gitea.io/gitea/modules/setting" + + "github.com/Unknwon/com" + "github.com/go-xorm/xorm" +) + +func generateAndMigrateGitHooks(x *xorm.Engine) (err error) { + type Repository struct { + ID int64 + OwnerID int64 + Name string + } + type User struct { + ID int64 + Name string + } + + var ( + hookNames = []string{"pre-receive", "update", "post-receive"} + hookTpls = []string{ + fmt.Sprintf("#!/usr/bin/env %s\nORI_DIR=`pwd`\nSHELL_FOLDER=$(cd \"$(dirname \"$0\")\";pwd)\ncd \"$ORI_DIR\"\nfor i in `ls \"$SHELL_FOLDER/pre-receive.d\"`; do\n sh \"$SHELL_FOLDER/pre-receive.d/$i\"\ndone", setting.ScriptType), + fmt.Sprintf("#!/usr/bin/env %s\nORI_DIR=`pwd`\nSHELL_FOLDER=$(cd \"$(dirname \"$0\")\";pwd)\ncd \"$ORI_DIR\"\nfor i in `ls \"$SHELL_FOLDER/update.d\"`; do\n sh \"$SHELL_FOLDER/update.d/$i\" $1 $2 $3\ndone", setting.ScriptType), + fmt.Sprintf("#!/usr/bin/env %s\nORI_DIR=`pwd`\nSHELL_FOLDER=$(cd \"$(dirname \"$0\")\";pwd)\ncd \"$ORI_DIR\"\nfor i in `ls \"$SHELL_FOLDER/post-receive.d\"`; do\n sh \"$SHELL_FOLDER/post-receive.d/$i\"\ndone", 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), + } + ) + + return x.Where("id > 0").Iterate(new(Repository), + func(idx int, bean interface{}) error { + repo := bean.(*Repository) + user := new(User) + has, err := x.Where("id = ?", repo.OwnerID).Get(user) + if err != nil { + return fmt.Errorf("query owner of repository [repo_id: %d, owner_id: %d]: %v", repo.ID, repo.OwnerID, err) + } else if !has { + return nil + } + + repoPath := filepath.Join(setting.RepoRootPath, strings.ToLower(user.Name), strings.ToLower(repo.Name)) + ".git" + 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: Old server-side hooks will be moved to sub directory with the same name + if hookName != "update" && com.IsExist(oldHookPath) { + newPlace := filepath.Join(hookDir, hookName+".d", hookName) + if err = os.Rename(oldHookPath, newPlace); err != nil { + return fmt.Errorf("Remove old hook file '%s' to '%s': %v", oldHookPath, newPlace, 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 = ioutil.WriteFile(newHookPath, []byte(giteaHookTpls[i]), 0777); err != nil { + return fmt.Errorf("write new hook file '%s': %v", oldHookPath, err) + } + } + return nil + }) +} diff --git a/models/repo.go b/models/repo.go index af8f688339..e276a87ae6 100644 --- a/models/repo.go +++ b/models/repo.go @@ -831,20 +831,54 @@ func cleanUpMigrateGitConfig(configPath string) error { return nil } -func createUpdateHook(repoPath string) error { - return git.SetUpdateHook(repoPath, - fmt.Sprintf(tplUpdateHook, setting.ScriptType, "\""+setting.AppPath+"\"", setting.CustomConf)) +// 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\nORI_DIR=`pwd`\nSHELL_FOLDER=$(cd \"$(dirname \"$0\")\";pwd)\ncd \"$ORI_DIR\"\nfor i in `ls \"$SHELL_FOLDER/pre-receive.d\"`; do\n sh \"$SHELL_FOLDER/pre-receive.d/$i\"\ndone", setting.ScriptType), + fmt.Sprintf("#!/usr/bin/env %s\nORI_DIR=`pwd`\nSHELL_FOLDER=$(cd \"$(dirname \"$0\")\";pwd)\ncd \"$ORI_DIR\"\nfor i in `ls \"$SHELL_FOLDER/update.d\"`; do\n sh \"$SHELL_FOLDER/update.d/$i\" $1 $2 $3\ndone", setting.ScriptType), + fmt.Sprintf("#!/usr/bin/env %s\nORI_DIR=`pwd`\nSHELL_FOLDER=$(cd \"$(dirname \"$0\")\";pwd)\ncd \"$ORI_DIR\"\nfor i in `ls \"$SHELL_FOLDER/post-receive.d\"`; do\n sh \"$SHELL_FOLDER/post-receive.d/$i\"\ndone", 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 = ioutil.WriteFile(oldHookPath, []byte(hookTpls[i]), 0777); err != nil { + return fmt.Errorf("write old hook file '%s': %v", oldHookPath, 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 } // CleanUpMigrateInfo finishes migrating repository and/or wiki with things that don't need to be done for mirrors. func CleanUpMigrateInfo(repo *Repository) (*Repository, error) { repoPath := repo.RepoPath() - if err := createUpdateHook(repoPath); err != nil { - return repo, fmt.Errorf("createUpdateHook: %v", err) + if err := createDelegateHooks(repoPath); err != nil { + return repo, fmt.Errorf("createDelegateHooks: %v", err) } if repo.HasWiki() { - if err := createUpdateHook(repo.WikiPath()); err != nil { - return repo, fmt.Errorf("createUpdateHook (wiki): %v", err) + if err := createDelegateHooks(repo.WikiPath()); err != nil { + return repo, fmt.Errorf("createDelegateHooks.(wiki): %v", err) } } @@ -994,8 +1028,8 @@ func initRepository(e Engine, repoPath string, u *User, repo *Repository, opts C // Init bare new repository. if err = git.InitRepository(repoPath, true); err != nil { return fmt.Errorf("InitRepository: %v", err) - } else if err = createUpdateHook(repoPath); err != nil { - return fmt.Errorf("createUpdateHook: %v", err) + } else if err = createDelegateHooks(repoPath); err != nil { + return fmt.Errorf("createDelegateHooks: %v", err) } tmpDir := filepath.Join(os.TempDir(), "gitea-"+repo.Name+"-"+com.ToStr(time.Now().Nanosecond())) @@ -2009,15 +2043,16 @@ func ReinitMissingRepositories() error { return nil } -// RewriteRepositoryUpdateHook rewrites all repositories' update hook. -func RewriteRepositoryUpdateHook() error { - return x. - Where("id > 0"). - Iterate(new(Repository), - func(idx int, bean interface{}) error { - repo := bean.(*Repository) - return createUpdateHook(repo.RepoPath()) - }) +// 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.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) + } + return nil + }) } // Prevent duplicate running tasks. @@ -2345,8 +2380,8 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Reposit return nil, fmt.Errorf("git update-server-info: %v", stderr) } - if err = createUpdateHook(repoPath); err != nil { - return nil, fmt.Errorf("createUpdateHook: %v", err) + if err = createDelegateHooks(repoPath); err != nil { + return nil, fmt.Errorf("createDelegateHooks: %v", err) } //Commit repo to get Fork ID diff --git a/models/wiki.go b/models/wiki.go index 39e4b2a443..690da707c6 100644 --- a/models/wiki.go +++ b/models/wiki.go @@ -69,8 +69,8 @@ func (repo *Repository) InitWiki() error { if err := git.InitRepository(repo.WikiPath(), true); err != nil { return fmt.Errorf("InitRepository: %v", err) - } else if err = createUpdateHook(repo.WikiPath()); err != nil { - return fmt.Errorf("createUpdateHook: %v", err) + } else if err = createDelegateHooks(repo.WikiPath()); err != nil { + return fmt.Errorf("createDelegateHooks: %v", err) } return nil } |