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 }