2016-11-04 01:16:01 +03:00
// Copyright 2015 The Gogs Authors. All rights reserved.
2021-06-25 19:54:08 +03:00
// Copyright 2021 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2016-11-04 01:16:01 +03:00
package git
import (
"errors"
"os"
"path"
2017-02-23 06:40:44 +03:00
"path/filepath"
2016-11-04 01:16:01 +03:00
"strings"
2021-06-25 19:54:08 +03:00
"code.gitea.io/gitea/modules/log"
2020-08-11 23:05:34 +03:00
"code.gitea.io/gitea/modules/util"
2016-11-04 01:16:01 +03:00
)
// hookNames is a list of Git server hooks' name that are supported.
var hookNames = [ ] string {
"pre-receive" ,
2017-02-23 06:40:44 +03:00
"update" ,
2016-11-04 01:16:01 +03:00
"post-receive" ,
}
2022-01-20 20:46:10 +03:00
// ErrNotValidHook error when a git hook is not valid
var ErrNotValidHook = errors . New ( "not a valid Git hook" )
2016-11-04 01:16:01 +03:00
// IsValidHookName returns true if given name is a valid Git hook.
func IsValidHookName ( name string ) bool {
for _ , hn := range hookNames {
if hn == name {
return true
}
}
return false
}
// Hook represents a Git hook.
type Hook struct {
name string
IsActive bool // Indicates whether repository has this hook.
Content string // Content of hook if it's active.
Sample string // Sample content from Git.
path string // Hook file path.
}
// GetHook returns a Git hook by given name and repository.
func GetHook ( repoPath , name string ) ( * Hook , error ) {
if ! IsValidHookName ( name ) {
return nil , ErrNotValidHook
}
h := & Hook {
name : name ,
2017-02-23 06:40:44 +03:00
path : path . Join ( repoPath , "hooks" , name + ".d" , name ) ,
2016-11-04 01:16:01 +03:00
}
2017-02-23 06:40:44 +03:00
samplePath := filepath . Join ( repoPath , "hooks" , name + ".sample" )
2016-11-04 01:16:01 +03:00
if isFile ( h . path ) {
2021-09-22 08:38:34 +03:00
data , err := os . ReadFile ( h . path )
2016-11-04 01:16:01 +03:00
if err != nil {
return nil , err
}
h . IsActive = true
h . Content = string ( data )
2017-02-23 06:40:44 +03:00
} else if isFile ( samplePath ) {
2021-09-22 08:38:34 +03:00
data , err := os . ReadFile ( samplePath )
2016-11-04 01:16:01 +03:00
if err != nil {
return nil , err
}
h . Sample = string ( data )
}
return h , nil
}
2016-12-22 12:30:52 +03:00
// Name return the name of the hook
2016-11-04 01:16:01 +03:00
func ( h * Hook ) Name ( ) string {
return h . name
}
// Update updates hook settings.
func ( h * Hook ) Update ( ) error {
if len ( strings . TrimSpace ( h . Content ) ) == 0 {
if isExist ( h . path ) {
2020-08-11 23:05:34 +03:00
err := util . Remove ( h . path )
2019-03-27 12:33:00 +03:00
if err != nil {
return err
}
2016-11-04 01:16:01 +03:00
}
2019-03-27 12:33:00 +03:00
h . IsActive = false
2016-11-04 01:16:01 +03:00
return nil
}
2019-11-02 16:38:11 +03:00
d := filepath . Dir ( h . path )
if err := os . MkdirAll ( d , os . ModePerm ) ; err != nil {
return err
}
2021-09-22 08:38:34 +03:00
err := os . WriteFile ( h . path , [ ] byte ( strings . ReplaceAll ( h . Content , "\r" , "" ) ) , os . ModePerm )
2019-03-27 12:33:00 +03:00
if err != nil {
return err
}
h . IsActive = true
return nil
2016-11-04 01:16:01 +03:00
}
// ListHooks returns a list of Git hooks of given repository.
func ListHooks ( repoPath string ) ( _ [ ] * Hook , err error ) {
if ! isDir ( path . Join ( repoPath , "hooks" ) ) {
return nil , errors . New ( "hooks path does not exist" )
}
hooks := make ( [ ] * Hook , len ( hookNames ) )
for i , name := range hookNames {
hooks [ i ] , err = GetHook ( repoPath , name )
if err != nil {
return nil , err
}
}
return hooks , nil
}
const (
2016-12-22 12:30:52 +03:00
// HookPathUpdate hook update path
2016-11-15 18:24:08 +03:00
HookPathUpdate = "hooks/update"
2016-11-04 01:16:01 +03:00
)
2020-08-20 20:41:08 +03:00
// SetUpdateHook writes given content to update hook of the repository.
2016-11-04 01:16:01 +03:00
func SetUpdateHook ( repoPath , content string ) ( err error ) {
2021-06-25 19:54:08 +03:00
log . Debug ( "Setting update hook: %s" , repoPath )
2016-11-15 18:24:08 +03:00
hookPath := path . Join ( repoPath , HookPathUpdate )
2020-11-28 05:42:08 +03:00
isExist , err := util . IsExist ( hookPath )
if err != nil {
2021-06-25 19:54:08 +03:00
log . Debug ( "Unable to check if %s exists. Error: %v" , hookPath , err )
2020-11-28 05:42:08 +03:00
return err
}
if isExist {
2020-08-11 23:05:34 +03:00
err = util . Remove ( hookPath )
2016-11-04 01:16:01 +03:00
} else {
err = os . MkdirAll ( path . Dir ( hookPath ) , os . ModePerm )
}
if err != nil {
return err
}
2022-01-20 20:46:10 +03:00
return os . WriteFile ( hookPath , [ ] byte ( content ) , 0 o777 )
2016-11-04 01:16:01 +03:00
}