github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/util/config/config.go (about)

     1  // Package config contains helper methods for
     2  // client side config management (`~/.micro/config.json` file).
     3  // It uses the `JSONValues` helper
     4  package config
     5  
     6  import (
     7  	"fmt"
     8  	"io/ioutil"
     9  	"os"
    10  	"path/filepath"
    11  	"strings"
    12  	"sync"
    13  
    14  	conf "github.com/tickoalcantara12/micro/v3/service/config"
    15  	"github.com/tickoalcantara12/micro/v3/util/user"
    16  	"github.com/nightlyone/lockfile"
    17  )
    18  
    19  var (
    20  
    21  	// lock in single process
    22  	mtx sync.Mutex
    23  
    24  	// File is the filepath to the config file that
    25  	// contains all user configuration
    26  	File = filepath.Join(user.Dir, "config.json")
    27  
    28  	// a global lock for the config
    29  	lock, _ = lockfile.New(File)
    30  )
    31  
    32  // SetConfig sets the config file
    33  func SetConfig(configFilePath string) {
    34  	mtx.Lock()
    35  	defer mtx.Unlock()
    36  
    37  	File = configFilePath
    38  	// new lock for the file
    39  	lock, _ = lockfile.New(File)
    40  }
    41  
    42  // config is a singleton which is required to ensure
    43  // each function call doesn't load the .micro file
    44  // from disk
    45  
    46  // Get a value from the .micro file
    47  func Get(path string) (string, error) {
    48  	mtx.Lock()
    49  	defer mtx.Unlock()
    50  
    51  	config, err := newConfig()
    52  	if err != nil {
    53  		return "", err
    54  	}
    55  
    56  	val := config.Get(path)
    57  	v := strings.TrimSpace(val.String(""))
    58  	if len(v) > 0 {
    59  		return v, nil
    60  	}
    61  
    62  	// try as bytes
    63  	v = string(val.Bytes())
    64  	v = strings.TrimSpace(v)
    65  
    66  	// don't return nil decoded value
    67  	if strings.TrimSpace(v) == "null" {
    68  		return "", nil
    69  	}
    70  
    71  	return v, nil
    72  }
    73  
    74  // Set a value in the .micro file
    75  func Set(path, value string) error {
    76  	mtx.Lock()
    77  	defer mtx.Unlock()
    78  
    79  	config, err := newConfig()
    80  	if err != nil {
    81  		return err
    82  	}
    83  	// acquire lock
    84  	if err := lock.TryLock(); err != nil {
    85  		return err
    86  	}
    87  	defer lock.Unlock()
    88  
    89  	// set the value
    90  	config.Set(path, value)
    91  
    92  	// write to the file
    93  	return ioutil.WriteFile(File, config.Bytes(), 0644)
    94  }
    95  
    96  func moveConfig(from, to string) error {
    97  	// read the config
    98  	b, err := ioutil.ReadFile(from)
    99  	if err != nil {
   100  		return fmt.Errorf("Failed to read config file %s: %v", from, err)
   101  	}
   102  	// remove the file
   103  	os.Remove(from)
   104  
   105  	// create new directory
   106  	dir := filepath.Dir(to)
   107  	if err := os.MkdirAll(dir, 0755); err != nil {
   108  		return fmt.Errorf("Failed to create dir %s: %v", dir, err)
   109  	}
   110  	// write the file to new location
   111  	return ioutil.WriteFile(to, b, 0644)
   112  }
   113  
   114  // newConfig returns a loaded config
   115  func newConfig() (*conf.JSONValues, error) {
   116  	// check if the directory exists, otherwise create it
   117  	dir := filepath.Dir(File)
   118  
   119  	// for legacy purposes check if .micro is a file or directory
   120  	if f, err := os.Stat(dir); err != nil {
   121  		// check the error to see if the directory exists
   122  		if os.IsNotExist(err) {
   123  			if err := os.MkdirAll(dir, 0755); err != nil {
   124  				return nil, fmt.Errorf("Failed to create dir %s: %v", dir, err)
   125  			}
   126  		} else {
   127  			return nil, fmt.Errorf("Failed to create config dir %s: %v", dir, err)
   128  		}
   129  	} else {
   130  		// if not a directory, copy and move the config
   131  		if !f.IsDir() {
   132  			if err := moveConfig(dir, File); err != nil {
   133  				return nil, fmt.Errorf("Failed to move config from %s to %s: %v", dir, File, err)
   134  			}
   135  		}
   136  	}
   137  
   138  	// now write the file if it does not exist
   139  	if _, err := os.Stat(File); os.IsNotExist(err) {
   140  		ioutil.WriteFile(File, []byte(`{"env":"local"}`), 0644)
   141  	} else if err != nil {
   142  		return nil, fmt.Errorf("Failed to write config file %s: %v", File, err)
   143  	}
   144  
   145  	contents, err := ioutil.ReadFile(File)
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  
   150  	c := conf.NewJSONValues(contents)
   151  
   152  	// return the conf
   153  	return c, nil
   154  }
   155  
   156  func Path(paths ...string) string {
   157  	return strings.Join(paths, ".")
   158  }