github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/core/commands/config.go (about) 1 package commands 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "io" 9 "io/ioutil" 10 "os" 11 "os/exec" 12 13 cmds "github.com/ipfs/go-ipfs/commands" 14 repo "github.com/ipfs/go-ipfs/repo" 15 config "github.com/ipfs/go-ipfs/repo/config" 16 fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" 17 u "github.com/ipfs/go-ipfs/util" 18 ) 19 20 type ConfigField struct { 21 Key string 22 Value interface{} 23 } 24 25 var ConfigCmd = &cmds.Command{ 26 Helptext: cmds.HelpText{ 27 Tagline: "get and set IPFS config values", 28 Synopsis: ` 29 ipfs config <key> - Get value of <key> 30 ipfs config <key> <value> - Set value of <key> to <value> 31 ipfs config show - Show config file 32 ipfs config edit - Edit config file in $EDITOR 33 ipfs config replace <file> - Replaces the config file with <file> 34 `, 35 ShortDescription: ` 36 ipfs config controls configuration variables. It works like 'git config'. 37 The configuration values are stored in a config file inside your IPFS 38 repository.`, 39 LongDescription: ` 40 ipfs config controls configuration variables. It works 41 much like 'git config'. The configuration values are stored in a config 42 file inside your IPFS repository. 43 44 EXAMPLES: 45 46 Get the value of the 'datastore.path' key: 47 48 ipfs config datastore.path 49 50 Set the value of the 'datastore.path' key: 51 52 ipfs config datastore.path ~/.ipfs/datastore 53 `, 54 }, 55 56 Arguments: []cmds.Argument{ 57 cmds.StringArg("key", true, false, "The key of the config entry (e.g. \"Addresses.API\")"), 58 cmds.StringArg("value", false, false, "The value to set the config entry to"), 59 }, 60 Options: []cmds.Option{ 61 cmds.BoolOption("bool", "Set a boolean value"), 62 cmds.BoolOption("json", "Parse stringified JSON"), 63 }, 64 Run: func(req cmds.Request, res cmds.Response) { 65 args := req.Arguments() 66 key := args[0] 67 68 r, err := fsrepo.Open(req.InvocContext().ConfigRoot) 69 if err != nil { 70 res.SetError(err, cmds.ErrNormal) 71 return 72 } 73 defer r.Close() 74 75 var output *ConfigField 76 if len(args) == 2 { 77 value := args[1] 78 79 if parseJson, _, _ := req.Option("json").Bool(); parseJson { 80 var jsonVal interface{} 81 if err := json.Unmarshal([]byte(value), &jsonVal); err != nil { 82 err = fmt.Errorf("failed to unmarshal json. %s", err) 83 res.SetError(err, cmds.ErrNormal) 84 return 85 } 86 87 output, err = setConfig(r, key, jsonVal) 88 } else if isbool, _, _ := req.Option("bool").Bool(); isbool { 89 output, err = setConfig(r, key, value == "true") 90 } else { 91 output, err = setConfig(r, key, value) 92 } 93 } else { 94 output, err = getConfig(r, key) 95 } 96 if err != nil { 97 res.SetError(err, cmds.ErrNormal) 98 return 99 } 100 res.SetOutput(output) 101 }, 102 Marshalers: cmds.MarshalerMap{ 103 cmds.Text: func(res cmds.Response) (io.Reader, error) { 104 if len(res.Request().Arguments()) == 2 { 105 return nil, nil // dont output anything 106 } 107 108 v := res.Output() 109 if v == nil { 110 k := res.Request().Arguments()[0] 111 return nil, fmt.Errorf("config does not contain key: %s", k) 112 } 113 vf, ok := v.(*ConfigField) 114 if !ok { 115 return nil, u.ErrCast() 116 } 117 118 buf, err := config.HumanOutput(vf.Value) 119 if err != nil { 120 return nil, err 121 } 122 buf = append(buf, byte('\n')) 123 return bytes.NewReader(buf), nil 124 }, 125 }, 126 Type: ConfigField{}, 127 Subcommands: map[string]*cmds.Command{ 128 "show": configShowCmd, 129 "edit": configEditCmd, 130 "replace": configReplaceCmd, 131 }, 132 } 133 134 var configShowCmd = &cmds.Command{ 135 Helptext: cmds.HelpText{ 136 Tagline: "Outputs the content of the config file", 137 ShortDescription: ` 138 WARNING: Your private key is stored in the config file, and it will be 139 included in the output of this command. 140 `, 141 }, 142 143 Run: func(req cmds.Request, res cmds.Response) { 144 filename, err := config.Filename(req.InvocContext().ConfigRoot) 145 if err != nil { 146 res.SetError(err, cmds.ErrNormal) 147 return 148 } 149 150 output, err := showConfig(filename) 151 if err != nil { 152 res.SetError(err, cmds.ErrNormal) 153 return 154 } 155 res.SetOutput(output) 156 }, 157 } 158 159 var configEditCmd = &cmds.Command{ 160 Helptext: cmds.HelpText{ 161 Tagline: "Opens the config file for editing in $EDITOR", 162 ShortDescription: ` 163 To use 'ipfs config edit', you must have the $EDITOR environment 164 variable set to your preferred text editor. 165 `, 166 }, 167 168 Run: func(req cmds.Request, res cmds.Response) { 169 filename, err := config.Filename(req.InvocContext().ConfigRoot) 170 if err != nil { 171 res.SetError(err, cmds.ErrNormal) 172 return 173 } 174 175 err = editConfig(filename) 176 if err != nil { 177 res.SetError(err, cmds.ErrNormal) 178 } 179 }, 180 } 181 182 var configReplaceCmd = &cmds.Command{ 183 Helptext: cmds.HelpText{ 184 Tagline: "Replaces the config with <file>", 185 ShortDescription: ` 186 Make sure to back up the config file first if neccessary, this operation 187 can't be undone. 188 `, 189 }, 190 191 Arguments: []cmds.Argument{ 192 cmds.FileArg("file", true, false, "The file to use as the new config"), 193 }, 194 Run: func(req cmds.Request, res cmds.Response) { 195 r, err := fsrepo.Open(req.InvocContext().ConfigRoot) 196 if err != nil { 197 res.SetError(err, cmds.ErrNormal) 198 return 199 } 200 defer r.Close() 201 202 file, err := req.Files().NextFile() 203 if err != nil { 204 res.SetError(err, cmds.ErrNormal) 205 return 206 } 207 defer file.Close() 208 209 err = replaceConfig(r, file) 210 if err != nil { 211 res.SetError(err, cmds.ErrNormal) 212 return 213 } 214 }, 215 } 216 217 func getConfig(r repo.Repo, key string) (*ConfigField, error) { 218 value, err := r.GetConfigKey(key) 219 if err != nil { 220 return nil, fmt.Errorf("Failed to get config value: %s", err) 221 } 222 return &ConfigField{ 223 Key: key, 224 Value: value, 225 }, nil 226 } 227 228 func setConfig(r repo.Repo, key string, value interface{}) (*ConfigField, error) { 229 err := r.SetConfigKey(key, value) 230 if err != nil { 231 return nil, fmt.Errorf("Failed to set config value: %s (maybe use --json?)", err) 232 } 233 return getConfig(r, key) 234 } 235 236 func showConfig(filename string) (io.Reader, error) { 237 // TODO maybe we should omit privkey so we don't accidentally leak it? 238 239 data, err := ioutil.ReadFile(filename) 240 if err != nil { 241 return nil, err 242 } 243 244 return bytes.NewReader(data), nil 245 } 246 247 func editConfig(filename string) error { 248 editor := os.Getenv("EDITOR") 249 if editor == "" { 250 return errors.New("ENV variable $EDITOR not set") 251 } 252 253 cmd := exec.Command("sh", "-c", editor+" "+filename) 254 cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr 255 return cmd.Run() 256 } 257 258 func replaceConfig(r repo.Repo, file io.Reader) error { 259 var cfg config.Config 260 if err := json.NewDecoder(file).Decode(&cfg); err != nil { 261 return errors.New("Failed to decode file as config") 262 } 263 264 return r.SetConfig(&cfg) 265 }