2016-11-04 01:16:01 +03:00
// Copyright 2015 The Gogs 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 git
import (
"errors"
"io/ioutil"
"os"
"path"
2017-02-23 06:40:44 +03:00
"path/filepath"
2016-11-04 01:16:01 +03:00
"strings"
"github.com/Unknwon/com"
)
// 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" ,
}
var (
2016-12-22 12:30:52 +03:00
// ErrNotValidHook error when a git hook is not valid
2016-11-04 01:16:01 +03:00
ErrNotValidHook = errors . New ( "not a valid Git hook" )
)
// 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 ) {
data , err := ioutil . ReadFile ( h . path )
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 ) {
data , err := ioutil . 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 ) {
2019-03-27 12:33:00 +03:00
err := os . Remove ( h . path )
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-03-27 12:33:00 +03:00
err := ioutil . WriteFile ( h . path , [ ] byte ( strings . Replace ( h . Content , "\r" , "" , - 1 ) ) , os . ModePerm )
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
)
// SetUpdateHook writes given content to update hook of the reposiotry.
func SetUpdateHook ( repoPath , content string ) ( err error ) {
log ( "Setting update hook: %s" , repoPath )
2016-11-15 18:24:08 +03:00
hookPath := path . Join ( repoPath , HookPathUpdate )
2016-11-04 01:16:01 +03:00
if com . IsExist ( hookPath ) {
err = os . Remove ( hookPath )
} else {
err = os . MkdirAll ( path . Dir ( hookPath ) , os . ModePerm )
}
if err != nil {
return err
}
return ioutil . WriteFile ( hookPath , [ ] byte ( content ) , 0777 )
}