github.com/d0sbit/gocode@v0.0.0-20211001144653-a968ce917518/config/config.go (about)

     1  // Package config has gocode config file reading and writing.
     2  package config
     3  
     4  import (
     5  	"bytes"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"io/fs"
    10  	"io/ioutil"
    11  	"os"
    12  
    13  	"github.com/BurntSushi/toml"
    14  )
    15  
    16  // Config houses configuration settings and corresponds to a TOML file.
    17  type Config struct {
    18  	Settings map[string]interface{}
    19  }
    20  
    21  // GetString returns an entry as a string or def if not found.
    22  func (c *Config) GetString(key string, def string) string {
    23  	v, ok := c.Settings[key]
    24  	if !ok {
    25  		return def
    26  	}
    27  	return fmt.Sprint(v)
    28  }
    29  
    30  // ReadFrom implements the ReaderFrom interface and reads and parses a TOML file.
    31  func (c *Config) ReadFrom(r io.Reader) (n int64, err error) {
    32  
    33  	b, err := ioutil.ReadAll(r)
    34  	n = int64(len(b))
    35  	if err != nil {
    36  		return n, err
    37  	}
    38  
    39  	if c.Settings == nil {
    40  		c.Settings = make(map[string]interface{})
    41  	}
    42  	err = toml.Unmarshal(b, &c.Settings)
    43  	return n, err
    44  
    45  }
    46  
    47  // WriteTo implements the WriterTo interafce and writes out a TOML file.
    48  func (c *Config) WriteTo(w io.Writer) (n int64, err error) {
    49  
    50  	var buf bytes.Buffer
    51  	enc := toml.NewEncoder(&buf)
    52  	err = enc.Encode(&c.Settings)
    53  	if err != nil {
    54  		return 0, err
    55  	}
    56  
    57  	wn, err := w.Write(buf.Bytes())
    58  	return int64(wn), err
    59  }
    60  
    61  // LoadFS will look for the config file in .gocode/gocode.toml and load it.
    62  // If emptyIfNotFound is true then the case of the file not being present
    63  // returns empty config instead of an error, or if it is false then
    64  // the underlying filesystem's not found error will be returned.
    65  func LoadFS(moduleFS fs.FS, emptyIfNotFound bool) (*Config, error) {
    66  	f, err := moduleFS.Open(".gocode/gocode.toml")
    67  	if err != nil {
    68  		if errors.Is(err, os.ErrNotExist) && emptyIfNotFound {
    69  			return &Config{Settings: make(map[string]interface{})}, nil
    70  		}
    71  		return nil, err
    72  	}
    73  	defer f.Close()
    74  	var c Config
    75  	_, err = c.ReadFrom(f)
    76  	return &c, err
    77  }
    78  
    79  // StoreFS writes a Config to the .gocode/gocode.toml.
    80  // The filesystem must provide an appropriate WriteFile
    81  // and MkdirAll methods.
    82  // (see FileWriter and MkdirAller interfaces).
    83  func StoreFS(moduleFS fs.FS, c *Config) error {
    84  	fw, ok := moduleFS.(wfs)
    85  	if !ok {
    86  		return errors.New("moduleFS must implement FileWriter and MkdirAller")
    87  	}
    88  
    89  	err := fw.MkdirAll(".gocode", 0755)
    90  	if err != nil {
    91  		return err
    92  	}
    93  
    94  	var buf bytes.Buffer
    95  	_, err = c.WriteTo(&buf)
    96  	if err != nil {
    97  		return err
    98  	}
    99  
   100  	return fw.WriteFile(".gocode/gocode.toml", buf.Bytes(), 0644)
   101  }
   102  
   103  // FileWriter is an FS that has a WriteFile method on it.
   104  type FileWriter interface {
   105  	// memfs and other implementations should provide such a method to support writes
   106  	WriteFile(name string, data []byte, perm fs.FileMode) error
   107  }
   108  
   109  // MkdirAller has a MkdirAll call matching the os.MkdirAll signature.
   110  type MkdirAller interface {
   111  	MkdirAll(path string, perm os.FileMode) error
   112  }
   113  
   114  type wfs interface {
   115  	FileWriter
   116  	MkdirAller
   117  }