github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/utils/config/file_config.go (about) 1 // Copyright 2019 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package config 16 17 import ( 18 "encoding/json" 19 "errors" 20 "os" 21 "path/filepath" 22 23 "github.com/dolthub/dolt/go/libraries/utils/filesys" 24 ) 25 26 // FileConfig is backed by a file in the filesystem. 27 type FileConfig struct { 28 // The path of the config file in the filesystem 29 Path string 30 31 fs filesys.ReadWriteFS 32 properties map[string]string 33 } 34 35 var _ ReadableConfig = &FileConfig{} 36 var _ WritableConfig = &FileConfig{} 37 var _ ReadWriteConfig = &FileConfig{} 38 39 // NewFileConfig creates a new empty config and writes it to a newly created file. If a file already exists at this 40 // location it will be overwritten. If a directory does not exist where this file should live, it will be created. 41 func NewFileConfig(path string, fs filesys.ReadWriteFS, properties map[string]string) (*FileConfig, error) { 42 dir := filepath.Dir(path) 43 err := fs.MkDirs(dir) 44 45 if err != nil { 46 return nil, err 47 } 48 49 fc := &FileConfig{path, fs, properties} 50 err = fc.write() 51 52 if err != nil { 53 return nil, err 54 } 55 56 return fc, err 57 } 58 59 // FromFile reads configuration from a file on the given filesystem. Calls to SetStrings will result in this file 60 // being updated. 61 func FromFile(path string, fs filesys.ReadWriteFS) (*FileConfig, error) { 62 data, err := fs.ReadFile(path) 63 64 if err != nil { 65 return nil, err 66 } 67 68 properties := make(map[string]string) 69 err = json.Unmarshal(data, &properties) 70 71 if err != nil { 72 return nil, err 73 } 74 75 return &FileConfig{path, fs, properties}, nil 76 } 77 78 // GetString retrieves a string from the cached config state 79 func (fc *FileConfig) GetString(k string) (string, error) { 80 if val, ok := fc.properties[k]; ok { 81 return val, nil 82 } 83 84 return "", ErrConfigParamNotFound 85 } 86 87 // GetString retrieves a string from the cached config state 88 func (fc *FileConfig) GetStringOrDefault(k, defStr string) string { 89 if val, ok := fc.properties[k]; ok { 90 return val 91 } 92 93 return defStr 94 } 95 96 // SetStrings will set the value of configuration parameters in memory, and persist any changes to the backing file. 97 func (fc *FileConfig) SetStrings(updates map[string]string) error { 98 modified := false 99 for k, v := range updates { 100 if val, ok := fc.properties[k]; !ok || val != v { 101 fc.properties[k] = v 102 modified = true 103 } 104 } 105 106 if modified == false { 107 return nil 108 } 109 110 return fc.write() 111 } 112 113 // Iter will perform a callback for ech value in a config until all values have been exhausted or until the 114 // callback returns true indicating that it should stop. 115 func (fc *FileConfig) Iter(cb func(string, string) (stop bool)) { 116 for k, v := range fc.properties { 117 stop := cb(k, v) 118 119 if stop { 120 break 121 } 122 } 123 } 124 125 func (fc *FileConfig) write() error { 126 data, err := json.Marshal(fc.properties) 127 128 if err != nil { 129 return err 130 } 131 132 return fc.fs.WriteFile(fc.Path, data, os.ModePerm) 133 } 134 135 // Unset removes a configuration parameter from the config 136 func (fc *FileConfig) Unset(params []string) error { 137 for _, param := range params { 138 if _, ok := fc.properties[param]; !ok { 139 return errors.New("key does not exist on this configuration") 140 } 141 delete(fc.properties, param) 142 143 } 144 145 return fc.write() 146 } 147 148 // Size returns the number of properties contained within the config 149 func (fc *FileConfig) Size() int { 150 return len(fc.properties) 151 }