2017-10-18 18:22:45 +00:00
|
|
|
package git
|
|
|
|
|
|
|
|
import (
|
2018-10-25 21:24:58 +00:00
|
|
|
"errors"
|
2017-10-18 18:22:45 +00:00
|
|
|
"os"
|
2017-10-25 19:47:13 +00:00
|
|
|
"path/filepath"
|
2017-10-18 18:22:45 +00:00
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
|
2017-10-26 01:46:36 +00:00
|
|
|
"github.com/git-lfs/git-lfs/subprocess"
|
2017-10-18 18:22:45 +00:00
|
|
|
)
|
|
|
|
|
2018-10-25 21:24:58 +00:00
|
|
|
var (
|
|
|
|
ErrReadOnly = errors.New("configuration is read-only")
|
|
|
|
)
|
|
|
|
|
2019-08-09 15:25:23 +00:00
|
|
|
// Environment is a restricted version of config.Environment that only provides
|
|
|
|
// a single method.
|
|
|
|
type Environment interface {
|
|
|
|
// Get is shorthand for calling `e.Fetcher.Get(key)`.
|
|
|
|
Get(key string) (val string, ok bool)
|
|
|
|
}
|
|
|
|
|
2017-10-18 18:22:45 +00:00
|
|
|
// Configuration can fetch or modify the current Git config and track the Git
|
|
|
|
// version.
|
|
|
|
type Configuration struct {
|
2018-10-25 21:24:58 +00:00
|
|
|
WorkDir string
|
|
|
|
GitDir string
|
|
|
|
version *string
|
|
|
|
readOnly bool
|
|
|
|
mu sync.Mutex
|
2017-10-18 18:22:45 +00:00
|
|
|
}
|
|
|
|
|
2017-10-25 19:47:13 +00:00
|
|
|
func NewConfig(workdir, gitdir string) *Configuration {
|
|
|
|
if len(gitdir) == 0 && len(workdir) > 0 {
|
|
|
|
gitdir = filepath.Join(workdir, ".git")
|
|
|
|
}
|
|
|
|
return &Configuration{WorkDir: workdir, GitDir: gitdir}
|
|
|
|
}
|
|
|
|
|
2018-10-25 21:24:58 +00:00
|
|
|
// NewReadOnlyConfig creates a new confguration that returns an error if an
|
|
|
|
// attempt to write to the configuration is made.
|
|
|
|
func NewReadOnlyConfig(workdir, gitdir string) *Configuration {
|
|
|
|
cfg := NewConfig(workdir, gitdir)
|
|
|
|
cfg.readOnly = true
|
|
|
|
return cfg
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-10-18 18:22:45 +00:00
|
|
|
func ParseConfigLines(lines string, onlySafeKeys bool) *ConfigurationSource {
|
|
|
|
return &ConfigurationSource{
|
|
|
|
Lines: strings.Split(lines, "\n"),
|
|
|
|
OnlySafeKeys: onlySafeKeys,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type ConfigurationSource struct {
|
|
|
|
Lines []string
|
|
|
|
OnlySafeKeys bool
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find returns the git config value for the key
|
|
|
|
func (c *Configuration) Find(val string) string {
|
2017-10-26 01:46:36 +00:00
|
|
|
output, _ := c.gitConfig(val)
|
2017-10-18 18:22:45 +00:00
|
|
|
return output
|
|
|
|
}
|
|
|
|
|
2020-06-26 08:57:09 +00:00
|
|
|
// FindGlobal returns the git config value in global scope for the key
|
2017-10-18 18:52:24 +00:00
|
|
|
func (c *Configuration) FindGlobal(key string) string {
|
2017-10-26 01:46:36 +00:00
|
|
|
output, _ := c.gitConfig("--global", key)
|
2017-10-18 18:22:45 +00:00
|
|
|
return output
|
|
|
|
}
|
|
|
|
|
|
|
|
// FindSystem returns the git config value in system scope for the key
|
2017-10-18 18:52:24 +00:00
|
|
|
func (c *Configuration) FindSystem(key string) string {
|
2017-10-26 01:46:36 +00:00
|
|
|
output, _ := c.gitConfig("--system", key)
|
2017-10-18 18:22:45 +00:00
|
|
|
return output
|
|
|
|
}
|
|
|
|
|
2020-06-26 08:57:09 +00:00
|
|
|
// FindLocal returns the git config value in local scope for the key
|
2017-10-18 18:52:24 +00:00
|
|
|
func (c *Configuration) FindLocal(key string) string {
|
2017-10-26 01:46:36 +00:00
|
|
|
output, _ := c.gitConfig("--local", key)
|
2017-10-18 18:22:45 +00:00
|
|
|
return output
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetGlobal sets the git config value for the key in the global config
|
|
|
|
func (c *Configuration) SetGlobal(key, val string) (string, error) {
|
2018-10-25 21:24:58 +00:00
|
|
|
return c.gitConfigWrite("--global", "--replace-all", key, val)
|
2017-10-18 18:22:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// SetSystem sets the git config value for the key in the system config
|
|
|
|
func (c *Configuration) SetSystem(key, val string) (string, error) {
|
2018-10-25 21:24:58 +00:00
|
|
|
return c.gitConfigWrite("--system", "--replace-all", key, val)
|
2017-10-18 18:22:45 +00:00
|
|
|
}
|
|
|
|
|
2020-06-26 08:57:09 +00:00
|
|
|
// SetLocal sets the git config value for the key in the specified config file
|
|
|
|
func (c *Configuration) SetLocal(key, val string) (string, error) {
|
|
|
|
return c.gitConfigWrite("--replace-all", key, val)
|
|
|
|
}
|
|
|
|
|
2017-10-18 18:22:45 +00:00
|
|
|
// UnsetGlobalSection removes the entire named section from the global config
|
|
|
|
func (c *Configuration) UnsetGlobalSection(key string) (string, error) {
|
2018-10-25 21:24:58 +00:00
|
|
|
return c.gitConfigWrite("--global", "--remove-section", key)
|
2017-10-18 18:22:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// UnsetSystemSection removes the entire named section from the system config
|
|
|
|
func (c *Configuration) UnsetSystemSection(key string) (string, error) {
|
2018-10-25 21:24:58 +00:00
|
|
|
return c.gitConfigWrite("--system", "--remove-section", key)
|
2017-10-18 18:22:45 +00:00
|
|
|
}
|
|
|
|
|
2020-06-26 08:57:09 +00:00
|
|
|
// UnsetLocalSection removes the entire named section from the local config
|
2017-10-18 18:22:45 +00:00
|
|
|
func (c *Configuration) UnsetLocalSection(key string) (string, error) {
|
2018-10-25 21:24:58 +00:00
|
|
|
return c.gitConfigWrite("--local", "--remove-section", key)
|
2017-10-18 18:22:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// UnsetLocalKey removes the git config value for the key from the specified config file
|
2017-10-26 01:20:35 +00:00
|
|
|
func (c *Configuration) UnsetLocalKey(key string) (string, error) {
|
2018-10-25 21:24:58 +00:00
|
|
|
return c.gitConfigWrite("--unset", key)
|
2017-10-18 18:22:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Configuration) Sources(optionalFilename string) ([]*ConfigurationSource, error) {
|
|
|
|
gitconfig, err := c.Source()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
fileconfig, err := c.FileSource(optionalFilename)
|
|
|
|
if err != nil && !os.IsNotExist(err) {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
configs := make([]*ConfigurationSource, 0, 2)
|
|
|
|
if fileconfig != nil {
|
|
|
|
configs = append(configs, fileconfig)
|
|
|
|
}
|
|
|
|
|
|
|
|
return append(configs, gitconfig), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Configuration) FileSource(filename string) (*ConfigurationSource, error) {
|
|
|
|
if _, err := os.Stat(filename); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2017-10-26 01:46:36 +00:00
|
|
|
out, err := c.gitConfig("-l", "-f", filename)
|
2017-10-18 18:22:45 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return ParseConfigLines(out, true), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Configuration) Source() (*ConfigurationSource, error) {
|
2017-10-26 01:46:36 +00:00
|
|
|
out, err := c.gitConfig("-l")
|
2017-10-18 18:22:45 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return ParseConfigLines(out, false), nil
|
|
|
|
}
|
|
|
|
|
2017-10-26 01:46:36 +00:00
|
|
|
func (c *Configuration) gitConfig(args ...string) (string, error) {
|
|
|
|
args = append([]string{"config"}, args...)
|
|
|
|
subprocess.Trace("git", args...)
|
|
|
|
cmd := subprocess.ExecCommand("git", args...)
|
2017-10-25 19:47:13 +00:00
|
|
|
if len(c.GitDir) > 0 {
|
2017-10-26 01:46:36 +00:00
|
|
|
cmd.Dir = c.GitDir
|
2017-10-25 19:47:13 +00:00
|
|
|
}
|
2017-10-26 01:46:36 +00:00
|
|
|
return subprocess.Output(cmd)
|
2017-10-25 19:47:13 +00:00
|
|
|
}
|
2018-10-25 21:24:58 +00:00
|
|
|
|
|
|
|
func (c *Configuration) gitConfigWrite(args ...string) (string, error) {
|
|
|
|
if c.readOnly {
|
|
|
|
return "", ErrReadOnly
|
|
|
|
}
|
|
|
|
return c.gitConfig(args...)
|
|
|
|
}
|