You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

87 lines
2.6 KiB

  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package migrations
  5. import (
  6. "crypto/md5"
  7. "encoding/hex"
  8. "fmt"
  9. "io"
  10. "io/ioutil"
  11. "os"
  12. "path/filepath"
  13. "strings"
  14. "code.gitea.io/gitea/modules/setting"
  15. "github.com/unknwon/com"
  16. "xorm.io/xorm"
  17. )
  18. func generateAndMigrateGitHookChains(x *xorm.Engine) (err error) {
  19. type Repository struct {
  20. ID int64
  21. OwnerID int64
  22. Name string
  23. }
  24. type User struct {
  25. ID int64
  26. Name string
  27. }
  28. var (
  29. hookNames = []string{"pre-receive", "update", "post-receive"}
  30. hookTpl = 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)
  31. )
  32. return x.Where("id > 0").BufferSize(setting.Database.IterateBufferSize).Iterate(new(Repository),
  33. func(idx int, bean interface{}) error {
  34. repo := bean.(*Repository)
  35. user := new(User)
  36. has, err := x.Where("id = ?", repo.OwnerID).Get(user)
  37. if err != nil {
  38. return fmt.Errorf("query owner of repository [repo_id: %d, owner_id: %d]: %v", repo.ID, repo.OwnerID, err)
  39. } else if !has {
  40. return nil
  41. }
  42. repoPaths := []string{
  43. filepath.Join(setting.RepoRootPath, strings.ToLower(user.Name), strings.ToLower(repo.Name)) + ".git",
  44. filepath.Join(setting.RepoRootPath, strings.ToLower(user.Name), strings.ToLower(repo.Name)) + ".wiki.git",
  45. }
  46. for _, repoPath := range repoPaths {
  47. if com.IsExist(repoPath) {
  48. hookDir := filepath.Join(repoPath, "hooks")
  49. for _, hookName := range hookNames {
  50. oldHookPath := filepath.Join(hookDir, hookName)
  51. // compare md5sums of hooks
  52. if com.IsExist(oldHookPath) {
  53. f, err := os.Open(oldHookPath)
  54. if err != nil {
  55. return fmt.Errorf("cannot open old hook file '%s': %v", oldHookPath, err)
  56. }
  57. defer f.Close()
  58. h := md5.New()
  59. if _, err := io.Copy(h, f); err != nil {
  60. return fmt.Errorf("cannot read old hook file '%s': %v", oldHookPath, err)
  61. }
  62. if hex.EncodeToString(h.Sum(nil)) == "6718ef67d0834e0a7908259acd566e3f" {
  63. return nil
  64. }
  65. }
  66. if err = ioutil.WriteFile(oldHookPath, []byte(hookTpl), 0777); err != nil {
  67. return fmt.Errorf("write old hook file '%s': %v", oldHookPath, err)
  68. }
  69. }
  70. }
  71. }
  72. return nil
  73. })
  74. }