github.com/markgemmill/dover@v0.2.1-dev.4/app/config.go (about)

     1  package app
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"github.com/pelletier/go-toml"
     8  	"io/fs"
     9  	"io/ioutil"
    10  	"os"
    11  )
    12  
    13  func findConfigFile(fileName string) (string, error) {
    14  	/*
    15  		We're looking for dover config info in the following locations:
    16  
    17  			.dover         (universal)
    18  			pyproject.toml (python)
    19  			package.json   (javascript)
    20  
    21  	*/
    22  
    23  	root := "./"
    24  	fileSystem := os.DirFS(root)
    25  	entries, err := fs.Glob(fileSystem, fileName)
    26  	check(err)
    27  
    28  	if len(entries) == 1 {
    29  		return entries[0], nil
    30  	}
    31  
    32  	return "", errors.New(fmt.Sprintf("Could not find %s config.", fileName))
    33  }
    34  
    35  type ConfigValues struct {
    36  	files  []string
    37  	format string
    38  }
    39  
    40  type configParser func(string) (ConfigValues, error)
    41  
    42  func getTomlConfigValues(configFile string) (ConfigValues, error) {
    43  	/*
    44  		Read the .dover configuration file
    45  	*/
    46  	cfg, err := toml.LoadFile(configFile)
    47  	check(err)
    48  
    49  	cfgV := ConfigValues{}
    50  
    51  	getVersionedFiles := func(c *toml.Tree, pth string) []string {
    52  		if c.Has(pth) {
    53  			return c.GetArray(pth).([]string)
    54  		}
    55  		return []string{}
    56  	}
    57  
    58  	getVersionFormat := func(c *toml.Tree, pth string) string {
    59  		if c.Has(pth) {
    60  			return c.Get(pth).(string)
    61  		}
    62  		return ""
    63  	}
    64  
    65  	if cfg.Has("dover") {
    66  		// .dover
    67  		cfgV.files = getVersionedFiles(cfg, "dover.versioned_files")
    68  		cfgV.format = getVersionFormat(cfg, "dover.version_format")
    69  		return cfgV, nil
    70  	} else if cfg.Has("tool.dover") {
    71  		// pyproject.toml
    72  		cfgV.files = getVersionedFiles(cfg, "tool.dover.versioned_files")
    73  		cfgV.format = getVersionFormat(cfg, "tool.dover.version_format")
    74  		return cfgV, nil
    75  	}
    76  
    77  	return cfgV, errors.New(fmt.Sprint("No dover config entries in ", configFile))
    78  }
    79  
    80  func readJSONConfig(configFile string) []byte {
    81  	file, err := os.Open(configFile)
    82  	check(err)
    83  	defer file.Close()
    84  
    85  	content, _ := ioutil.ReadAll(file)
    86  	return content
    87  
    88  }
    89  
    90  func parseJSONConfig(content string) (ConfigValues, error) {
    91  	/*
    92  		Read the project.json configuration file
    93  	*/
    94  	type ProjectJSON struct {
    95  		Dover struct {
    96  			VersionFormat  string   `json:"version_format"`
    97  			VersionedFiles []string `json:"versioned_files"`
    98  		} `json:"dover"`
    99  	}
   100  
   101  	cfgV := ConfigValues{}
   102  
   103  	var payload ProjectJSON
   104  	err := json.Unmarshal([]byte(content), &payload)
   105  
   106  	if err != nil {
   107  		return cfgV, errors.New(fmt.Sprintf("Json parsing failed: %s.", err))
   108  	}
   109  
   110  	if len(payload.Dover.VersionedFiles) == 0 {
   111  		return cfgV, errors.New("no `dover` section or `dover.versioned_files` contains no file references.")
   112  	}
   113  
   114  	cfgV.format = payload.Dover.VersionFormat
   115  	cfgV.files = payload.Dover.VersionedFiles
   116  
   117  	return cfgV, nil
   118  }
   119  
   120  func getJSONConfigValues(configFile string) (ConfigValues, error) {
   121  	content := readJSONConfig(configFile)
   122  	cfgV, err := parseJSONConfig(string(content))
   123  	if err != nil {
   124  		return cfgV, err
   125  	}
   126  
   127  	return cfgV, nil
   128  }
   129  
   130  const DOVER_CONFIG_FILE = ".dover"
   131  const PYPROJECT_CONFIG_FILE = "pyproject.toml"
   132  const PACKAGE_JSON_CONFIG_FILE = "package.json"
   133  
   134  const DOVER_DEFAULT_CONFIG = `[dover]
   135  version_format = "000-A.0"
   136  versioned_files = [
   137  ]
   138  `
   139  
   140  func configValues() (ConfigValues, error) {
   141  
   142  	configOrder := []string{DOVER_CONFIG_FILE, PYPROJECT_CONFIG_FILE, PACKAGE_JSON_CONFIG_FILE}
   143  
   144  	possibleConfigFiles := map[string]configParser{
   145  		DOVER_CONFIG_FILE:        getTomlConfigValues,
   146  		PYPROJECT_CONFIG_FILE:    getTomlConfigValues,
   147  		PACKAGE_JSON_CONFIG_FILE: getJSONConfigValues,
   148  	}
   149  
   150  	var cfg ConfigValues
   151  
   152  	for _, fileName := range configOrder {
   153  
   154  		configParser := possibleConfigFiles[fileName]
   155  		cfgFile, err := findConfigFile(fileName)
   156  
   157  		if err != nil {
   158  			continue
   159  		}
   160  
   161  		cfg, err := configParser(cfgFile)
   162  		if err != nil {
   163  			fmt.Printf("%s: %s", fileName, err)
   164  			continue
   165  		}
   166  
   167  		if len(cfg.files) == 0 {
   168  			return cfg, errors.New(fmt.Sprintf("`%s` config has no versioned_files.", fileName))
   169  		}
   170  
   171  		for _, filePath := range cfg.files {
   172  			filePath, _ := splitFileAndLineNotation(filePath)
   173  			if !fileExists(filePath) {
   174  				return cfg, errors.New(fmt.Sprintf("No such file: %s", filePath))
   175  			}
   176  		}
   177  
   178  		if cfg.format == "" {
   179  			cfg.format = "000.A.0"
   180  		}
   181  
   182  		return cfg, nil
   183  	}
   184  
   185  	return cfg, errors.New("Unable to find dover configuration.")
   186  
   187  }