config.go 4.31 KB
Newer Older
1 2 3
package commands

import (
4
	"bytes"
5 6 7
	"errors"
	"fmt"
	"io"
8
	"io/ioutil"
9 10 11 12
	"os"
	"os/exec"

	cmds "github.com/jbenet/go-ipfs/commands"
13
	repo "github.com/jbenet/go-ipfs/repo"
14
	config "github.com/jbenet/go-ipfs/repo/config"
15
	fsrepo "github.com/jbenet/go-ipfs/repo/fsrepo"
16
	u "github.com/jbenet/go-ipfs/util"
17 18 19 20 21 22 23
)

type ConfigField struct {
	Key   string
	Value interface{}
}

24
var ConfigCmd = &cmds.Command{
25 26 27 28 29
	Helptext: cmds.HelpText{
		Tagline: "get and set IPFS config values",
		Synopsis: `
ipfs config <key>          - Get value of <key>
ipfs config <key> <value>  - Set value of <key> to <value>
30 31
ipfs config show           - Show config file
ipfs config edit           - Edit config file in $EDITOR
32 33 34 35 36 37 38 39 40 41 42
`,
		ShortDescription: `
ipfs config controls configuration variables. It works like 'git config'.
The configuration values are stored in a config file inside your IPFS
repository.`,
		LongDescription: `
ipfs config controls configuration variables. It works
much like 'git config'. The configuration values are stored in a config
file inside your IPFS repository.

EXAMPLES:
43

44
Get the value of the 'datastore.path' key:
45

46
  ipfs config datastore.path
47

48
Set the value of the 'datastore.path' key:
49

50
  ipfs config datastore.path ~/.go-ipfs/datastore
51
`,
52
	},
53 54

	Arguments: []cmds.Argument{
55 56
		cmds.StringArg("key", true, false, "The key of the config entry (e.g. \"Addresses.API\")"),
		cmds.StringArg("value", false, false, "The value to set the config entry to"),
57
	},
58
	Run: func(req cmds.Request) (interface{}, error) {
59
		args := req.Arguments()
60
		key := args[0]
61

62 63
		r := fsrepo.At(req.Context().ConfigRoot)
		if err := r.Open(); err != nil {
64
			return nil, err
65
		}
66
		defer r.Close()
67 68 69

		var value string
		if len(args) == 2 {
70
			value = args[1]
71
			return setConfig(r, key, value)
72 73

		} else {
74
			return getConfig(r, key)
75 76
		}
	},
77
	Marshalers: cmds.MarshalerMap{
78
		cmds.Text: func(res cmds.Response) (io.Reader, error) {
79
			if len(res.Request().Arguments()) == 2 {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
80
				return nil, nil // dont output anything
81 82
			}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
83 84 85 86 87 88 89 90 91 92 93
			v := res.Output()
			if v == nil {
				k := res.Request().Arguments()[0]
				return nil, fmt.Errorf("config does not contain key: %s", k)
			}
			vf, ok := v.(*ConfigField)
			if !ok {
				return nil, u.ErrCast()
			}

			buf, err := config.HumanOutput(vf.Value)
94 95 96
			if err != nil {
				return nil, err
			}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
97
			buf = append(buf, byte('\n'))
98
			return bytes.NewReader(buf), nil
99 100
		},
	},
101
	Type: ConfigField{},
102 103 104 105 106 107 108
	Subcommands: map[string]*cmds.Command{
		"show": configShowCmd,
		"edit": configEditCmd,
	},
}

var configShowCmd = &cmds.Command{
109 110 111 112
	Helptext: cmds.HelpText{
		Tagline: "Outputs the content of the config file",
		ShortDescription: `
WARNING: Your private key is stored in the config file, and it will be
113 114
included in the output of this command.
`,
115
	},
116

117
	Run: func(req cmds.Request) (interface{}, error) {
118 119
		filename, err := config.Filename(req.Context().ConfigRoot)
		if err != nil {
120
			return nil, err
121 122
		}

123
		return showConfig(filename)
124 125 126 127
	},
}

var configEditCmd = &cmds.Command{
128 129 130 131
	Helptext: cmds.HelpText{
		Tagline: "Opens the config file for editing in $EDITOR",
		ShortDescription: `
To use 'ipfs config edit', you must have the $EDITOR environment
132 133
variable set to your preferred text editor.
`,
134
	},
135

136
	Run: func(req cmds.Request) (interface{}, error) {
137 138
		filename, err := config.Filename(req.Context().ConfigRoot)
		if err != nil {
139
			return nil, err
140 141
		}

142
		return nil, editConfig(filename)
143 144 145
	},
}

146 147
func getConfig(r repo.Interface, key string) (*ConfigField, error) {
	value, err := r.GetConfigKey(key)
148 149 150 151 152 153 154 155 156
	if err != nil {
		return nil, fmt.Errorf("Failed to get config value: %s", err)
	}
	return &ConfigField{
		Key:   key,
		Value: value,
	}, nil
}

157 158
func setConfig(r repo.Interface, key, value string) (*ConfigField, error) {
	err := r.SetConfigKey(key, value)
159 160 161
	if err != nil {
		return nil, fmt.Errorf("Failed to set config value: %s", err)
	}
162
	return getConfig(r, key)
163 164 165
}

func showConfig(filename string) (io.Reader, error) {
Brian Tiger Chow's avatar
todo  
Brian Tiger Chow committed
166
	// TODO maybe we should omit privkey so we don't accidentally leak it?
167

168
	data, err := ioutil.ReadFile(filename)
169 170 171 172
	if err != nil {
		return nil, err
	}

173
	return bytes.NewReader(data), nil
174 175 176 177 178 179 180 181 182 183 184 185
}

func editConfig(filename string) error {
	editor := os.Getenv("EDITOR")
	if editor == "" {
		return errors.New("ENV variable $EDITOR not set")
	}

	cmd := exec.Command("sh", "-c", editor+" "+filename)
	cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
	return cmd.Run()
}