github.com/jbendotnet/noms@v0.0.0-20190904222105-c43e4293ea92/go/config/config.go (about)

     1  // Copyright 2016 Attic Labs, Inc. All rights reserved.
     2  // Licensed under the Apache License, version 2.0:
     3  // http://www.apache.org/licenses/LICENSE-2.0
     4  
     5  package config
     6  
     7  import (
     8  	"bytes"
     9  	"errors"
    10  	"fmt"
    11  	"io/ioutil"
    12  	"os"
    13  	"path/filepath"
    14  
    15  	"github.com/BurntSushi/toml"
    16  	"github.com/attic-labs/noms/go/spec"
    17  )
    18  
    19  type Config struct {
    20  	File string
    21  	Db   map[string]DbConfig
    22  }
    23  
    24  type DbConfig struct {
    25  	Url string
    26  }
    27  
    28  const (
    29  	NomsConfigFile = ".nomsconfig"
    30  	DefaultDbAlias = "default"
    31  )
    32  
    33  var NoConfig = errors.New(fmt.Sprintf("no %s found", NomsConfigFile))
    34  
    35  // Find the closest directory containing .nomsconfig starting
    36  // in cwd and then searching up ancestor tree.
    37  // Look first looking in cwd and then up through its ancestors
    38  func FindNomsConfig() (*Config, error) {
    39  	curDir, err := os.Getwd()
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  	for {
    44  		nomsConfig := filepath.Join(curDir, NomsConfigFile)
    45  		info, err := os.Stat(nomsConfig)
    46  		if err == nil && !info.IsDir() {
    47  			// found
    48  			return ReadConfig(nomsConfig)
    49  		} else if err != nil && !os.IsNotExist(err) {
    50  			// can't read
    51  			return nil, err
    52  		}
    53  		nextDir := filepath.Dir(curDir)
    54  		if nextDir == curDir {
    55  			// stop at root
    56  			return nil, NoConfig
    57  		}
    58  		curDir = nextDir
    59  	}
    60  }
    61  
    62  func ReadConfig(name string) (*Config, error) {
    63  	data, err := ioutil.ReadFile(name)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  	c, err := NewConfig(string(data))
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  	c.File = name
    72  	return qualifyPaths(name, c)
    73  }
    74  
    75  func NewConfig(data string) (*Config, error) {
    76  	c := new(Config)
    77  	if _, err := toml.Decode(data, c); err != nil {
    78  		return nil, err
    79  	}
    80  	return c, nil
    81  }
    82  
    83  func (c *Config) WriteTo(configHome string) (string, error) {
    84  	file := filepath.Join(configHome, NomsConfigFile)
    85  	if err := os.MkdirAll(filepath.Dir(file), os.ModePerm); err != nil {
    86  		return "", err
    87  	}
    88  	if err := ioutil.WriteFile(file, []byte(c.writeableString()), os.ModePerm); err != nil {
    89  		return "", err
    90  	}
    91  	return file, nil
    92  }
    93  
    94  // Replace relative directory in path part of spec with an absolute
    95  // directory. Assumes the path is relative to the location of the config file
    96  func absDbSpec(configHome string, url string) string {
    97  	dbSpec, err := spec.ForDatabase(url)
    98  	if err != nil {
    99  		return url
   100  	}
   101  	if dbSpec.Protocol != "nbs" {
   102  		return url
   103  	}
   104  	dbName := dbSpec.DatabaseName
   105  	if !filepath.IsAbs(dbName) {
   106  		dbName = filepath.Join(configHome, dbName)
   107  	}
   108  	return "nbs:" + dbName
   109  }
   110  
   111  func qualifyPaths(configPath string, c *Config) (*Config, error) {
   112  	file, err := filepath.Abs(configPath)
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	dir := filepath.Dir(file)
   117  	qc := *c
   118  	qc.File = file
   119  	for k, r := range c.Db {
   120  		qc.Db[k] = DbConfig{absDbSpec(dir, r.Url)}
   121  	}
   122  	return &qc, nil
   123  }
   124  
   125  func (c *Config) String() string {
   126  	var buffer bytes.Buffer
   127  	if c.File != "" {
   128  		buffer.WriteString(fmt.Sprintf("file = %s\n", c.File))
   129  	}
   130  	buffer.WriteString(c.writeableString())
   131  	return buffer.String()
   132  }
   133  
   134  func (c *Config) writeableString() string {
   135  	var buffer bytes.Buffer
   136  	for k, r := range c.Db {
   137  		buffer.WriteString(fmt.Sprintf("[db.%s]\n", k))
   138  		buffer.WriteString(fmt.Sprintf("\t"+`url = "%s"`+"\n", r.Url))
   139  	}
   140  	return buffer.String()
   141  }