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.

141 lines
3.1 KiB

  1. // Copyright 2015 The Gogs 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 git
  5. import (
  6. "errors"
  7. "io/ioutil"
  8. "os"
  9. "path"
  10. "path/filepath"
  11. "strings"
  12. "code.gitea.io/gitea/modules/util"
  13. "github.com/unknwon/com"
  14. )
  15. // hookNames is a list of Git server hooks' name that are supported.
  16. var hookNames = []string{
  17. "pre-receive",
  18. "update",
  19. "post-receive",
  20. }
  21. var (
  22. // ErrNotValidHook error when a git hook is not valid
  23. ErrNotValidHook = errors.New("not a valid Git hook")
  24. )
  25. // IsValidHookName returns true if given name is a valid Git hook.
  26. func IsValidHookName(name string) bool {
  27. for _, hn := range hookNames {
  28. if hn == name {
  29. return true
  30. }
  31. }
  32. return false
  33. }
  34. // Hook represents a Git hook.
  35. type Hook struct {
  36. name string
  37. IsActive bool // Indicates whether repository has this hook.
  38. Content string // Content of hook if it's active.
  39. Sample string // Sample content from Git.
  40. path string // Hook file path.
  41. }
  42. // GetHook returns a Git hook by given name and repository.
  43. func GetHook(repoPath, name string) (*Hook, error) {
  44. if !IsValidHookName(name) {
  45. return nil, ErrNotValidHook
  46. }
  47. h := &Hook{
  48. name: name,
  49. path: path.Join(repoPath, "hooks", name+".d", name),
  50. }
  51. samplePath := filepath.Join(repoPath, "hooks", name+".sample")
  52. if isFile(h.path) {
  53. data, err := ioutil.ReadFile(h.path)
  54. if err != nil {
  55. return nil, err
  56. }
  57. h.IsActive = true
  58. h.Content = string(data)
  59. } else if isFile(samplePath) {
  60. data, err := ioutil.ReadFile(samplePath)
  61. if err != nil {
  62. return nil, err
  63. }
  64. h.Sample = string(data)
  65. }
  66. return h, nil
  67. }
  68. // Name return the name of the hook
  69. func (h *Hook) Name() string {
  70. return h.name
  71. }
  72. // Update updates hook settings.
  73. func (h *Hook) Update() error {
  74. if len(strings.TrimSpace(h.Content)) == 0 {
  75. if isExist(h.path) {
  76. err := util.Remove(h.path)
  77. if err != nil {
  78. return err
  79. }
  80. }
  81. h.IsActive = false
  82. return nil
  83. }
  84. d := filepath.Dir(h.path)
  85. if err := os.MkdirAll(d, os.ModePerm); err != nil {
  86. return err
  87. }
  88. err := ioutil.WriteFile(h.path, []byte(strings.Replace(h.Content, "\r", "", -1)), os.ModePerm)
  89. if err != nil {
  90. return err
  91. }
  92. h.IsActive = true
  93. return nil
  94. }
  95. // ListHooks returns a list of Git hooks of given repository.
  96. func ListHooks(repoPath string) (_ []*Hook, err error) {
  97. if !isDir(path.Join(repoPath, "hooks")) {
  98. return nil, errors.New("hooks path does not exist")
  99. }
  100. hooks := make([]*Hook, len(hookNames))
  101. for i, name := range hookNames {
  102. hooks[i], err = GetHook(repoPath, name)
  103. if err != nil {
  104. return nil, err
  105. }
  106. }
  107. return hooks, nil
  108. }
  109. const (
  110. // HookPathUpdate hook update path
  111. HookPathUpdate = "hooks/update"
  112. )
  113. // SetUpdateHook writes given content to update hook of the repository.
  114. func SetUpdateHook(repoPath, content string) (err error) {
  115. log("Setting update hook: %s", repoPath)
  116. hookPath := path.Join(repoPath, HookPathUpdate)
  117. if com.IsExist(hookPath) {
  118. err = util.Remove(hookPath)
  119. } else {
  120. err = os.MkdirAll(path.Dir(hookPath), os.ModePerm)
  121. }
  122. if err != nil {
  123. return err
  124. }
  125. return ioutil.WriteFile(hookPath, []byte(content), 0777)
  126. }