<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"os"
)

type Config struct {
	UpdateMicros     uint
	TapDelayMicros   uint
	KeepPushedMicros uint

	ThumbCircle bool

	ThumbLX      *AxisConfig
	ThumbLY      *AxisConfig
	ThumbRX      *AxisConfig
	ThumbRY      *AxisConfig
	LeftTrigger  *TriggerConfig
	RightTrigger *TriggerConfig
	Buttons      []*ButtonConfig
}

func NewConfig() *Config {
	var btn buttonConfigBuilder
	c := &Config{
		ThumbCircle:      true,
		ThumbLX:          NewAxisConfig(),
		ThumbLY:          NewAxisConfig(),
		ThumbRX:          NewAxisConfig(),
		ThumbRY:          NewAxisConfig(),
		LeftTrigger:      NewTriggerConfig(),
		RightTrigger:     NewTriggerConfig(),
		UpdateMicros:     1000,   // 1ms
		TapDelayMicros:   300000, // 0.3s
		KeepPushedMicros: 500000, // 0.05s
		Buttons: []*ButtonConfig{
			btn.NewDouble(1, 6, 13),
			btn.NewDouble(2, 7, 14),
			btn.NewSimple(3, 15),
			btn.NewSimple(4, 16),
			btn.NewSimple(5, 9, 13),
		},
	}
	c.update()
	return c
}

func (c *Config) Load(fn string) error {
	f, err := os.Open(fn)
	if err != nil {
		return err
	}
	defer f.Close()
	err = json.NewDecoder(f).Decode(c)
	c.update()
	return err
}

func (c *Config) Save(fn string) error {
	data, err := json.Marshal(c)
	if err != nil {
		return err
	}
	var buf bytes.Buffer
	if err = json.Indent(&buf, data, "", "  "); err != nil {
		return err
	}
	buf.WriteByte('\n')
	f, err := os.Create(fn)
	if err != nil {
		return err
	}
	defer f.Close()
	_, err = f.Write(buf.Bytes())
	return err
}

func (c *Config) update() {
	if c.UpdateMicros == 0 {
		c.UpdateMicros = 1000
	}

	c.LeftTrigger.update()
	c.RightTrigger.update()

	for _, b := range c.Buttons {
		b.update(c)
	}

	for i, bi := range c.Buttons {
		bi.fmask = bi.imask
		for j, bj := range c.Buttons {
			if i == j {
				continue
			}
			if (bi.imask & bj.imask) != 0 {
				bi.fmask |= bj.imask
			}
		}
	}
}

func (c *Config) tapDelayTicks() uint {
	n := c.TapDelayMicros / c.UpdateMicros
	if n == 0 {
		n = 1
	}
	return n
}

func (c *Config) keepPushedTicks() uint {
	n := c.KeepPushedMicros / c.UpdateMicros
	if n == 0 {
		n = 1
	}
	return n
}

type AxisConfig struct {
	Min float64 // 0 will be reported under this value (0..1)
	Max float64 // 1 will be reported above this value (0..1)
	Pow float64 // smoothen small movements in input: raise to this power (1..∞)
}

func NewAxisConfig() *AxisConfig {
	return &AxisConfig{Min: 0.1, Max: 0.95, Pow: 2.0}
}

type TriggerConfig struct {
	TouchTreshold float64
	PullTreshold  float64
	Axis          bool
	touch         uint16
	pull          uint16
}

func NewTriggerConfig() *TriggerConfig {
	t := &TriggerConfig{
		TouchTreshold: 0.15,
		PullTreshold:  0.9,
		Axis:          false,
	}
	t.update()
	return t
}

func (t *TriggerConfig) update() {
	if t.TouchTreshold <= 1.0 {
		t.touch = uint16(t.TouchTreshold * 255)
	} else {
		t.touch = 1000
	}
	if t.PullTreshold <= 1.0 {
		t.pull = uint16(t.PullTreshold * 255)
	} else {
		t.pull = 1000
	}
	if t.pull < t.touch {
		t.touch = t.pull
	}
}

type ButtonConfig struct {
	Output  int    // output
	Double  int    // output for doubleclick
	Inputs  []int  // these sources must be pressed together to trigger
	imask   uint32 // input mask created from Inputs
	fmask   uint32 // filtering mask when button is used in multiple configs
	handler ButtonHandler
}

type buttonConfigBuilder struct {
	output int
}

func (b *buttonConfigBuilder) NewSimple(output int, inputs ...int) *ButtonConfig {
	b.output++
	return &ButtonConfig{Output: b.output, Inputs: inputs}
}

func (b *buttonConfigBuilder) NewDouble(output, double, input int) *ButtonConfig {
	b.output++
	return &ButtonConfig{Output: b.output, Double: double, Inputs: []int{input}}
}

func (b *ButtonConfig) update(c *Config) {
	var m uint32
	for _, v := range b.Inputs {
		m |= 1 << uint(v-1)
	}
	b.imask = m
	if b.Double != 0 {
		b.handler = &MultiButton{
			taptick: c.tapDelayTicks(),
			needtap: 2,
			pushlen: c.keepPushedTicks(),
		}
	} else {
		b.handler = &SimpleButton{}
	}
}
<commit_msg>fix 0 trigger tresholds in config<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"os"
)

type Config struct {
	UpdateMicros     uint
	TapDelayMicros   uint
	KeepPushedMicros uint

	ThumbCircle bool

	ThumbLX      *AxisConfig
	ThumbLY      *AxisConfig
	ThumbRX      *AxisConfig
	ThumbRY      *AxisConfig
	LeftTrigger  *TriggerConfig
	RightTrigger *TriggerConfig
	Buttons      []*ButtonConfig
}

func NewConfig() *Config {
	var btn buttonConfigBuilder
	c := &Config{
		ThumbCircle:      true,
		ThumbLX:          NewAxisConfig(),
		ThumbLY:          NewAxisConfig(),
		ThumbRX:          NewAxisConfig(),
		ThumbRY:          NewAxisConfig(),
		LeftTrigger:      NewTriggerConfig(),
		RightTrigger:     NewTriggerConfig(),
		UpdateMicros:     1000,   // 1ms
		TapDelayMicros:   300000, // 0.3s
		KeepPushedMicros: 500000, // 0.05s
		Buttons: []*ButtonConfig{
			btn.NewDouble(1, 6, 13),
			btn.NewDouble(2, 7, 14),
			btn.NewSimple(3, 15),
			btn.NewSimple(4, 16),
			btn.NewSimple(5, 9, 13),
		},
	}
	c.update()
	return c
}

func (c *Config) Load(fn string) error {
	f, err := os.Open(fn)
	if err != nil {
		return err
	}
	defer f.Close()
	err = json.NewDecoder(f).Decode(c)
	c.update()
	return err
}

func (c *Config) Save(fn string) error {
	data, err := json.Marshal(c)
	if err != nil {
		return err
	}
	var buf bytes.Buffer
	if err = json.Indent(&buf, data, "", "  "); err != nil {
		return err
	}
	buf.WriteByte('\n')
	f, err := os.Create(fn)
	if err != nil {
		return err
	}
	defer f.Close()
	_, err = f.Write(buf.Bytes())
	return err
}

func (c *Config) update() {
	if c.UpdateMicros == 0 {
		c.UpdateMicros = 1000
	}

	c.LeftTrigger.update()
	c.RightTrigger.update()

	for _, b := range c.Buttons {
		b.update(c)
	}

	for i, bi := range c.Buttons {
		bi.fmask = bi.imask
		for j, bj := range c.Buttons {
			if i == j {
				continue
			}
			if (bi.imask & bj.imask) != 0 {
				bi.fmask |= bj.imask
			}
		}
	}
}

func (c *Config) tapDelayTicks() uint {
	n := c.TapDelayMicros / c.UpdateMicros
	if n == 0 {
		n = 1
	}
	return n
}

func (c *Config) keepPushedTicks() uint {
	n := c.KeepPushedMicros / c.UpdateMicros
	if n == 0 {
		n = 1
	}
	return n
}

type AxisConfig struct {
	Min float64 // 0 will be reported under this value (0..1)
	Max float64 // 1 will be reported above this value (0..1)
	Pow float64 // smoothen small movements in input: raise to this power (1..∞)
}

func NewAxisConfig() *AxisConfig {
	return &AxisConfig{Min: 0.1, Max: 0.95, Pow: 2.0}
}

type TriggerConfig struct {
	TouchTreshold float64
	PullTreshold  float64
	Axis          bool
	touch         uint16
	pull          uint16
}

func NewTriggerConfig() *TriggerConfig {
	t := &TriggerConfig{
		TouchTreshold: 0.15,
		PullTreshold:  0.9,
		Axis:          false,
	}
	t.update()
	return t
}

func (t *TriggerConfig) update() {
	if t.TouchTreshold <= 1.0 {
		t.touch = uint16(t.TouchTreshold * 255)
	} else {
		t.touch = 1000
	}
	if t.PullTreshold <= 1.0 {
		t.pull = uint16(t.PullTreshold * 255)
	} else {
		t.pull = 1000
	}
	if t.pull == 0 {
		t.pull = 1
	}
	if t.touch == 0 {
		t.touch = 1
	}
	if t.pull < t.touch {
		t.touch = t.pull
	}
}

type ButtonConfig struct {
	Output  int    // output
	Double  int    // output for doubleclick
	Inputs  []int  // these sources must be pressed together to trigger
	imask   uint32 // input mask created from Inputs
	fmask   uint32 // filtering mask when button is used in multiple configs
	handler ButtonHandler
}

type buttonConfigBuilder struct {
	output int
}

func (b *buttonConfigBuilder) NewSimple(output int, inputs ...int) *ButtonConfig {
	b.output++
	return &ButtonConfig{Output: b.output, Inputs: inputs}
}

func (b *buttonConfigBuilder) NewDouble(output, double, input int) *ButtonConfig {
	b.output++
	return &ButtonConfig{Output: b.output, Double: double, Inputs: []int{input}}
}

func (b *ButtonConfig) update(c *Config) {
	var m uint32
	for _, v := range b.Inputs {
		m |= 1 << uint(v-1)
	}
	b.imask = m
	if b.Double != 0 {
		b.handler = &MultiButton{
			taptick: c.tapDelayTicks(),
			needtap: 2,
			pushlen: c.keepPushedTicks(),
		}
	} else {
		b.handler = &SimpleButton{}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/ecdsa"
	"crypto/ed25519"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"errors"
	"io/ioutil"
	"log"
	"os"
	"path"
	"strings"

	"github.com/adrg/xdg"
	"github.com/sirupsen/logrus"
	"golang.org/x/crypto/ssh"
	"gopkg.in/yaml.v2"
)

type config struct {
	ListenAddress                 string
	RekeyThreshold                uint64
	KeyExchanges                  []string
	Ciphers                       []string
	MACs                          []string
	HostKeys                      []string
	NoClientAuth                  bool
	MaxAuthTries                  int
	PasswordAuth                  bool
	PublicKeyAuth                 bool
	KeyboardInteractiveAuth       bool
	KeyboardInteractiveAuthConfig struct {
		Instruction string
		Questions   []struct {
			Text string
			Echo bool
		}
	}
	ServerVersion string
	Banner        string
}

func (cfg config) createSSHServerConfig() *ssh.ServerConfig {
	sshServerConfig := &ssh.ServerConfig{
		Config: ssh.Config{
			RekeyThreshold: cfg.RekeyThreshold,
			KeyExchanges:   cfg.KeyExchanges,
			Ciphers:        cfg.Ciphers,
			MACs:           cfg.MACs,
		},
		NoClientAuth: cfg.NoClientAuth,
		MaxAuthTries: cfg.MaxAuthTries,
		AuthLogCallback: func(conn ssh.ConnMetadata, method string, err error) {
			getLogEntry(conn).WithFields(logrus.Fields{
				"method":  method,
				"success": err == nil,
			}).Infoln("Client authenticated")
		},
		ServerVersion:  cfg.ServerVersion,
		BannerCallback: func(conn ssh.ConnMetadata) string { return strings.ReplaceAll(cfg.Banner, "\n", "\r\n") },
	}
	if cfg.PasswordAuth {
		sshServerConfig.PasswordCallback = func(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
			getLogEntry(conn).WithField("password", string(password)).Infoln("Password authentication accepted")
			return nil, nil
		}
	}
	if cfg.PublicKeyAuth {
		sshServerConfig.PublicKeyCallback = func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
			getLogEntry(conn).WithField("public_key_fingerprint", ssh.FingerprintSHA256(key)).Infoln("Public key authentication accepted")
			return nil, nil
		}
	}
	if cfg.KeyboardInteractiveAuth {
		sshServerConfig.KeyboardInteractiveCallback = func(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error) {
			var questions []string
			var echos []bool
			for _, question := range cfg.KeyboardInteractiveAuthConfig.Questions {
				questions = append(questions, question.Text)
				echos = append(echos, question.Echo)
			}
			answers, err := client(conn.User(), cfg.KeyboardInteractiveAuthConfig.Instruction, questions, echos)
			if err != nil {
				log.Println("Failed to process keyboard interactive authentication:", err)
			}
			getLogEntry(conn).WithField("answers", answers).Infoln("Keyboard interactive authentication accepted")
			return nil, nil
		}
	}
	for _, hostKeyFileName := range cfg.HostKeys {
		hostKeyBytes, err := ioutil.ReadFile(hostKeyFileName)
		if err != nil {
			log.Fatalln("Failed to read host key", hostKeyFileName, ":", err)
		}
		signer, err := ssh.ParsePrivateKey(hostKeyBytes)
		if err != nil {
			log.Fatalln("Failed to parse host key", hostKeyFileName, ":", err)
		}
		sshServerConfig.AddHostKey(signer)
	}
	return sshServerConfig
}

type hostKeyType int

const (
	rsa_key hostKeyType = iota
	ecdsa_key
	ed25519_key
)

func generateKey(fileName string, keyType hostKeyType) error {
	if _, err := os.Stat(fileName); err != nil {
		if !os.IsNotExist(err) {
			return err
		}
		log.Println("Host key", fileName, "not found, generating it")
		if _, err := os.Stat(path.Dir(fileName)); os.IsNotExist(err) {
			if err := os.MkdirAll(path.Dir(fileName), 0755); err != nil {
				return err
			}
		}
		var key interface{}
		if keyType == rsa_key {
			key, err = rsa.GenerateKey(rand.Reader, 3072)
		} else if keyType == ecdsa_key {
			key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
		} else if keyType == ed25519_key {
			_, key, err = ed25519.GenerateKey(rand.Reader)
		} else {
			return errors.New("unsupported key type")
		}
		if err != nil {
			return err
		}
		keyBytes, err := x509.MarshalPKCS8PrivateKey(key)
		if err != nil {
			return err
		}
		if err := ioutil.WriteFile(fileName, pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: keyBytes}), 0600); err != nil {
			return err
		}
	}
	return nil
}

func getConfig(fileName string) (*config, error) {
	result := &config{
		ListenAddress: "127.0.0.1:2022",
	}

	var configBytes []byte
	var err error
	if fileName == "" {
		configBytes, err = ioutil.ReadFile(path.Join(xdg.ConfigHome, "sshesame.yaml"))
		if err != nil && !os.IsNotExist(err) {
			return nil, err
		}
	} else {
		configBytes, err = ioutil.ReadFile(fileName)
		if err != nil {
			return nil, err
		}
	}
	if configBytes != nil {
		if err := yaml.UnmarshalStrict(configBytes, result); err != nil {
			return nil, err
		}
	}

	if len(result.HostKeys) == 0 {
		dataDir := path.Join(xdg.DataHome, "sshesame")
		log.Println("No host keys configured, using keys at", dataDir)

		for _, key := range []struct {
			keyType  hostKeyType
			filename string
		}{
			{keyType: rsa_key, filename: "host_rsa_key"},
			{keyType: ecdsa_key, filename: "host_ecdsa_key"},
			{keyType: ed25519_key, filename: "host_ed25519_key"},
		} {
			keyFileName := path.Join(dataDir, key.filename)
			if err := generateKey(keyFileName, key.keyType); err != nil {
				return nil, err
			}
			result.HostKeys = []string{keyFileName}
		}
	}

	return result, nil
}
<commit_msg>Minor host key generation refactor<commit_after>package main

import (
	"crypto/ecdsa"
	"crypto/ed25519"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"errors"
	"io/ioutil"
	"log"
	"os"
	"path"
	"strings"

	"github.com/adrg/xdg"
	"github.com/sirupsen/logrus"
	"golang.org/x/crypto/ssh"
	"gopkg.in/yaml.v2"
)

type config struct {
	ListenAddress                 string
	RekeyThreshold                uint64
	KeyExchanges                  []string
	Ciphers                       []string
	MACs                          []string
	HostKeys                      []string
	NoClientAuth                  bool
	MaxAuthTries                  int
	PasswordAuth                  bool
	PublicKeyAuth                 bool
	KeyboardInteractiveAuth       bool
	KeyboardInteractiveAuthConfig struct {
		Instruction string
		Questions   []struct {
			Text string
			Echo bool
		}
	}
	ServerVersion string
	Banner        string
}

func (cfg config) createSSHServerConfig() *ssh.ServerConfig {
	sshServerConfig := &ssh.ServerConfig{
		Config: ssh.Config{
			RekeyThreshold: cfg.RekeyThreshold,
			KeyExchanges:   cfg.KeyExchanges,
			Ciphers:        cfg.Ciphers,
			MACs:           cfg.MACs,
		},
		NoClientAuth: cfg.NoClientAuth,
		MaxAuthTries: cfg.MaxAuthTries,
		AuthLogCallback: func(conn ssh.ConnMetadata, method string, err error) {
			getLogEntry(conn).WithFields(logrus.Fields{
				"method":  method,
				"success": err == nil,
			}).Infoln("Client authenticated")
		},
		ServerVersion:  cfg.ServerVersion,
		BannerCallback: func(conn ssh.ConnMetadata) string { return strings.ReplaceAll(cfg.Banner, "\n", "\r\n") },
	}
	if cfg.PasswordAuth {
		sshServerConfig.PasswordCallback = func(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
			getLogEntry(conn).WithField("password", string(password)).Infoln("Password authentication accepted")
			return nil, nil
		}
	}
	if cfg.PublicKeyAuth {
		sshServerConfig.PublicKeyCallback = func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
			getLogEntry(conn).WithField("public_key_fingerprint", ssh.FingerprintSHA256(key)).Infoln("Public key authentication accepted")
			return nil, nil
		}
	}
	if cfg.KeyboardInteractiveAuth {
		sshServerConfig.KeyboardInteractiveCallback = func(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error) {
			var questions []string
			var echos []bool
			for _, question := range cfg.KeyboardInteractiveAuthConfig.Questions {
				questions = append(questions, question.Text)
				echos = append(echos, question.Echo)
			}
			answers, err := client(conn.User(), cfg.KeyboardInteractiveAuthConfig.Instruction, questions, echos)
			if err != nil {
				log.Println("Failed to process keyboard interactive authentication:", err)
			}
			getLogEntry(conn).WithField("answers", answers).Infoln("Keyboard interactive authentication accepted")
			return nil, nil
		}
	}
	for _, hostKeyFileName := range cfg.HostKeys {
		hostKeyBytes, err := ioutil.ReadFile(hostKeyFileName)
		if err != nil {
			log.Fatalln("Failed to read host key", hostKeyFileName, ":", err)
		}
		signer, err := ssh.ParsePrivateKey(hostKeyBytes)
		if err != nil {
			log.Fatalln("Failed to parse host key", hostKeyFileName, ":", err)
		}
		sshServerConfig.AddHostKey(signer)
	}
	return sshServerConfig
}

type hostKeyType int

const (
	rsa_key hostKeyType = iota
	ecdsa_key
	ed25519_key
)

func generateKey(fileName string, keyType hostKeyType) error {
	if _, err := os.Stat(fileName); err != nil {
		if !os.IsNotExist(err) {
			return err
		}
		log.Println("Host key", fileName, "not found, generating it")
		if _, err := os.Stat(path.Dir(fileName)); os.IsNotExist(err) {
			if err := os.MkdirAll(path.Dir(fileName), 0755); err != nil {
				return err
			}
		}
		var key interface{}
		switch keyType {
		case rsa_key:
			key, err = rsa.GenerateKey(rand.Reader, 3072)
		case ecdsa_key:
			key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
		case ed25519_key:
			_, key, err = ed25519.GenerateKey(rand.Reader)
		default:
			err = errors.New("unsupported key type")
		}
		if err != nil {
			return err
		}
		keyBytes, err := x509.MarshalPKCS8PrivateKey(key)
		if err != nil {
			return err
		}
		if err := ioutil.WriteFile(fileName, pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: keyBytes}), 0600); err != nil {
			return err
		}
	}
	return nil
}

func getConfig(fileName string) (*config, error) {
	result := &config{
		ListenAddress: "127.0.0.1:2022",
	}

	var configBytes []byte
	var err error
	if fileName == "" {
		configBytes, err = ioutil.ReadFile(path.Join(xdg.ConfigHome, "sshesame.yaml"))
		if err != nil && !os.IsNotExist(err) {
			return nil, err
		}
	} else {
		configBytes, err = ioutil.ReadFile(fileName)
		if err != nil {
			return nil, err
		}
	}
	if configBytes != nil {
		if err := yaml.UnmarshalStrict(configBytes, result); err != nil {
			return nil, err
		}
	}

	if len(result.HostKeys) == 0 {
		dataDir := path.Join(xdg.DataHome, "sshesame")
		log.Println("No host keys configured, using keys at", dataDir)

		for _, key := range []struct {
			keyType  hostKeyType
			filename string
		}{
			{keyType: rsa_key, filename: "host_rsa_key"},
			{keyType: ecdsa_key, filename: "host_ecdsa_key"},
			{keyType: ed25519_key, filename: "host_ed25519_key"},
		} {
			keyFileName := path.Join(dataDir, key.filename)
			if err := generateKey(keyFileName, key.keyType); err != nil {
				return nil, err
			}
			result.HostKeys = []string{keyFileName}
		}
	}

	return result, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"os"
	"regexp"
	"strings"

	"github.com/skratchdot/open-golang/open"
)

const configURL = "http://slackcat.chat/configure"

//Slack team and channel read from file
type Config struct {
	teams          map[string]string
	defaultTeam    string
	defaultChannel string
}

func (c *Config) parseChannelOpt(channel string) (string, string, error) {
	//use default channel if none provided
	if channel == "" {
		if c.defaultChannel == "" {
			return "", "", fmt.Errorf("no channel provided")
		}
		return c.defaultTeam, c.defaultChannel, nil
	}
	//if channel is prefixed with a team
	if strings.Contains(channel, ":") {
		s := strings.Split(channel, ":")
		return s[0], s[1], nil
	}
	//use default team with provided channel
	return c.defaultTeam, channel, nil
}

func readConfig() *Config {
	config := &Config{
		teams:          make(map[string]string),
		defaultTeam:    "",
		defaultChannel: "",
	}
	lines := readLines(getConfigPath())

	//simple config file
	if len(lines) == 1 {
		config.teams["default"] = lines[0]
		config.defaultTeam = "default"
		return config
	}

	//advanced config file
	for _, line := range lines {
		s := strings.Split(line, "=")
		if len(s) != 2 {
			exitErr(fmt.Errorf("failed to parse config at: %s", line))
		}
		key, val := strip(s[0]), strip(s[1])
		switch key {
		case "default_team":
			config.defaultTeam = val
		case "default_channel":
			config.defaultChannel = val
		default:
			config.teams[key] = val
		}
	}
	return config
}

func getConfigPath() string {
	userHome := os.Getenv("HOME")
	if userHome == "" {
		exitErr(fmt.Errorf("$HOME not set"))
	}

	if xdgSupport() {
		xdgHome := os.Getenv("XDG_CONFIG_HOME")
		if xdgHome == "" {
			xdgHome = fmt.Sprintf("%s/.config", userHome)
		}
		return fmt.Sprintf("%s/slackcat/config", xdgHome)
	}

	return fmt.Sprintf("%s/.slackcat", userHome)
}

func xdgSupport() bool {
	re := regexp.MustCompile("^XDG_*")
	for _, e := range os.Environ() {
		if re.FindAllString(e, 1) != nil {
			return true
		}
	}
	return false
}

func strip(s string) string { return strings.Replace(s, " ", "", -1) }

func readLines(path string) []string {
	var lines []string

	file, err := os.Open(path)
	failOnError(err, "unable to read config", true)
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		if scanner.Text() != "" {
			lines = append(lines, scanner.Text())
		}
	}
	return lines
}

func configureOA() {
	output("Creating token request for Slackcat")
	open.Run(configURL)
	output("Use the below URL to authorize slackcat if browser fails to launch")
	output(configURL)
}
<commit_msg>replace Getenv with LookupEnv<commit_after>package main

import (
	"bufio"
	"fmt"
	"os"
	"regexp"
	"strings"

	"github.com/skratchdot/open-golang/open"
)

const configURL = "http://slackcat.chat/configure"

//Slack team and channel read from file
type Config struct {
	teams          map[string]string
	defaultTeam    string
	defaultChannel string
}

func (c *Config) parseChannelOpt(channel string) (string, string, error) {
	//use default channel if none provided
	if channel == "" {
		if c.defaultChannel == "" {
			return "", "", fmt.Errorf("no channel provided")
		}
		return c.defaultTeam, c.defaultChannel, nil
	}
	//if channel is prefixed with a team
	if strings.Contains(channel, ":") {
		s := strings.Split(channel, ":")
		return s[0], s[1], nil
	}
	//use default team with provided channel
	return c.defaultTeam, channel, nil
}

func readConfig() *Config {
	config := &Config{
		teams:          make(map[string]string),
		defaultTeam:    "",
		defaultChannel: "",
	}
	lines := readLines(getConfigPath())

	//simple config file
	if len(lines) == 1 {
		config.teams["default"] = lines[0]
		config.defaultTeam = "default"
		return config
	}

	//advanced config file
	for _, line := range lines {
		s := strings.Split(line, "=")
		if len(s) != 2 {
			exitErr(fmt.Errorf("failed to parse config at: %s", line))
		}
		key, val := strip(s[0]), strip(s[1])
		switch key {
		case "default_team":
			config.defaultTeam = val
		case "default_channel":
			config.defaultChannel = val
		default:
			config.teams[key] = val
		}
	}
	return config
}

func getConfigPath() string {
	userHome, ok := os.LookupEnv("HOME")
	if !ok {
		exitErr(fmt.Errorf("$HOME not set"))
	}

	if xdgSupport() {
		xdgHome, ok := os.LookupEnv("XDG_CONFIG_HOME")
		if !ok {
			xdgHome = fmt.Sprintf("%s/.config", userHome)
		}
		return fmt.Sprintf("%s/slackcat/config", xdgHome)
	}

	return fmt.Sprintf("%s/.slackcat", userHome)
}

func xdgSupport() bool {
	re := regexp.MustCompile("^XDG_*")
	for _, e := range os.Environ() {
		if re.FindAllString(e, 1) != nil {
			return true
		}
	}
	return false
}

func strip(s string) string { return strings.Replace(s, " ", "", -1) }

func readLines(path string) []string {
	var lines []string

	file, err := os.Open(path)
	failOnError(err, "unable to read config", true)
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		if scanner.Text() != "" {
			lines = append(lines, scanner.Text())
		}
	}
	return lines
}

func configureOA() {
	output("Creating token request for Slackcat")
	open.Run(configURL)
	output("Use the below URL to authorize slackcat if browser fails to launch")
	output(configURL)
}
<|endoftext|>


<commit_before>// Copyright 2015 Globo.com. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package config provide configuration facilities, handling configuration
// files in yaml format.
//
// This package has been optimized for reads, so functions write functions (Set
// and Unset) are really slow when compared to Get functions.
package config

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/howeyc/fsnotify"
	"gopkg.in/yaml.v1"
)

var ErrMismatchConf = errors.New("Your conf is wrong:")

type configuration struct {
	data map[interface{}]interface{}
	sync.RWMutex
}

func (c *configuration) Store(data map[interface{}]interface{}) {
	c.Lock()
	defer c.Unlock()
	c.store(data)
}

func (c *configuration) store(data map[interface{}]interface{}) {
	c.data = data
}

func (c *configuration) Data() map[interface{}]interface{} {
	c.RLock()
	defer c.RUnlock()
	return c.data
}

var configs configuration

func readConfigBytes(data []byte, out interface{}) error {
	return yaml.Unmarshal(data, out)
}

// ReadConfigBytes receives a slice of bytes and builds the internal
// configuration object.
//
// If the given slice is not a valid yaml file, ReadConfigBytes returns a
// non-nil error.
func ReadConfigBytes(data []byte) error {
	var newConfig map[interface{}]interface{}
	err := readConfigBytes(data, &newConfig)
	if err == nil {
		configs.Store(newConfig)
	}
	return err
}

// ReadConfigFile reads the content of a file and calls ReadConfigBytes to
// build the internal configuration object.
//
// It returns error if it can not read the given file or if the file contents
// is not valid yaml.
func ReadConfigFile(filePath string) error {
	data, err := ioutil.ReadFile(filePath)
	if err != nil {
		return err
	}
	return ReadConfigBytes(data)
}

// ReadAndWatchConfigFile reads and watchs for changes in the configuration
// file. Whenever the file change, and its contents are valid YAML, the
// configuration gets updated. With this function, daemons that use this
// package may reload configuration without restarting.
func ReadAndWatchConfigFile(filePath string) error {
	err := ReadConfigFile(filePath)
	if err != nil {
		return err
	}
	w, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}
	err = w.Watch(filePath)
	if err != nil {
		return err
	}
	go func() {
		for {
			select {
			case e := <-w.Event:
				if e.IsModify() {
					ReadConfigFile(filePath)
				}
			case <-w.Error: // just ignore errors
			}
		}
	}()
	return nil
}

// Bytes serialize the configuration in YAML format.
func Bytes() ([]byte, error) {
	return yaml.Marshal(configs.Data())
}

// WriteConfigFile writes the configuration to the disc, using the given path.
// The configuration is serialized in YAML format.
//
// This function will create the file if it does not exist, setting permissions
// to "perm".
func WriteConfigFile(filePath string, perm os.FileMode) error {
	b, err := Bytes()
	if err != nil {
		return err
	}
	f, err := os.OpenFile(filePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY|os.O_EXCL, perm)
	if err != nil {
		return err
	}
	defer f.Close()
	n, err := f.Write(b)
	if err != nil {
		return err
	}
	if n != len(b) {
		return io.ErrShortWrite
	}
	return nil
}

// Get returns the value for the given key, or an error if the key is undefined.
//
// The key is composed of all the key names separated by :, in case of nested
// keys. For example, suppose we have the following configuration yaml:
//
//   databases:
//     mysql:
//       host: localhost
//       port: 3306
//
// The key "databases:mysql:host" would return "localhost", while the key
// "port" would return an error.
//
// Get will expand the value with environment values, ex.:
//
//   mongo: $MONGOURI
//
// If there is an environment variable MONGOURI=localhost/test, the key "mongo"
// would return "localhost/test". If the variable value is a json object/list, this
// object will also be expanded.
func Get(key string) (interface{}, error) {
	keys := strings.Split(key, ":")
	configs.RLock()
	defer configs.RUnlock()
	conf, ok := configs.data[keys[0]]
	if !ok {
		return nil, fmt.Errorf("key %q not found", key)
	}
	for _, k := range keys[1:] {
		switch c := conf.(type) {
		case map[interface{}]interface{}:
			if conf, ok = c[k]; !ok {
				return nil, fmt.Errorf("key %q not found", key)
			}
		case string:
			value, err := expandEnv(c)
			if err != nil {
				return nil, ErrMismatchConf
			}
			if conf, ok = value.(map[interface{}]interface{})[k]; !ok {
				return nil, fmt.Errorf("key %q not found", key)
			}
		default:
			return nil, ErrMismatchConf
		}
	}
	if v, ok := conf.(func() interface{}); ok {
		conf = v()
	}
	if v, ok := conf.(string); ok {
		value, _ := expandEnv(v)
		return value, nil
	}
	return conf, nil
}

// expandEnv expands an environment variable and unmarshalls
// an json object or slice if it's found.
func expandEnv(s string) (interface{}, error) {
	raw := os.ExpandEnv(s)
	var jsonMap map[string]interface{}
	err := json.Unmarshal([]byte(raw), &jsonMap)
	if err != nil {
		var jsonSlice []interface{}
		errS := json.Unmarshal([]byte(raw), &jsonSlice)
		if errS != nil {
			return raw, err
		}
		return jsonSlice, nil
	}
	return toInfMap(jsonMap), nil
}

// toInfMap takes an map[string]interface{} and recursively converts it
// to an map[interface{}]interface{}.
func toInfMap(sMap map[string]interface{}) map[interface{}]interface{} {
	newMap := make(map[interface{}]interface{})
	for k, v := range sMap {
		var newValue interface{}
		switch v := v.(type) {
		case map[string]interface{}:
			newValue = toInfMap(v)
		default:
			newValue = v
		}
		newMap[k] = newValue
	}
	return newMap
}

// GetString works like Get, but does an string type assertion before returning
// the value.
//
// It returns error if the key is undefined or if it is not a string.
func GetString(key string) (string, error) {
	value, err := Get(key)
	if err != nil {
		return "", err
	}
	switch v := value.(type) {
	case int:
		return strconv.Itoa(v), nil
	case int64:
		return strconv.FormatInt(v, 10), nil
	default:
		if v, ok := value.(string); ok {
			return v, nil
		}
	}
	return "", &invalidValue{key, "string|int|int64"}
}

// GetInt works like Get, but does an int type assertion and attempts string
// conversion before returning the value.
//
// It returns error if the key is undefined or if it is not a int.
func GetInt(key string) (int, error) {
	value, err := Get(key)
	if err != nil {
		return 0, err
	}
	if v, ok := value.(int); ok {
		return v, nil
	} else if v, ok := value.(string); ok {
		if i, err := strconv.ParseInt(v, 10, 64); err == nil {
			return int(i), nil
		}
	}
	return 0, &invalidValue{key, "int"}
}

// GetFloat works like Get, but does a float type assertion and attempts string
// conversion before returning the value.
//
// It returns error if the key is undefined or if it is not a float.
func GetFloat(key string) (float64, error) {
	value, err := Get(key)
	if err != nil {
		return 0, err
	}
	switch v := value.(type) {
	case float64:
		return v, nil
	case float32:
		return float64(v), nil
	case int:
		return float64(v), nil
	case string:
		if floatVal, err := strconv.ParseFloat(v, 64); err == nil {
			return floatVal, nil
		}
	}
	return 0, &invalidValue{key, "float"}
}

// GetUint parses and returns an unsigned integer from the config file.
func GetUint(key string) (uint, error) {
	value, err := Get(key)
	if err != nil {
		return 0, err
	}
	if v, ok := value.(int); ok {
		if v < 0 {
			return 0, &invalidValue{key, "uint"}
		}
		return uint(v), nil
	}
	return 0, &invalidValue{key, "uint"}
}

// GetDuration parses and returns a duration from the config file. It may be an
// integer or a number specifying the amount of nanoseconds.
//
// Here are some examples of valid durations:
//
//  - 1h30m0s
//  - 1e9 (one second)
//  - 100e6 (one hundred milliseconds)
//  - 1 (one nanosecond)
//  - 1000000000 (one billion nanoseconds, or one second)
func GetDuration(key string) (time.Duration, error) {
	value, err := Get(key)
	if err != nil {
		return 0, err
	}
	switch v := value.(type) {
	case int:
		return time.Duration(v), nil
	case float64:
		return time.Duration(v), nil
	case string:
		if value, err := time.ParseDuration(value.(string)); err == nil {
			return value, nil
		}
	}
	return 0, &invalidValue{key, "duration"}
}

// GetBool does a type assertion before returning the requested value
func GetBool(key string) (bool, error) {
	value, err := Get(key)
	if err != nil {
		return false, err
	}
	if v, ok := value.(bool); ok {
		return v, nil
	}
	return false, &invalidValue{key, "boolean"}
}

// GetList works like Get, but returns a slice of strings instead. It must be
// written down in the config as YAML lists.
//
// Here are two example of YAML lists:
//
//   names:
//     - Mary
//     - John
//     - Paul
//     - Petter
//
// If GetList find an item that is not a string (for example 5.08734792), it
// will convert the item.
func GetList(key string) ([]string, error) {
	value, err := Get(key)
	if err != nil {
		return nil, err
	}
	switch value.(type) {
	case []interface{}:
		v := value.([]interface{})
		result := make([]string, len(v))
		for i, item := range v {
			switch v := item.(type) {
			case int:
				result[i] = strconv.Itoa(v)
			case bool:
				result[i] = strconv.FormatBool(v)
			case float64:
				result[i] = strconv.FormatFloat(v, 'f', -1, 64)
			case string:
				result[i] = v
			default:
				result[i] = fmt.Sprintf("%v", item)
			}
		}
		return result, nil
	case []string:
		return value.([]string), nil
	}
	return nil, &invalidValue{key, "list"}
}

// mergeMaps takes two maps and merge its keys and values recursively.
//
// In case of conflicts, the function picks value from map2.
func mergeMaps(map1, map2 map[interface{}]interface{}) map[interface{}]interface{} {
	result := make(map[interface{}]interface{})
	for k, v2 := range map2 {
		if v1, ok := map1[k]; !ok {
			result[k] = v2
		} else {
			map1, ok1 := v1.(map[interface{}]interface{})
			map2, ok2 := v2.(map[interface{}]interface{})
			if ok1 && ok2 {
				result[k] = mergeMaps(map1, map2)
			} else {
				result[k] = v2
			}
		}
	}
	for k, v := range map1 {
		if v2, ok := map2[k]; !ok {
			result[k] = v
		} else {
			map1, ok1 := v.(map[interface{}]interface{})
			map2, ok2 := v2.(map[interface{}]interface{})
			if ok1 && ok2 {
				result[k] = mergeMaps(map1, map2)
			}
		}
	}
	return result
}

// Set redefines or defines a value for a key. The key has the same format that
// it has in Get and GetString.
//
// Values defined by this function affects only runtime informatin, nothing
// defined by Set is persisted in the filesystem or any database.
func Set(key string, value interface{}) {
	parts := strings.Split(key, ":")
	last := map[interface{}]interface{}{
		parts[len(parts)-1]: value,
	}
	for i := len(parts) - 2; i >= 0; i-- {
		last = map[interface{}]interface{}{
			parts[i]: last,
		}
	}
	configs.Lock()
	defer configs.Unlock()
	configs.store(mergeMaps(configs.data, last))
}

// Unset removes a key from the configuration map. It returns an error if the
// key is not defined.
//
// Calling this function does not remove a key from a configuration file, only
// from the in-memory configuration object.
func Unset(key string) error {
	var i int
	var part string
	configs.Lock()
	defer configs.Unlock()
	data := configs.data
	m := make(map[interface{}]interface{}, len(data))
	for k, v := range data {
		m[k] = v
	}
	root := m
	parts := strings.Split(key, ":")
	for i, part = range parts {
		if item, ok := m[part]; ok {
			if nm, ok := item.(map[interface{}]interface{}); ok && i < len(parts)-1 {
				m = nm
			} else {
				break
			}
		} else {
			return fmt.Errorf("key %q not found", key)
		}
	}
	delete(m, part)
	configs.store(root)
	return nil
}

type invalidValue struct {
	key  string
	kind string
}

func (e *invalidValue) Error() string {
	return fmt.Sprintf("value for the key %q is not a %s", e.key, e.kind)
}
<commit_msg>config: converts float to int/uint on GetInt and GetUint<commit_after>// Copyright 2015 Globo.com. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package config provide configuration facilities, handling configuration
// files in yaml format.
//
// This package has been optimized for reads, so functions write functions (Set
// and Unset) are really slow when compared to Get functions.
package config

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/howeyc/fsnotify"
	"gopkg.in/yaml.v1"
)

var ErrMismatchConf = errors.New("Your conf is wrong:")

type configuration struct {
	data map[interface{}]interface{}
	sync.RWMutex
}

func (c *configuration) Store(data map[interface{}]interface{}) {
	c.Lock()
	defer c.Unlock()
	c.store(data)
}

func (c *configuration) store(data map[interface{}]interface{}) {
	c.data = data
}

func (c *configuration) Data() map[interface{}]interface{} {
	c.RLock()
	defer c.RUnlock()
	return c.data
}

var configs configuration

func readConfigBytes(data []byte, out interface{}) error {
	return yaml.Unmarshal(data, out)
}

// ReadConfigBytes receives a slice of bytes and builds the internal
// configuration object.
//
// If the given slice is not a valid yaml file, ReadConfigBytes returns a
// non-nil error.
func ReadConfigBytes(data []byte) error {
	var newConfig map[interface{}]interface{}
	err := readConfigBytes(data, &newConfig)
	if err == nil {
		configs.Store(newConfig)
	}
	return err
}

// ReadConfigFile reads the content of a file and calls ReadConfigBytes to
// build the internal configuration object.
//
// It returns error if it can not read the given file or if the file contents
// is not valid yaml.
func ReadConfigFile(filePath string) error {
	data, err := ioutil.ReadFile(filePath)
	if err != nil {
		return err
	}
	return ReadConfigBytes(data)
}

// ReadAndWatchConfigFile reads and watchs for changes in the configuration
// file. Whenever the file change, and its contents are valid YAML, the
// configuration gets updated. With this function, daemons that use this
// package may reload configuration without restarting.
func ReadAndWatchConfigFile(filePath string) error {
	err := ReadConfigFile(filePath)
	if err != nil {
		return err
	}
	w, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}
	err = w.Watch(filePath)
	if err != nil {
		return err
	}
	go func() {
		for {
			select {
			case e := <-w.Event:
				if e.IsModify() {
					ReadConfigFile(filePath)
				}
			case <-w.Error: // just ignore errors
			}
		}
	}()
	return nil
}

// Bytes serialize the configuration in YAML format.
func Bytes() ([]byte, error) {
	return yaml.Marshal(configs.Data())
}

// WriteConfigFile writes the configuration to the disc, using the given path.
// The configuration is serialized in YAML format.
//
// This function will create the file if it does not exist, setting permissions
// to "perm".
func WriteConfigFile(filePath string, perm os.FileMode) error {
	b, err := Bytes()
	if err != nil {
		return err
	}
	f, err := os.OpenFile(filePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY|os.O_EXCL, perm)
	if err != nil {
		return err
	}
	defer f.Close()
	n, err := f.Write(b)
	if err != nil {
		return err
	}
	if n != len(b) {
		return io.ErrShortWrite
	}
	return nil
}

// Get returns the value for the given key, or an error if the key is undefined.
//
// The key is composed of all the key names separated by :, in case of nested
// keys. For example, suppose we have the following configuration yaml:
//
//   databases:
//     mysql:
//       host: localhost
//       port: 3306
//
// The key "databases:mysql:host" would return "localhost", while the key
// "port" would return an error.
//
// Get will expand the value with environment values, ex.:
//
//   mongo: $MONGOURI
//
// If there is an environment variable MONGOURI=localhost/test, the key "mongo"
// would return "localhost/test". If the variable value is a json object/list, this
// object will also be expanded.
func Get(key string) (interface{}, error) {
	keys := strings.Split(key, ":")
	configs.RLock()
	defer configs.RUnlock()
	conf, ok := configs.data[keys[0]]
	if !ok {
		return nil, fmt.Errorf("key %q not found", key)
	}
	for _, k := range keys[1:] {
		switch c := conf.(type) {
		case map[interface{}]interface{}:
			if conf, ok = c[k]; !ok {
				return nil, fmt.Errorf("key %q not found", key)
			}
		case string:
			value, err := expandEnv(c)
			if err != nil {
				return nil, ErrMismatchConf
			}
			if conf, ok = value.(map[interface{}]interface{})[k]; !ok {
				return nil, fmt.Errorf("key %q not found", key)
			}
		default:
			return nil, ErrMismatchConf
		}
	}
	if v, ok := conf.(func() interface{}); ok {
		conf = v()
	}
	if v, ok := conf.(string); ok {
		value, _ := expandEnv(v)
		return value, nil
	}
	return conf, nil
}

// expandEnv expands an environment variable and unmarshalls
// an json object or slice if it's found.
func expandEnv(s string) (interface{}, error) {
	raw := os.ExpandEnv(s)
	var jsonMap map[string]interface{}
	err := json.Unmarshal([]byte(raw), &jsonMap)
	if err != nil {
		var jsonSlice []interface{}
		errS := json.Unmarshal([]byte(raw), &jsonSlice)
		if errS != nil {
			return raw, err
		}
		return jsonSlice, nil
	}
	return toInfMap(jsonMap), nil
}

// toInfMap takes an map[string]interface{} and recursively converts it
// to an map[interface{}]interface{}.
func toInfMap(sMap map[string]interface{}) map[interface{}]interface{} {
	newMap := make(map[interface{}]interface{})
	for k, v := range sMap {
		var newValue interface{}
		switch v := v.(type) {
		case map[string]interface{}:
			newValue = toInfMap(v)
		default:
			newValue = v
		}
		newMap[k] = newValue
	}
	return newMap
}

// GetString works like Get, but does an string type assertion before returning
// the value.
//
// It returns error if the key is undefined or if it is not a string.
func GetString(key string) (string, error) {
	value, err := Get(key)
	if err != nil {
		return "", err
	}
	switch v := value.(type) {
	case int:
		return strconv.Itoa(v), nil
	case int64:
		return strconv.FormatInt(v, 10), nil
	default:
		if v, ok := value.(string); ok {
			return v, nil
		}
	}
	return "", &invalidValue{key, "string|int|int64"}
}

// GetInt works like Get, but does an int type assertion and attempts string
// conversion before returning the value.
//
// It returns error if the key is undefined or if it is not a int.
func GetInt(key string) (int, error) {
	value, err := Get(key)
	if err != nil {
		return 0, err
	}
	if v, ok := value.(int); ok {
		return v, nil
	} else if v, ok := value.(string); ok {
		if i, err := strconv.ParseInt(v, 10, 64); err == nil {
			return int(i), nil
		}
	} else if v, err := GetFloat(key); err == nil {
		if float64(int(v)) == v {
			return int(v), nil
		}
	}
	return 0, &invalidValue{key, "int"}
}

// GetFloat works like Get, but does a float type assertion and attempts string
// conversion before returning the value.
//
// It returns error if the key is undefined or if it is not a float.
func GetFloat(key string) (float64, error) {
	value, err := Get(key)
	if err != nil {
		return 0, err
	}
	switch v := value.(type) {
	case float64:
		return v, nil
	case float32:
		return float64(v), nil
	case int:
		return float64(v), nil
	case string:
		if floatVal, err := strconv.ParseFloat(v, 64); err == nil {
			return floatVal, nil
		}
	}
	return 0, &invalidValue{key, "float"}
}

// GetUint parses and returns an unsigned integer from the config file.
func GetUint(key string) (uint, error) {
	if v, err := GetInt(key); err == nil {
		if v < 0 {
			return 0, &invalidValue{key, "uint"}
		}
		return uint(v), nil
	}
	return 0, &invalidValue{key, "uint"}
}

// GetDuration parses and returns a duration from the config file. It may be an
// integer or a number specifying the amount of nanoseconds.
//
// Here are some examples of valid durations:
//
//  - 1h30m0s
//  - 1e9 (one second)
//  - 100e6 (one hundred milliseconds)
//  - 1 (one nanosecond)
//  - 1000000000 (one billion nanoseconds, or one second)
func GetDuration(key string) (time.Duration, error) {
	value, err := Get(key)
	if err != nil {
		return 0, err
	}
	switch v := value.(type) {
	case int:
		return time.Duration(v), nil
	case float64:
		return time.Duration(v), nil
	case string:
		if value, err := time.ParseDuration(value.(string)); err == nil {
			return value, nil
		}
	}
	return 0, &invalidValue{key, "duration"}
}

// GetBool does a type assertion before returning the requested value
func GetBool(key string) (bool, error) {
	value, err := Get(key)
	if err != nil {
		return false, err
	}
	if v, ok := value.(bool); ok {
		return v, nil
	}
	return false, &invalidValue{key, "boolean"}
}

// GetList works like Get, but returns a slice of strings instead. It must be
// written down in the config as YAML lists.
//
// Here are two example of YAML lists:
//
//   names:
//     - Mary
//     - John
//     - Paul
//     - Petter
//
// If GetList find an item that is not a string (for example 5.08734792), it
// will convert the item.
func GetList(key string) ([]string, error) {
	value, err := Get(key)
	if err != nil {
		return nil, err
	}
	switch value.(type) {
	case []interface{}:
		v := value.([]interface{})
		result := make([]string, len(v))
		for i, item := range v {
			switch v := item.(type) {
			case int:
				result[i] = strconv.Itoa(v)
			case bool:
				result[i] = strconv.FormatBool(v)
			case float64:
				result[i] = strconv.FormatFloat(v, 'f', -1, 64)
			case string:
				result[i] = v
			default:
				result[i] = fmt.Sprintf("%v", item)
			}
		}
		return result, nil
	case []string:
		return value.([]string), nil
	}
	return nil, &invalidValue{key, "list"}
}

// mergeMaps takes two maps and merge its keys and values recursively.
//
// In case of conflicts, the function picks value from map2.
func mergeMaps(map1, map2 map[interface{}]interface{}) map[interface{}]interface{} {
	result := make(map[interface{}]interface{})
	for k, v2 := range map2 {
		if v1, ok := map1[k]; !ok {
			result[k] = v2
		} else {
			map1, ok1 := v1.(map[interface{}]interface{})
			map2, ok2 := v2.(map[interface{}]interface{})
			if ok1 && ok2 {
				result[k] = mergeMaps(map1, map2)
			} else {
				result[k] = v2
			}
		}
	}
	for k, v := range map1 {
		if v2, ok := map2[k]; !ok {
			result[k] = v
		} else {
			map1, ok1 := v.(map[interface{}]interface{})
			map2, ok2 := v2.(map[interface{}]interface{})
			if ok1 && ok2 {
				result[k] = mergeMaps(map1, map2)
			}
		}
	}
	return result
}

// Set redefines or defines a value for a key. The key has the same format that
// it has in Get and GetString.
//
// Values defined by this function affects only runtime informatin, nothing
// defined by Set is persisted in the filesystem or any database.
func Set(key string, value interface{}) {
	parts := strings.Split(key, ":")
	last := map[interface{}]interface{}{
		parts[len(parts)-1]: value,
	}
	for i := len(parts) - 2; i >= 0; i-- {
		last = map[interface{}]interface{}{
			parts[i]: last,
		}
	}
	configs.Lock()
	defer configs.Unlock()
	configs.store(mergeMaps(configs.data, last))
}

// Unset removes a key from the configuration map. It returns an error if the
// key is not defined.
//
// Calling this function does not remove a key from a configuration file, only
// from the in-memory configuration object.
func Unset(key string) error {
	var i int
	var part string
	configs.Lock()
	defer configs.Unlock()
	data := configs.data
	m := make(map[interface{}]interface{}, len(data))
	for k, v := range data {
		m[k] = v
	}
	root := m
	parts := strings.Split(key, ":")
	for i, part = range parts {
		if item, ok := m[part]; ok {
			if nm, ok := item.(map[interface{}]interface{}); ok && i < len(parts)-1 {
				m = nm
			} else {
				break
			}
		} else {
			return fmt.Errorf("key %q not found", key)
		}
	}
	delete(m, part)
	configs.store(root)
	return nil
}

type invalidValue struct {
	key  string
	kind string
}

func (e *invalidValue) Error() string {
	return fmt.Sprintf("value for the key %q is not a %s", e.key, e.kind)
}
<|endoftext|>


<commit_before>package lfs

import (
	"fmt"
	"runtime"
)

type WrappedError struct {
	Err     error
	Message string
	Panic   bool
	stack   []byte
	context map[string]string
}

func Error(err error) *WrappedError {
	return Errorf(err, "")
}

func Errorf(err error, format string, args ...interface{}) *WrappedError {
	if err == nil {
		return nil
	}

	e := &WrappedError{
		Err:     err,
		Message: err.Error(),
		Panic:   true,
		stack:   Stack(),
	}

	if len(format) > 0 {
		e.Errorf(format, args...)
	}

	return e
}

func (e *WrappedError) Set(key, value string) {
	if e.context == nil {
		e.context = make(map[string]string)
	}
	e.context[key] = value
}

func (e *WrappedError) Get(key string) string {
	if e.context == nil {
		return ""
	}
	return e.context[key]
}

func (e *WrappedError) Del(key string) {
	if e.context == nil {
		return
	}
	delete(e.context, key)
}

func (e *WrappedError) Error() string {
	return e.Message
}

func (e *WrappedError) Errorf(format string, args ...interface{}) {
	e.Message = fmt.Sprintf(format, args...)
}

func (e *WrappedError) InnerError() string {
	return e.Err.Error()
}

func (e *WrappedError) Stack() []byte {
	return e.stack
}

func (e *WrappedError) Context() map[string]string {
	if e.context == nil {
		e.context = make(map[string]string)
	}
	return e.context
}

func Stack() []byte {
	stackBuf := make([]byte, 1024*1024)
	written := runtime.Stack(stackBuf, false)
	return stackBuf[:written]
}
<commit_msg>ンンン ンンン ンン<commit_after>package lfs

import (
	"fmt"
	"runtime"
)

type errorWrapper interface {
	InnerError() error
	Error() string
}

type wrappedError struct {
	Message string
	stack   []byte
	context map[string]string
	error
}

func newWrappedError(err error) errorWrapper {
	if e, ok := err.(errorWrapper); ok {
		return e
	}
	return wrappedError{
		Message: err.Error(),
		stack:   Stack(),
		context: make(map[string]string),
		error:   err,
	}
}

func (e wrappedError) InnerError() error {
	return e.error
}

func ErrorSetContext(err error, key, value string) {
	if e, ok := err.(wrappedError); ok {
		e.context[key] = value
	}
}

func ErrorGetContext(err error, key string) string {
	if e, ok := err.(wrappedError); ok {
		return e.context[key]
	}
	return ""
}

func ErrorDelContext(err error, key string) {
	if e, ok := err.(wrappedError); ok {
		delete(e.context, key)
	}
}

// ErrorStack returns the stack for an error if it is a wrappedError. If it is
// not a wrappedError it will return an empty byte slice.
func ErrorStack(err error) []byte {
	if e, ok := err.(wrappedError); ok {
		return e.stack
	}
	return nil
}

// ErrorContext returns the context map for an error if it is a wrappedError.
// If it is not a wrappedError it will return an empty map.
func ErrorContext(err error) map[string]string {
	if e, ok := err.(wrappedError); ok {
		return e.context
	}
	return nil
}

// fatalError indicates that the process should halt
type fatalError struct {
	errorWrapper
}

func (e fatalError) InnerError() error {
	return e.errorWrapper
}

func (e fatalError) Fatal() bool {
	return true
}

func newFatalError(err error) error {
	return fatalError{newWrappedError(err)}
}

func IsFatalError(err error) bool {
	type fatalerror interface {
		Fatal() bool
	}
	if e, ok := err.(fatalerror); ok {
		return e.Fatal()
	}
	if e, ok := err.(errorWrapper); ok {
		return IsFatalError(e.InnerError())
	}
	return false
}

// notImplementedError indicates that a feature (e.g. batch) is not implemented
// on the server.
type notImplementedError struct {
	errorWrapper
}

func (e notImplementedError) InnerError() error {
	return e.errorWrapper
}

func (e notImplementedError) NotImplemented() bool {
	return true
}

func newNotImplementedError(err error) error {
	return notImplementedError{newWrappedError(err)}
}

func IsNotImplementedError(err error) bool {
	type notimplerror interface {
		NotImplemented() bool
	}
	if e, ok := err.(notimplerror); ok {
		return e.NotImplemented()
	}
	if e, ok := err.(errorWrapper); ok {
		return IsFatalError(e.InnerError())
	}
	return false
}

// invalidPointerError indicates the the pointer was invalid.
type invalidPointerError struct {
	errorWrapper
}

func (e invalidPointerError) InnerError() error {
	return e.errorWrapper
}

func (e invalidPointerError) InvalidPointer() bool {
	return true
}

func newInvalidPointerError(err error) error {
	return invalidPointerError{newWrappedError(err)}
}

func IsInvalidPointerError(err error) bool {
	type invalidptrerror interface {
		InvalidPointer() bool
	}
	if e, ok := err.(invalidptrerror); ok {
		return e.InvalidPointer()
	}
	if e, ok := err.(errorWrapper); ok {
		return IsInvalidPointerError(e.InnerError())
	}
	return false
}

// invalidRepo error indicates that we are not in a git repository.
type invalidRepoError struct {
	errorWrapper
}

func (e invalidRepoError) InnerError() error {
	return e.errorWrapper
}

func (e invalidRepoError) InvalidRepo() bool {
	return true
}

func newInvalidrepoError(err error) error {
	return invalidRepoError{newWrappedError(err)}
}

func IsInvalidRepoError(err error) bool {
	type invalidrepoerror interface {
		InvalidRepo() bool
	}
	if e, ok := err.(invalidrepoerror); ok {
		return e.InvalidRepo()
	}
	if e, ok := err.(errorWrapper); ok {
		return IsInvalidRepoError(e.InnerError())
	}
	return false
}

// Old

type WrappedError struct {
	Err     error
	Message string
	Panic   bool
	stack   []byte
	context map[string]string
}

func Error(err error) *WrappedError {
	return Errorf(err, "")
}

func Errorf(err error, format string, args ...interface{}) *WrappedError {
	if err == nil {
		return nil
	}

	e := &WrappedError{
		Err:     err,
		Message: err.Error(),
		Panic:   true,
		stack:   Stack(),
	}

	if len(format) > 0 {
		e.Errorf(format, args...)
	}

	return e
}

func (e *WrappedError) Set(key, value string) {
	if e.context == nil {
		e.context = make(map[string]string)
	}
	e.context[key] = value
}

func (e *WrappedError) Get(key string) string {
	if e.context == nil {
		return ""
	}
	return e.context[key]
}

func (e *WrappedError) Del(key string) {
	if e.context == nil {
		return
	}
	delete(e.context, key)
}

func (e *WrappedError) Error() string {
	return e.Message
}

func (e *WrappedError) Errorf(format string, args ...interface{}) {
	e.Message = fmt.Sprintf(format, args...)
}

func (e *WrappedError) InnerError() string {
	return e.Err.Error()
}

func (e *WrappedError) Stack() []byte {
	return e.stack
}

func (e *WrappedError) Context() map[string]string {
	if e.context == nil {
		e.context = make(map[string]string)
	}
	return e.context
}

func Stack() []byte {
	stackBuf := make([]byte, 1024*1024)
	written := runtime.Stack(stackBuf, false)
	return stackBuf[:written]
}
<|endoftext|>


<commit_before>package toml

import (
	"bytes"
	"reflect"
	"testing"
	"time"

	"github.com/kylelemons/godebug/diff"
	"github.com/kylelemons/godebug/pretty"
)

func init() {
	// These settings make 'mismatch' output look nicer.
	pretty.DefaultConfig.ShortList = 80
	pretty.CompareConfig.ShortList = 80
}

type testMarshaler struct{ S string }

type testMarshalerPtr struct{ S string }

func (t testMarshaler) MarshalTOML() ([]byte, error) {
	return []byte(t.S), nil
}

func (t *testMarshalerPtr) MarshalTOML() ([]byte, error) {
	return []byte(t.S), nil
}

type testMarshalerRec struct{ replacement interface{} }

type testMarshalerRecPtr struct{ replacement interface{} }

func (t testMarshalerRec) MarshalTOML() (interface{}, error) {
	return t.replacement, nil
}

func (t *testMarshalerRecPtr) MarshalTOML() (interface{}, error) {
	return t.replacement, nil
}

var marshalTests = []struct {
	v      interface{}
	expect []byte
}{
	// single string:
	{
		v:      struct{ Name string }{"alice"},
		expect: []byte("name = \"alice\"\n"),
	},
	// single int:
	{
		v:      struct{ Age int }{7},
		expect: []byte("age = 7\n"),
	},
	// multiple fields:
	{
		v: struct {
			Name string
			Age  int
		}{"alice", 7},
		expect: []byte("name = \"alice\"\nage = 7\n"),
	},
	// ignored fields:
	{
		v: struct {
			Name string `toml:"-"`
			Age  int
		}{"alice", 7},
		expect: []byte("age = 7\n"),
	},
	// field name override:
	{
		v: struct {
			Name string `toml:"my_name"`
		}{"bob"},
		expect: []byte("my_name = \"bob\"\n"),
	},
	{
		v: struct {
			Name string `toml:"my_name,omitempty"`
		}{"bob"},
		expect: []byte("my_name = \"bob\"\n"),
	},
	// omitempty:
	{
		v: struct {
			Name string `toml:",omitempty"`
		}{"bob"},
		expect: []byte("name = \"bob\"\n"),
	},
	// slices:
	{
		v: struct {
			Ints []int
		}{[]int{1, 2, 3}},
		expect: []byte("ints = [1, 2, 3]\n"),
	},
	{
		v: struct {
			IntsOfInts [][]int
		}{[][]int{{}, {1}, {}, {2}, {3, 4}}},
		expect: []byte("ints_of_ints = [[], [1], [], [2], [3, 4]]\n"),
	},
	{
		v: struct {
			IntsOfInts [][]int
		}{[][]int{{1, 2}, {3, 4}}},
		expect: []byte("ints_of_ints = [[1, 2], [3, 4]]\n"),
	},
	// pointer:
	{
		v:      struct{ Named *Name }{&Name{First: "name"}},
		expect: []byte("[named]\nfirst = \"name\"\nlast = \"\"\n"),
	},
	// canon test document:
	{
		v:      theTestStruct(),
		expect: loadTestData("marshal-teststruct.toml"),
	},
	// funky map key types:
	{
		v: map[string]interface{}{
			"intKeys":       map[int]int{1: 1, 2: 2, 3: 3},
			"marshalerKeys": map[time.Time]int{{}: 1},
		},
		expect: loadTestData("marshal-funkymapkeys.toml"),
	},
	// Marshaler:
	{
		v: map[string]interface{}{
			"m1": testMarshaler{"1"},
			"m2": &testMarshaler{"2"},
			"m3": &testMarshalerPtr{"3"},
		},
		expect: loadTestData("marshal-marshaler.toml"),
	},
	// MarshalerRec:
	{
		v: map[string]interface{}{
			"m1": testMarshalerRec{1},
			"m2": &testMarshalerRec{2},
			"m3": &testMarshalerRecPtr{3},
			"sub": &testMarshalerRec{map[string]interface{}{
				"key": 1,
			}},
		},
		expect: loadTestData("marshal-marshalerrec.toml"),
	},
	// key escaping:
	{
		v: map[string]interface{}{
			"":    "empty",
			" ":   "space",
			"ʎǝʞ": "reverse",
			"1":   "number (not quoted)",
			"-":   "dash (not quoted)",
			"subtable with space": map[string]interface{}{
				"depth": 1,
				"subsubtable with space": map[string]interface{}{
					"depth": 2,
				},
			},
		},
		expect: loadTestData("marshal-key-escape.toml"),
	},
}

func TestMarshal(t *testing.T) {
	for _, test := range marshalTests {
		b, err := Marshal(test.v)
		if err != nil {
			t.Errorf("Unexpected error %v\nfor value:\n%s", err, pretty.Sprint(test.v))
		}
		if d := checkOutput(b, test.expect); d != "" {
			t.Errorf("Output mismatch:\nValue:\n%s\nDiff:\n%s", pretty.Sprint(test.v), d)
		}
	}
}

func TestMarshalRoundTrip(t *testing.T) {
	v := theTestStruct()
	b, err := Marshal(v)
	if err != nil {
		t.Error("Unexpected Marshal error:", err)
	}
	dest := testStruct{}
	if err := Unmarshal(b, &dest); err != nil {
		t.Error("Unmarshal error:", err)
	}
	if !reflect.DeepEqual(theTestStruct(), dest) {
		t.Errorf("Unmarshaled value mismatch:\n%s", pretty.Compare(v, dest))
	}
}

func TestMarshalArrayTableEmptyParent(t *testing.T) {
	type Baz struct {
		Key int
	}
	type Bar struct {
		Baz Baz
	}
	type Foo struct {
		Bars []Bar
	}

	v := Foo{[]Bar{{Baz{1}}, {Baz{2}}}}
	b, err := Marshal(v)
	if err != nil {
		t.Fatal(err)
	}
	if d := checkOutput(b, loadTestData("marshal-arraytable-empty.toml")); d != "" {
		t.Errorf("Output mismatch:\n%s", d)
	}
}

func TestMarshalPointerError(t *testing.T) {
	type X struct{ Sub *X }
	want := &marshalNilError{reflect.TypeOf((*X)(nil))}

	if _, err := Marshal((*X)(nil)); !reflect.DeepEqual(err, want) {
		t.Errorf("Got %q, expected %q", err, want)
	}
	if _, err := Marshal(&X{nil}); !reflect.DeepEqual(err, want) {
		t.Errorf("Got %q, expected %q", err, want)
	}
}

func TestMarshalNonStruct(t *testing.T) {
	val := []string{}
	want := &marshalTableError{reflect.TypeOf(val)}
	if _, err := Marshal(val); !reflect.DeepEqual(err, want) {
		t.Errorf("Got %q, expected %q", err, want)
	}
}

func TestMarshalOmitempty(t *testing.T) {
	var x struct {
		ZeroArray  [0]int  `toml:",omitempty"`
		ZeroArray2 [10]int `toml:",omitempty"`
		Slice      []int   `toml:",omitempty"`
		Pointer    *int    `toml:",omitempty"`
		Int        int     `toml:",omitempty"`
	}
	out, err := Marshal(x)
	if err != nil {
		t.Fatal(err)
	}
	if len(out) > 0 {
		t.Fatalf("want no output, got %q", out)
	}
}

func checkOutput(got, want []byte) string {
	if bytes.Equal(got, want) {
		return ""
	}
	return diff.Diff(string(got), string(want))
}
<commit_msg>Fix tests on Go 1.3<commit_after>package toml

import (
	"bytes"
	"reflect"
	"testing"
	"time"

	"github.com/kylelemons/godebug/diff"
	"github.com/kylelemons/godebug/pretty"
)

func init() {
	// These settings make 'mismatch' output look nicer.
	pretty.DefaultConfig.ShortList = 80
	pretty.CompareConfig.ShortList = 80
}

type testMarshaler struct{ S string }

type testMarshalerPtr struct{ S string }

func (t testMarshaler) MarshalTOML() ([]byte, error) {
	return []byte(t.S), nil
}

func (t *testMarshalerPtr) MarshalTOML() ([]byte, error) {
	return []byte(t.S), nil
}

type testMarshalerRec struct{ replacement interface{} }

type testMarshalerRecPtr struct{ replacement interface{} }

func (t testMarshalerRec) MarshalTOML() (interface{}, error) {
	return t.replacement, nil
}

func (t *testMarshalerRecPtr) MarshalTOML() (interface{}, error) {
	return t.replacement, nil
}

var marshalTests = []struct {
	v      interface{}
	expect []byte
}{
	// single string:
	{
		v:      struct{ Name string }{"alice"},
		expect: []byte("name = \"alice\"\n"),
	},
	// single int:
	{
		v:      struct{ Age int }{7},
		expect: []byte("age = 7\n"),
	},
	// multiple fields:
	{
		v: struct {
			Name string
			Age  int
		}{"alice", 7},
		expect: []byte("name = \"alice\"\nage = 7\n"),
	},
	// ignored fields:
	{
		v: struct {
			Name string `toml:"-"`
			Age  int
		}{"alice", 7},
		expect: []byte("age = 7\n"),
	},
	// field name override:
	{
		v: struct {
			Name string `toml:"my_name"`
		}{"bob"},
		expect: []byte("my_name = \"bob\"\n"),
	},
	{
		v: struct {
			Name string `toml:"my_name,omitempty"`
		}{"bob"},
		expect: []byte("my_name = \"bob\"\n"),
	},
	// omitempty:
	{
		v: struct {
			Name string `toml:",omitempty"`
		}{"bob"},
		expect: []byte("name = \"bob\"\n"),
	},
	// slices:
	{
		v: struct {
			Ints []int
		}{[]int{1, 2, 3}},
		expect: []byte("ints = [1, 2, 3]\n"),
	},
	{
		v: struct {
			IntsOfInts [][]int
		}{[][]int{{}, {1}, {}, {2}, {3, 4}}},
		expect: []byte("ints_of_ints = [[], [1], [], [2], [3, 4]]\n"),
	},
	{
		v: struct {
			IntsOfInts [][]int
		}{[][]int{{1, 2}, {3, 4}}},
		expect: []byte("ints_of_ints = [[1, 2], [3, 4]]\n"),
	},
	// pointer:
	{
		v:      struct{ Named *Name }{&Name{First: "name"}},
		expect: []byte("[named]\nfirst = \"name\"\nlast = \"\"\n"),
	},
	// canon test document:
	{
		v:      theTestStruct(),
		expect: loadTestData("marshal-teststruct.toml"),
	},
	// funky map key types:
	{
		v: map[string]interface{}{
			"intKeys":       map[int]int{1: 1, 2: 2, 3: 3},
			"marshalerKeys": map[time.Time]int{time.Time{}: 1},
		},
		expect: loadTestData("marshal-funkymapkeys.toml"),
	},
	// Marshaler:
	{
		v: map[string]interface{}{
			"m1": testMarshaler{"1"},
			"m2": &testMarshaler{"2"},
			"m3": &testMarshalerPtr{"3"},
		},
		expect: loadTestData("marshal-marshaler.toml"),
	},
	// MarshalerRec:
	{
		v: map[string]interface{}{
			"m1": testMarshalerRec{1},
			"m2": &testMarshalerRec{2},
			"m3": &testMarshalerRecPtr{3},
			"sub": &testMarshalerRec{map[string]interface{}{
				"key": 1,
			}},
		},
		expect: loadTestData("marshal-marshalerrec.toml"),
	},
	// key escaping:
	{
		v: map[string]interface{}{
			"":    "empty",
			" ":   "space",
			"ʎǝʞ": "reverse",
			"1":   "number (not quoted)",
			"-":   "dash (not quoted)",
			"subtable with space": map[string]interface{}{
				"depth": 1,
				"subsubtable with space": map[string]interface{}{
					"depth": 2,
				},
			},
		},
		expect: loadTestData("marshal-key-escape.toml"),
	},
}

func TestMarshal(t *testing.T) {
	for _, test := range marshalTests {
		b, err := Marshal(test.v)
		if err != nil {
			t.Errorf("Unexpected error %v\nfor value:\n%s", err, pretty.Sprint(test.v))
		}
		if d := checkOutput(b, test.expect); d != "" {
			t.Errorf("Output mismatch:\nValue:\n%s\nDiff:\n%s", pretty.Sprint(test.v), d)
		}
	}
}

func TestMarshalRoundTrip(t *testing.T) {
	v := theTestStruct()
	b, err := Marshal(v)
	if err != nil {
		t.Error("Unexpected Marshal error:", err)
	}
	dest := testStruct{}
	if err := Unmarshal(b, &dest); err != nil {
		t.Error("Unmarshal error:", err)
	}
	if !reflect.DeepEqual(theTestStruct(), dest) {
		t.Errorf("Unmarshaled value mismatch:\n%s", pretty.Compare(v, dest))
	}
}

func TestMarshalArrayTableEmptyParent(t *testing.T) {
	type Baz struct {
		Key int
	}
	type Bar struct {
		Baz Baz
	}
	type Foo struct {
		Bars []Bar
	}

	v := Foo{[]Bar{{Baz{1}}, {Baz{2}}}}
	b, err := Marshal(v)
	if err != nil {
		t.Fatal(err)
	}
	if d := checkOutput(b, loadTestData("marshal-arraytable-empty.toml")); d != "" {
		t.Errorf("Output mismatch:\n%s", d)
	}
}

func TestMarshalPointerError(t *testing.T) {
	type X struct{ Sub *X }
	want := &marshalNilError{reflect.TypeOf((*X)(nil))}

	if _, err := Marshal((*X)(nil)); !reflect.DeepEqual(err, want) {
		t.Errorf("Got %q, expected %q", err, want)
	}
	if _, err := Marshal(&X{nil}); !reflect.DeepEqual(err, want) {
		t.Errorf("Got %q, expected %q", err, want)
	}
}

func TestMarshalNonStruct(t *testing.T) {
	val := []string{}
	want := &marshalTableError{reflect.TypeOf(val)}
	if _, err := Marshal(val); !reflect.DeepEqual(err, want) {
		t.Errorf("Got %q, expected %q", err, want)
	}
}

func TestMarshalOmitempty(t *testing.T) {
	var x struct {
		ZeroArray  [0]int  `toml:",omitempty"`
		ZeroArray2 [10]int `toml:",omitempty"`
		Slice      []int   `toml:",omitempty"`
		Pointer    *int    `toml:",omitempty"`
		Int        int     `toml:",omitempty"`
	}
	out, err := Marshal(x)
	if err != nil {
		t.Fatal(err)
	}
	if len(out) > 0 {
		t.Fatalf("want no output, got %q", out)
	}
}

func checkOutput(got, want []byte) string {
	if bytes.Equal(got, want) {
		return ""
	}
	return diff.Diff(string(got), string(want))
}
<|endoftext|>


<commit_before>// Copyright 2014 The Azul3D Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package wav

import (
	"io/ioutil"
	"os"
	"testing"

	"azul3d.org/audio.v1"
)

type encodeTest struct {
	file string
	audio.Config
	format audio.Slice
}

func countFill(s audio.Slice) {
	var x audio.F64
	for i := 0; i < s.Len(); i++ {
		s.Set(i, x)
		x += 1.0
	}
}

func testEncode(t *testing.T, tst encodeTest) {
	tmpFile, err := ioutil.TempFile("", "wav")
	if err != nil {
		t.Fatal(err)
	}
	defer func() {
		err := tmpFile.Close()
		if err != nil {
			t.Fatal(err)
		}
		err = os.Remove(tmpFile.Name())
	}()

	enc, err := NewEncoder(tmpFile, tst.Config)
	if err != nil {
		t.Fatal(err)
	}

	// Create a slice large enough to hold 1 tenth second of audio samples.
	bufSize := 1 * tst.Config.SampleRate * tst.Config.Channels
	buf := tst.format.Make(bufSize, bufSize)

	// Fill the buffer with counting numbers.
	countFill(buf)

	// Encode the buffer into wav (we make ten small writes here to ensure that
	// multiple writes work correctly).
	n := 10
	bn := buf.Len() / n // e.g. one-tenth the buffer's size
	var totalWrote int
	for i := 0; i < n; i++ {
		start := i * bn
		end := start + bn
		s := buf.Slice(start, end)
		wrote, err := audio.Copy(enc, audio.NewBuffer(s))
		if err != nil {
			t.Fatal(err)
		}
		totalWrote += int(wrote)
	}

	// Verify that we wrote everything.
	if totalWrote != bufSize {
		t.Fatalf("wrote %d samples wanted %d\n", totalWrote, bufSize)
	}

	// Done encoding, close the encoder.
	err = enc.Close()
	if err != nil {
		t.Fatal(err)
	}

	// Seek to the start of the file now.
	tmpFile.Seek(0, 0)

	// Use a decoder to decode the WAV file and validate things.
	decoder, format, err := audio.NewDecoder(tmpFile)
	if err != nil {
		t.Fatal(err)
	}

	// Verify format.
	if format != "wav" {
		t.Logf("got format=%q, want format=%q\n", format, "wav")
	}

	// Verify config.
	conf := decoder.Config()
	if conf != tst.Config {
		t.Log("got config", conf)
		t.Fatal("want config", tst.Config)
	}

	// Create a new buffer and read the entire file.
	buf2 := audio.NewBuffer(tst.format.Make(0, 0))
	read, err := audio.Copy(buf2, decoder)
	if err != nil {
		t.Fatal(err)
	}

	// Verify samples. To account for lossy conversions, for example:
	//
	//  encode -> float64 -> int16
	//  decode -> int16 -> float64
	//
	// We convert our buffer (buf/float64) to the target format
	// (lossyBuf/int16) and then back.

	// Right now the encoder only supports PCM16, so we use that directly.
	//lossyBuf := tst.format.Make(buf.Len(), buf.Len())
	lossyBuf := make(audio.PCM16Samples, buf.Len())
	buf.CopyTo(lossyBuf)
	lossyBuf.CopyTo(buf)

	if int(read) != totalWrote {
		// TODO(slimsag): fix this, see issue #12.
		//t.Fatalf("read %d samples wanted %d\n", read, totalWrote)
	}
	for i := 0; i < buf2.Samples().Len(); i++ {
		got := buf2.Samples().At(i)
		want := buf.At(i)
		if got != want {
			t.Fatalf("Decoded sample %d: got %f want %f\n", i, got, want)
		}
	}
}

func TestEncodeFloat32(t *testing.T) {
	testEncode(t, encodeTest{
		Config: audio.Config{
			SampleRate: 44100,
			Channels:   2,
		},
		format: audio.F32Samples{},
	})
}

func TestEncodeFloat64(t *testing.T) {
	testEncode(t, encodeTest{
		Config: audio.Config{
			SampleRate: 44100,
			Channels:   2,
		},
		format: audio.F64Samples{},
	})
}

func TestEncodeUInt8(t *testing.T) {
	testEncode(t, encodeTest{
		Config: audio.Config{
			SampleRate: 44100,
			Channels:   2,
		},
		format: audio.PCM8Samples{},
	})
}

func TestEncodeInt16(t *testing.T) {
	testEncode(t, encodeTest{
		Config: audio.Config{
			SampleRate: 44100,
			Channels:   2,
		},
		format: audio.PCM16Samples{},
	})
}

func TestEncodeInt32(t *testing.T) {
	testEncode(t, encodeTest{
		Config: audio.Config{
			SampleRate: 44100,
			Channels:   2,
		},
		format: audio.PCM32Samples{},
	})
}

func TestEncodeALaw(t *testing.T) {
	testEncode(t, encodeTest{
		Config: audio.Config{
			SampleRate: 44100,
			Channels:   2,
		},
		format: audio.ALawSamples{},
	})
}

func TestEncodeMuLaw(t *testing.T) {
	testEncode(t, encodeTest{
		Config: audio.Config{
			SampleRate: 44100,
			Channels:   2,
		},
		format: audio.MuLawSamples{},
	})
}
<commit_msg>encoder: Document tests more; Updates #7<commit_after>// Copyright 2014 The Azul3D Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package wav

import (
	"io/ioutil"
	"os"
	"testing"

	"azul3d.org/audio.v1"
)

type encodeTest struct {
	file string
	audio.Config
	format audio.Slice
}

func countFill(s audio.Slice) {
	var x audio.F64
	for i := 0; i < s.Len(); i++ {
		s.Set(i, x)
		x += 1.0
	}
}

func testEncode(t *testing.T, tst encodeTest) {
	// Create a temp file that we will encode to.
	tmpFile, err := ioutil.TempFile("", "wav")
	if err != nil {
		t.Fatal(err)
	}

	// Once we are done, we need to close the temp file and remove it.
	defer func() {
		err := tmpFile.Close()
		if err != nil {
			t.Fatal(err)
		}
		err = os.Remove(tmpFile.Name())
	}()

	// Create a new encoder, writing to the temp file with the given config.
	enc, err := NewEncoder(tmpFile, tst.Config)
	if err != nil {
		t.Fatal(err)
	}

	// Create a slice large enough to hold 1 tenth second of audio samples.
	bufSize := 1 * tst.Config.SampleRate * tst.Config.Channels
	buf := tst.format.Make(bufSize, bufSize)

	// Fill the buffer with counting numbers.
	countFill(buf)

	// Encode the buffer into wav (we make ten small writes here to ensure that
	// multiple writes work correctly).
	n := 10
	bn := buf.Len() / n // e.g. one-tenth the buffer's size
	var totalWrote int
	for i := 0; i < n; i++ {
		start := i * bn
		end := start + bn
		s := buf.Slice(start, end)
		wrote, err := audio.Copy(enc, audio.NewBuffer(s))
		if err != nil {
			t.Fatal(err)
		}
		totalWrote += int(wrote)
	}

	// Verify that we wrote everything.
	if totalWrote != bufSize {
		t.Fatalf("wrote %d samples wanted %d\n", totalWrote, bufSize)
	}

	// Done encoding, close the encoder.
	err = enc.Close()
	if err != nil {
		t.Fatal(err)
	}

	// Seek to the start of the file now.
	tmpFile.Seek(0, 0)

	// Use a decoder to decode the WAV file and validate things.
	decoder, format, err := audio.NewDecoder(tmpFile)
	if err != nil {
		t.Fatal(err)
	}

	// Verify format.
	if format != "wav" {
		t.Logf("got format=%q, want format=%q\n", format, "wav")
	}

	// Verify config.
	conf := decoder.Config()
	if conf != tst.Config {
		t.Log("got config", conf)
		t.Fatal("want config", tst.Config)
	}

	// Create a new buffer and read the entire file.
	buf2 := audio.NewBuffer(tst.format.Make(0, 0))
	read, err := audio.Copy(buf2, decoder)
	if err != nil {
		t.Fatal(err)
	}

	// Verify samples. To account for lossy conversions, for example:
	//
	//  encode -> float64 -> int16
	//  decode -> int16 -> float64
	//
	// We convert our buffer (buf/float64) to the target format
	// (lossyBuf/int16) and then back.

	// Right now the encoder only supports PCM16, so we use that directly.
	//lossyBuf := tst.format.Make(buf.Len(), buf.Len())
	lossyBuf := make(audio.PCM16Samples, buf.Len())
	buf.CopyTo(lossyBuf)
	lossyBuf.CopyTo(buf)

	if int(read) != totalWrote {
		// TODO(slimsag): fix this, see issue #12.
		//t.Fatalf("read %d samples wanted %d\n", read, totalWrote)
	}
	for i := 0; i < buf2.Samples().Len(); i++ {
		got := buf2.Samples().At(i)
		want := buf.At(i)
		if got != want {
			t.Fatalf("Decoded sample %d: got %f want %f\n", i, got, want)
		}
	}
}

func TestEncodeFloat32(t *testing.T) {
	testEncode(t, encodeTest{
		Config: audio.Config{
			SampleRate: 44100,
			Channels:   2,
		},
		format: audio.F32Samples{},
	})
}

func TestEncodeFloat64(t *testing.T) {
	testEncode(t, encodeTest{
		Config: audio.Config{
			SampleRate: 44100,
			Channels:   2,
		},
		format: audio.F64Samples{},
	})
}

func TestEncodeUInt8(t *testing.T) {
	testEncode(t, encodeTest{
		Config: audio.Config{
			SampleRate: 44100,
			Channels:   2,
		},
		format: audio.PCM8Samples{},
	})
}

func TestEncodeInt16(t *testing.T) {
	testEncode(t, encodeTest{
		Config: audio.Config{
			SampleRate: 44100,
			Channels:   2,
		},
		format: audio.PCM16Samples{},
	})
}

func TestEncodeInt32(t *testing.T) {
	testEncode(t, encodeTest{
		Config: audio.Config{
			SampleRate: 44100,
			Channels:   2,
		},
		format: audio.PCM32Samples{},
	})
}

func TestEncodeALaw(t *testing.T) {
	testEncode(t, encodeTest{
		Config: audio.Config{
			SampleRate: 44100,
			Channels:   2,
		},
		format: audio.ALawSamples{},
	})
}

func TestEncodeMuLaw(t *testing.T) {
	testEncode(t, encodeTest{
		Config: audio.Config{
			SampleRate: 44100,
			Channels:   2,
		},
		format: audio.MuLawSamples{},
	})
}
<|endoftext|>


<commit_before>package config

import (
	"bytes"
	"os"
	"path/filepath"
	"text/template"

	cmn "github.com/tendermint/tmlibs/common"
)

var configTemplate *template.Template

func init() {
	var err error
	if configTemplate, err = template.New("configFileTemplate").Parse(defaultConfigTemplate); err != nil {
		panic(err)
	}
}

/****** these are for production settings ***********/

// EnsureRoot creates the root, config, and data directories if they don't exist,
// and panics if it fails.
func EnsureRoot(rootDir string) {
	if err := cmn.EnsureDir(rootDir, 0700); err != nil {
		cmn.PanicSanity(err.Error())
	}
	if err := cmn.EnsureDir(filepath.Join(rootDir, defaultConfigDir), 0700); err != nil {
		cmn.PanicSanity(err.Error())
	}
	if err := cmn.EnsureDir(filepath.Join(rootDir, defaultDataDir), 0700); err != nil {
		cmn.PanicSanity(err.Error())
	}

	configFilePath := filepath.Join(rootDir, defaultConfigFilePath)

	// Write default config file if missing.
	if !cmn.FileExists(configFilePath) {
		writeDefaultCondigFile(configFilePath)
	}
}

// XXX: this func should probably be called by cmd/tendermint/commands/init.go
// alongside the writing of the genesis.json and priv_validator.json
func writeDefaultCondigFile(configFilePath string) {
	WriteConfigFile(configFilePath, DefaultConfig())
}

// WriteConfigFile renders config using the template and writes it to configFilePath.
func WriteConfigFile(configFilePath string, config *Config) {
	var buffer bytes.Buffer

	if err := configTemplate.Execute(&buffer, config); err != nil {
		panic(err)
	}

	cmn.MustWriteFile(configFilePath, buffer.Bytes(), 0644)
}

// Note: any changes to the comments/variables/mapstructure
// must be reflected in the appropriate struct in config/config.go
const defaultConfigTemplate = `# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml

##### main base config options #####

# TCP or UNIX socket address of the ABCI application,
# or the name of an ABCI application compiled in with the Tendermint binary
proxy_app = "{{ .BaseConfig.ProxyApp }}"

# A custom human readable name for this node
moniker = "{{ .BaseConfig.Moniker }}"

# If this node is many blocks behind the tip of the chain, FastSync
# allows them to catchup quickly by downloading blocks in parallel
# and verifying their commits
fast_sync = {{ .BaseConfig.FastSync }}

# Database backend: leveldb | memdb
db_backend = "{{ .BaseConfig.DBBackend }}"

# Database directory
db_path = "{{ .BaseConfig.DBPath }}"

# Output level for logging, including package level options
log_level = "{{ .BaseConfig.LogLevel }}"

##### additional base config options #####

# Path to the JSON file containing the initial validator set and other meta data
genesis_file = "{{ .BaseConfig.Genesis }}"

# Path to the JSON file containing the private key to use as a validator in the consensus protocol
priv_validator_file = "{{ .BaseConfig.PrivValidator }}"

# Path to the JSON file containing the private key to use for node authentication in the p2p protocol
node_key_file = "{{ .BaseConfig.NodeKey}}"

# Mechanism to connect to the ABCI application: socket | grpc
abci = "{{ .BaseConfig.ABCI }}"

# TCP or UNIX socket address for the profiling server to listen on
prof_laddr = "{{ .BaseConfig.ProfListenAddress }}"

# If true, query the ABCI app on connecting to a new peer
# so the app can decide if we should keep the connection or not
filter_peers = {{ .BaseConfig.FilterPeers }}

##### advanced configuration options #####

##### rpc server configuration options #####
[rpc]

# TCP or UNIX socket address for the RPC server to listen on
laddr = "{{ .RPC.ListenAddress }}"

# TCP or UNIX socket address for the gRPC server to listen on
# NOTE: This server only supports /broadcast_tx_commit
grpc_laddr = "{{ .RPC.GRPCListenAddress }}"

# Activate unsafe RPC commands like /dial_seeds and /unsafe_flush_mempool
unsafe = {{ .RPC.Unsafe }}

##### peer to peer configuration options #####
[p2p]

# Address to listen for incoming connections
laddr = "{{ .P2P.ListenAddress }}"

# Comma separated list of seed nodes to connect to
seeds = "{{ .P2P.Seeds }}"

# Comma separated list of nodes to keep persistent connections to
# Do not add private peers to this list if you don't want them advertised
persistent_peers = "{{ .P2P.PersistentPeers }}"

# Path to address book
addr_book_file = "{{ .P2P.AddrBook }}"

# Set true for strict address routability rules
addr_book_strict = {{ .P2P.AddrBookStrict }}

# Time to wait before flushing messages out on the connection, in ms
flush_throttle_timeout = {{ .P2P.FlushThrottleTimeout }}

# Maximum number of peers to connect to
max_num_peers = {{ .P2P.MaxNumPeers }}

# Maximum size of a message packet payload, in bytes
max_packet_msg_payload_size = {{ .P2P.MaxPacketMsgPayloadSize }}

# Rate at which packets can be sent, in bytes/second
send_rate = {{ .P2P.SendRate }}

# Rate at which packets can be received, in bytes/second
recv_rate = {{ .P2P.RecvRate }}

# Set true to enable the peer-exchange reactor
pex = {{ .P2P.PexReactor }}

# Seed mode, in which node constantly crawls the network and looks for
# peers. If another node asks it for addresses, it responds and disconnects.
#
# Does not work if the peer-exchange reactor is disabled.
seed_mode = {{ .P2P.SeedMode }}

# Authenticated encryption
auth_enc = {{ .P2P.AuthEnc }}

# Comma separated list of peer IDs to keep private (will not be gossiped to other peers)
private_peer_ids = "{{ .P2P.PrivatePeerIDs }}"

##### mempool configuration options #####
[mempool]

recheck = {{ .Mempool.Recheck }}
recheck_empty = {{ .Mempool.RecheckEmpty }}
broadcast = {{ .Mempool.Broadcast }}
wal_dir = "{{ .Mempool.WalPath }}"

##### consensus configuration options #####
[consensus]

wal_file = "{{ .Consensus.WalPath }}"
wal_light = {{ .Consensus.WalLight }}

# All timeouts are in milliseconds
timeout_propose = {{ .Consensus.TimeoutPropose }}
timeout_propose_delta = {{ .Consensus.TimeoutProposeDelta }}
timeout_prevote = {{ .Consensus.TimeoutPrevote }}
timeout_prevote_delta = {{ .Consensus.TimeoutPrevoteDelta }}
timeout_precommit = {{ .Consensus.TimeoutPrecommit }}
timeout_precommit_delta = {{ .Consensus.TimeoutPrecommitDelta }}
timeout_commit = {{ .Consensus.TimeoutCommit }}

# Make progress as soon as we have all the precommits (as if TimeoutCommit = 0)
skip_timeout_commit = {{ .Consensus.SkipTimeoutCommit }}

# BlockSize
max_block_size_txs = {{ .Consensus.MaxBlockSizeTxs }}
max_block_size_bytes = {{ .Consensus.MaxBlockSizeBytes }}

# EmptyBlocks mode and possible interval between empty blocks in seconds
create_empty_blocks = {{ .Consensus.CreateEmptyBlocks }}
create_empty_blocks_interval = {{ .Consensus.CreateEmptyBlocksInterval }}

# Reactor sleep duration parameters are in milliseconds
peer_gossip_sleep_duration = {{ .Consensus.PeerGossipSleepDuration }}
peer_query_maj23_sleep_duration = {{ .Consensus.PeerQueryMaj23SleepDuration }}

##### transactions indexer configuration options #####
[tx_index]

# What indexer to use for transactions
#
# Options:
#   1) "null" (default)
#   2) "kv" - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend).
indexer = "{{ .TxIndex.Indexer }}"

# Comma-separated list of tags to index (by default the only tag is tx hash)
#
# It's recommended to index only a subset of tags due to possible memory
# bloat. This is, of course, depends on the indexer's DB and the volume of
# transactions.
index_tags = "{{ .TxIndex.IndexTags }}"

# When set to true, tells indexer to index all tags. Note this may be not
# desirable (see the comment above). IndexTags has a precedence over
# IndexAllTags (i.e. when given both, IndexTags will be indexed).
index_all_tags = {{ .TxIndex.IndexAllTags }}
`

/****** these are for test settings ***********/

func ResetTestRoot(testName string) *Config {
	rootDir := os.ExpandEnv("$HOME/.tendermint_test")
	rootDir = filepath.Join(rootDir, testName)
	// Remove ~/.tendermint_test_bak
	if cmn.FileExists(rootDir + "_bak") {
		if err := os.RemoveAll(rootDir + "_bak"); err != nil {
			cmn.PanicSanity(err.Error())
		}
	}
	// Move ~/.tendermint_test to ~/.tendermint_test_bak
	if cmn.FileExists(rootDir) {
		if err := os.Rename(rootDir, rootDir+"_bak"); err != nil {
			cmn.PanicSanity(err.Error())
		}
	}
	// Create new dir
	if err := cmn.EnsureDir(rootDir, 0700); err != nil {
		cmn.PanicSanity(err.Error())
	}
	if err := cmn.EnsureDir(filepath.Join(rootDir, defaultConfigDir), 0700); err != nil {
		cmn.PanicSanity(err.Error())
	}
	if err := cmn.EnsureDir(filepath.Join(rootDir, defaultDataDir), 0700); err != nil {
		cmn.PanicSanity(err.Error())
	}

	baseConfig := DefaultBaseConfig()
	configFilePath := filepath.Join(rootDir, defaultConfigFilePath)
	genesisFilePath := filepath.Join(rootDir, baseConfig.Genesis)
	privFilePath := filepath.Join(rootDir, baseConfig.PrivValidator)

	// Write default config file if missing.
	if !cmn.FileExists(configFilePath) {
		writeDefaultCondigFile(configFilePath)
	}
	if !cmn.FileExists(genesisFilePath) {
		cmn.MustWriteFile(genesisFilePath, []byte(testGenesis), 0644)
	}
	// we always overwrite the priv val
	cmn.MustWriteFile(privFilePath, []byte(testPrivValidator), 0644)

	config := TestConfig().SetRoot(rootDir)
	return config
}

var testGenesis = `{
  "genesis_time": "0001-01-01T00:00:00.000Z",
  "chain_id": "tendermint_test",
  "validators": [
    {
      "pub_key": {
        "type": "AC26791624DE60",
        "value":"AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="
      },
      "power": 10,
      "name": ""
    }
  ],
  "app_hash": ""
}`

var testPrivValidator = `{
  "address": "849CB2C877F87A20925F35D00AE6688342D25B47",
  "pub_key": {
    "type": "AC26791624DE60",
    "value": "AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="
  },
  "priv_key": {
    "type": "954568A3288910",
    "value": "EVkqJO/jIXp3rkASXfh9YnyToYXRXhBr6g9cQVxPFnQBP/5povV4HTjvsy530kybxKHwEi85iU8YL0qQhSYVoQ=="
  },
  "last_height": 0,
  "last_round": 0,
  "last_step": 0
}`
<commit_msg>writeDefaultCondigFile -> writeDefaultConfigFile (#1490)<commit_after>package config

import (
	"bytes"
	"os"
	"path/filepath"
	"text/template"

	cmn "github.com/tendermint/tmlibs/common"
)

var configTemplate *template.Template

func init() {
	var err error
	if configTemplate, err = template.New("configFileTemplate").Parse(defaultConfigTemplate); err != nil {
		panic(err)
	}
}

/****** these are for production settings ***********/

// EnsureRoot creates the root, config, and data directories if they don't exist,
// and panics if it fails.
func EnsureRoot(rootDir string) {
	if err := cmn.EnsureDir(rootDir, 0700); err != nil {
		cmn.PanicSanity(err.Error())
	}
	if err := cmn.EnsureDir(filepath.Join(rootDir, defaultConfigDir), 0700); err != nil {
		cmn.PanicSanity(err.Error())
	}
	if err := cmn.EnsureDir(filepath.Join(rootDir, defaultDataDir), 0700); err != nil {
		cmn.PanicSanity(err.Error())
	}

	configFilePath := filepath.Join(rootDir, defaultConfigFilePath)

	// Write default config file if missing.
	if !cmn.FileExists(configFilePath) {
		writeDefaultConfigFile(configFilePath)
	}
}

// XXX: this func should probably be called by cmd/tendermint/commands/init.go
// alongside the writing of the genesis.json and priv_validator.json
func writeDefaultConfigFile(configFilePath string) {
	WriteConfigFile(configFilePath, DefaultConfig())
}

// WriteConfigFile renders config using the template and writes it to configFilePath.
func WriteConfigFile(configFilePath string, config *Config) {
	var buffer bytes.Buffer

	if err := configTemplate.Execute(&buffer, config); err != nil {
		panic(err)
	}

	cmn.MustWriteFile(configFilePath, buffer.Bytes(), 0644)
}

// Note: any changes to the comments/variables/mapstructure
// must be reflected in the appropriate struct in config/config.go
const defaultConfigTemplate = `# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml

##### main base config options #####

# TCP or UNIX socket address of the ABCI application,
# or the name of an ABCI application compiled in with the Tendermint binary
proxy_app = "{{ .BaseConfig.ProxyApp }}"

# A custom human readable name for this node
moniker = "{{ .BaseConfig.Moniker }}"

# If this node is many blocks behind the tip of the chain, FastSync
# allows them to catchup quickly by downloading blocks in parallel
# and verifying their commits
fast_sync = {{ .BaseConfig.FastSync }}

# Database backend: leveldb | memdb
db_backend = "{{ .BaseConfig.DBBackend }}"

# Database directory
db_path = "{{ .BaseConfig.DBPath }}"

# Output level for logging, including package level options
log_level = "{{ .BaseConfig.LogLevel }}"

##### additional base config options #####

# Path to the JSON file containing the initial validator set and other meta data
genesis_file = "{{ .BaseConfig.Genesis }}"

# Path to the JSON file containing the private key to use as a validator in the consensus protocol
priv_validator_file = "{{ .BaseConfig.PrivValidator }}"

# Path to the JSON file containing the private key to use for node authentication in the p2p protocol
node_key_file = "{{ .BaseConfig.NodeKey}}"

# Mechanism to connect to the ABCI application: socket | grpc
abci = "{{ .BaseConfig.ABCI }}"

# TCP or UNIX socket address for the profiling server to listen on
prof_laddr = "{{ .BaseConfig.ProfListenAddress }}"

# If true, query the ABCI app on connecting to a new peer
# so the app can decide if we should keep the connection or not
filter_peers = {{ .BaseConfig.FilterPeers }}

##### advanced configuration options #####

##### rpc server configuration options #####
[rpc]

# TCP or UNIX socket address for the RPC server to listen on
laddr = "{{ .RPC.ListenAddress }}"

# TCP or UNIX socket address for the gRPC server to listen on
# NOTE: This server only supports /broadcast_tx_commit
grpc_laddr = "{{ .RPC.GRPCListenAddress }}"

# Activate unsafe RPC commands like /dial_seeds and /unsafe_flush_mempool
unsafe = {{ .RPC.Unsafe }}

##### peer to peer configuration options #####
[p2p]

# Address to listen for incoming connections
laddr = "{{ .P2P.ListenAddress }}"

# Comma separated list of seed nodes to connect to
seeds = "{{ .P2P.Seeds }}"

# Comma separated list of nodes to keep persistent connections to
# Do not add private peers to this list if you don't want them advertised
persistent_peers = "{{ .P2P.PersistentPeers }}"

# Path to address book
addr_book_file = "{{ .P2P.AddrBook }}"

# Set true for strict address routability rules
addr_book_strict = {{ .P2P.AddrBookStrict }}

# Time to wait before flushing messages out on the connection, in ms
flush_throttle_timeout = {{ .P2P.FlushThrottleTimeout }}

# Maximum number of peers to connect to
max_num_peers = {{ .P2P.MaxNumPeers }}

# Maximum size of a message packet payload, in bytes
max_packet_msg_payload_size = {{ .P2P.MaxPacketMsgPayloadSize }}

# Rate at which packets can be sent, in bytes/second
send_rate = {{ .P2P.SendRate }}

# Rate at which packets can be received, in bytes/second
recv_rate = {{ .P2P.RecvRate }}

# Set true to enable the peer-exchange reactor
pex = {{ .P2P.PexReactor }}

# Seed mode, in which node constantly crawls the network and looks for
# peers. If another node asks it for addresses, it responds and disconnects.
#
# Does not work if the peer-exchange reactor is disabled.
seed_mode = {{ .P2P.SeedMode }}

# Authenticated encryption
auth_enc = {{ .P2P.AuthEnc }}

# Comma separated list of peer IDs to keep private (will not be gossiped to other peers)
private_peer_ids = "{{ .P2P.PrivatePeerIDs }}"

##### mempool configuration options #####
[mempool]

recheck = {{ .Mempool.Recheck }}
recheck_empty = {{ .Mempool.RecheckEmpty }}
broadcast = {{ .Mempool.Broadcast }}
wal_dir = "{{ .Mempool.WalPath }}"

##### consensus configuration options #####
[consensus]

wal_file = "{{ .Consensus.WalPath }}"
wal_light = {{ .Consensus.WalLight }}

# All timeouts are in milliseconds
timeout_propose = {{ .Consensus.TimeoutPropose }}
timeout_propose_delta = {{ .Consensus.TimeoutProposeDelta }}
timeout_prevote = {{ .Consensus.TimeoutPrevote }}
timeout_prevote_delta = {{ .Consensus.TimeoutPrevoteDelta }}
timeout_precommit = {{ .Consensus.TimeoutPrecommit }}
timeout_precommit_delta = {{ .Consensus.TimeoutPrecommitDelta }}
timeout_commit = {{ .Consensus.TimeoutCommit }}

# Make progress as soon as we have all the precommits (as if TimeoutCommit = 0)
skip_timeout_commit = {{ .Consensus.SkipTimeoutCommit }}

# BlockSize
max_block_size_txs = {{ .Consensus.MaxBlockSizeTxs }}
max_block_size_bytes = {{ .Consensus.MaxBlockSizeBytes }}

# EmptyBlocks mode and possible interval between empty blocks in seconds
create_empty_blocks = {{ .Consensus.CreateEmptyBlocks }}
create_empty_blocks_interval = {{ .Consensus.CreateEmptyBlocksInterval }}

# Reactor sleep duration parameters are in milliseconds
peer_gossip_sleep_duration = {{ .Consensus.PeerGossipSleepDuration }}
peer_query_maj23_sleep_duration = {{ .Consensus.PeerQueryMaj23SleepDuration }}

##### transactions indexer configuration options #####
[tx_index]

# What indexer to use for transactions
#
# Options:
#   1) "null" (default)
#   2) "kv" - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend).
indexer = "{{ .TxIndex.Indexer }}"

# Comma-separated list of tags to index (by default the only tag is tx hash)
#
# It's recommended to index only a subset of tags due to possible memory
# bloat. This is, of course, depends on the indexer's DB and the volume of
# transactions.
index_tags = "{{ .TxIndex.IndexTags }}"

# When set to true, tells indexer to index all tags. Note this may be not
# desirable (see the comment above). IndexTags has a precedence over
# IndexAllTags (i.e. when given both, IndexTags will be indexed).
index_all_tags = {{ .TxIndex.IndexAllTags }}
`

/****** these are for test settings ***********/

func ResetTestRoot(testName string) *Config {
	rootDir := os.ExpandEnv("$HOME/.tendermint_test")
	rootDir = filepath.Join(rootDir, testName)
	// Remove ~/.tendermint_test_bak
	if cmn.FileExists(rootDir + "_bak") {
		if err := os.RemoveAll(rootDir + "_bak"); err != nil {
			cmn.PanicSanity(err.Error())
		}
	}
	// Move ~/.tendermint_test to ~/.tendermint_test_bak
	if cmn.FileExists(rootDir) {
		if err := os.Rename(rootDir, rootDir+"_bak"); err != nil {
			cmn.PanicSanity(err.Error())
		}
	}
	// Create new dir
	if err := cmn.EnsureDir(rootDir, 0700); err != nil {
		cmn.PanicSanity(err.Error())
	}
	if err := cmn.EnsureDir(filepath.Join(rootDir, defaultConfigDir), 0700); err != nil {
		cmn.PanicSanity(err.Error())
	}
	if err := cmn.EnsureDir(filepath.Join(rootDir, defaultDataDir), 0700); err != nil {
		cmn.PanicSanity(err.Error())
	}

	baseConfig := DefaultBaseConfig()
	configFilePath := filepath.Join(rootDir, defaultConfigFilePath)
	genesisFilePath := filepath.Join(rootDir, baseConfig.Genesis)
	privFilePath := filepath.Join(rootDir, baseConfig.PrivValidator)

	// Write default config file if missing.
	if !cmn.FileExists(configFilePath) {
		writeDefaultConfigFile(configFilePath)
	}
	if !cmn.FileExists(genesisFilePath) {
		cmn.MustWriteFile(genesisFilePath, []byte(testGenesis), 0644)
	}
	// we always overwrite the priv val
	cmn.MustWriteFile(privFilePath, []byte(testPrivValidator), 0644)

	config := TestConfig().SetRoot(rootDir)
	return config
}

var testGenesis = `{
  "genesis_time": "0001-01-01T00:00:00.000Z",
  "chain_id": "tendermint_test",
  "validators": [
    {
      "pub_key": {
        "type": "AC26791624DE60",
        "value":"AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="
      },
      "power": 10,
      "name": ""
    }
  ],
  "app_hash": ""
}`

var testPrivValidator = `{
  "address": "849CB2C877F87A20925F35D00AE6688342D25B47",
  "pub_key": {
    "type": "AC26791624DE60",
    "value": "AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="
  },
  "priv_key": {
    "type": "954568A3288910",
    "value": "EVkqJO/jIXp3rkASXfh9YnyToYXRXhBr6g9cQVxPFnQBP/5povV4HTjvsy530kybxKHwEi85iU8YL0qQhSYVoQ=="
  },
  "last_height": 0,
  "last_round": 0,
  "last_step": 0
}`
<|endoftext|>