<commit_before>package config

import (
	"bytes"
	"fmt"
	"sort"
	"strconv"
	"strings"
	"text/tabwriter"

	"github.com/wallix/awless/aws"
	"github.com/wallix/awless/aws/config"
	"github.com/wallix/awless/cloud"
	"github.com/wallix/awless/database"
	"github.com/wallix/awless/logger"
	"github.com/wallix/awless/sync"
)

var (
	Config   = map[string]interface{}{}
	Defaults = map[string]interface{}{}
)

const (
	configDatabaseKey   = "userconfig"
	defaultsDatabaseKey = "defaults"

	//Config
	autosyncConfigKey              = "autosync"
	checkUpgradeFrequencyConfigKey = "upgrade.checkfrequency"
	schedulerURL                   = "scheduler.url"
	RegionConfigKey                = "aws.region"
	ProfileConfigKey               = "aws.profile"

	//Config prefix
	awsCloudPrefix = "aws."

	//Defaults
	instanceImageDefaultsKey = "instance.image"
)

var configDefinitions = map[string]*Definition{
	autosyncConfigKey:              {help: "Automatically synchronize your cloud locally", defaultValue: "true", parseParamFn: parseBool},
	RegionConfigKey:                {help: "AWS region", parseParamFn: awsconfig.ParseRegion, stdinParamProviderFn: awsconfig.StdinRegionSelector, onUpdateFns: []onUpdateFunc{awsconfig.WarningChangeRegion, runSyncWithUpdatedRegion}},
	ProfileConfigKey:               {help: "AWS profile", defaultValue: "default"},
	"aws.infra.sync":               {help: "Sync AWS EC2/ELBv2 service (when empty: true)", defaultValue: "true", parseParamFn: parseBool},
	"aws.access.sync":              {help: "Sync AWS IAM service (when empty: true)", defaultValue: "true", parseParamFn: parseBool},
	"aws.storage.sync":             {help: "Sync AWS S3 service (when empty: true)", defaultValue: "true", parseParamFn: parseBool},
	"aws.storage.s3object.sync":    {help: "Sync AWS S3/s3object (when empty: true)", defaultValue: "false", parseParamFn: parseBool},
	"aws.notification.sync":        {help: "Sync AWS SNS service (when empty: true)", defaultValue: "true", parseParamFn: parseBool},
	"aws.monitoring.sync":          {help: "Sync AWS metric/alarm/cloudwatch service (when empty: true)", defaultValue: "false", parseParamFn: parseBool},
	"aws.lambda.sync":              {help: "Sync AWS Lambda service (when empty: true)", defaultValue: "true", parseParamFn: parseBool},
	"aws.messaging.sync":           {help: "Sync AWS SQS/SNS service (when empty: true)", defaultValue: "true", parseParamFn: parseBool},
	"aws.dns.sync":                 {help: "Sync AWS Route53 service (when empty: true)", defaultValue: "true", parseParamFn: parseBool},
	"aws.cdn.sync":                 {help: "Sync AWS CloudFront service (when empty: true)", defaultValue: "true", parseParamFn: parseBool},
	"aws.cloudformation.sync":      {help: "Sync AWS CloudFormation service (when empty: true)", defaultValue: "true", parseParamFn: parseBool},
	checkUpgradeFrequencyConfigKey: {help: "Upgrade check frequency (hours); a negative value disables check", defaultValue: "8", parseParamFn: parseInt},
	schedulerURL:                   {help: "URL used by awless CLI to interact with pre-installed awless-scheduler", defaultValue: "http://localhost:8082"},
}

var defaultsDefinitions = map[string]*Definition{
	"instance.type":          {defaultValue: "t2.micro", help: "AWS EC2 instance type", stdinParamProviderFn: awsconfig.StdinInstanceTypeSelector, parseParamFn: awsconfig.ParseInstanceType},
	instanceImageDefaultsKey: {help: "AWS EC2 AMI"},
	"instance.count":         {defaultValue: "1", help: "Number of instances to create on AWS EC2", parseParamFn: parseInt},
	"instance.timeout":       {defaultValue: "180", help: "Time to wait when checking instance states on AWS EC2", parseParamFn: parseInt},
	"volume.device":          {defaultValue: "/dev/sdh", help: "Device name to expose to an EC2 instance"},
	"elasticip.domain":       {defaultValue: "vpc", help: "The domain of elastic IP addresses (standard or vpc)"},
	"image.delete-snapshots": {defaultValue: "true", help: "Delete linked snapshots when deleting an image"},
	"database.type":          {defaultValue: "db.t2.micro", help: "Default RDS database type"},
}

var deprecated = map[string]string{
	"sync.auto": autosyncConfigKey,
	"region":    RegionConfigKey,
}

type onUpdateFunc func(interface{})

type Definition struct {
	help                 string
	parseParamFn         func(string) (interface{}, error)
	stdinParamProviderFn func() string
	onUpdateFns          []onUpdateFunc
	defaultValue         string
}

func LoadConfig() error {
	err := database.Execute(func(db *database.DB) (dberr error) {
		Config, dberr = db.GetConfigs(configDatabaseKey)
		if dberr != nil {
			return fmt.Errorf("config: load config: %s", dberr)
		}

		Defaults, dberr = db.GetConfigs(defaultsDatabaseKey)
		if dberr != nil {
			return fmt.Errorf("config: load defaults: %s", dberr)
		}
		return
	})

	return err
}

func DisplayConfig() string {
	return fmt.Sprintf("%s\n%s", displayConfig(), displayDefaults())
}

func InitConfig(fromEnv map[string]string) error {
	for k, v := range configDefinitions {
		val := v.defaultValue
		if vv, ok := fromEnv[k]; ok {
			val = vv
		}
		if err := Set(k, val); err != nil {
			return err
		}
	}
	for k, v := range defaultsDefinitions {
		val := v.defaultValue
		if vv, ok := fromEnv[k]; ok {
			val = vv
		}
		if err := Set(k, val); err != nil {
			return err
		}
	}
	return nil
}

func Set(key, value string) error {
	v, def, isConf, err := setVolatile(key, value)
	if err != nil {
		return err
	}
	var databaseKey string
	if isConf {
		databaseKey = configDatabaseKey
	} else {
		databaseKey = defaultsDatabaseKey
	}

	if err := database.Execute(func(db *database.DB) error {
		return db.SetConfig(databaseKey, key, v)
	}); err != nil {
		return err
	}

	if def != nil {
		for _, fn := range def.onUpdateFns {
			fn(v)
		}
	}

	return nil
}

func Unset(key string) error {
	var dbKey string
	if _, ok := Config[key]; ok {
		delete(Config, key)
		dbKey = configDatabaseKey
	}
	if _, ok := Defaults[key]; ok {
		delete(Defaults, key)
		dbKey = defaultsDatabaseKey
	}
	if dbKey != "" {
		if err := database.Execute(func(db *database.DB) error {
			return db.UnsetConfig(dbKey, key)
		}); err != nil {
			return fmt.Errorf("unset config: %s", err)
		}
	}

	return nil
}

func Get(key string) (interface{}, bool) {
	if v, ok := Config[key]; ok {
		return v, ok
	}
	v, ok := Defaults[key]
	return v, ok
}

func SetVolatile(key, value string) error {
	_, _, _, err := setVolatile(key, value)
	return err
}

func InteractiveSet(key string) error {
	var val string
	if def, ok := configDefinitions[key]; ok && def.stdinParamProviderFn != nil {
		val = def.stdinParamProviderFn()
	} else if def, ok := defaultsDefinitions[key]; ok && def.stdinParamProviderFn != nil {
		val = def.stdinParamProviderFn()
	} else {
		val = defaultStdinParamProvider()
	}
	return Set(key, val)
}

func parseBool(i string) (interface{}, error) {
	b, err := strconv.ParseBool(i)
	if err != nil {
		return b, fmt.Errorf("invalid value, expected a boolean, got '%s'", i)
	}
	return b, nil
}

func parseInt(a string) (interface{}, error) {
	i, err := strconv.Atoi(a)
	if err != nil {
		return i, fmt.Errorf("invalid value, expected an int, got '%s'", a)
	}
	return i, nil
}

func defaultParser(value string) (interface{}, error) {
	if num, err := strconv.Atoi(value); err == nil {
		return num, nil
	}
	if b, err := strconv.ParseBool(value); err == nil {
		return b, nil
	}
	return value, nil
}

func defaultStdinParamProvider() string {
	var value string
	for value == "" {
		fmt.Print("Value ? > ")
		fmt.Scan(&value)
	}
	return value
}

func setVolatile(key, value string) (interface{}, *Definition, bool, error) {
	var isConf bool
	confDef, confOk := configDefinitions[key]
	defDef, defOk := defaultsDefinitions[key]
	var def *Definition
	switch {
	case confOk && defOk:
		return nil, def, isConf, fmt.Errorf("%s can not be in both config and defaults", key)
	case confOk:
		isConf = true
		def = confDef
	case defOk:
		def = defDef
	default:
		if strings.Contains(key, awsCloudPrefix) {
			isConf = true
		}
	}
	var v interface{}
	var err error
	if def != nil && def.parseParamFn != nil {
		if v, err = def.parseParamFn(value); err != nil {
			return nil, def, isConf, err
		}
	} else {
		if v, err = defaultParser(value); err != nil {
			return nil, def, isConf, err
		}
	}
	if isConf {
		Config[key] = v
	} else {
		Defaults[key] = v
	}
	return v, def, isConf, nil
}

func displayConfig() string {
	var b bytes.Buffer
	b.WriteString("# Config parameters\n")
	t := tabwriter.NewWriter(&b, 0, 0, 3, ' ', 0)
	var keys []string
	for k := range Config {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	for _, k := range keys {
		fmt.Fprintf(t, "\t%s:\t%v\t(%[2]T)", k, Config[k])
		if def, ok := configDefinitions[k]; ok && def.help != "" {
			fmt.Fprintf(t, "\t# %s\n", def.help)
		} else {
			fmt.Fprintln(t)
		}
	}
	for k := range configDefinitions {
		if _, ok := Config[k]; !ok {
			fmt.Fprintf(t, "\t%s:\t\t", k)
			if def, ok := configDefinitions[k]; ok && def.help != "" {
				fmt.Fprintf(t, "\t# %s\n", def.help)
			} else {
				fmt.Fprintln(t)
			}
		}
	}
	t.Flush()
	return b.String()
}

func displayDefaults() string {
	var b bytes.Buffer
	b.WriteString("# Template defaults\n")
	b.WriteString("   ## Predefined\n")
	t := tabwriter.NewWriter(&b, 0, 0, 3, ' ', 0)
	var keys []string
	for k := range Defaults {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	for _, k := range keys {
		if def, ok := defaultsDefinitions[k]; ok {
			if def.help != "" {
				fmt.Fprintf(t, "\t%s:\t%v\t(%[2]T)\t# %s\n", k, Defaults[k], def.help)
			} else {
				fmt.Fprintf(t, "\t%s:\t%v\t(%[2]T)\n", k, Defaults[k])
			}
		}
	}
	for k := range defaultsDefinitions {
		if _, ok := Defaults[k]; !ok {
			fmt.Fprintf(t, "\t%s:\t \t(UNSET)", k)
			if def, ok := defaultsDefinitions[k]; ok && def.help != "" {
				fmt.Fprintf(t, "\t# %s\n", def.help)
			} else {
				fmt.Fprintln(t)
			}
		}
	}
	t.Flush()
	count := 0
	t = tabwriter.NewWriter(&b, 0, 0, 3, ' ', 0)
	for _, k := range keys {
		if _, ok := defaultsDefinitions[k]; !ok {
			count++
			fmt.Fprintf(t, "\t%s:\t%v\t(%[2]T)", k, Defaults[k])
			if newKey, ok := deprecated[k]; ok {
				fmt.Fprintf(t, "\t# DEPRECATED, update with `awless config set %s` `awless config unset %s`", newKey, k)
			}
			fmt.Fprintln(t)
		}
	}
	if count > 0 {
		b.WriteString("\n   ## User defined\n")
		t.Flush()
	}
	return b.String()
}

func runSyncWithUpdatedRegion(i interface{}) {
	if !GetAutosync() {
		return
	}

	if !awsconfig.IsValidRegion(fmt.Sprint(i)) {
		return
	}

	fmt.Println("Syncing new region...")
	aws.InitServices(GetConfigWithPrefix("aws."), logger.DiscardLogger)

	var services []cloud.Service
	for _, srv := range cloud.ServiceRegistry {
		services = append(services, srv)
	}

	sync.NewSyncer().Sync(services...)
}
<commit_msg>Default: security group protocol is 'tcp' by default<commit_after>package config

import (
	"bytes"
	"fmt"
	"sort"
	"strconv"
	"strings"
	"text/tabwriter"

	"github.com/wallix/awless/aws"
	"github.com/wallix/awless/aws/config"
	"github.com/wallix/awless/cloud"
	"github.com/wallix/awless/database"
	"github.com/wallix/awless/logger"
	"github.com/wallix/awless/sync"
)

var (
	Config   = map[string]interface{}{}
	Defaults = map[string]interface{}{}
)

const (
	configDatabaseKey   = "userconfig"
	defaultsDatabaseKey = "defaults"

	//Config
	autosyncConfigKey              = "autosync"
	checkUpgradeFrequencyConfigKey = "upgrade.checkfrequency"
	schedulerURL                   = "scheduler.url"
	RegionConfigKey                = "aws.region"
	ProfileConfigKey               = "aws.profile"

	//Config prefix
	awsCloudPrefix = "aws."

	//Defaults
	instanceImageDefaultsKey = "instance.image"
)

var configDefinitions = map[string]*Definition{
	autosyncConfigKey:              {help: "Automatically synchronize your cloud locally", defaultValue: "true", parseParamFn: parseBool},
	RegionConfigKey:                {help: "AWS region", parseParamFn: awsconfig.ParseRegion, stdinParamProviderFn: awsconfig.StdinRegionSelector, onUpdateFns: []onUpdateFunc{awsconfig.WarningChangeRegion, runSyncWithUpdatedRegion}},
	ProfileConfigKey:               {help: "AWS profile", defaultValue: "default"},
	"aws.infra.sync":               {help: "Sync AWS EC2/ELBv2 service (when empty: true)", defaultValue: "true", parseParamFn: parseBool},
	"aws.access.sync":              {help: "Sync AWS IAM service (when empty: true)", defaultValue: "true", parseParamFn: parseBool},
	"aws.storage.sync":             {help: "Sync AWS S3 service (when empty: true)", defaultValue: "true", parseParamFn: parseBool},
	"aws.storage.s3object.sync":    {help: "Sync AWS S3/s3object (when empty: true)", defaultValue: "false", parseParamFn: parseBool},
	"aws.notification.sync":        {help: "Sync AWS SNS service (when empty: true)", defaultValue: "true", parseParamFn: parseBool},
	"aws.monitoring.sync":          {help: "Sync AWS metric/alarm/cloudwatch service (when empty: true)", defaultValue: "false", parseParamFn: parseBool},
	"aws.lambda.sync":              {help: "Sync AWS Lambda service (when empty: true)", defaultValue: "true", parseParamFn: parseBool},
	"aws.messaging.sync":           {help: "Sync AWS SQS/SNS service (when empty: true)", defaultValue: "true", parseParamFn: parseBool},
	"aws.dns.sync":                 {help: "Sync AWS Route53 service (when empty: true)", defaultValue: "true", parseParamFn: parseBool},
	"aws.cdn.sync":                 {help: "Sync AWS CloudFront service (when empty: true)", defaultValue: "true", parseParamFn: parseBool},
	"aws.cloudformation.sync":      {help: "Sync AWS CloudFormation service (when empty: true)", defaultValue: "true", parseParamFn: parseBool},
	checkUpgradeFrequencyConfigKey: {help: "Upgrade check frequency (hours); a negative value disables check", defaultValue: "8", parseParamFn: parseInt},
	schedulerURL:                   {help: "URL used by awless CLI to interact with pre-installed awless-scheduler", defaultValue: "http://localhost:8082"},
}

var defaultsDefinitions = map[string]*Definition{
	"instance.type":          {defaultValue: "t2.micro", help: "AWS EC2 instance type", stdinParamProviderFn: awsconfig.StdinInstanceTypeSelector, parseParamFn: awsconfig.ParseInstanceType},
	instanceImageDefaultsKey: {help: "AWS EC2 AMI"},
	"instance.count":         {defaultValue: "1", help: "Number of instances to create on AWS EC2", parseParamFn: parseInt},
	"instance.timeout":       {defaultValue: "180", help: "Time to wait when checking instance states on AWS EC2", parseParamFn: parseInt},
	"securitygroup.protocol": {defaultValue: "tcp", help: "The IP protocol to authorize on the security group"},
	"volume.device":          {defaultValue: "/dev/sdh", help: "Device name to expose to an EC2 instance"},
	"elasticip.domain":       {defaultValue: "vpc", help: "The domain of elastic IP addresses (standard or vpc)"},
	"image.delete-snapshots": {defaultValue: "true", help: "Delete linked snapshots when deleting an image"},
	"database.type":          {defaultValue: "db.t2.micro", help: "Default RDS database type"},
}

var deprecated = map[string]string{
	"sync.auto": autosyncConfigKey,
	"region":    RegionConfigKey,
}

type onUpdateFunc func(interface{})

type Definition struct {
	help                 string
	parseParamFn         func(string) (interface{}, error)
	stdinParamProviderFn func() string
	onUpdateFns          []onUpdateFunc
	defaultValue         string
}

func LoadConfig() error {
	err := database.Execute(func(db *database.DB) (dberr error) {
		Config, dberr = db.GetConfigs(configDatabaseKey)
		if dberr != nil {
			return fmt.Errorf("config: load config: %s", dberr)
		}

		Defaults, dberr = db.GetConfigs(defaultsDatabaseKey)
		if dberr != nil {
			return fmt.Errorf("config: load defaults: %s", dberr)
		}
		return
	})

	return err
}

func DisplayConfig() string {
	return fmt.Sprintf("%s\n%s", displayConfig(), displayDefaults())
}

func InitConfig(fromEnv map[string]string) error {
	for k, v := range configDefinitions {
		val := v.defaultValue
		if vv, ok := fromEnv[k]; ok {
			val = vv
		}
		if err := Set(k, val); err != nil {
			return err
		}
	}
	for k, v := range defaultsDefinitions {
		val := v.defaultValue
		if vv, ok := fromEnv[k]; ok {
			val = vv
		}
		if err := Set(k, val); err != nil {
			return err
		}
	}
	return nil
}

func Set(key, value string) error {
	v, def, isConf, err := setVolatile(key, value)
	if err != nil {
		return err
	}
	var databaseKey string
	if isConf {
		databaseKey = configDatabaseKey
	} else {
		databaseKey = defaultsDatabaseKey
	}

	if err := database.Execute(func(db *database.DB) error {
		return db.SetConfig(databaseKey, key, v)
	}); err != nil {
		return err
	}

	if def != nil {
		for _, fn := range def.onUpdateFns {
			fn(v)
		}
	}

	return nil
}

func Unset(key string) error {
	var dbKey string
	if _, ok := Config[key]; ok {
		delete(Config, key)
		dbKey = configDatabaseKey
	}
	if _, ok := Defaults[key]; ok {
		delete(Defaults, key)
		dbKey = defaultsDatabaseKey
	}
	if dbKey != "" {
		if err := database.Execute(func(db *database.DB) error {
			return db.UnsetConfig(dbKey, key)
		}); err != nil {
			return fmt.Errorf("unset config: %s", err)
		}
	}

	return nil
}

func Get(key string) (interface{}, bool) {
	if v, ok := Config[key]; ok {
		return v, ok
	}
	v, ok := Defaults[key]
	return v, ok
}

func SetVolatile(key, value string) error {
	_, _, _, err := setVolatile(key, value)
	return err
}

func InteractiveSet(key string) error {
	var val string
	if def, ok := configDefinitions[key]; ok && def.stdinParamProviderFn != nil {
		val = def.stdinParamProviderFn()
	} else if def, ok := defaultsDefinitions[key]; ok && def.stdinParamProviderFn != nil {
		val = def.stdinParamProviderFn()
	} else {
		val = defaultStdinParamProvider()
	}
	return Set(key, val)
}

func parseBool(i string) (interface{}, error) {
	b, err := strconv.ParseBool(i)
	if err != nil {
		return b, fmt.Errorf("invalid value, expected a boolean, got '%s'", i)
	}
	return b, nil
}

func parseInt(a string) (interface{}, error) {
	i, err := strconv.Atoi(a)
	if err != nil {
		return i, fmt.Errorf("invalid value, expected an int, got '%s'", a)
	}
	return i, nil
}

func defaultParser(value string) (interface{}, error) {
	if num, err := strconv.Atoi(value); err == nil {
		return num, nil
	}
	if b, err := strconv.ParseBool(value); err == nil {
		return b, nil
	}
	return value, nil
}

func defaultStdinParamProvider() string {
	var value string
	for value == "" {
		fmt.Print("Value ? > ")
		fmt.Scan(&value)
	}
	return value
}

func setVolatile(key, value string) (interface{}, *Definition, bool, error) {
	var isConf bool
	confDef, confOk := configDefinitions[key]
	defDef, defOk := defaultsDefinitions[key]
	var def *Definition
	switch {
	case confOk && defOk:
		return nil, def, isConf, fmt.Errorf("%s can not be in both config and defaults", key)
	case confOk:
		isConf = true
		def = confDef
	case defOk:
		def = defDef
	default:
		if strings.Contains(key, awsCloudPrefix) {
			isConf = true
		}
	}
	var v interface{}
	var err error
	if def != nil && def.parseParamFn != nil {
		if v, err = def.parseParamFn(value); err != nil {
			return nil, def, isConf, err
		}
	} else {
		if v, err = defaultParser(value); err != nil {
			return nil, def, isConf, err
		}
	}
	if isConf {
		Config[key] = v
	} else {
		Defaults[key] = v
	}
	return v, def, isConf, nil
}

func displayConfig() string {
	var b bytes.Buffer
	b.WriteString("# Config parameters\n")
	t := tabwriter.NewWriter(&b, 0, 0, 3, ' ', 0)
	var keys []string
	for k := range Config {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	for _, k := range keys {
		fmt.Fprintf(t, "\t%s:\t%v\t(%[2]T)", k, Config[k])
		if def, ok := configDefinitions[k]; ok && def.help != "" {
			fmt.Fprintf(t, "\t# %s\n", def.help)
		} else {
			fmt.Fprintln(t)
		}
	}
	for k := range configDefinitions {
		if _, ok := Config[k]; !ok {
			fmt.Fprintf(t, "\t%s:\t\t", k)
			if def, ok := configDefinitions[k]; ok && def.help != "" {
				fmt.Fprintf(t, "\t# %s\n", def.help)
			} else {
				fmt.Fprintln(t)
			}
		}
	}
	t.Flush()
	return b.String()
}

func displayDefaults() string {
	var b bytes.Buffer
	b.WriteString("# Template defaults\n")
	b.WriteString("   ## Predefined\n")
	t := tabwriter.NewWriter(&b, 0, 0, 3, ' ', 0)
	var keys []string
	for k := range Defaults {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	for _, k := range keys {
		if def, ok := defaultsDefinitions[k]; ok {
			if def.help != "" {
				fmt.Fprintf(t, "\t%s:\t%v\t(%[2]T)\t# %s\n", k, Defaults[k], def.help)
			} else {
				fmt.Fprintf(t, "\t%s:\t%v\t(%[2]T)\n", k, Defaults[k])
			}
		}
	}
	for k := range defaultsDefinitions {
		if _, ok := Defaults[k]; !ok {
			fmt.Fprintf(t, "\t%s:\t \t(UNSET)", k)
			if def, ok := defaultsDefinitions[k]; ok && def.help != "" {
				fmt.Fprintf(t, "\t# %s\n", def.help)
			} else {
				fmt.Fprintln(t)
			}
		}
	}
	t.Flush()
	count := 0
	t = tabwriter.NewWriter(&b, 0, 0, 3, ' ', 0)
	for _, k := range keys {
		if _, ok := defaultsDefinitions[k]; !ok {
			count++
			fmt.Fprintf(t, "\t%s:\t%v\t(%[2]T)", k, Defaults[k])
			if newKey, ok := deprecated[k]; ok {
				fmt.Fprintf(t, "\t# DEPRECATED, update with `awless config set %s` `awless config unset %s`", newKey, k)
			}
			fmt.Fprintln(t)
		}
	}
	if count > 0 {
		b.WriteString("\n   ## User defined\n")
		t.Flush()
	}
	return b.String()
}

func runSyncWithUpdatedRegion(i interface{}) {
	if !GetAutosync() {
		return
	}

	if !awsconfig.IsValidRegion(fmt.Sprint(i)) {
		return
	}

	fmt.Println("Syncing new region...")
	aws.InitServices(GetConfigWithPrefix("aws."), logger.DiscardLogger)

	var services []cloud.Service
	for _, srv := range cloud.ServiceRegistry {
		services = append(services, srv)
	}

	sync.NewSyncer().Sync(services...)
}
<|endoftext|>


<commit_before>package config

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

const (
	// File is the default name of the JSON file where the config written.
	// The user can pass an alternate filename when using the CLI.
	File = ".exercism.json"
	// LegacyFile is the name of the original config file.
	// It is a misnomer, since the config was in json, not go.
	LegacyFile = ".exercism.go"
	// Host is the default hostname for fetching problems and submitting exercises.
	// TODO: We need to operate against two hosts (one for problems and one for submissions),
	// or define a proxy that both APIs can go through.
	Host = "http://exercism.io"

	// DirExercises is the default name of the directory for active users.
	DirExercises = "exercism"
)

var (
	errHomeNotFound = errors.New("unable to locate home directory")
)

// Config represents the settings for particular user.
// This defines both the auth for talking to the API, as well as
// where to put problems that get downloaded.
type Config struct {
	APIKey   string `json:"apiKey"`
	Dir      string `json:"exercismDirectory"`
	Hostname string `json:"hostname"`
	home     string // cache user's home directory
	path     string // path to config file
}

// New returns a new config.
// It will attempt to set defaults where no value is passed in.
func New(key, host, dir string) (*Config, error) {
	c := &Config{
		APIKey:   key,
		Hostname: host,
		Dir:      dir,
	}
	return c.configure()
}

func (c *Config) configure() (*Config, error) {
	c.sanitize()

	if c.Hostname == "" {
		c.Hostname = Host
	}

	dir, err := c.homeDir()
	if err != nil {
		return c, err
	}
	c.path = fmt.Sprintf("%s/%s", dir, File)

	if c.Dir == "" {
		c.Dir = fmt.Sprintf("%s/%s", dir, DirExercises)
	}
	c.Dir = strings.Replace(c.Dir, "~/", fmt.Sprintf("%s/", dir), 1)
	return c, nil
}

// SavePath allows the user to customize the location of the JSON file.
func (c *Config) SavePath(path string) {
	if path != "" {
		c.path = path
	}
}

func (c *Config) File() string {
	return c.path
}

func (c *Config) Write() error {
	// truncates existing file if it exists
	f, err := os.Create(c.path)
	if err != nil {
		return err
	}
	defer f.Close()

	err = c.Encode(f)
	if err != nil {
		return err
	}
	return nil
}

// ToFile writes a Config to a JSON file.
func (c *Config) ToFile(path string) error {
	path = WithDefaultPath(path)
	f, err := os.Create(path) // truncates existing file if it exists
	if err != nil {
		return err
	}
	defer f.Close()

	c.path = path
	err = c.Encode(f)
	if err != nil {
		return err
	}
	return nil
}

// FromFile loads a Config object from a JSON file.
func FromFile(path string) (*Config, error) {
	path = WithDefaultPath(path)
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	return Decode(f)
}

// Encode writes a Config into JSON format.
func (c *Config) Encode(w io.Writer) error {
	c.sanitize()
	e := json.NewEncoder(w)
	return e.Encode(c)
}

// Decode loads a Config from JSON format.
func Decode(r io.Reader) (*Config, error) {
	d := json.NewDecoder(r)
	var c *Config
	err := d.Decode(&c)
	if err != nil {
		return c, err
	}
	c.configure()
	return c, nil
}

// Path returns the path to the config file.
func Path(path string) (string, error) {
	if path != "" {
		return path, nil
	}

	dir, err := Home()
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("%s/%s", dir, File), nil
}

// WithDefaultPath returns the default configuration path if none is provided.
func WithDefaultPath(p string) string {
	if p == "" {
		return fmt.Sprintf("%s/%s", HomeDir(), File)
	}

	return p
}

// See: http://stackoverflow.com/questions/7922270/obtain-users-home-directory
// we can't cross compile using cgo and use user.Current()
func (c *Config) homeDir() (string, error) {
	if c.home != "" {
		return c.home, nil
	}
	return Home()
}

// HomeDir returns the user's canonical home directory.
// See: http://stackoverflow.com/questions/7922270/obtain-users-home-directory
// we can't cross compile using cgo and use user.Current()
func Home() (string, error) {
	var dir string
	if runtime.GOOS == "windows" {
		dir = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
		if dir == "" {
			dir = os.Getenv("USERPROFILE")
		}
	} else {
		dir = os.Getenv("HOME")
	}

	if dir == "" {
		return dir, errHomeNotFound
	}
	return dir, nil
}

// HomeDir returns the user's canonical home directory.
// See: http://stackoverflow.com/questions/7922270/obtain-users-home-directory
// we can't cross compile using cgo and use user.Current()
// FIXME: This one will go away. Refactoring in progress.
func HomeDir() string {
	var dir string
	if runtime.GOOS == "windows" {
		dir = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
		if dir == "" {
			dir = os.Getenv("USERPROFILE")
		}
	} else {
		dir = os.Getenv("HOME")
	}

	if dir == "" {
		panic("unable to determine the location of your home directory")
	}

	return dir
}

// Demo is a default configuration for unauthenticated users.
func Demo() *Config {
	return &Config{
		Hostname: Host,
		APIKey:   "",
		Dir:      DefaultAssignmentPath(),
	}
}

// DefaultAssignmentPath returns the absolute path of the default exercism directory
func DefaultAssignmentPath() string {
	return filepath.Join(HomeDir(), DirExercises)
}

// ReplaceTilde replaces the short-hand home path with the absolute path.
func ReplaceTilde(path string) string {
	return strings.Replace(path, "~/", HomeDir()+"/", 1)
}

func (c *Config) sanitize() {
	c.APIKey = strings.TrimSpace(c.APIKey)
	c.Dir = strings.TrimSpace(c.Dir)
	c.Hostname = strings.TrimSpace(c.Hostname)
}
<commit_msg>Clean up config<commit_after>package config

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

const (
	// File is the default name of the JSON file where the config written.
	// The user can pass an alternate filename when using the CLI.
	File = ".exercism.json"
	// LegacyFile is the name of the original config file.
	// It is a misnomer, since the config was in json, not go.
	LegacyFile = ".exercism.go"
	// Host is the default hostname for fetching problems and submitting exercises.
	// TODO: We need to operate against two hosts (one for problems and one for submissions),
	// or define a proxy that both APIs can go through.
	Host = "http://exercism.io"

	// DirExercises is the default name of the directory for active users.
	DirExercises = "exercism"
)

var (
	errHomeNotFound = errors.New("unable to locate home directory")
)

// Config represents the settings for particular user.
// This defines both the auth for talking to the API, as well as
// where to put problems that get downloaded.
type Config struct {
	APIKey   string `json:"apiKey"`
	Dir      string `json:"exercismDirectory"`
	Hostname string `json:"hostname"`
	home     string // cache user's home directory
	path     string // path to config file
}

// New returns a new config.
// It will attempt to set defaults where no value is passed in.
func New(key, host, dir string) (*Config, error) {
	c := &Config{
		APIKey:   key,
		Hostname: host,
		Dir:      dir,
	}
	return c.configure()
}

func (c *Config) configure() (*Config, error) {
	c.sanitize()

	if c.Hostname == "" {
		c.Hostname = Host
	}

	dir, err := c.homeDir()
	if err != nil {
		return c, err
	}
	c.path = fmt.Sprintf("%s/%s", dir, File)

	if c.Dir == "" {
		c.Dir = fmt.Sprintf("%s/%s", dir, DirExercises)
	}
	c.Dir = strings.Replace(c.Dir, "~/", fmt.Sprintf("%s/", dir), 1)
	return c, nil
}

// SavePath allows the user to customize the location of the JSON file.
func (c *Config) SavePath(path string) {
	if path != "" {
		c.path = path
	}
}

func (c *Config) File() string {
	return c.path
}

func (c *Config) Write() error {
	// truncates existing file if it exists
	f, err := os.Create(c.path)
	if err != nil {
		return err
	}
	defer f.Close()

	err = c.Encode(f)
	if err != nil {
		return err
	}
	return nil
}

// ToFile writes a Config to a JSON file.
func (c *Config) ToFile(path string) error {
	path = WithDefaultPath(path)
	f, err := os.Create(path) // truncates existing file if it exists
	if err != nil {
		return err
	}
	defer f.Close()

	c.path = path
	err = c.Encode(f)
	if err != nil {
		return err
	}
	return nil
}

// FromFile loads a Config object from a JSON file.
func FromFile(path string) (*Config, error) {
	path = WithDefaultPath(path)
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	return Decode(f)
}

// Encode writes a Config into JSON format.
func (c *Config) Encode(w io.Writer) error {
	c.sanitize()
	e := json.NewEncoder(w)
	return e.Encode(c)
}

// Decode loads a Config from JSON format.
func Decode(r io.Reader) (*Config, error) {
	d := json.NewDecoder(r)
	var c *Config
	err := d.Decode(&c)
	if err != nil {
		return c, err
	}
	c.configure()
	return c, nil
}

// Path returns the path to the config file.
func Path(path string) (string, error) {
	if path != "" {
		return path, nil
	}

	dir, err := Home()
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("%s/%s", dir, File), nil
}

// WithDefaultPath returns the default configuration path if none is provided.
func WithDefaultPath(p string) string {
	if p == "" {
		return fmt.Sprintf("%s/%s", HomeDir(), File)
	}

	return p
}

// See: http://stackoverflow.com/questions/7922270/obtain-users-home-directory
// we can't cross compile using cgo and use user.Current()
func (c *Config) homeDir() (string, error) {
	if c.home != "" {
		return c.home, nil
	}
	return Home()
}

// Home returns the user's canonical home directory.
// See: http://stackoverflow.com/questions/7922270/obtain-users-home-directory
// we can't cross compile using cgo and use user.Current()
func Home() (string, error) {
	var dir string
	if runtime.GOOS == "windows" {
		dir = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
		if dir == "" {
			dir = os.Getenv("USERPROFILE")
		}
	} else {
		dir = os.Getenv("HOME")
	}

	if dir == "" {
		return dir, errHomeNotFound
	}
	return dir, nil
}

// HomeDir returns the user's canonical home directory.
// FIXME: This one will go away. Refactoring in progress.
func HomeDir() string {
	dir, err := Home()
	if err != nil {
		panic("unable to determine the location of your home directory")
	}
	return dir
}

// Demo is a default configuration for unauthenticated users.
func Demo() *Config {
	return &Config{
		Hostname: Host,
		APIKey:   "",
		Dir:      DefaultAssignmentPath(),
	}
}

// DefaultAssignmentPath returns the absolute path of the default exercism directory
func DefaultAssignmentPath() string {
	return filepath.Join(HomeDir(), DirExercises)
}

// ReplaceTilde replaces the short-hand home path with the absolute path.
func ReplaceTilde(path string) string {
	return strings.Replace(path, "~/", HomeDir()+"/", 1)
}

func (c *Config) sanitize() {
	c.APIKey = strings.TrimSpace(c.APIKey)
	c.Dir = strings.TrimSpace(c.Dir)
	c.Hostname = strings.TrimSpace(c.Hostname)
}
<|endoftext|>


<commit_before>package config

import (
	"github.com/mitchellh/go-homedir"
	"path"
	"os"
	"github.com/BurntSushi/toml"
	"github.com/matthistuff/amazon/helper"
	"time"
	"fmt"
	"strings"
)

type Config struct {
	Version     string
	Locale      string
	ResultCache map[string]map[string]string
	Carts       map[string]*Cart
}

type Cart struct {
	Name    string
	Created time.Time
	CartId  string
	HMAC    string
}

func (c *Config) Flush() {
	file, _ := os.Create(confPath)
	encoder := toml.NewEncoder(file)

	if err := encoder.Encode(c); err != nil {
		panic(err)
	}
}

func (c Config) FromCache(cache string, key string) (string, bool) {
	cached, exists := c.ResultCache[cache]

	if !exists {
		return "", exists
	}

	cachedValue, exists := cached[key]

	return cachedValue, exists
}

func (c Config) CartNameFromCache(indexOrName string) string {
	cached, exists := c.FromCache("Carts", indexOrName)

	if !exists {
		if indexOrName == "" {
			return "default"
		}

		return indexOrName
	}

	return cached
}

func (c Config) ASINFromCache(cache string, item string) (string, bool) {
	if helper.IsASIN(item) {
		return item, true
	}

	return c.FromCache(cache, item)
}

func (c Config) CartItemIdFromCache(cartName string, item string) (string, bool) {
	if helper.IsCartItemId(item) {
		return item, true
	}

	return c.FromCache(fmt.Sprintf("Cart%sItems", strings.Title(cartName)), item)
}

func (c Config) NumericFromCache(cache string, index string) string {
	if helper.IsNumeric(index) {
		value, exists := c.FromCache(cache, index)

		if exists {
			return value
		}
	}

	return index
}

var (
	confPath string
	conf *Config
)

func LoadConfig() error {
	err := ensureConfig()

	if err != nil {
		return err
	}

	_, err = toml.DecodeFile(confPath, &conf)

	if err != nil {
		return err
	}

	return nil
}

func ensureConfig() error {
	home, err := homedir.Dir()

	if err == nil {
		confPath = path.Join(home, ".amazon-cli")

		if _, err := os.Stat(confPath); os.IsNotExist(err) {
			conf = &Config{
				Version: "0.0.1",
				Locale: "US",
				ResultCache: make(map[string]map[string]string),
				Carts: make(map[string]*Cart),
			}

			conf.Flush()
		}
	}

	return err
}

func GetConfig() *Config {
	return conf
}<commit_msg>version 0.1.0<commit_after>package config

import (
	"github.com/mitchellh/go-homedir"
	"path"
	"os"
	"github.com/BurntSushi/toml"
	"github.com/matthistuff/amazon/helper"
	"time"
	"fmt"
	"strings"
)

type Config struct {
	Version     string
	Locale      string
	ResultCache map[string]map[string]string
	Carts       map[string]*Cart
}

type Cart struct {
	Name    string
	Created time.Time
	CartId  string
	HMAC    string
}

func (c *Config) Flush() {
	file, _ := os.Create(confPath)
	encoder := toml.NewEncoder(file)

	if err := encoder.Encode(c); err != nil {
		panic(err)
	}
}

func (c Config) FromCache(cache string, key string) (string, bool) {
	cached, exists := c.ResultCache[cache]

	if !exists {
		return "", exists
	}

	cachedValue, exists := cached[key]

	return cachedValue, exists
}

func (c Config) CartNameFromCache(indexOrName string) string {
	cached, exists := c.FromCache("Carts", indexOrName)

	if !exists {
		if indexOrName == "" {
			return "default"
		}

		return indexOrName
	}

	return cached
}

func (c Config) ASINFromCache(cache string, item string) (string, bool) {
	if helper.IsASIN(item) {
		return item, true
	}

	return c.FromCache(cache, item)
}

func (c Config) CartItemIdFromCache(cartName string, item string) (string, bool) {
	if helper.IsCartItemId(item) {
		return item, true
	}

	return c.FromCache(fmt.Sprintf("Cart%sItems", strings.Title(cartName)), item)
}

func (c Config) NumericFromCache(cache string, index string) string {
	if helper.IsNumeric(index) {
		value, exists := c.FromCache(cache, index)

		if exists {
			return value
		}
	}

	return index
}

var (
	confPath string
	conf *Config
)

func LoadConfig() error {
	err := ensureConfig()

	if err != nil {
		return err
	}

	_, err = toml.DecodeFile(confPath, &conf)

	if err != nil {
		return err
	}

	return nil
}

func ensureConfig() error {
	home, err := homedir.Dir()

	if err == nil {
		confPath = path.Join(home, ".amazon-cli")

		if _, err := os.Stat(confPath); os.IsNotExist(err) {
			conf = &Config{
				Version: "0.1.0",
				Locale: "US",
				ResultCache: make(map[string]map[string]string),
				Carts: make(map[string]*Cart),
			}

			conf.Flush()
		}
	}

	return err
}

func GetConfig() *Config {
	return conf
}<|endoftext|>


<commit_before>package config

import (
	"encoding/json"
	"github.com/aphistic/gomol"
	"io/ioutil"
)

type Configuration struct {
	Category string
	Path     string
}

var Configs []Configuration

func Load() {
	configFile, err := ioutil.ReadFile("config.json")
	if err != nil {
		gomol.Err(err.Error())
		panic(err)
	}

	if err := json.Unmarshal(configFile, &Configs); err != nil {
		gomol.Err(err.Error())
		panic(err)
	}
}
<commit_msg>updated config load to log Fatal rather than Error.<commit_after>package config

import (
	"encoding/json"
	"github.com/aphistic/gomol"
	"io/ioutil"
)

type Configuration struct {
	Category string
	Path     string
}

var Configs []Configuration

func Load() {
	configFile, err := ioutil.ReadFile("config.json")
	if err != nil {
		gomol.Err(err.Error())
		panic(err)
	}

	if err := json.Unmarshal(configFile, &Configs); err != nil {
		gomol.Fatal(err.Error())
		panic(err)
	}
}
<|endoftext|>


<commit_before>package config

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"

	"github.com/erroneousboat/termui"
)

const (
	NotifyAll     = "all"
	NotifyMention = "mention"
)

// Config is the definition of a Config struct
type Config struct {
	SlackToken   string                `json:"slack_token"`
	Notify       string                `json:"notify"`
	Emoji        bool                  `json:"emoji"`
	SidebarWidth int                   `json:"sidebar_width"`
	MainWidth    int                   `json:"-"`
	KeyMap       map[string]keyMapping `json:"key_map"`
	Theme        Theme                 `json:"theme"`
}

type keyMapping map[string]string

// NewConfig loads the config file and returns a Config struct
func NewConfig(filepath string) (*Config, error) {
	cfg := getDefaultConfig()

	file, err := os.Open(filepath)
	if err != nil {
		return &cfg, fmt.Errorf("couldn't find the slack-term config file: %v", err)
	}

	if err := json.NewDecoder(file).Decode(&cfg); err != nil {
		return &cfg, fmt.Errorf("the slack-term config file isn't valid json: %v", err)
	}

	if cfg.SidebarWidth < 1 || cfg.SidebarWidth > 11 {
		return &cfg, errors.New("please specify the 'sidebar_width' between 1 and 11")
	}

	cfg.MainWidth = 12 - cfg.SidebarWidth

	switch cfg.Notify {
	case NotifyAll, NotifyMention, "":
		break
	default:
		return &cfg, fmt.Errorf("unsupported setting for notify: %s", cfg.Notify)
	}

	termui.ColorMap = map[string]termui.Attribute{
		"fg":        termui.StringToAttribute(cfg.Theme.View.Fg),
		"bg":        termui.StringToAttribute(cfg.Theme.View.Bg),
		"border.fg": termui.StringToAttribute(cfg.Theme.View.BorderFg),
		"border.bg": termui.StringToAttribute(cfg.Theme.View.BorderBg),
		"label.fg":  termui.StringToAttribute(cfg.Theme.View.LabelFg),
		"label.bg":  termui.StringToAttribute(cfg.Theme.View.LabelBg),
	}

	return &cfg, nil
}

func getDefaultConfig() Config {
	return Config{
		SidebarWidth: 1,
		MainWidth:    11,
		Notify:       "",
		Emoji:        false,
		KeyMap: map[string]keyMapping{
			"command": {
				"i":          "mode-insert",
				"/":          "mode-search",
				"k":          "channel-up",
				"j":          "channel-down",
				"g":          "channel-top",
				"G":          "channel-bottom",
				"<previous>": "chat-up",
				"C-b":        "chat-up",
				"C-u":        "chat-up",
				"<next>":     "chat-down",
				"C-f":        "chat-down",
				"C-d":        "chat-down",
				"n":          "channel-search-next",
				"N":          "channel-search-prev",
				"'":          "channel-jump",
				"q":          "quit",
				"<f1>":       "help",
			},
			"insert": {
				"<left>":      "cursor-left",
				"<right>":     "cursor-right",
				"<enter>":     "send",
				"<escape>":    "mode-command",
				"<backspace>": "backspace",
				"C-8":         "backspace",
				"<delete>":    "delete",
				"<space>":     "space",
			},
			"search": {
				"<left>":      "cursor-left",
				"<right>":     "cursor-right",
				"<escape>":    "clear-input",
				"<enter>":     "clear-input",
				"<backspace>": "backspace",
				"C-8":         "backspace",
				"<delete>":    "delete",
				"<space>":     "space",
			},
		},
		Theme: Theme{
			View: View{
				Fg:       "white",
				Bg:       "default",
				BorderFg: "white",
				BorderBg: "",
				LabelFg:  "green,bold",
				LabelBg:  "",
			},
			Channel: Channel{
				Prefix: "",
				Icon:   "",
				Text:   "",
			},
			Message: Message{
				Time:       "",
				TimeFormat: "15:04",
				Thread:     "fg-bold",
				Name:       "",
				Text:       "",
			},
		},
	}
}
<commit_msg>Create default config file when not present<commit_after>package config

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"os"

	"github.com/erroneousboat/termui"
)

const (
	NotifyAll     = "all"
	NotifyMention = "mention"
)

// Config is the definition of a Config struct
type Config struct {
	SlackToken   string                `json:"slack_token"`
	Notify       string                `json:"notify"`
	Emoji        bool                  `json:"emoji"`
	SidebarWidth int                   `json:"sidebar_width"`
	MainWidth    int                   `json:"-"`
	KeyMap       map[string]keyMapping `json:"key_map"`
	Theme        Theme                 `json:"theme"`
}

type keyMapping map[string]string

// NewConfig loads the config file and returns a Config struct
func NewConfig(filepath string) (*Config, error) {
	cfg := getDefaultConfig()

	// Open config file, and when none is found or present create
	// a default empty one, at the filepath location
	file, err := os.Open(filepath)
	if err != nil {
		file, err = CreateConfigFile(filepath)
		if err != nil {
			return &cfg, fmt.Errorf("couldn't open the slack-term config file: %v", err)
		}
	}

	if err := json.NewDecoder(file).Decode(&cfg); err != nil {
		return &cfg, fmt.Errorf("the slack-term config file isn't valid json: %v", err)
	}

	if cfg.SidebarWidth < 1 || cfg.SidebarWidth > 11 {
		return &cfg, errors.New("please specify the 'sidebar_width' between 1 and 11")
	}

	cfg.MainWidth = 12 - cfg.SidebarWidth

	switch cfg.Notify {
	case NotifyAll, NotifyMention, "":
		break
	default:
		return &cfg, fmt.Errorf("unsupported setting for notify: %s", cfg.Notify)
	}

	termui.ColorMap = map[string]termui.Attribute{
		"fg":        termui.StringToAttribute(cfg.Theme.View.Fg),
		"bg":        termui.StringToAttribute(cfg.Theme.View.Bg),
		"border.fg": termui.StringToAttribute(cfg.Theme.View.BorderFg),
		"border.bg": termui.StringToAttribute(cfg.Theme.View.BorderBg),
		"label.fg":  termui.StringToAttribute(cfg.Theme.View.LabelFg),
		"label.bg":  termui.StringToAttribute(cfg.Theme.View.LabelBg),
	}

	return &cfg, nil
}

func CreateConfigFile(filepath string) (*os.File, error) {
	payload := "{\"slack_token\": \"\"}"
	err := ioutil.WriteFile(filepath, []byte(payload), 0755)
	if err != nil {
		return nil, err
	}

	file, err := os.Open(filepath)
	if err != nil {
		return nil, err
	}

	return file, nil
}

func getDefaultConfig() Config {
	return Config{
		SidebarWidth: 1,
		MainWidth:    11,
		Notify:       "",
		Emoji:        false,
		KeyMap: map[string]keyMapping{
			"command": {
				"i":          "mode-insert",
				"/":          "mode-search",
				"k":          "channel-up",
				"j":          "channel-down",
				"g":          "channel-top",
				"G":          "channel-bottom",
				"<previous>": "chat-up",
				"C-b":        "chat-up",
				"C-u":        "chat-up",
				"<next>":     "chat-down",
				"C-f":        "chat-down",
				"C-d":        "chat-down",
				"n":          "channel-search-next",
				"N":          "channel-search-prev",
				"'":          "channel-jump",
				"q":          "quit",
				"<f1>":       "help",
			},
			"insert": {
				"<left>":      "cursor-left",
				"<right>":     "cursor-right",
				"<enter>":     "send",
				"<escape>":    "mode-command",
				"<backspace>": "backspace",
				"C-8":         "backspace",
				"<delete>":    "delete",
				"<space>":     "space",
			},
			"search": {
				"<left>":      "cursor-left",
				"<right>":     "cursor-right",
				"<escape>":    "clear-input",
				"<enter>":     "clear-input",
				"<backspace>": "backspace",
				"C-8":         "backspace",
				"<delete>":    "delete",
				"<space>":     "space",
			},
		},
		Theme: Theme{
			View: View{
				Fg:       "white",
				Bg:       "default",
				BorderFg: "white",
				BorderBg: "",
				LabelFg:  "green,bold",
				LabelBg:  "",
			},
			Channel: Channel{
				Prefix: "",
				Icon:   "",
				Text:   "",
			},
			Message: Message{
				Time:       "",
				TimeFormat: "15:04",
				Thread:     "fg-bold",
				Name:       "",
				Text:       "",
			},
		},
	}
}
<|endoftext|>


<commit_before>package config

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
)

type Configuration struct {
	Username   string `json:"username"`
	Password   string
	RememberMe bool `json:"remember_me"`
}

func configWizard() *Configuration {
	configuration := new(Configuration)
	fmt.Println("Welcome to gotify !\nThis wizard will help you set up gotify, follow it carefully !")
	StartWizard(configuration)
	return configuration
}

func LoadConfig() *Configuration {
	if _, err := os.Stat("config.json"); os.IsNotExist(err) {
		configuration := ConfigWizard()
		return configuration
	}
	file, err := ioutil.ReadFile("config.json")
	if err != nil {
		log.Fatal(err)
	}
	configuration := new(Configuration)
	err = json.Unmarshal(file, &configuration)
	if err != nil {
		log.Fatal(err)
	}
	return configuration
}
<commit_msg>Typo issue<commit_after>package config

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
)

type Configuration struct {
	Username   string `json:"username"`
	Password   string
	RememberMe bool `json:"remember_me"`
}

func configWizard() *Configuration {
	configuration := new(Configuration)
	fmt.Println("Welcome to gotify !\nThis wizard will help you set up gotify, follow it carefully !")
	StartWizard(configuration)
	return configuration
}

func LoadConfig() *Configuration {
	if _, err := os.Stat("config.json"); os.IsNotExist(err) {
		configuration := configWizard()
		return configuration
	}
	file, err := ioutil.ReadFile("config.json")
	if err != nil {
		log.Fatal(err)
	}
	configuration := new(Configuration)
	err = json.Unmarshal(file, &configuration)
	if err != nil {
		log.Fatal(err)
	}
	return configuration
}
<|endoftext|>


<commit_before>package config

import (
	"encoding/json"
	"os"
)

/*Root is the base struct containing bloodlines configs */
type Root struct {
	SQL        MySQL      `json:"mysql"`
	Sendgrid   Sendgrid   `json:"sendgrid"`
	TownCenter TownCenter `json:"towncenter"`
	Bloodlines Bloodlines `json:"bloodlines"`
	Covenant   Covenant   `json:"covenant"`
	Warehouse  Warehouse  `json:"warehouse"`
	Rabbit     Rabbit     `json:"rabbit"`
	Statsd     Statsd     `json:"statsd"`
	Stripe     Stripe     `json:"stripe"`
	Port       string     `json:"port"`
}

/*MySQL contains information for connecting to a MySQL instance */
type MySQL struct {
	Host     string `json:"host"`
	Port     string `json:"port"`
	User     string `json:"user"`
	Password string `json:"password"`
	Database string `json:"database"`
}

/*Sendgrid has connection information for the sendgrid gateway */
type Sendgrid struct {
	APIKey    string `json:"api_key"`
	FromEmail string `json:"from_email"`
	FromName  string `json:"from_name"`
	Host      string `json:"host"`
}

type Stripe struct {
	Secret string `json:"secret"`
	Public string `json:"public"`
}

/*TownCenter has connection information for the town center service */
type TownCenter struct {
	Host string `json:"host"`
	Port string `json:"port"`
}

/*Bloodlines has connection information for the bloodlines service */
type Bloodlines struct {
	Host string `json:"host"`
	Port string `json:"port"`
}

/*Covenant has connection information for the covenant service */
type Covenant struct {
	Host string `json:"host"`
	Port string `json:"port"`
}

/*Warehouse has connection information for the inventory service*/
type Warehouse struct {
	Host string `json:"host"`
	Port string `json:"port"`
}

/*Rabbit has connection info for RabbitMQ*/
type Rabbit struct {
	Host string `json:"host"`
	Port string `json:"port"`
	PubQ string `json:"pubq"`
}

/*Statsd contains connection information for graphite stats*/
type Statsd struct {
	Host   string `json:"host"`
	Port   string `json:"port"`
	Prefix string `json:"prefix"`
}

/*Init returns a populated Root struct from config.json */
func Init(filename string) (*Root, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}

	decoder := json.NewDecoder(file)

	root := &Root{}
	err = decoder.Decode(root)
	if err != nil {
		return nil, err
	}
	return root, nil
}
<commit_msg>Add coinage config<commit_after>package config

import (
	"encoding/json"
	"os"
)

/*Root is the base struct containing bloodlines configs */
type Root struct {
	SQL        MySQL      `json:"mysql"`
	Sendgrid   Sendgrid   `json:"sendgrid"`
	TownCenter TownCenter `json:"towncenter"`
	Bloodlines Bloodlines `json:"bloodlines"`
	Covenant   Covenant   `json:"covenant"`
	Warehouse  Warehouse  `json:"warehouse"`
	Coinage    Coinage    `json:"coinage"`
	Rabbit     Rabbit     `json:"rabbit"`
	Statsd     Statsd     `json:"statsd"`
	Stripe     Stripe     `json:"stripe"`
	Port       string     `json:"port"`
}

/*MySQL contains information for connecting to a MySQL instance */
type MySQL struct {
	Host     string `json:"host"`
	Port     string `json:"port"`
	User     string `json:"user"`
	Password string `json:"password"`
	Database string `json:"database"`
}

/*Sendgrid has connection information for the sendgrid gateway */
type Sendgrid struct {
	APIKey    string `json:"api_key"`
	FromEmail string `json:"from_email"`
	FromName  string `json:"from_name"`
	Host      string `json:"host"`
}

type Stripe struct {
	Secret string `json:"secret"`
	Public string `json:"public"`
}

/*TownCenter has connection information for the town center service */
type TownCenter struct {
	Host string `json:"host"`
	Port string `json:"port"`
}

/*Bloodlines has connection information for the bloodlines service */
type Bloodlines struct {
	Host string `json:"host"`
	Port string `json:"port"`
}

/*Coinage has connection information for the coinage service */
type Coinage struct {
	Host string `json:"host"`
	Port string `json:"port"`
}

/*Covenant has connection information for the covenant service */
type Covenant struct {
	Host string `json:"host"`
	Port string `json:"port"`
}

/*Warehouse has connection information for the inventory service*/
type Warehouse struct {
	Host string `json:"host"`
	Port string `json:"port"`
}

/*Rabbit has connection info for RabbitMQ*/
type Rabbit struct {
	Host string `json:"host"`
	Port string `json:"port"`
	PubQ string `json:"pubq"`
}

/*Statsd contains connection information for graphite stats*/
type Statsd struct {
	Host   string `json:"host"`
	Port   string `json:"port"`
	Prefix string `json:"prefix"`
}

/*Init returns a populated Root struct from config.json */
func Init(filename string) (*Root, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}

	decoder := json.NewDecoder(file)

	root := &Root{}
	err = decoder.Decode(root)
	if err != nil {
		return nil, err
	}
	return root, nil
}
<|endoftext|>


<commit_before>package labyrinth

import "github.com/hajimehoshi/ebiten"

type KeyboardWrapper struct {
	keyState map[ebiten.Key]int
	keys     []ebiten.Key
}

func NewKeyboardWrapper() *KeyboardWrapper {
	var kw = &KeyboardWrapper{
		keyState: map[ebiten.Key]int{},
		keys: []ebiten.Key{
			ebiten.Key0,
			ebiten.Key1,
			ebiten.Key2,
			ebiten.Key3,
			ebiten.Key4,
			ebiten.Key5,
			ebiten.Key6,
			ebiten.Key7,
			ebiten.Key8,
			ebiten.Key9,
			ebiten.KeyA,
			ebiten.KeyB,
			ebiten.KeyC,
			ebiten.KeyD,
			ebiten.KeyE,
			ebiten.KeyF,
			ebiten.KeyG,
			ebiten.KeyH,
			ebiten.KeyI,
			ebiten.KeyJ,
			ebiten.KeyK,
			ebiten.KeyL,
			ebiten.KeyM,
			ebiten.KeyN,
			ebiten.KeyO,
			ebiten.KeyP,
			ebiten.KeyQ,
			ebiten.KeyR,
			ebiten.KeyS,
			ebiten.KeyT,
			ebiten.KeyU,
			ebiten.KeyV,
			ebiten.KeyW,
			ebiten.KeyX,
			ebiten.KeyY,
			ebiten.KeyZ,
			ebiten.KeyAlt,
			ebiten.KeyBackspace,
			ebiten.KeyCapsLock,
			ebiten.KeyComma,
			ebiten.KeyControl,
			ebiten.KeyDelete,
			ebiten.KeyDown,
			ebiten.KeyEnd,
			ebiten.KeyEnter,
			ebiten.KeyEscape,
			ebiten.KeyF1,
			ebiten.KeyF2,
			ebiten.KeyF3,
			ebiten.KeyF4,
			ebiten.KeyF5,
			ebiten.KeyF6,
			ebiten.KeyF7,
			ebiten.KeyF8,
			ebiten.KeyF9,
			ebiten.KeyF10,
			ebiten.KeyF11,
			ebiten.KeyF12,
			ebiten.KeyHome,
			ebiten.KeyInsert,
			ebiten.KeyLeft,
			ebiten.KeyPageDown,
			ebiten.KeyPageUp,
			ebiten.KeyPeriod,
			ebiten.KeyRight,
			ebiten.KeyShift,
			ebiten.KeySpace,
			ebiten.KeyTab,
			ebiten.KeyUp,
		},
	}
	return kw
}

func (kw *KeyboardWrapper) IsKeyPressed(key ebiten.Key) bool {
	return ebiten.IsKeyPressed(key)
}

func (kw *KeyboardWrapper) KeyPushed(key ebiten.Key) bool {
	return kw.keyState[key] == 1
}

// LastKeysPushed returns all keys that were pushed
// useful if you don't know what the user input might be for
// changing the key bindings.
// Careful using this looping through a map is slow
func (kw *KeyboardWrapper) LastKeysPushed() []ebiten.Key {
	keysPressed := []ebiten.Key{}
	for key, value := range kw.keyState {
		if value > 0 {
			keysPressed = append(keysPressed, key)
		}
	}
	return keysPressed
}

func (kw *KeyboardWrapper) Update() {
	for _, key := range kw.keys {
		if kw.IsKeyPressed(key) {
			kw.keyState[key]++
		} else {
			kw.keyState[key] = 0
		}
	}
}
<commit_msg>add a key string parser<commit_after>package labyrinth

import (
	"errors"
	"strings"

	"github.com/hajimehoshi/ebiten"
)

type KeyboardWrapper struct {
	keyState map[ebiten.Key]int
	keys     []ebiten.Key
}

func NewKeyboardWrapper() *KeyboardWrapper {
	var kw = &KeyboardWrapper{
		keyState: map[ebiten.Key]int{},
		keys: []ebiten.Key{
			ebiten.Key0,
			ebiten.Key1,
			ebiten.Key2,
			ebiten.Key3,
			ebiten.Key4,
			ebiten.Key5,
			ebiten.Key6,
			ebiten.Key7,
			ebiten.Key8,
			ebiten.Key9,
			ebiten.KeyA,
			ebiten.KeyB,
			ebiten.KeyC,
			ebiten.KeyD,
			ebiten.KeyE,
			ebiten.KeyF,
			ebiten.KeyG,
			ebiten.KeyH,
			ebiten.KeyI,
			ebiten.KeyJ,
			ebiten.KeyK,
			ebiten.KeyL,
			ebiten.KeyM,
			ebiten.KeyN,
			ebiten.KeyO,
			ebiten.KeyP,
			ebiten.KeyQ,
			ebiten.KeyR,
			ebiten.KeyS,
			ebiten.KeyT,
			ebiten.KeyU,
			ebiten.KeyV,
			ebiten.KeyW,
			ebiten.KeyX,
			ebiten.KeyY,
			ebiten.KeyZ,
			ebiten.KeyAlt,
			ebiten.KeyBackspace,
			ebiten.KeyCapsLock,
			ebiten.KeyComma,
			ebiten.KeyControl,
			ebiten.KeyDelete,
			ebiten.KeyDown,
			ebiten.KeyEnd,
			ebiten.KeyEnter,
			ebiten.KeyEscape,
			ebiten.KeyF1,
			ebiten.KeyF2,
			ebiten.KeyF3,
			ebiten.KeyF4,
			ebiten.KeyF5,
			ebiten.KeyF6,
			ebiten.KeyF7,
			ebiten.KeyF8,
			ebiten.KeyF9,
			ebiten.KeyF10,
			ebiten.KeyF11,
			ebiten.KeyF12,
			ebiten.KeyHome,
			ebiten.KeyInsert,
			ebiten.KeyLeft,
			ebiten.KeyPageDown,
			ebiten.KeyPageUp,
			ebiten.KeyPeriod,
			ebiten.KeyRight,
			ebiten.KeyShift,
			ebiten.KeySpace,
			ebiten.KeyTab,
			ebiten.KeyUp,
		},
	}
	return kw
}

func (kw *KeyboardWrapper) IsKeyPressed(key ebiten.Key) bool {
	return ebiten.IsKeyPressed(key)
}

func (kw *KeyboardWrapper) KeyPushed(key ebiten.Key) bool {
	return kw.keyState[key] == 1
}

// LastKeysPushed returns all keys that were pushed
// useful if you don't know what the user input might be for
// changing the key bindings.
// Careful using this looping through a map is slow
func (kw *KeyboardWrapper) LastKeysPushed() []ebiten.Key {
	keysPressed := []ebiten.Key{}
	for key, value := range kw.keyState {
		if value > 0 {
			keysPressed = append(keysPressed, key)
		}
	}
	return keysPressed
}

func (kw *KeyboardWrapper) Update() {
	for _, key := range kw.keys {
		if kw.IsKeyPressed(key) {
			kw.keyState[key]++
		} else {
			kw.keyState[key] = 0
		}
	}
}

// Parse converts a string version of a key to a ebiten.Key
func (kw *KeyboardWrapper) Parse(id string) (ebiten.Key, error) {
	switch strings.ToUpper(id) {
	case "0":
		return ebiten.Key0, nil
	case "1":
		return ebiten.Key1, nil
	case "2":
		return ebiten.Key2, nil
	case "3":
		return ebiten.Key3, nil
	case "4":
		return ebiten.Key4, nil
	case "5":
		return ebiten.Key5, nil
	case "6":
		return ebiten.Key6, nil
	case "7":
		return ebiten.Key7, nil
	case "8":
		return ebiten.Key8, nil
	case "9":
		return ebiten.Key9, nil
	case "A":
		return ebiten.KeyA, nil
	case "B":
		return ebiten.KeyB, nil
	case "C":
		return ebiten.KeyC, nil
	case "D":
		return ebiten.KeyD, nil
	case "E":
		return ebiten.KeyE, nil
	case "F":
		return ebiten.KeyF, nil
	case "G":
		return ebiten.KeyG, nil
	case "H":
		return ebiten.KeyH, nil
	case "I":
		return ebiten.KeyI, nil
	case "J":
		return ebiten.KeyJ, nil
	case "K":
		return ebiten.KeyK, nil
	case "L":
		return ebiten.KeyL, nil
	case "M":
		return ebiten.KeyM, nil
	case "N":
		return ebiten.KeyN, nil
	case "O":
		return ebiten.KeyO, nil
	case "P":
		return ebiten.KeyP, nil
	case "Q":
		return ebiten.KeyQ, nil
	case "R":
		return ebiten.KeyR, nil
	case "S":
		return ebiten.KeyS, nil
	case "T":
		return ebiten.KeyT, nil
	case "U":
		return ebiten.KeyU, nil
	case "V":
		return ebiten.KeyV, nil
	case "W":
		return ebiten.KeyW, nil
	case "X":
		return ebiten.KeyX, nil
	case "Y":
		return ebiten.KeyY, nil
	case "Z":
		return ebiten.KeyZ, nil
	case "ALT":
		return ebiten.KeyAlt, nil
	case "BS":
		return ebiten.KeyBackspace, nil
	case "CAPS":
		return ebiten.KeyCapsLock, nil
	case "COMMA":
		return ebiten.KeyComma, nil
	case "CTRL":
		return ebiten.KeyControl, nil
	case "DEL":
		return ebiten.KeyDelete, nil
	case "DOWN":
		return ebiten.KeyDown, nil
	case "END":
		return ebiten.KeyEnd, nil
	case "ENTER":
		return ebiten.KeyEnter, nil
	case "ESC":
		return ebiten.KeyEscape, nil
	case "F1":
		return ebiten.KeyF1, nil
	case "F2":
		return ebiten.KeyF2, nil
	case "F3":
		return ebiten.KeyF3, nil
	case "F4":
		return ebiten.KeyF4, nil
	case "F5":
		return ebiten.KeyF5, nil
	case "F6":
		return ebiten.KeyF6, nil
	case "F7":
		return ebiten.KeyF7, nil
	case "F8":
		return ebiten.KeyF8, nil
	case "F9":
		return ebiten.KeyF9, nil
	case "F10":
		return ebiten.KeyF10, nil
	case "F11":
		return ebiten.KeyF11, nil
	case "F12":
		return ebiten.KeyF12, nil
	case "HOME":
		return ebiten.KeyHome, nil
	case "INS":
		return ebiten.KeyInsert, nil
	case "LEFT":
		return ebiten.KeyLeft, nil
	case "PAGEDOWN":
		return ebiten.KeyPageDown, nil
	case "PAGEUP":
		return ebiten.KeyPageUp, nil
	case "PERIOD":
		return ebiten.KeyPeriod, nil
	case "RIGHT":
		return ebiten.KeyRight, nil
	case "SHIFT":
		return ebiten.KeyShift, nil
	case "SPACE":
		return ebiten.KeySpace, nil
	case "TAB":
		return ebiten.KeyTab, nil
	case "UP":
		return ebiten.KeyUp, nil
	default:
		return ebiten.Key(-1), errors.New("Not a valid key")
	}
}
<|endoftext|>


<commit_before><commit_msg>fix bug that distribute more gas than given when internal call happens<commit_after><|endoftext|>


<commit_before>/*
Package session provides configuration for the SDK's service clients.

Sessions can be shared across all service clients that share the same base
configuration.  The Session is built from the SDK's default configuration and
request handlers.

Sessions should be cached when possible, because creating a new Session will
load all configuration values from the environment, and config files each time
the Session is created. Sharing the Session value across all of your service
clients will ensure the configuration is loaded the fewest number of times possible.

Concurrency

Sessions are safe to use concurrently as long as the Session is not being
modified. The SDK will not modify the Session once the Session has been created.
Creating service clients concurrently from a shared Session is safe.

Sessions from Shared Config

Sessions can be created using the method above that will only load the
additional config if the AWS_SDK_LOAD_CONFIG environment variable is set.
Alternatively you can explicitly create a Session with shared config enabled.
To do this you can use NewSessionWithOptions to configure how the Session will
be created. Using the NewSessionWithOptions with SharedConfigState set to
SharedConfigEnable will create the session as if the AWS_SDK_LOAD_CONFIG
environment variable was set.

Creating Sessions

When creating Sessions optional aws.Config values can be passed in that will
override the default, or loaded config values the Session is being created
with. This allows you to provide additional, or case based, configuration
as needed.

By default NewSession will only load credentials from the shared credentials
file (~/.aws/credentials). If the AWS_SDK_LOAD_CONFIG environment variable is
set to a truthy value the Session will be created from the configuration
values from the shared config (~/.aws/config) and shared credentials
(~/.aws/credentials) files. See the section Sessions from Shared Config for
more information.

Create a Session with the default config and request handlers. With credentials
region, and profile loaded from the environment and shared config automatically.
Requires the AWS_PROFILE to be set, or "default" is used.

	// Create Session
	sess := session.Must(session.NewSession())

	// Create a Session with a custom region
	sess := session.Must(session.NewSession(&aws.Config{
		Region: aws.String("us-east-1"),
	}))

	// Create a S3 client instance from a session
	sess := session.Must(session.NewSession())

	svc := s3.New(sess)

Create Session With Option Overrides

In addition to NewSession, Sessions can be created using NewSessionWithOptions.
This func allows you to control and override how the Session will be created
through code instead of being driven by environment variables only.

Use NewSessionWithOptions when you want to provide the config profile, or
override the shared config state (AWS_SDK_LOAD_CONFIG).

	// Equivalent to session.NewSession()
	sess := session.Must(session.NewSessionWithOptions(session.Options{
		// Options
	}))

	// Specify profile to load for the session's config
	sess := session.Must(session.NewSessionWithOptions(session.Options{
		 Profile: "profile_name",
	}))

	// Specify profile for config and region for requests
	sess := session.Must(session.NewSessionWithOptions(session.Options{
		 Config: aws.Config{Region: aws.String("us-east-1")},
		 Profile: "profile_name",
	}))

	// Force enable Shared Config support
	sess := session.Must(session.NewSessionWithOptions(session.Options{
		SharedConfigState: session.SharedConfigEnable,
	}))

Adding Handlers

You can add handlers to a session for processing HTTP requests. All service
clients that use the session inherit the handlers. For example, the following
handler logs every request and its payload made by a service client:

	// Create a session, and add additional handlers for all service
	// clients created with the Session to inherit. Adds logging handler.
	sess := session.Must(session.NewSession())

	sess.Handlers.Send.PushFront(func(r *request.Request) {
		// Log every request made and its payload
		logger.Println("Request: %s/%s, Payload: %s",
			r.ClientInfo.ServiceName, r.Operation, r.Params)
	})

Deprecated "New" function

The New session function has been deprecated because it does not provide good
way to return errors that occur when loading the configuration files and values.
Because of this, NewSession was created so errors can be retrieved when
creating a session fails.

Shared Config Fields

By default the SDK will only load the shared credentials file's (~/.aws/credentials)
credentials values, and all other config is provided by the environment variables,
SDK defaults, and user provided aws.Config values.

If the AWS_SDK_LOAD_CONFIG environment variable is set, or SharedConfigEnable
option is used to create the Session the full shared config values will be
loaded. This includes credentials, region, and support for assume role. In
addition the Session will load its configuration from both the shared config
file (~/.aws/config) and shared credentials file (~/.aws/credentials). Both
files have the same format.

If both config files are present the configuration from both files will be
read. The Session will be created from  configuration values from the shared
credentials file (~/.aws/credentials) over those in the shared credentials
file (~/.aws/config).

Credentials are the values the SDK should use for authenticating requests with
AWS Services. They arfrom a configuration file will need to include both
aws_access_key_id and aws_secret_access_key must be provided together in the
same file to be considered valid. The values will be ignored if not a complete
group. aws_session_token is an optional field that can be provided if both of
the other two fields are also provided.

	aws_access_key_id = AKID
	aws_secret_access_key = SECRET
	aws_session_token = TOKEN

Assume Role values allow you to configure the SDK to assume an IAM role using
a set of credentials provided in a config file via the source_profile field.
Both "role_arn" and "source_profile" are required. The SDK supports assuming
a role with MFA token if the session option AssumeRoleTokenProvider
is set.

	role_arn = arn:aws:iam::<account_number>:role/<role_name>
	source_profile = profile_with_creds
	external_id = 1234
	mfa_serial = <serial or mfa arn>
	role_session_name = session_name

Region is the region the SDK should use for looking up AWS service endpoints
and signing requests.

	region = us-east-1

Assume Role with MFA token

To create a session with support for assuming an IAM role with MFA set the
session option AssumeRoleTokenProvider to a function that will prompt for the
MFA token code when the SDK assumes the role and refreshes the role's credentials.
This allows you to configure the SDK via the shared config to assumea role
with MFA tokens.

In order for the SDK to assume a role with MFA the SharedConfigState
session option must be set to SharedConfigEnable, or AWS_SDK_LOAD_CONFIG
environment variable set.

The shared configuration instructs the SDK to assume an IAM role with MFA
when the mfa_serial configuration field is set in the shared config
(~/.aws/config) or shared credentials (~/.aws/credentials) file.

If mfa_serial is set in the configuration, the SDK will assume the role, and
the AssumeRoleTokenProvider session option is not set an an error will
be returned when creating the session.

    sess := session.Must(session.NewSessionWithOptions(session.Options{
        AssumeRoleTokenProvider: stscreds.StdinTokenProvider,
    }))

    // Create service client value configured for credentials
    // from assumed role.
    svc := s3.New(sess)

To setup assume role outside of a session see the stscrds.AssumeRoleProvider
documentation.

Environment Variables

When a Session is created several environment variables can be set to adjust
how the SDK functions, and what configuration data it loads when creating
Sessions. All environment values are optional, but some values like credentials
require multiple of the values to set or the partial values will be ignored.
All environment variable values are strings unless otherwise noted.

Environment configuration values. If set both Access Key ID and Secret Access
Key must be provided. Session Token and optionally also be provided, but is
not required.

	# Access Key ID
	AWS_ACCESS_KEY_ID=AKID
	AWS_ACCESS_KEY=AKID # only read if AWS_ACCESS_KEY_ID is not set.

	# Secret Access Key
	AWS_SECRET_ACCESS_KEY=SECRET
	AWS_SECRET_KEY=SECRET=SECRET # only read if AWS_SECRET_ACCESS_KEY is not set.

	# Session Token
	AWS_SESSION_TOKEN=TOKEN

Region value will instruct the SDK where to make service API requests to. If is
not provided in the environment the region must be provided before a service
client request is made.

	AWS_REGION=us-east-1

	# AWS_DEFAULT_REGION is only read if AWS_SDK_LOAD_CONFIG is also set,
	# and AWS_REGION is not also set.
	AWS_DEFAULT_REGION=us-east-1

Profile name the SDK should load use when loading shared config from the
configuration files. If not provided "default" will be used as the profile name.

	AWS_PROFILE=my_profile

	# AWS_DEFAULT_PROFILE is only read if AWS_SDK_LOAD_CONFIG is also set,
	# and AWS_PROFILE is not also set.
	AWS_DEFAULT_PROFILE=my_profile

SDK load config instructs the SDK to load the shared config in addition to
shared credentials. This also expands the configuration loaded so the shared
credentials will have parity with the shared config file. This also enables
Region and Profile support for the AWS_DEFAULT_REGION and AWS_DEFAULT_PROFILE
env values as well.

	AWS_SDK_LOAD_CONFIG=1

Shared credentials file path can be set to instruct the SDK to use an alternative
file for the shared credentials. If not set the file will be loaded from
$HOME/.aws/credentials on Linux/Unix based systems, and
%USERPROFILE%\.aws\credentials on Windows.

	AWS_SHARED_CREDENTIALS_FILE=$HOME/my_shared_credentials

Shared config file path can be set to instruct the SDK to use an alternative
file for the shared config. If not set the file will be loaded from
$HOME/.aws/config on Linux/Unix based systems, and
%USERPROFILE%\.aws\config on Windows.

	AWS_CONFIG_FILE=$HOME/my_shared_config

Path to a custom Credentials Authority (CA) bundle PEM file that the SDK
will use instead of the default system's root CA bundle. Use this only
if you want to replace the CA bundle the SDK uses for TLS requests.

	AWS_CA_BUNDLE=$HOME/my_custom_ca_bundle

Enabling this option will attempt to merge the Transport into the SDK's HTTP
client. If the client's Transport is not a http.Transport an error will be
returned. If the Transport's TLS config is set this option will cause the SDK
to overwrite the Transport's TLS config's  RootCAs value. If the CA bundle file
contains multiple certificates all of them will be loaded.

The Session option CustomCABundle is also available when creating sessions
to also enable this feature. CustomCABundle session option field has priority
over the AWS_CA_BUNDLE environment variable, and will be used if both are set.

Setting a custom HTTPClient in the aws.Config options will override this setting.
To use this option and custom HTTP client, the HTTP client needs to be provided
when creating the session. Not the service client.
*/
package session
<commit_msg>Change dup. mention of "credentials" to "config" (#1244)<commit_after>/*
Package session provides configuration for the SDK's service clients.

Sessions can be shared across all service clients that share the same base
configuration.  The Session is built from the SDK's default configuration and
request handlers.

Sessions should be cached when possible, because creating a new Session will
load all configuration values from the environment, and config files each time
the Session is created. Sharing the Session value across all of your service
clients will ensure the configuration is loaded the fewest number of times possible.

Concurrency

Sessions are safe to use concurrently as long as the Session is not being
modified. The SDK will not modify the Session once the Session has been created.
Creating service clients concurrently from a shared Session is safe.

Sessions from Shared Config

Sessions can be created using the method above that will only load the
additional config if the AWS_SDK_LOAD_CONFIG environment variable is set.
Alternatively you can explicitly create a Session with shared config enabled.
To do this you can use NewSessionWithOptions to configure how the Session will
be created. Using the NewSessionWithOptions with SharedConfigState set to
SharedConfigEnable will create the session as if the AWS_SDK_LOAD_CONFIG
environment variable was set.

Creating Sessions

When creating Sessions optional aws.Config values can be passed in that will
override the default, or loaded config values the Session is being created
with. This allows you to provide additional, or case based, configuration
as needed.

By default NewSession will only load credentials from the shared credentials
file (~/.aws/credentials). If the AWS_SDK_LOAD_CONFIG environment variable is
set to a truthy value the Session will be created from the configuration
values from the shared config (~/.aws/config) and shared credentials
(~/.aws/credentials) files. See the section Sessions from Shared Config for
more information.

Create a Session with the default config and request handlers. With credentials
region, and profile loaded from the environment and shared config automatically.
Requires the AWS_PROFILE to be set, or "default" is used.

	// Create Session
	sess := session.Must(session.NewSession())

	// Create a Session with a custom region
	sess := session.Must(session.NewSession(&aws.Config{
		Region: aws.String("us-east-1"),
	}))

	// Create a S3 client instance from a session
	sess := session.Must(session.NewSession())

	svc := s3.New(sess)

Create Session With Option Overrides

In addition to NewSession, Sessions can be created using NewSessionWithOptions.
This func allows you to control and override how the Session will be created
through code instead of being driven by environment variables only.

Use NewSessionWithOptions when you want to provide the config profile, or
override the shared config state (AWS_SDK_LOAD_CONFIG).

	// Equivalent to session.NewSession()
	sess := session.Must(session.NewSessionWithOptions(session.Options{
		// Options
	}))

	// Specify profile to load for the session's config
	sess := session.Must(session.NewSessionWithOptions(session.Options{
		 Profile: "profile_name",
	}))

	// Specify profile for config and region for requests
	sess := session.Must(session.NewSessionWithOptions(session.Options{
		 Config: aws.Config{Region: aws.String("us-east-1")},
		 Profile: "profile_name",
	}))

	// Force enable Shared Config support
	sess := session.Must(session.NewSessionWithOptions(session.Options{
		SharedConfigState: session.SharedConfigEnable,
	}))

Adding Handlers

You can add handlers to a session for processing HTTP requests. All service
clients that use the session inherit the handlers. For example, the following
handler logs every request and its payload made by a service client:

	// Create a session, and add additional handlers for all service
	// clients created with the Session to inherit. Adds logging handler.
	sess := session.Must(session.NewSession())

	sess.Handlers.Send.PushFront(func(r *request.Request) {
		// Log every request made and its payload
		logger.Println("Request: %s/%s, Payload: %s",
			r.ClientInfo.ServiceName, r.Operation, r.Params)
	})

Deprecated "New" function

The New session function has been deprecated because it does not provide good
way to return errors that occur when loading the configuration files and values.
Because of this, NewSession was created so errors can be retrieved when
creating a session fails.

Shared Config Fields

By default the SDK will only load the shared credentials file's (~/.aws/credentials)
credentials values, and all other config is provided by the environment variables,
SDK defaults, and user provided aws.Config values.

If the AWS_SDK_LOAD_CONFIG environment variable is set, or SharedConfigEnable
option is used to create the Session the full shared config values will be
loaded. This includes credentials, region, and support for assume role. In
addition the Session will load its configuration from both the shared config
file (~/.aws/config) and shared credentials file (~/.aws/credentials). Both
files have the same format.

If both config files are present the configuration from both files will be
read. The Session will be created from configuration values from the shared
credentials file (~/.aws/credentials) over those in the shared config file (~/.aws/config).

Credentials are the values the SDK should use for authenticating requests with
AWS Services. They arfrom a configuration file will need to include both
aws_access_key_id and aws_secret_access_key must be provided together in the
same file to be considered valid. The values will be ignored if not a complete
group. aws_session_token is an optional field that can be provided if both of
the other two fields are also provided.

	aws_access_key_id = AKID
	aws_secret_access_key = SECRET
	aws_session_token = TOKEN

Assume Role values allow you to configure the SDK to assume an IAM role using
a set of credentials provided in a config file via the source_profile field.
Both "role_arn" and "source_profile" are required. The SDK supports assuming
a role with MFA token if the session option AssumeRoleTokenProvider
is set.

	role_arn = arn:aws:iam::<account_number>:role/<role_name>
	source_profile = profile_with_creds
	external_id = 1234
	mfa_serial = <serial or mfa arn>
	role_session_name = session_name

Region is the region the SDK should use for looking up AWS service endpoints
and signing requests.

	region = us-east-1

Assume Role with MFA token

To create a session with support for assuming an IAM role with MFA set the
session option AssumeRoleTokenProvider to a function that will prompt for the
MFA token code when the SDK assumes the role and refreshes the role's credentials.
This allows you to configure the SDK via the shared config to assumea role
with MFA tokens.

In order for the SDK to assume a role with MFA the SharedConfigState
session option must be set to SharedConfigEnable, or AWS_SDK_LOAD_CONFIG
environment variable set.

The shared configuration instructs the SDK to assume an IAM role with MFA
when the mfa_serial configuration field is set in the shared config
(~/.aws/config) or shared credentials (~/.aws/credentials) file.

If mfa_serial is set in the configuration, the SDK will assume the role, and
the AssumeRoleTokenProvider session option is not set an an error will
be returned when creating the session.

    sess := session.Must(session.NewSessionWithOptions(session.Options{
        AssumeRoleTokenProvider: stscreds.StdinTokenProvider,
    }))

    // Create service client value configured for credentials
    // from assumed role.
    svc := s3.New(sess)

To setup assume role outside of a session see the stscrds.AssumeRoleProvider
documentation.

Environment Variables

When a Session is created several environment variables can be set to adjust
how the SDK functions, and what configuration data it loads when creating
Sessions. All environment values are optional, but some values like credentials
require multiple of the values to set or the partial values will be ignored.
All environment variable values are strings unless otherwise noted.

Environment configuration values. If set both Access Key ID and Secret Access
Key must be provided. Session Token and optionally also be provided, but is
not required.

	# Access Key ID
	AWS_ACCESS_KEY_ID=AKID
	AWS_ACCESS_KEY=AKID # only read if AWS_ACCESS_KEY_ID is not set.

	# Secret Access Key
	AWS_SECRET_ACCESS_KEY=SECRET
	AWS_SECRET_KEY=SECRET=SECRET # only read if AWS_SECRET_ACCESS_KEY is not set.

	# Session Token
	AWS_SESSION_TOKEN=TOKEN

Region value will instruct the SDK where to make service API requests to. If is
not provided in the environment the region must be provided before a service
client request is made.

	AWS_REGION=us-east-1

	# AWS_DEFAULT_REGION is only read if AWS_SDK_LOAD_CONFIG is also set,
	# and AWS_REGION is not also set.
	AWS_DEFAULT_REGION=us-east-1

Profile name the SDK should load use when loading shared config from the
configuration files. If not provided "default" will be used as the profile name.

	AWS_PROFILE=my_profile

	# AWS_DEFAULT_PROFILE is only read if AWS_SDK_LOAD_CONFIG is also set,
	# and AWS_PROFILE is not also set.
	AWS_DEFAULT_PROFILE=my_profile

SDK load config instructs the SDK to load the shared config in addition to
shared credentials. This also expands the configuration loaded so the shared
credentials will have parity with the shared config file. This also enables
Region and Profile support for the AWS_DEFAULT_REGION and AWS_DEFAULT_PROFILE
env values as well.

	AWS_SDK_LOAD_CONFIG=1

Shared credentials file path can be set to instruct the SDK to use an alternative
file for the shared credentials. If not set the file will be loaded from
$HOME/.aws/credentials on Linux/Unix based systems, and
%USERPROFILE%\.aws\credentials on Windows.

	AWS_SHARED_CREDENTIALS_FILE=$HOME/my_shared_credentials

Shared config file path can be set to instruct the SDK to use an alternative
file for the shared config. If not set the file will be loaded from
$HOME/.aws/config on Linux/Unix based systems, and
%USERPROFILE%\.aws\config on Windows.

	AWS_CONFIG_FILE=$HOME/my_shared_config

Path to a custom Credentials Authority (CA) bundle PEM file that the SDK
will use instead of the default system's root CA bundle. Use this only
if you want to replace the CA bundle the SDK uses for TLS requests.

	AWS_CA_BUNDLE=$HOME/my_custom_ca_bundle

Enabling this option will attempt to merge the Transport into the SDK's HTTP
client. If the client's Transport is not a http.Transport an error will be
returned. If the Transport's TLS config is set this option will cause the SDK
to overwrite the Transport's TLS config's  RootCAs value. If the CA bundle file
contains multiple certificates all of them will be loaded.

The Session option CustomCABundle is also available when creating sessions
to also enable this feature. CustomCABundle session option field has priority
over the AWS_CA_BUNDLE environment variable, and will be used if both are set.

Setting a custom HTTPClient in the aws.Config options will override this setting.
To use this option and custom HTTP client, the HTTP client needs to be provided
when creating the session. Not the service client.
*/
package session
<|endoftext|>


<commit_before>package assertions

import (
	"fmt"
	"reflect"

	"github.com/tamccall/moconvey/testify"
	"errors"
)

const (
	testPassedMessage = ""
)

func getMock(iFace interface{}) (testify.Mock, error) {
	if m, ok := iFace.(testify.Mock); !ok {
		return nil, errors.New("Cannot get mock")
	} else {
		return m, nil
	}
}

// ShouldHaveReceived is a goconvey style assertion.
// It is similar to https://godoc.org/github.com/stretchr/testify/mock#Mock.AssertCalled
// , and it asserts that the specified method was called.
//
// See Also
//
// https://github.com/smartystreets/goconvey/wiki/Custom-Assertions
func ShouldHaveReceived(iFace interface{}, args ...interface{}) string {
	t := new(fakeT)
	m, err := getMock(iFace)
	if err != nil {
		return err.Error()
	}
	var methodName string
	if stringVal, ok := args[0].(string); ok {
		methodName = stringVal
	} else {
		typ := reflect.TypeOf(iFace)
		return fmt.Sprintf("Argument 0 (methodName) should be a string. (was %s)", typ.Name())
	}

	passed := m.AssertCalled(t, methodName, args[1:]...)

	if !passed {
		return t.error()
	}

	return testPassedMessage
}

// ShouldHaveReceivedN is a goconvey style assertion.
// It is similar to https://godoc.org/github.com/stretchr/testify/mock#Mock.AssertNumberOfCalls
// , and it asserts that the specified method was called N times.
//
// See Also
//
// https://github.com/smartystreets/goconvey/wiki/Custom-Assertions
func ShouldHaveReceivedN(iFace interface{}, args ...interface{}) string {
	t := new(fakeT)
	m, err := getMock(iFace)
	if err != nil {
		return err.Error()
	}

	if len(args) < 2 {
		return fmt.Sprint("Received less that the expected 2 arguments")
	}

	var methodName string
	if stringVal, ok := args[0].(string); ok {
		methodName = stringVal
	} else {
		typ := reflect.TypeOf(iFace)
		return fmt.Sprintf("Argument 0 (methodName) should be a string. (was %s)", typ.Name())
	}

	var times int
	if intVal, ok := args[1].(int); ok {
		times = intVal
	} else {
		typ := reflect.TypeOf(iFace)
		return fmt.Sprintf("Argument 1 (times) should be an int. (was %s)", typ.Name())
	}

	passed := m.AssertNumberOfCalls(t, methodName, times)

	if !passed {
		return t.error()
	}

	return testPassedMessage
}

// ShouldNotHaveReceived is a goconvey style assertion.
// It is similar to https://godoc.org/github.com/stretchr/testify/mock#Mock.AssertNotCalled
// , and it asserts that the specified method was not called.
//
// See Also
//
// https://github.com/smartystreets/goconvey/wiki/Custom-Assertions
func ShouldNotHaveReceived(iFace interface{}, args ...interface{}) string {
	t := new(fakeT)
	m, err := getMock(iFace)
	if err != nil {
		return err.Error()
	}
	var methodName string
	if stringVal, ok := args[0].(string); ok {
		methodName = stringVal
	} else {
		typ := reflect.TypeOf(iFace)
		return fmt.Sprintf("Argument 0 (methodName) should be a string. (was %s)", typ.Name())
	}

	passed := m.AssertNotCalled(t, methodName, args[1:]...)

	if !passed {
		return t.error()
	}

	return testPassedMessage
}

// HadExpectationsMet is a goconvey style assertion.
// It is similar to https://godoc.org/github.com/stretchr/testify/mock#Mock.AssertExpectations, and asserts that
// everything specified with On and Return was in fact called as expected.
//
// See Also
//
// https://github.com/smartystreets/goconvey/wiki/Custom-Assertions
func HadExpectationsMet(iFace interface{}, args ...interface{}) string {
	m, err := getMock(iFace)
	if err != nil {
		return err.Error()
	}

	t := new(fakeT)
	passed := m.AssertExpectations(t)

	if !passed {
		return t.error()
	}

	return testPassedMessage
}
<commit_msg>linting errors<commit_after>package assertions

import (
	"errors"
	"fmt"
	"reflect"

	"github.com/tamccall/moconvey/testify"
)

const (
	testPassedMessage = ""
)

func getMock(iFace interface{}) (testify.Mock, error) {
	if m, ok := iFace.(testify.Mock); !ok {
		return nil, errors.New("Cannot get mock")
	} else {
		return m, nil
	}
}

// ShouldHaveReceived is a goconvey style assertion.
// It is similar to https://godoc.org/github.com/stretchr/testify/mock#Mock.AssertCalled
// , and it asserts that the specified method was called.
//
// See Also
//
// https://github.com/smartystreets/goconvey/wiki/Custom-Assertions
func ShouldHaveReceived(iFace interface{}, args ...interface{}) string {
	t := new(fakeT)
	m, err := getMock(iFace)
	if err != nil {
		return err.Error()
	}
	var methodName string
	if stringVal, ok := args[0].(string); ok {
		methodName = stringVal
	} else {
		typ := reflect.TypeOf(iFace)
		return fmt.Sprintf("Argument 0 (methodName) should be a string. (was %s)", typ.Name())
	}

	passed := m.AssertCalled(t, methodName, args[1:]...)

	if !passed {
		return t.error()
	}

	return testPassedMessage
}

// ShouldHaveReceivedN is a goconvey style assertion.
// It is similar to https://godoc.org/github.com/stretchr/testify/mock#Mock.AssertNumberOfCalls
// , and it asserts that the specified method was called N times.
//
// See Also
//
// https://github.com/smartystreets/goconvey/wiki/Custom-Assertions
func ShouldHaveReceivedN(iFace interface{}, args ...interface{}) string {
	t := new(fakeT)
	m, err := getMock(iFace)
	if err != nil {
		return err.Error()
	}

	if len(args) < 2 {
		return fmt.Sprint("Received less that the expected 2 arguments")
	}

	var methodName string
	if stringVal, ok := args[0].(string); ok {
		methodName = stringVal
	} else {
		typ := reflect.TypeOf(iFace)
		return fmt.Sprintf("Argument 0 (methodName) should be a string. (was %s)", typ.Name())
	}

	var times int
	if intVal, ok := args[1].(int); ok {
		times = intVal
	} else {
		typ := reflect.TypeOf(iFace)
		return fmt.Sprintf("Argument 1 (times) should be an int. (was %s)", typ.Name())
	}

	passed := m.AssertNumberOfCalls(t, methodName, times)

	if !passed {
		return t.error()
	}

	return testPassedMessage
}

// ShouldNotHaveReceived is a goconvey style assertion.
// It is similar to https://godoc.org/github.com/stretchr/testify/mock#Mock.AssertNotCalled
// , and it asserts that the specified method was not called.
//
// See Also
//
// https://github.com/smartystreets/goconvey/wiki/Custom-Assertions
func ShouldNotHaveReceived(iFace interface{}, args ...interface{}) string {
	t := new(fakeT)
	m, err := getMock(iFace)
	if err != nil {
		return err.Error()
	}
	var methodName string
	if stringVal, ok := args[0].(string); ok {
		methodName = stringVal
	} else {
		typ := reflect.TypeOf(iFace)
		return fmt.Sprintf("Argument 0 (methodName) should be a string. (was %s)", typ.Name())
	}

	passed := m.AssertNotCalled(t, methodName, args[1:]...)

	if !passed {
		return t.error()
	}

	return testPassedMessage
}

// HadExpectationsMet is a goconvey style assertion.
// It is similar to https://godoc.org/github.com/stretchr/testify/mock#Mock.AssertExpectations, and asserts that
// everything specified with On and Return was in fact called as expected.
//
// See Also
//
// https://github.com/smartystreets/goconvey/wiki/Custom-Assertions
func HadExpectationsMet(iFace interface{}, args ...interface{}) string {
	m, err := getMock(iFace)
	if err != nil {
		return err.Error()
	}

	t := new(fakeT)
	passed := m.AssertExpectations(t)

	if !passed {
		return t.error()
	}

	return testPassedMessage
}
<|endoftext|>


<commit_before>package log

func (v *Config) Apply() error {
	if v == nil {
		return nil
	}
	if v.AccessLogType == LogType_File {
		if err := InitAccessLogger(v.AccessLogPath); err != nil {
			return err
		}
	}

	if v.ErrorLogType == LogType_None {
		SetLogLevel(LogLevel_Disabled)
	} else {
		if v.ErrorLogType == LogType_File {
			if err := InitErrorLogger(v.ErrorLogPath); err != nil {
				return err
			}
		}
		SetLogLevel(v.ErrorLogLevel)
	}

	return nil
}
<commit_msg>remove unused file<commit_after><|endoftext|>