github.com/getgauge/gauge@v1.6.9/config/properties.go (about)

     1  /*----------------------------------------------------------------
     2   *  Copyright (c) ThoughtWorks, Inc.
     3   *  Licensed under the Apache License, Version 2.0
     4   *  See LICENSE in the project root for license information.
     5   *----------------------------------------------------------------*/
     6  
     7  package config
     8  
     9  import (
    10  	"bufio"
    11  	"fmt"
    12  	"io"
    13  	"os"
    14  	"path/filepath"
    15  	"sort"
    16  	"strings"
    17  
    18  	"github.com/getgauge/common"
    19  	"github.com/getgauge/gauge/version"
    20  	logging "github.com/op/go-logging"
    21  )
    22  
    23  var Log = logging.MustGetLogger("gauge")
    24  
    25  const comment = `This file contains Gauge specific internal configurations. Do not delete`
    26  
    27  type Property struct {
    28  	Key          string `json:"key"`
    29  	Value        string `json:"value"`
    30  	Description  string
    31  	defaultValue string
    32  }
    33  
    34  type properties struct {
    35  	p map[string]*Property
    36  }
    37  
    38  func (p *properties) set(k, v string) error {
    39  	if _, ok := p.p[k]; ok {
    40  		p.p[k].Value = v
    41  		return nil
    42  	}
    43  	return fmt.Errorf("config '%s' doesn't exist", k)
    44  }
    45  
    46  func (p *properties) get(k string) (string, error) {
    47  	if _, ok := p.p[k]; ok {
    48  		return p.p[k].Value, nil
    49  	}
    50  	return "", fmt.Errorf("config '%s' doesn't exist", k)
    51  }
    52  
    53  func (p *properties) Format(f Formatter) (string, error) {
    54  	var all []Property
    55  	for _, v := range p.p {
    56  		all = append(all, *v)
    57  	}
    58  	return f.Format(all)
    59  }
    60  
    61  func (p *properties) String() (string, error) {
    62  	var buffer strings.Builder
    63  	_, err := buffer.WriteString(fmt.Sprintf("# Version %s\n# %s\n", version.FullVersion(), comment))
    64  	if err != nil {
    65  		return "", err
    66  	}
    67  	var keys []string
    68  	for k := range p.p {
    69  		keys = append(keys, k)
    70  	}
    71  	sort.Strings(keys)
    72  	for _, k := range keys {
    73  		v := p.p[k]
    74  		_, err := buffer.WriteString(fmt.Sprintf("\n# %s\n%s = %s\n", v.Description, v.Key, v.Value))
    75  		if err != nil {
    76  			return "", err
    77  		}
    78  	}
    79  	return buffer.String(), nil
    80  }
    81  
    82  func (p *properties) Write(w io.Writer) (int, error) {
    83  	s, err := p.String()
    84  	if err != nil {
    85  		return 0, err
    86  	}
    87  	return w.Write([]byte(s))
    88  }
    89  
    90  func defaults() *properties {
    91  	return &properties{p: map[string]*Property{
    92  		allowInsecureDownload:   NewProperty(allowInsecureDownload, "false", "Allow Gauge to download template from insecure URLs."),
    93  		gaugeRepositoryURL:      NewProperty(gaugeRepositoryURL, "https://downloads.gauge.org/plugin", "Url to get plugin versions"),
    94  		runnerConnectionTimeout: NewProperty(runnerConnectionTimeout, "30000", "Timeout in milliseconds for making a connection to the language runner."),
    95  		pluginConnectionTimeout: NewProperty(pluginConnectionTimeout, "10000", "Timeout in milliseconds for making a connection to plugins."),
    96  		pluginKillTimeOut:       NewProperty(pluginKillTimeOut, "4000", "Timeout in milliseconds for a plugin to stop after a kill message has been sent."),
    97  		runnerRequestTimeout:    NewProperty(runnerRequestTimeout, "30000", "Timeout in milliseconds for requests from the language runner."),
    98  		ideRequestTimeout:       NewProperty(ideRequestTimeout, "30000", "Timeout in milliseconds for requests from runner when invoked for ide."),
    99  		checkUpdates:            NewProperty(checkUpdates, "true", "Allow Gauge and its plugin updates to be notified."),
   100  	}}
   101  }
   102  
   103  func mergedProperties() (*properties, error) {
   104  	p := defaults()
   105  	config, err := common.GetGaugeConfigurationFor(common.GaugePropertiesFile)
   106  	if err != nil {
   107  		// if unable to get from gauge.properties, just return defaults.
   108  		return p, nil
   109  	}
   110  	for k, v := range config {
   111  		if _, ok := p.p[k]; ok {
   112  			err := p.set(k, v)
   113  			if err != nil {
   114  				return nil, err
   115  			}
   116  		}
   117  	}
   118  	return p, nil
   119  }
   120  
   121  func Update(name, value string) error {
   122  	p, err := mergedProperties()
   123  	if err != nil {
   124  		return err
   125  	}
   126  	err = p.set(name, value)
   127  	if err != nil {
   128  		return err
   129  	}
   130  	s, err := p.String()
   131  	if err != nil {
   132  		return err
   133  	}
   134  	return Write(s, common.GaugePropertiesFile)
   135  }
   136  
   137  func Merge() error {
   138  	v, err := GaugeVersionInPropertiesFile(common.GaugePropertiesFile)
   139  	if err != nil || version.CompareVersions(v, version.CurrentGaugeVersion, version.LesserThanFunc) {
   140  		mp, err := mergedProperties()
   141  		if err != nil {
   142  			return err
   143  		}
   144  		s, err := mp.String()
   145  		if err != nil {
   146  			return err
   147  		}
   148  		return Write(s, common.GaugePropertiesFile)
   149  	}
   150  	return nil
   151  }
   152  
   153  func GetProperty(name string) (string, error) {
   154  	mp, err := mergedProperties()
   155  	if err != nil {
   156  		return "", err
   157  	}
   158  	return mp.get(name)
   159  }
   160  
   161  func List(machineReadable bool) (string, error) {
   162  	var f Formatter
   163  	f = TextFormatter{Headers: []string{"Key", "Value"}}
   164  	if machineReadable {
   165  		f = &JsonFormatter{}
   166  	}
   167  	mp, err := mergedProperties()
   168  	if err != nil {
   169  		return "", err
   170  	}
   171  	return mp.Format(f)
   172  }
   173  
   174  func NewProperty(key, defaultValue, description string) *Property {
   175  	return &Property{
   176  		Key:          key,
   177  		defaultValue: defaultValue,
   178  		Description:  description,
   179  		Value:        defaultValue,
   180  	}
   181  }
   182  
   183  func Write(text, file string) error {
   184  	file, err := FilePath(file)
   185  	if err != nil {
   186  		return err
   187  	}
   188  	var f *os.File
   189  	if _, err = os.Stat(file); err != nil {
   190  		f, err = os.Create(file)
   191  		if err != nil {
   192  			return err
   193  		}
   194  	} else {
   195  		f, err = os.OpenFile(file, os.O_WRONLY, os.ModeExclusive)
   196  		if err != nil {
   197  			return err
   198  		}
   199  	}
   200  	defer f.Close()
   201  	_, err = f.Write([]byte(text))
   202  	return err
   203  }
   204  
   205  func FilePath(name string) (string, error) {
   206  	dir, err := common.GetConfigurationDir()
   207  	if err != nil {
   208  		return "", err
   209  	}
   210  	return filepath.Join(dir, name), err
   211  }
   212  
   213  func GaugeVersionInPropertiesFile(name string) (*version.Version, error) {
   214  	var v *version.Version
   215  	pf, err := FilePath(name)
   216  	if err != nil {
   217  		return v, err
   218  	}
   219  	f, err := os.Open(pf)
   220  	if err != nil {
   221  		return v, err
   222  	}
   223  	defer f.Close()
   224  	r := bufio.NewReader(f)
   225  	l, _, err := r.ReadLine()
   226  	if err != nil {
   227  		return v, err
   228  	}
   229  	return version.ParseVersion(strings.TrimPrefix(string(l), "# Version "))
   230  }
   231  
   232  var GetPropertyFromConfig = func(propertyName string) string {
   233  	config, err := common.GetGaugeConfiguration()
   234  	if err != nil {
   235  		APILog.Warningf("Failed to get configuration from Gauge properties file. Error: %s", err.Error())
   236  		return ""
   237  	}
   238  	return config[propertyName]
   239  }