2015-03-19 19:30:55 +00:00
package lfs
2014-06-03 22:03:43 +00:00
import (
"errors"
"fmt"
2015-04-24 17:33:22 +00:00
"io"
2014-06-04 14:29:19 +00:00
"io/ioutil"
"os"
"path/filepath"
2014-06-03 22:03:43 +00:00
"regexp"
2015-04-24 17:33:22 +00:00
"strings"
2015-05-13 19:43:41 +00:00
"github.com/github/git-lfs/git"
2014-06-03 22:03:43 +00:00
)
2014-06-04 14:29:19 +00:00
var (
2014-06-05 18:48:23 +00:00
valueRegexp = regexp . MustCompile ( "\\Agit[\\-\\s]media" )
NotInARepositoryError = errors . New ( "Not in a repository" )
2015-04-24 17:33:22 +00:00
2015-05-27 15:43:06 +00:00
prePushHook = "#!/bin/sh\ncommand -v git-lfs >/dev/null 2>&1 || { echo >&2 \"\\nThis repository has been set up with Git LFS but Git LFS is not installed.\\n\"; exit 0; }\ngit lfs pre-push \"$@\""
2015-04-24 17:33:22 +00:00
prePushUpgrades = map [ string ] bool {
"#!/bin/sh\ngit lfs push --stdin $*" : true ,
"#!/bin/sh\ngit lfs push --stdin \"$@\"" : true ,
2015-05-27 15:43:06 +00:00
"#!/bin/sh\ngit lfs pre-push \"$@\"" : true ,
2015-04-24 17:33:22 +00:00
}
2014-06-04 14:29:19 +00:00
)
2014-06-03 22:03:43 +00:00
2014-06-05 18:48:23 +00:00
type HookExists struct {
2015-04-24 17:33:22 +00:00
Name string
Path string
Contents string
2014-06-05 18:48:23 +00:00
}
func ( e * HookExists ) Error ( ) string {
2015-04-24 17:33:22 +00:00
return fmt . Sprintf ( "Hook already exists: %s\n\n%s\n" , e . Name , e . Contents )
2014-06-05 18:48:23 +00:00
}
2014-09-23 21:42:47 +00:00
func InstallHooks ( force bool ) error {
2014-06-03 22:03:43 +00:00
if ! InRepo ( ) {
2014-06-05 18:48:23 +00:00
return NotInARepositoryError
2014-06-03 22:03:43 +00:00
}
2014-08-06 20:41:43 +00:00
if err := os . MkdirAll ( filepath . Join ( LocalGitDir , "hooks" ) , 0755 ) ; err != nil {
return err
}
2014-06-04 14:29:19 +00:00
hookPath := filepath . Join ( LocalGitDir , "hooks" , "pre-push" )
2014-09-23 21:42:47 +00:00
if _ , err := os . Stat ( hookPath ) ; err == nil && ! force {
2015-04-24 17:33:22 +00:00
return upgradeHookOrError ( hookPath , "pre-push" , prePushHook , prePushUpgrades )
}
2015-05-12 08:45:06 +00:00
return ioutil . WriteFile ( hookPath , [ ] byte ( prePushHook + "\n" ) , 0755 )
2015-04-24 17:33:22 +00:00
}
func upgradeHookOrError ( hookPath , hookName , hook string , upgrades map [ string ] bool ) error {
file , err := os . Open ( hookPath )
if err != nil {
return err
2014-06-04 14:29:19 +00:00
}
2015-04-24 17:33:22 +00:00
by , err := ioutil . ReadAll ( io . LimitReader ( file , 1024 ) )
file . Close ( )
if err != nil {
return err
}
contents := strings . TrimSpace ( string ( by ) )
if contents == hook {
return nil
}
if upgrades [ contents ] {
return ioutil . WriteFile ( hookPath , [ ] byte ( hook + "\n" ) , 0755 )
}
return & HookExists { hookName , hookPath , contents }
2014-06-03 22:03:43 +00:00
}
2014-06-05 18:48:23 +00:00
func InstallFilters ( ) error {
2015-05-12 08:50:20 +00:00
if err := setFilter ( "clean" ) ; err != nil {
return err
2014-06-05 18:48:23 +00:00
}
2015-05-12 08:50:20 +00:00
if err := setFilter ( "smudge" ) ; err != nil {
return err
2014-06-05 18:48:23 +00:00
}
2015-05-12 08:50:20 +00:00
if err := requireFilters ( ) ; err != nil {
return err
}
return nil
2014-06-03 22:03:43 +00:00
}
2014-06-05 18:48:23 +00:00
func setFilter ( filterName string ) error {
2015-03-19 19:30:55 +00:00
key := fmt . Sprintf ( "filter.lfs.%s" , filterName )
2015-06-10 13:21:11 +00:00
value := fmt . Sprintf ( "git-lfs %s %%f" , filterName )
2014-06-03 22:03:43 +00:00
2014-09-23 15:40:23 +00:00
existing := git . Config . Find ( key )
2014-06-03 22:03:43 +00:00
if shouldReset ( existing ) {
2014-09-23 15:40:23 +00:00
git . Config . UnsetGlobal ( key )
git . Config . SetGlobal ( key , value )
2014-06-03 22:03:43 +00:00
} else if existing != value {
2014-06-05 18:48:23 +00:00
return fmt . Errorf ( "The %s filter should be \"%s\" but is \"%s\"" , filterName , value , existing )
2014-06-03 22:03:43 +00:00
}
2014-06-05 18:48:23 +00:00
return nil
2014-06-03 22:03:43 +00:00
}
2014-06-05 18:48:23 +00:00
func requireFilters ( ) error {
2015-03-19 19:30:55 +00:00
key := "filter.lfs.required"
2014-06-03 22:03:43 +00:00
value := "true"
2014-09-23 15:40:23 +00:00
existing := git . Config . Find ( key )
2014-06-03 22:03:43 +00:00
if shouldReset ( existing ) {
2014-09-23 15:40:23 +00:00
git . Config . UnsetGlobal ( key )
git . Config . SetGlobal ( key , value )
2014-06-03 22:03:43 +00:00
} else if existing != value {
2015-03-19 19:30:55 +00:00
return errors . New ( "Git LFS filters should be required but are not." )
2014-06-03 22:03:43 +00:00
}
2014-06-05 18:48:23 +00:00
return nil
2014-06-03 22:03:43 +00:00
}
func shouldReset ( value string ) bool {
if len ( value ) == 0 {
return true
}
return valueRegexp . MatchString ( value )
}