github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/env/config.go (about)

     1  // Copyright 2019 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package env
    16  
    17  import (
    18  	"errors"
    19  	"path/filepath"
    20  	"strings"
    21  
    22  	"github.com/dolthub/dolt/go/libraries/doltcore/dbfactory"
    23  
    24  	"github.com/dolthub/dolt/go/libraries/utils/config"
    25  	"github.com/dolthub/dolt/go/libraries/utils/filesys"
    26  	"github.com/dolthub/dolt/go/libraries/utils/set"
    27  )
    28  
    29  const (
    30  	localConfigName  = "local"
    31  	globalConfigName = "global"
    32  
    33  	UserEmailKey = "user.email"
    34  	UserNameKey  = "user.name"
    35  
    36  	// should be able to have remote specific creds?
    37  	UserCreds = "user.creds"
    38  
    39  	DoltEditor = "core.editor"
    40  
    41  	RemotesApiHostKey     = "remotes.default_host"
    42  	RemotesApiHostPortKey = "remotes.default_port"
    43  
    44  	AddCredsUrlKey = "creds.add_url"
    45  
    46  	MetricsDisabled = "metrics.disabled"
    47  	MetricsHost     = "metrics.host"
    48  	MetricsPort     = "metrics.port"
    49  	MetricsInsecure = "metrics.insecure"
    50  )
    51  
    52  var LocalConfigWhitelist = set.NewStrSet([]string{UserNameKey, UserEmailKey})
    53  var GlobalConfigWhitelist = set.NewStrSet([]string{UserNameKey, UserEmailKey})
    54  
    55  // DoltConfigElement is an enum representing the elements that make up the ConfigHierarchy
    56  type DoltConfigElement int
    57  
    58  const (
    59  	// LocalConfig is the repository's local config portion of the ConfigHierarchy
    60  	LocalConfig DoltConfigElement = iota
    61  
    62  	// GlobalConfig is the user's global config portion of the ConfigHierarchy
    63  	GlobalConfig
    64  )
    65  
    66  // String gives the string name of an element that was used when it was added to the ConfigHierarchy, which is the
    67  // same name that is used to retrieve that element of the string hierarchy.
    68  func (ce DoltConfigElement) String() string {
    69  	switch ce {
    70  	case LocalConfig:
    71  		return localConfigName
    72  	case GlobalConfig:
    73  		return globalConfigName
    74  	}
    75  
    76  	return ""
    77  }
    78  
    79  // DoltCliConfig is the config for the cli
    80  type DoltCliConfig struct {
    81  	config.ReadableConfig
    82  
    83  	ch *config.ConfigHierarchy
    84  	fs filesys.ReadWriteFS
    85  }
    86  
    87  func loadDoltCliConfig(hdp HomeDirProvider, fs filesys.ReadWriteFS) (*DoltCliConfig, error) {
    88  	ch := config.NewConfigHierarchy()
    89  
    90  	gPath, err := getGlobalCfgPath(hdp)
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  
    95  	lPath := getLocalConfigPath()
    96  
    97  	gCfg, err := ensureGlobalConfig(gPath, fs)
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  
   102  	ch.AddConfig(globalConfigName, gCfg)
   103  
   104  	if exists, _ := fs.Exists(lPath); exists {
   105  		lCfg, err := config.FromFile(lPath, fs)
   106  
   107  		if err == nil {
   108  			ch.AddConfig(localConfigName, lCfg)
   109  		}
   110  	}
   111  
   112  	return &DoltCliConfig{ch, ch, fs}, nil
   113  }
   114  
   115  func ensureGlobalConfig(path string, fs filesys.ReadWriteFS) (config.ReadWriteConfig, error) {
   116  	if exists, isDir := fs.Exists(path); exists {
   117  		if isDir {
   118  			return nil, errors.New("A directory exists where this file should be. path: " + path)
   119  		}
   120  
   121  		return config.FromFile(path, fs)
   122  	}
   123  
   124  	return config.NewFileConfig(path, fs, map[string]string{})
   125  }
   126  
   127  // CreateLocalConfig creates a new repository local config file.  The current directory must have already been initialized
   128  // as a data repository before a local config can be created.
   129  func (dcc *DoltCliConfig) CreateLocalConfig(vals map[string]string) error {
   130  	return dcc.createLocalConfigAt(".", vals)
   131  }
   132  
   133  func (dcc *DoltCliConfig) createLocalConfigAt(dir string, vals map[string]string) error {
   134  	doltDir := filepath.Join(dir, dbfactory.DoltDir)
   135  	if exists, isDir := dcc.fs.Exists(doltDir); !exists {
   136  		return errors.New(dbfactory.DoltDir + " directory not found. Is the current directory a repository directory?")
   137  	} else if !isDir {
   138  		return errors.New("A file exists with the name \"" + dbfactory.DoltDir + "\". This is not a valid file within a data repository directory.")
   139  	}
   140  
   141  	path := filepath.Join(dir, getLocalConfigPath())
   142  	cfg, err := config.NewFileConfig(path, dcc.fs, vals)
   143  
   144  	if err != nil {
   145  		return err
   146  	}
   147  
   148  	dcc.ch.AddConfig(localConfigName, cfg)
   149  
   150  	return nil
   151  }
   152  
   153  // GetConfig retrieves a specific element of the config hierarchy.
   154  func (dcc *DoltCliConfig) GetConfig(element DoltConfigElement) (config.ReadWriteConfig, bool) {
   155  	return dcc.ch.GetConfig(element.String())
   156  }
   157  
   158  // GetStringOrDefault retrieves a string from the config hierarchy and returns it if available.  Otherwise it returns
   159  // the default string value
   160  func (dcc *DoltCliConfig) GetStringOrDefault(key, defStr string) *string {
   161  	val, err := dcc.ch.GetString(key)
   162  
   163  	if err != nil {
   164  		return &defStr
   165  	}
   166  
   167  	return &val
   168  }
   169  
   170  // IfEmptyUseConfig looks at a strings value and if it is an empty string will try to return a value from the config
   171  // hierarchy.  If it is missing in the config a pointer to an empty string will be returned.
   172  func (dcc *DoltCliConfig) IfEmptyUseConfig(val, key string) string {
   173  	if len(strings.TrimSpace(val)) > 0 {
   174  		return val
   175  	}
   176  
   177  	cfgVal, err := dcc.ch.GetString(key)
   178  
   179  	if err != nil {
   180  		s := ""
   181  		return s
   182  	}
   183  
   184  	return cfgVal
   185  }