<commit_before>package grim

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

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
)

var (
	defaultGrimQueueName      = "grim-queue"
	defaultConfigRoot         = "/etc/grim"
	defaultResultRoot         = "/var/log/grim"
	defaultWorkspaceRoot      = "/var/tmp/grim"
	configFileName            = "config.json"
	prepareScriptName         = "prepare.sh"
	buildScriptName           = "build.sh"
	repoBuildScriptName       = "grim_build.sh"
	repoHiddenBuildScriptName = ".grim_build.sh"
)

type config struct {
	GrimQueueName *string
	ResultRoot    *string
	WorkspaceRoot *string
	AWSRegion     *string
	AWSKey        *string
	AWSSecret     *string
	GitHubToken   *string
	PathToCloneIn *string
	HipChatRoom   *string
	HipChatToken  *string
}

type effectiveConfig struct {
	grimQueueName string
	resultRoot    string
	workspaceRoot string
	awsRegion     string
	awsKey        string
	awsSecret     string
	gitHubToken   string
	pathToCloneIn string
	hipChatRoom   string
	hipChatToken  string
}

type repo struct {
	owner, name string
}

func getEffectiveConfigRoot(configRootPtr *string) string {
	if stringPtrNotEmpty(configRootPtr) {
		return *configRootPtr
	}

	return defaultConfigRoot
}

func getAllConfiguredRepos(configRoot string) []repo {
	var repos []repo

	repoPattern := filepath.Join(configRoot, "*/*")
	matches, err := filepath.Glob(repoPattern)
	if err != nil {
		return repos
	}

	for _, match := range matches {
		fi, fiErr := os.Stat(match)
		if fiErr != nil || !fi.Mode().IsDir() {
			continue
		}

		rel, relErr := filepath.Rel(configRoot, match)
		if relErr != nil {
			continue
		}

		owner, name := filepath.Split(rel)
		if owner != "" && name != "" {
			repos = append(repos, repo{filepath.Clean(owner), filepath.Clean(name)})
		}
	}

	return repos
}

func getEffectiveGlobalConfig(configRoot string) (*effectiveConfig, error) {
	var err error
	var global *config

	if global, err = loadGlobalConfig(configRoot); err == nil {
		ec := effectiveConfig{
			grimQueueName: firstNonEmptyStringPtr(global.GrimQueueName, &defaultGrimQueueName),
			resultRoot:    firstNonEmptyStringPtr(global.ResultRoot, &defaultResultRoot),
			workspaceRoot: firstNonEmptyStringPtr(global.WorkspaceRoot, &defaultWorkspaceRoot),
			awsRegion:     firstNonEmptyStringPtr(global.AWSRegion),
			awsKey:        firstNonEmptyStringPtr(global.AWSKey),
			awsSecret:     firstNonEmptyStringPtr(global.AWSSecret),
			gitHubToken:   firstNonEmptyStringPtr(global.GitHubToken),
			hipChatRoom:   firstNonEmptyStringPtr(global.HipChatRoom),
			hipChatToken:  firstNonEmptyStringPtr(global.HipChatToken),
		}

		if err = validateEffectiveConfig(ec); err == nil {
			return &ec, nil
		}
	}

	return nil, err
}

func getEffectiveConfig(configRoot, owner, repo string) (*effectiveConfig, error) {
	var err error
	var global, local *config

	if global, err = loadGlobalConfig(configRoot); err == nil {
		if local, err = loadLocalConfig(configRoot, owner, repo); err == nil {
			ec := effectiveConfig{
				grimQueueName: firstNonEmptyStringPtr(global.GrimQueueName, &defaultGrimQueueName),
				resultRoot:    firstNonEmptyStringPtr(global.ResultRoot, &defaultResultRoot),
				workspaceRoot: firstNonEmptyStringPtr(global.WorkspaceRoot, &defaultWorkspaceRoot),
				awsRegion:     firstNonEmptyStringPtr(global.AWSRegion),
				awsKey:        firstNonEmptyStringPtr(global.AWSKey),
				awsSecret:     firstNonEmptyStringPtr(global.AWSSecret),
				gitHubToken:   firstNonEmptyStringPtr(local.GitHubToken, global.GitHubToken),
				pathToCloneIn: firstNonEmptyStringPtr(local.PathToCloneIn),
				hipChatRoom:   firstNonEmptyStringPtr(local.HipChatRoom, global.HipChatRoom),
				hipChatToken:  firstNonEmptyStringPtr(local.HipChatToken, global.HipChatToken),
			}

			if err = validateEffectiveConfig(ec); err == nil {
				return &ec, nil
			}
		}
	}

	return nil, err
}

func validateEffectiveConfig(ec effectiveConfig) error {
	if ec.awsRegion == "" {
		return fmt.Errorf("AWS region is required")
	} else if ec.awsKey == "" {
		return fmt.Errorf("AWS key is required")
	} else if ec.awsSecret == "" {
		return fmt.Errorf("AWS secret is required")
	}

	return nil
}

func loadGlobalConfig(configRoot string) (*config, error) {
	return loadConfig(filepath.Join(configRoot, configFileName))
}

func loadLocalConfig(configRoot, owner, repo string) (*config, error) {
	return loadConfig(filepath.Join(configRoot, owner, repo, configFileName))
}

func loadConfig(path string) (*config, error) {
	c := new(config)

	if bs, err := ioutil.ReadFile(path); err != nil {
		return nil, err
	} else if err := json.Unmarshal(bs, c); err != nil {
		return nil, err
	}

	return c, nil
}

func firstNonEmptyStringPtr(strPtrs ...*string) string {
	for _, strPtr := range strPtrs {
		if stringPtrNotEmpty(strPtr) {
			return *strPtr
		}
	}

	return ""
}

func stringPtrNotEmpty(strPtr *string) bool {
	return strPtr != nil && *strPtr != ""
}
<commit_msg>adding grim build server to config<commit_after>package grim

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

//TODO: add grim_server_id to config
//check if it is present, if not present, use grim_queue_name
//add the grim_server_id to message in message:grim_server_id/grim_queue_name

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
)

var (
	defaultGrimQueueName      = "grim-queue"
	defaultConfigRoot         = "/etc/grim"
	defaultResultRoot         = "/var/log/grim"
	defaultWorkspaceRoot      = "/var/tmp/grim"
	configFileName            = "config.json"
	prepareScriptName         = "prepare.sh"
	buildScriptName           = "build.sh"
	repoBuildScriptName       = "grim_build.sh"
	repoHiddenBuildScriptName = ".grim_build.sh"
)

type config struct {
	GrimQueueName *string
	ResultRoot    *string
	WorkspaceRoot *string
	AWSRegion     *string
	AWSKey        *string
	AWSSecret     *string
	GitHubToken   *string
	PathToCloneIn *string
	HipChatRoom   *string
	HipChatToken  *string
	GrimServerID  *string
}

type effectiveConfig struct {
	grimQueueName string
	resultRoot    string
	workspaceRoot string
	awsRegion     string
	awsKey        string
	awsSecret     string
	gitHubToken   string
	pathToCloneIn string
	hipChatRoom   string
	hipChatToken  string
	grimServerID  string
}

type repo struct {
	owner, name string
}

func getEffectiveConfigRoot(configRootPtr *string) string {
	if stringPtrNotEmpty(configRootPtr) {
		return *configRootPtr
	}

	return defaultConfigRoot
}

func getAllConfiguredRepos(configRoot string) []repo {
	var repos []repo

	repoPattern := filepath.Join(configRoot, "*/*")
	matches, err := filepath.Glob(repoPattern)
	if err != nil {
		return repos
	}

	for _, match := range matches {
		fi, fiErr := os.Stat(match)
		if fiErr != nil || !fi.Mode().IsDir() {
			continue
		}

		rel, relErr := filepath.Rel(configRoot, match)
		if relErr != nil {
			continue
		}

		owner, name := filepath.Split(rel)
		if owner != "" && name != "" {
			repos = append(repos, repo{filepath.Clean(owner), filepath.Clean(name)})
		}
	}

	return repos
}

func getEffectiveGlobalConfig(configRoot string) (*effectiveConfig, error) {
	var err error
	var global *config

	if global, err = loadGlobalConfig(configRoot); err == nil {
		ec := effectiveConfig{
			grimQueueName: firstNonEmptyStringPtr(global.GrimQueueName, &defaultGrimQueueName),
			resultRoot:    firstNonEmptyStringPtr(global.ResultRoot, &defaultResultRoot),
			workspaceRoot: firstNonEmptyStringPtr(global.WorkspaceRoot, &defaultWorkspaceRoot),
			awsRegion:     firstNonEmptyStringPtr(global.AWSRegion),
			awsKey:        firstNonEmptyStringPtr(global.AWSKey),
			awsSecret:     firstNonEmptyStringPtr(global.AWSSecret),
			gitHubToken:   firstNonEmptyStringPtr(global.GitHubToken),
			hipChatRoom:   firstNonEmptyStringPtr(global.HipChatRoom),
			hipChatToken:  firstNonEmptyStringPtr(global.HipChatToken),
			grimServerID:  firstNonEmptyStringPtr(global.GrimServerID, &defaultGrimQueueName),
		}

		if err = validateEffectiveConfig(ec); err == nil {
			return &ec, nil
		}
	}

	return nil, err
}

func getEffectiveConfig(configRoot, owner, repo string) (*effectiveConfig, error) {
	var err error
	var global, local *config

	if global, err = loadGlobalConfig(configRoot); err == nil {
		if local, err = loadLocalConfig(configRoot, owner, repo); err == nil {
			ec := effectiveConfig{
				grimQueueName: firstNonEmptyStringPtr(global.GrimQueueName, &defaultGrimQueueName),
				resultRoot:    firstNonEmptyStringPtr(global.ResultRoot, &defaultResultRoot),
				workspaceRoot: firstNonEmptyStringPtr(global.WorkspaceRoot, &defaultWorkspaceRoot),
				awsRegion:     firstNonEmptyStringPtr(global.AWSRegion),
				awsKey:        firstNonEmptyStringPtr(global.AWSKey),
				awsSecret:     firstNonEmptyStringPtr(global.AWSSecret),
				gitHubToken:   firstNonEmptyStringPtr(local.GitHubToken, global.GitHubToken),
				pathToCloneIn: firstNonEmptyStringPtr(local.PathToCloneIn),
				hipChatRoom:   firstNonEmptyStringPtr(local.HipChatRoom, global.HipChatRoom),
				hipChatToken:  firstNonEmptyStringPtr(local.HipChatToken, global.HipChatToken),
				grimServerID:  firstNonEmptyStringPtr(global.GrimServerID, &defaultGrimQueueName),
			}

			if err = validateEffectiveConfig(ec); err == nil {
				return &ec, nil
			}
		}
	}

	return nil, err
}

func validateEffectiveConfig(ec effectiveConfig) error {
	if ec.awsRegion == "" {
		return fmt.Errorf("AWS region is required")
	} else if ec.awsKey == "" {
		return fmt.Errorf("AWS key is required")
	} else if ec.awsSecret == "" {
		return fmt.Errorf("AWS secret is required")
	}

	return nil
}

func loadGlobalConfig(configRoot string) (*config, error) {
	return loadConfig(filepath.Join(configRoot, configFileName))
}

func loadLocalConfig(configRoot, owner, repo string) (*config, error) {
	return loadConfig(filepath.Join(configRoot, owner, repo, configFileName))
}

func loadConfig(path string) (*config, error) {
	c := new(config)

	if bs, err := ioutil.ReadFile(path); err != nil {
		return nil, err
	} else if err := json.Unmarshal(bs, c); err != nil {
		return nil, err
	}

	return c, nil
}

func firstNonEmptyStringPtr(strPtrs ...*string) string {
	for _, strPtr := range strPtrs {
		if stringPtrNotEmpty(strPtr) {
			return *strPtr
		}
	}

	return ""
}

func stringPtrNotEmpty(strPtr *string) bool {
	return strPtr != nil && *strPtr != ""
}
<|endoftext|>


<commit_before>package gosfdoc

import (
	"bytes"
	"encoding/json"
	"errors"
	"github.com/slowfei/gosfcore/utils/filemanager"
	"io/ioutil"
	"path/filepath"
)

const (
	DEFAULT_CONFIG_FILE_NAME = "gosfdoc.json"
)

var (
	_gosfdocConfigJson = `{
    "CodeLang"         : [%v],
    "Outdir"           : "doc",
    "CopyCode"         : false,
    "HtmlTitle"        : "Document",
    "DocTitle"         : "Document:",
    "MenuTitle"        : "package",
    "Languages"        : {"default" : "Default"},
    "FilterPaths"      : []
}`
)

/**
 *  main config info
 *  output `gosfdoc.json` use
 */
type MainConfig struct {
	CodeLang    []string          // code languages
	Outdir      string            // output document directory
	CopyCode    bool              // whether output source code to document directory
	HtmlTitle   string            // document html show title
	DocTitle    string            // html top tabbar show title
	MenuTitle   string            // html left menu show title
	Languages   map[string]string // document support the language. key is lang dirctory name, value is show text
	FilterPaths []string          // filter directory path
}

/**
 *  check config param value
 *  error value will update default.
 *
 *  @return error
 *  @return bool    fatal error is false, pass is true. (pass does not mean that there are no errors)
 */
func (mc *MainConfig) Check() (error, bool) {
	errBuf := bytes.NewBufferString("")
	pass := true
	if 0 == len(mc.CodeLang) {
		errBuf.WriteString("CodeLang: specify code language type nil.\n")
		pass = false
	} else {
		count := len(mc.CodeLang)
		for i := 0; i < count; i++ {
			lang := mc.CodeLang[i]
			if _, ok := _mapParser[lang]; !ok {
				errBuf.WriteString("CodeLang: not " + lang + " Parser.\n")
			}
		}
	}

	if 0 == len(mc.Outdir) {
		errBuf.WriteString("Outdir: output directory is nil, will use 'doc' default directory.\n")
		mc.Outdir = "doc"
	}

	if 0 == len(mc.HtmlTitle) {
		mc.HtmlTitle = "Document"
		errBuf.WriteString("HtmlTitle: to set the html title.\n")
	}

	if 0 == len(mc.DocTitle) {
		mc.DocTitle = "Document:"
		errBuf.WriteString("DocTitle: to set the doc title.\n")
	}

	if 0 == len(mc.MenuTitle) {
		mc.MenuTitle = "package"
		errBuf.WriteString("MenuTitle: to set the menu title.\n")
	}

	if 0 == len(mc.Languages) {
		mc.Languages = map[string]string{"Default": "default"}
		errBuf.WriteString("Languages: to set the default html text language.\n")
	} else {
		if _, ok := mc.Languages["default"]; !ok {
			mc.Languages["default"] = "Default"
			errBuf.WriteString("Languages: to set the default html text language.\n")
		}
	}

	var err error = nil
	if 0 != errBuf.Len() {
		err = errors.New(errBuf.String())
	}
	return err, pass
}

/**
 *  document directory html javascript use config
 *
 *  output `config.json`
 */
type DocConfig struct {
	ContentJson string                   // content json file
	IntroMd     string                   // intro markdown file
	AboutMd     string                   // about markdown file
	Languages   map[string]string        // key is directory name, value is show text
	Markdowns   map[string][]PackageInfo // markdown info list
}

/**
 *  conifg load
 *
 *  @param jsonData
 *  @return load error info
 */
func configLoadByJson(jsonData []byte, c *MainConfig) error {
	e2 := json.Unmarshal(jsonData, c)
	if nil != e2 {
		return e2
	}
	return nil
}

/**
 *  conifg load
 *
 *  @param configPath
 *  @return error info
 */
func configLoadByFilepath(configPath string, c *MainConfig) error {

	var path string
	if filepath.IsAbs(configPath) {
		path = configPath
	} else {
		path = filepath.Join(SFFileManager.GetExecDir(), configPath)
	}

	isExists, isDir, _ := SFFileManager.Exists(path)
	if !isExists || isDir {
		return errors.New("failed to load configuration file:" + configPath)
	}

	jsonData, e1 := ioutil.ReadFile(path)
	if nil != e1 {
		return e1
	}

	return configLoadByJson(jsonData, c)
}
<commit_msg>修改验证的错误信息返回<commit_after>package gosfdoc

import (
	"bytes"
	"encoding/json"
	"errors"
	"github.com/slowfei/gosfcore/utils/filemanager"
	"io/ioutil"
	"path/filepath"
)

const (
	DEFAULT_CONFIG_FILE_NAME = "gosfdoc.json"
)

var (
	_gosfdocConfigJson = `{
    "Path"             : %#v,
    "CodeLang"         : [%v],
    "Outdir"           : "doc",
    "CopyCode"         : false,
    "HtmlTitle"        : "Document",
    "DocTitle"         : "Document:",
    "MenuTitle"        : "package",
    "Languages"        : {"default" : "Default"},
    "FilterPaths"      : []
}`
)

/**
 *  main config info
 *  output `gosfdoc.json` use
 */
type MainConfig struct {
	Path        string            // operate absolute path
	CodeLang    []string          // code languages
	Outdir      string            // output document directory
	CopyCode    bool              // whether output source code to document directory
	HtmlTitle   string            // document html show title
	DocTitle    string            // html top tabbar show title
	MenuTitle   string            // html left menu show title
	Languages   map[string]string // document support the language. key is lang dirctory name, value is show text
	FilterPaths []string          // filter directory relative path
}

/**
 *  check config param value
 *  error value will update default.
 *
 *  @return error
 *  @return bool    fatal error is false, pass is true. (pass does not mean that there are no errors)
 */
func (mc *MainConfig) Check() (error, bool) {
	errBuf := bytes.NewBufferString("")
	pass := true

	if 0 == len(mc.Path) {
		errBuf.WriteString("Path: please set the absolute path need to operate.\n")
		pass = false
	}

	if 0 == len(mc.CodeLang) {
		errBuf.WriteString("CodeLang: specify code language type nil.\n")
		pass = false
	} else {
		count := len(mc.CodeLang)
		for i := 0; i < count; i++ {
			lang := mc.CodeLang[i]
			if _, ok := _mapParser[lang]; !ok {
				errBuf.WriteString("CodeLang: not " + lang + " Parser.\n")
			}
		}
	}

	if 0 == len(mc.Outdir) {
		errBuf.WriteString("Outdir: output directory is nil, will use 'doc' default directory.\n")
		mc.Outdir = "doc"
	}

	if 0 == len(mc.HtmlTitle) {
		mc.HtmlTitle = "Document"
		errBuf.WriteString("HtmlTitle: to set the html title.\n")
	}

	if 0 == len(mc.DocTitle) {
		mc.DocTitle = "Document:"
		errBuf.WriteString("DocTitle: to set the doc title.\n")
	}

	if 0 == len(mc.MenuTitle) {
		mc.MenuTitle = "package"
		errBuf.WriteString("MenuTitle: to set the menu title.\n")
	}

	if 0 == len(mc.Languages) {
		mc.Languages = map[string]string{"Default": "default"}
		errBuf.WriteString("Languages: to set the default html text language.\n")
	} else {
		if _, ok := mc.Languages["default"]; !ok {
			mc.Languages["default"] = "Default"
			errBuf.WriteString("Languages: to set the default html text language.\n")
		}
	}

	var err error = nil
	if 0 != errBuf.Len() {
		err = errors.New(errBuf.String())
	}
	return err, pass
}

/**
 *  document directory html javascript use config
 *
 *  output `config.json`
 */
type DocConfig struct {
	ContentJson string                   // content json file
	IntroMd     string                   // intro markdown file
	AboutMd     string                   // about markdown file
	Languages   map[string]string        // key is directory name, value is show text
	Markdowns   map[string][]PackageInfo // markdown info list
}

/**
 *  conifg load
 *
 *  @param jsonData
 *  @return load error info
 */
func configLoadByJson(jsonData []byte, c *MainConfig) error {
	e2 := json.Unmarshal(jsonData, c)
	if nil != e2 {
		return e2
	}
	return nil
}

/**
 *  conifg load
 *
 *  @param configPath
 *  @return error info
 */
func configLoadByFilepath(configPath string, c *MainConfig) error {

	var path string
	if filepath.IsAbs(configPath) {
		path = configPath
	} else {
		path = filepath.Join(SFFileManager.GetExecDir(), configPath)
	}

	isExists, isDir, _ := SFFileManager.Exists(path)
	if !isExists || isDir {
		return errors.New("failed to load configuration file:" + configPath)
	}

	jsonData, e1 := ioutil.ReadFile(path)
	if nil != e1 {
		return e1
	}

	return configLoadByJson(jsonData, c)
}
<|endoftext|>


<commit_before>package goConfig

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

	"github.com/pkg/errors"
)

const (
	defaultPath       = "./"
	defaultConfigFile = "config.json"
)

// Load config file
func Load(config interface{}) (err error) {
	configFile := defaultPath + defaultConfigFile
	file, err := os.Open(configFile)
	if err != nil {
		return
	}
	defer file.Close()

	decoder := json.NewDecoder(file)
	err = decoder.Decode(&config)
	if err != nil {
		return
	}
	return
}

// Save config file
func Save(config interface{}) (err error) {
	_, err = os.Stat(defaultPath)

	if os.IsNotExist(err) {
		os.Mkdir(defaultPath, 0700)
	}

	configFile := defaultPath + defaultConfigFile

	_, err = os.Stat(configFile)
	if err != nil {
		return
	}

	b, err := json.MarshalIndent(config, "", "\t")
	if err != nil {
		return
	}

	err = ioutil.WriteFile(defaultConfigFile, b, 0644)
	if err != nil {
		return
	}
	return
}

// Getenv get enviroment variable
func Getenv(env string) (r string) {
	r = os.Getenv(env)
	return
}

func parseTags(s interface{}) (err error) {

	st := reflect.TypeOf(s)
	vt := reflect.ValueOf(s)

	if st.Kind() != reflect.Ptr {
		err = errors.New("Not a pointer")
		return
	}

	ref := st.Elem()
	if ref.Kind() != reflect.Struct {
		err = errors.New("Not a struct")
		return
	}

	for i := 0; i < ref.NumField(); i++ {
		field := ref.Field(i)
		value := vt.Elem().Field(i)

		kindStr := ""
		if field.Type.Kind() == reflect.Struct {
			kindStr = "Struct"

			err = parseTags(value.Addr().Interface())
			if err != nil {
				return
			}

		}

		// change value POC
		if field.Type.Kind() == reflect.String {
			value.SetString("TEST")
		}

		fmt.Println("name:", field.Name,
			"| cfg:", field.Tag.Get("config"),
			"| cfgDefault:", field.Tag.Get("cfgDefault"),
			"| type:", field.Type, kindStr)

	}
	return
}
<commit_msg>add error to mkdir<commit_after>package goConfig

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

	"github.com/pkg/errors"
)

const (
	defaultPath       = "./"
	defaultConfigFile = "config.json"
)

// Load config file
func Load(config interface{}) (err error) {
	configFile := defaultPath + defaultConfigFile
	file, err := os.Open(configFile)
	if err != nil {
		return
	}
	defer file.Close()

	decoder := json.NewDecoder(file)
	err = decoder.Decode(&config)
	if err != nil {
		return
	}
	return
}

// Save config file
func Save(config interface{}) (err error) {
	_, err = os.Stat(defaultPath)
	if os.IsNotExist(err) {
		os.Mkdir(defaultPath, 0700)
	} else if err != nil {
		return
	}

	configFile := defaultPath + defaultConfigFile

	_, err = os.Stat(configFile)
	if err != nil {
		return
	}

	b, err := json.MarshalIndent(config, "", "\t")
	if err != nil {
		return
	}

	err = ioutil.WriteFile(defaultConfigFile, b, 0644)
	if err != nil {
		return
	}
	return
}

// Getenv get enviroment variable
func Getenv(env string) (r string) {
	r = os.Getenv(env)
	return
}

func parseTags(s interface{}) (err error) {

	st := reflect.TypeOf(s)
	vt := reflect.ValueOf(s)

	if st.Kind() != reflect.Ptr {
		err = errors.New("Not a pointer")
		return
	}

	ref := st.Elem()
	if ref.Kind() != reflect.Struct {
		err = errors.New("Not a struct")
		return
	}

	for i := 0; i < ref.NumField(); i++ {
		field := ref.Field(i)
		value := vt.Elem().Field(i)

		kindStr := ""
		if field.Type.Kind() == reflect.Struct {
			kindStr = "Struct"

			err = parseTags(value.Addr().Interface())
			if err != nil {
				return
			}

		}

		// change value POC
		if field.Type.Kind() == reflect.String {
			value.SetString("TEST")
		}

		fmt.Println("name:", field.Name,
			"| cfg:", field.Tag.Get("config"),
			"| cfgDefault:", field.Tag.Get("cfgDefault"),
			"| type:", field.Type, kindStr)

	}
	return
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"strings"

	"github.com/hashicorp/terraform/helper/multierror"

	"github.com/awslabs/aws-sdk-go/aws"
	"github.com/awslabs/aws-sdk-go/aws/credentials"
	"github.com/awslabs/aws-sdk-go/service/autoscaling"
	"github.com/awslabs/aws-sdk-go/service/ec2"
	"github.com/awslabs/aws-sdk-go/service/elasticache"
	"github.com/awslabs/aws-sdk-go/service/elb"
	"github.com/awslabs/aws-sdk-go/service/iam"
	"github.com/awslabs/aws-sdk-go/service/rds"
	"github.com/awslabs/aws-sdk-go/service/route53"
	"github.com/awslabs/aws-sdk-go/service/s3"
	"github.com/awslabs/aws-sdk-go/service/sqs"
	"github.com/awslabs/aws-sdk-go/service/sns"
)

type Config struct {
	AccessKey  string
	SecretKey  string
	Token      string
	Region     string
	MaxRetries int

	AllowedAccountIds   []interface{}
	ForbiddenAccountIds []interface{}
}

type AWSClient struct {
	ec2conn         *ec2.EC2
	elbconn         *elb.ELB
	autoscalingconn *autoscaling.AutoScaling
	s3conn          *s3.S3
	sqsconn         *sqs.SQS
	snsconn			*sns.SNS
	r53conn         *route53.Route53
	region          string
	rdsconn         *rds.RDS
	iamconn         *iam.IAM
	elasticacheconn *elasticache.ElastiCache
}

// Client configures and returns a fully initailized AWSClient
func (c *Config) Client() (interface{}, error) {
	var client AWSClient

	// Get the auth and region. This can fail if keys/regions were not
	// specified and we're attempting to use the environment.
	var errs []error

	log.Println("[INFO] Building AWS region structure")
	err := c.ValidateRegion()
	if err != nil {
		errs = append(errs, err)
	}

	if len(errs) == 0 {
		// store AWS region in client struct, for region specific operations such as
		// bucket storage in S3
		client.region = c.Region

		log.Println("[INFO] Building AWS auth structure")
		creds := credentials.NewChainCredentials([]credentials.Provider{
			&credentials.StaticProvider{Value: credentials.Value{
				AccessKeyID:     c.AccessKey,
				SecretAccessKey: c.SecretKey,
				SessionToken:    c.Token,
			}},
			&credentials.EnvProvider{},
			&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
			&credentials.EC2RoleProvider{},
		})
		awsConfig := &aws.Config{
			Credentials: creds,
			Region:      c.Region,
			MaxRetries:  c.MaxRetries,
		}

		log.Println("[INFO] Initializing ELB connection")
		client.elbconn = elb.New(awsConfig)

		log.Println("[INFO] Initializing S3 connection")
		client.s3conn = s3.New(awsConfig)

		log.Println("[INFO] Initializing SQS connection")
		client.sqsconn = sqs.New(awsConfig)

		log.Println("[INFO] Initializing SNS connection")
		client.snsconn = sns.New(awsConfig)

		log.Println("[INFO] Initializing RDS Connection")
		client.rdsconn = rds.New(awsConfig)

		log.Println("[INFO] Initializing IAM Connection")
		client.iamconn = iam.New(awsConfig)

		err := c.ValidateAccountId(client.iamconn)
		if err != nil {
			errs = append(errs, err)
		}

		log.Println("[INFO] Initializing AutoScaling connection")
		client.autoscalingconn = autoscaling.New(awsConfig)

		log.Println("[INFO] Initializing EC2 Connection")
		client.ec2conn = ec2.New(awsConfig)

		// aws-sdk-go uses v4 for signing requests, which requires all global
		// endpoints to use 'us-east-1'.
		// See http://docs.aws.amazon.com/general/latest/gr/sigv4_changes.html
		log.Println("[INFO] Initializing Route 53 connection")
		client.r53conn = route53.New(&aws.Config{
			Credentials: creds,
			Region:      "us-east-1",
			MaxRetries:  c.MaxRetries,
		})

		log.Println("[INFO] Initializing Elasticache Connection")
		client.elasticacheconn = elasticache.New(awsConfig)
	}

	if len(errs) > 0 {
		return nil, &multierror.Error{Errors: errs}
	}

	return &client, nil
}

// ValidateRegion returns an error if the configured region is not a
// valid aws region and nil otherwise.
func (c *Config) ValidateRegion() error {
	var regions = [11]string{"us-east-1", "us-west-2", "us-west-1", "eu-west-1",
		"eu-central-1", "ap-southeast-1", "ap-southeast-2", "ap-northeast-1",
		"sa-east-1", "cn-north-1", "us-gov-west-1"}

	for _, valid := range regions {
		if c.Region == valid {
			return nil
		}
	}
	return fmt.Errorf("Not a valid region: %s", c.Region)
}

// ValidateAccountId returns a context-specific error if the configured account
// id is explicitly forbidden or not authorised; and nil if it is authorised.
func (c *Config) ValidateAccountId(iamconn *iam.IAM) error {
	if c.AllowedAccountIds == nil && c.ForbiddenAccountIds == nil {
		return nil
	}

	log.Printf("[INFO] Validating account ID")

	out, err := iamconn.GetUser(nil)
	if err != nil {
		return fmt.Errorf("Failed getting account ID from IAM: %s", err)
	}

	account_id := strings.Split(*out.User.ARN, ":")[4]

	if c.ForbiddenAccountIds != nil {
		for _, id := range c.ForbiddenAccountIds {
			if id == account_id {
				return fmt.Errorf("Forbidden account ID (%s)", id)
			}
		}
	}

	if c.AllowedAccountIds != nil {
		for _, id := range c.AllowedAccountIds {
			if id == account_id {
				return nil
			}
		}
		return fmt.Errorf("Account ID not allowed (%s)", account_id)
	}

	return nil
}
<commit_msg>Indentation issue<commit_after>package aws

import (
	"fmt"
	"log"
	"strings"

	"github.com/hashicorp/terraform/helper/multierror"

	"github.com/awslabs/aws-sdk-go/aws"
	"github.com/awslabs/aws-sdk-go/aws/credentials"
	"github.com/awslabs/aws-sdk-go/service/autoscaling"
	"github.com/awslabs/aws-sdk-go/service/ec2"
	"github.com/awslabs/aws-sdk-go/service/elasticache"
	"github.com/awslabs/aws-sdk-go/service/elb"
	"github.com/awslabs/aws-sdk-go/service/iam"
	"github.com/awslabs/aws-sdk-go/service/rds"
	"github.com/awslabs/aws-sdk-go/service/route53"
	"github.com/awslabs/aws-sdk-go/service/s3"
	"github.com/awslabs/aws-sdk-go/service/sqs"
	"github.com/awslabs/aws-sdk-go/service/sns"
)

type Config struct {
	AccessKey  string
	SecretKey  string
	Token      string
	Region     string
	MaxRetries int

	AllowedAccountIds   []interface{}
	ForbiddenAccountIds []interface{}
}

type AWSClient struct {
	ec2conn         *ec2.EC2
	elbconn         *elb.ELB
	autoscalingconn *autoscaling.AutoScaling
	s3conn          *s3.S3
	sqsconn         *sqs.SQS
	snsconn         *sns.SNS
	r53conn         *route53.Route53
	region          string
	rdsconn         *rds.RDS
	iamconn         *iam.IAM
	elasticacheconn *elasticache.ElastiCache
}

// Client configures and returns a fully initailized AWSClient
func (c *Config) Client() (interface{}, error) {
	var client AWSClient

	// Get the auth and region. This can fail if keys/regions were not
	// specified and we're attempting to use the environment.
	var errs []error

	log.Println("[INFO] Building AWS region structure")
	err := c.ValidateRegion()
	if err != nil {
		errs = append(errs, err)
	}

	if len(errs) == 0 {
		// store AWS region in client struct, for region specific operations such as
		// bucket storage in S3
		client.region = c.Region

		log.Println("[INFO] Building AWS auth structure")
		creds := credentials.NewChainCredentials([]credentials.Provider{
			&credentials.StaticProvider{Value: credentials.Value{
				AccessKeyID:     c.AccessKey,
				SecretAccessKey: c.SecretKey,
				SessionToken:    c.Token,
			}},
			&credentials.EnvProvider{},
			&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
			&credentials.EC2RoleProvider{},
		})
		awsConfig := &aws.Config{
			Credentials: creds,
			Region:      c.Region,
			MaxRetries:  c.MaxRetries,
		}

		log.Println("[INFO] Initializing ELB connection")
		client.elbconn = elb.New(awsConfig)

		log.Println("[INFO] Initializing S3 connection")
		client.s3conn = s3.New(awsConfig)

		log.Println("[INFO] Initializing SQS connection")
		client.sqsconn = sqs.New(awsConfig)

		log.Println("[INFO] Initializing SNS connection")
		client.snsconn = sns.New(awsConfig)

		log.Println("[INFO] Initializing RDS Connection")
		client.rdsconn = rds.New(awsConfig)

		log.Println("[INFO] Initializing IAM Connection")
		client.iamconn = iam.New(awsConfig)

		err := c.ValidateAccountId(client.iamconn)
		if err != nil {
			errs = append(errs, err)
		}

		log.Println("[INFO] Initializing AutoScaling connection")
		client.autoscalingconn = autoscaling.New(awsConfig)

		log.Println("[INFO] Initializing EC2 Connection")
		client.ec2conn = ec2.New(awsConfig)

		// aws-sdk-go uses v4 for signing requests, which requires all global
		// endpoints to use 'us-east-1'.
		// See http://docs.aws.amazon.com/general/latest/gr/sigv4_changes.html
		log.Println("[INFO] Initializing Route 53 connection")
		client.r53conn = route53.New(&aws.Config{
			Credentials: creds,
			Region:      "us-east-1",
			MaxRetries:  c.MaxRetries,
		})

		log.Println("[INFO] Initializing Elasticache Connection")
		client.elasticacheconn = elasticache.New(awsConfig)
	}

	if len(errs) > 0 {
		return nil, &multierror.Error{Errors: errs}
	}

	return &client, nil
}

// ValidateRegion returns an error if the configured region is not a
// valid aws region and nil otherwise.
func (c *Config) ValidateRegion() error {
	var regions = [11]string{"us-east-1", "us-west-2", "us-west-1", "eu-west-1",
		"eu-central-1", "ap-southeast-1", "ap-southeast-2", "ap-northeast-1",
		"sa-east-1", "cn-north-1", "us-gov-west-1"}

	for _, valid := range regions {
		if c.Region == valid {
			return nil
		}
	}
	return fmt.Errorf("Not a valid region: %s", c.Region)
}

// ValidateAccountId returns a context-specific error if the configured account
// id is explicitly forbidden or not authorised; and nil if it is authorised.
func (c *Config) ValidateAccountId(iamconn *iam.IAM) error {
	if c.AllowedAccountIds == nil && c.ForbiddenAccountIds == nil {
		return nil
	}

	log.Printf("[INFO] Validating account ID")

	out, err := iamconn.GetUser(nil)
	if err != nil {
		return fmt.Errorf("Failed getting account ID from IAM: %s", err)
	}

	account_id := strings.Split(*out.User.ARN, ":")[4]

	if c.ForbiddenAccountIds != nil {
		for _, id := range c.ForbiddenAccountIds {
			if id == account_id {
				return fmt.Errorf("Forbidden account ID (%s)", id)
			}
		}
	}

	if c.AllowedAccountIds != nil {
		for _, id := range c.AllowedAccountIds {
			if id == account_id {
				return nil
			}
		}
		return fmt.Errorf("Account ID not allowed (%s)", account_id)
	}

	return nil
}
<|endoftext|>


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

// tsuru-admin is under development.
package main

import (
	"github.com/globocom/tsuru/cmd"
	"github.com/globocom/tsuru/cmd/tsuru-base"
	"os"
)

const (
	version = "0.2"
	header  = "Supported-Tsuru-Admin"
)

func buildManager(name string) *cmd.Manager {
	m := cmd.BuildBaseManager(name, version, header)
	m.Register(tsuru.AppList{})
	m.Register(&tsuru.SetCName{})
	m.Register(&tsuru.UnsetCName{})
	m.Register(&tokenGen{})
	return m
}

func main() {
	name := cmd.ExtractProgramName(os.Args[0])
	manager := buildManager(name)
	args := os.Args[1:]
	manager.Run(args)
}
<commit_msg>cmd/tsuru-admin: version 0.2.1.<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// tsuru-admin is under development.
package main

import (
	"github.com/globocom/tsuru/cmd"
	"github.com/globocom/tsuru/cmd/tsuru-base"
	"os"
)

const (
	version = "0.2.1"
	header  = "Supported-Tsuru-Admin"
)

func buildManager(name string) *cmd.Manager {
	m := cmd.BuildBaseManager(name, version, header)
	m.Register(tsuru.AppList{})
	m.Register(&tsuru.SetCName{})
	m.Register(&tsuru.UnsetCName{})
	m.Register(&tokenGen{})
	return m
}

func main() {
	name := cmd.ExtractProgramName(os.Args[0])
	manager := buildManager(name)
	args := os.Args[1:]
	manager.Run(args)
}
<|endoftext|>


<commit_before>package via

import (
	"os"
	"path"
	"strings"
)

var (
	cache  Cache
	home   = os.Getenv("HOME")
	cfile  = path.Join(home, "via.json")
	config = &Config{
		Arch:      "arm",
		OS:        "linux",
		Cache:     "$HOME/via/cache",
		DB:        "/data/data/gnuoid/var/db/via",
		Identity:  "test user <test@test.com>",
		Plans:     "$HOME/via/plans",
		PlansRepo: "https://code.google.com/p/via.plans",
		Repo:      "$HOME/via/repo",
		Root:      "/",
		Flags: []string{
			//"--target=arm-linux-gnueabi",
			"--host=arm-linux-gnueabi",
			"--disable-multilib",
			"--disable-dependency-tracking",
			"--disable-nls",
			"--with-shared",
			"--prefix=$PREFIX",
			"-q",
		},
		Env: map[string]string{
			"PREFIX":      "/data/data/gnuoid",
			"MAKEFLAGS":   "-j3 -sw",
			"CFLAGS":      "-pipe -O2 -static-libgcc -I/data/data/gnuoid/include",
			"LD_RUN_PATH": "/data/data/gnuoid/lib",
			"LDFLAGS":     "-L/data/data/gnuoid/lib",
		},
		Remove: []string{
			"data/data/gnuoid/share/doc",
			"data/data/gnuoid/share/info",
			"data/data/gnuoid/share/man",
		},
	}
	join = path.Join
)

func init() {
	/*
		if !file.Exists(cfile) {
			elog.Println("WARNING no config was found writing new one to", cfile)
			elog.Println("please review it.")
			err := json.Write(&config, cfile)
			if err != nil {
				elog.Fatal(err)
			}
			return
		}
		config = &Config{}
		err := json.Read(&config, cfile)
		if err != nil {
			elog.Fatal(err)
		}
		// TODO: provide Lint for master config
		err = json.Write(&config, cfile)
		if err != nil {
			elog.Fatal(err)
		}
	*/
	cache = Cache(os.ExpandEnv(string(config.Cache)))
	config.Plans = os.ExpandEnv(config.Plans)
	config.Repo = os.ExpandEnv(config.Repo)
	for i, j := range config.Env {
		os.Setenv(i, j)
	}
}

type Config struct {
	Identity  string
	Arch      string
	OS        string
	Root      string
	PlansRepo string

	// Paths
	Cache Cache
	DB    DB
	Plans string
	Repo  string

	// Toolchain
	Flags Flags

	Env    map[string]string
	Remove []string
}

type Flags []string

func (f Flags) String() string {
	return strings.Join(f, " ")
}

type DB string

func (d DB) Installed() string {
	return join(config.Root, string(d), "installed")
}

type Cache string

func (c Cache) Pkgs() string {
	return path.Join(string(c), "pkg")
}

func (c Cache) Srcs() string {
	return path.Join(string(c), "src")
}

func (c Cache) Builds() string {
	return path.Join(string(c), "bld")
}

func (c Cache) Stages() string {
	return path.Join(string(c), "stg")
}
<commit_msg>config: android<commit_after>package via

import (
	"os"
	"path"
	"strings"
)

var (
	cache  Cache
	home   = os.Getenv("HOME")
	cfile  = path.Join(home, "via.json")
	config = &Config{
		Arch:      "arm",
		OS:        "linux",
		Cache:     "$HOME/via/cache",
		DB:        "/data/data/gnuoid/var/db/via",
		Identity:  "test user <test@test.com>",
		Plans:     "$HOME/via/plans",
		PlansRepo: "https://code.google.com/p/via.plans",
		Repo:      "$HOME/via/repo",
		Root:      "/",
		Flags: []string{
			"--host=arm-linux-gnueabi",
			"--disable-multilib",
			"--disable-dependency-tracking",
			"--disable-nls",
			"--with-shared",
			"--prefix=$PREFIX",
			"--config-cache",
			"-q",
		},
		Env: map[string]string{
			"CFLAGS":    "-pipe -O2 -static-libgcc -I/data/data/gnuoid/include",
			"LDFLAGS":   "-L/data/data/gnuoid/lib",
			"MAKEFLAGS": "-j3 -sw",
			"PREFIX":    "/data/data/gnuoid",
			"STRIP":     "arm-linux-gnueabi-strip",
		},
		Remove: []string{
			"data/data/gnuoid/share/doc",
			"data/data/gnuoid/share/info",
			"data/data/gnuoid/share/man",
		},
	}
	join = path.Join
)

func init() {
	/*
		if !file.Exists(cfile) {
			elog.Println("WARNING no config was found writing new one to", cfile)
			elog.Println("please review it.")
			err := json.Write(&config, cfile)
			if err != nil {
				elog.Fatal(err)
			}
			return
		}
		config = &Config{}
		err := json.Read(&config, cfile)
		if err != nil {
			elog.Fatal(err)
		}
		// TODO: provide Lint for master config
		err = json.Write(&config, cfile)
		if err != nil {
			elog.Fatal(err)
		}
	*/
	cache = Cache(os.ExpandEnv(string(config.Cache)))
	config.Plans = os.ExpandEnv(config.Plans)
	config.Repo = os.ExpandEnv(config.Repo)
	for i, j := range config.Env {
		os.Setenv(i, j)
	}
}

type Config struct {
	Identity  string
	Arch      string
	OS        string
	Root      string
	PlansRepo string

	// Paths
	Cache Cache
	DB    DB
	Plans string
	Repo  string

	// Toolchain
	Flags Flags

	Env    map[string]string
	Remove []string
}

type Flags []string

func (f Flags) String() string {
	return strings.Join(f, " ")
}

type DB string

func (d DB) Installed() string {
	return join(config.Root, string(d), "installed")
}

type Cache string

func (c Cache) Pkgs() string {
	return path.Join(string(c), "pkg")
}

func (c Cache) Srcs() string {
	return path.Join(string(c), "src")
}

func (c Cache) Builds() string {
	return path.Join(string(c), "bld")
}

func (c Cache) Stages() string {
	return path.Join(string(c), "stg")
}
<|endoftext|>


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

// tsuru-admin is under development.
package main

import (
	"github.com/globocom/tsuru/cmd"
	"github.com/globocom/tsuru/cmd/tsuru-base"
	"os"
)

const (
	version = "0.1.6"
	header  = "Supported-Tsuru-Admin"
)

func buildManager(name string) *cmd.Manager {
	m := cmd.BuildBaseManager(name, version, header)
	m.Register(tsuru.AppList{})
	m.Register(&tsuru.SetCName{})
	m.Register(&tsuru.UnsetCName{})
	m.Register(&tokenGen{})
	return m
}

func main() {
	name := cmd.ExtractProgramName(os.Args[0])
	manager := buildManager(name)
	args := os.Args[1:]
	manager.Run(args)
}
<commit_msg>cmd/tsuru-admin: version 0.1.7<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// tsuru-admin is under development.
package main

import (
	"github.com/globocom/tsuru/cmd"
	"github.com/globocom/tsuru/cmd/tsuru-base"
	"os"
)

const (
	version = "0.1.7"
	header  = "Supported-Tsuru-Admin"
)

func buildManager(name string) *cmd.Manager {
	m := cmd.BuildBaseManager(name, version, header)
	m.Register(tsuru.AppList{})
	m.Register(&tsuru.SetCName{})
	m.Register(&tsuru.UnsetCName{})
	m.Register(&tokenGen{})
	return m
}

func main() {
	name := cmd.ExtractProgramName(os.Args[0])
	manager := buildManager(name)
	args := os.Args[1:]
	manager.Run(args)
}
<|endoftext|>


<commit_before>// Copyright 2012 config 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 config provide configuration facilities, handling configuration
// files in yaml format.
package config

import (
	"errors"
	"fmt"
	"io/ioutil"
	"launchpad.net/goyaml"
	"strings"
)

var configs map[interface{}]interface{}

// 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 {
	return goyaml.Unmarshal(data, &configs)
}

// 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)
}

// Get returns the value for the given key, or an eror if the key is undefined.
//
// The key is composed by 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.
func Get(key string) (interface{}, error) {
	keys := strings.Split(key, ":")
	conf, ok := configs[keys[0]]
	if !ok {
		return nil, fmt.Errorf("key %s not found", key)
	}
	for _, k := range keys[1:] {
		conf, ok = conf.(map[interface{}]interface{})[k]
		if !ok {
			return nil, fmt.Errorf("key %s not found", key)
		}
	}
	return conf, nil
}

// GetString works like Get, but doing a string type assertion before return
// 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
	}
	if v, ok := value.(string); ok {
		return v, nil
	}
	return "", fmt.Errorf("key %s has non-string value", key)
}

// 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, fmt.Errorf("key %s has non-boolean value", key)
}

// mergeMaps takes two maps and merge its keys and values.
//
// 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 = mergeMaps(configs, last)
}

// Unset removes a key from the configuration map. It returns 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
	m := configs
	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 errors.New("Key " + key + " not found")
		}
	}
	delete(m, part)
	return nil
}
<commit_msg>config: improve docs for mergeMaps<commit_after>// Copyright 2012 config 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 config provide configuration facilities, handling configuration
// files in yaml format.
package config

import (
	"errors"
	"fmt"
	"io/ioutil"
	"launchpad.net/goyaml"
	"strings"
)

var configs map[interface{}]interface{}

// 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 {
	return goyaml.Unmarshal(data, &configs)
}

// 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)
}

// Get returns the value for the given key, or an eror if the key is undefined.
//
// The key is composed by 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.
func Get(key string) (interface{}, error) {
	keys := strings.Split(key, ":")
	conf, ok := configs[keys[0]]
	if !ok {
		return nil, fmt.Errorf("key %s not found", key)
	}
	for _, k := range keys[1:] {
		conf, ok = conf.(map[interface{}]interface{})[k]
		if !ok {
			return nil, fmt.Errorf("key %s not found", key)
		}
	}
	return conf, nil
}

// GetString works like Get, but doing a string type assertion before return
// 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
	}
	if v, ok := value.(string); ok {
		return v, nil
	}
	return "", fmt.Errorf("key %s has non-string value", key)
}

// 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, fmt.Errorf("key %s has non-boolean value", key)
}

// 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 = mergeMaps(configs, last)
}

// Unset removes a key from the configuration map. It returns 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
	m := configs
	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 errors.New("Key " + key + " not found")
		}
	}
	delete(m, part)
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"text/tabwriter"

	"github.com/mdlayher/untappd"
)

// printBadges turns a slice of *untappd.Badge structs into a human-friendly
// output format, and prints it to stdout.
func printBadges(badges []*untappd.Badge) {
	tw := tabWriter()

	// Print field header
	fmt.Fprintln(tw, "ID\tName\tEarned\tCheckinID")

	// Function to be invoked for each badge and badge level
	printFn := func(b *untappd.Badge) {
		y, m, d := b.Earned.Date()

		fmt.Fprintf(tw, "%d\t%s\t%s\t%d\n",
			b.ID,
			b.Name,
			fmt.Sprintf("%04d-%02d-%02d", y, m, d),
			b.CheckinID,
		)
	}

	// Print out each badge
	for _, b := range badges {
		printFn(b)

		// Print out each badge level
		for _, bb := range b.Levels {
			printFn(bb)
		}
	}

	// Flush buffered output
	if err := tw.Flush(); err != nil {
		log.Fatal(err)
	}
}

// printBeers turns a slice of *untappd.Beer structs into a human-friendly
// output format, and prints it to stdout.
func printBeers(beers []*untappd.Beer) {
	tw := tabWriter()

	// Print field header
	fmt.Fprintln(tw, "ID\tName\tBrewery\tStyle\tABV\tIBU")

	// Print out each beer
	for _, b := range beers {
		fmt.Fprintf(tw, "%d\t%s\t%s\t%s\t%0.1f\t%03d\n",
			b.ID,
			b.Name,
			b.Brewery.Name,
			b.Style,
			b.ABV,
			b.IBU,
		)
	}

	// Flush buffered output
	if err := tw.Flush(); err != nil {
		log.Fatal(err)
	}
}

// printBreweries turns a slice of *untappd.Brewery structs into a human-friendly
// output format, and prints it to stdout.
func printBreweries(breweries []*untappd.Brewery) {
	tw := tabWriter()

	// Print field header
	fmt.Fprintln(tw, "ID\tName\tLocation")

	// Print out each brewery
	for _, b := range breweries {
		// Use country as default location
		l := b.Country

		// Add extended information if available
		if b.Location.City != "" && b.Location.State != "" {
			l = fmt.Sprintf("%s, %s, %s",
				b.Location.City,
				b.Location.State,
				b.Country,
			)
		}

		fmt.Fprintf(tw, "%d\t%s\t%s\n",
			b.ID,
			b.Name,
			l,
		)
	}

	// Flush buffered output
	if err := tw.Flush(); err != nil {
		log.Fatal(err)
	}
}

// printCheckins turns a slice of *untappd.Checkin structs into a human-friendly
// output format, and prints it to stdout.
func printCheckins(checkins []*untappd.Checkin) {
	tw := tabWriter()

	// Print field header
	fmt.Fprintln(tw, "ID\tName\tBrewery\tRating\tComment")

	// Print out each checkin
	for _, c := range checkins {
		fmt.Fprintf(tw, "%d\t%s\t%s\t%0.1f\t%s\n",
			c.ID,
			c.Beer.Name,
			c.Brewery.Name,
			c.UserRating,
			c.Comment,
		)
	}

	// Flush buffered output
	if err := tw.Flush(); err != nil {
		log.Fatal(err)
	}
}

// printUsers turns a slice of *untappd.User structs into a human-friendly
// output format, and prints it to stdout.  The info parameter allows
// extended information to be printed for user info.
func printUsers(users []*untappd.User, info bool) {
	tw := tabWriter()

	header := "ID\tUserName\tName"
	if info {
		header += "\tCheckins\tBadges\tBeers"
	}

	// Print field header
	fmt.Fprintln(tw, header)

	// Print out each user
	for _, u := range users {
		fmt.Fprintf(tw, "%d\t%s\t%s %s",
			u.UID,
			u.UserName,
			u.FirstName,
			u.LastName,
		)

		if info {
			fmt.Fprintf(tw, "\t%d\t%d\t%d",
				u.Stats.TotalCheckins,
				u.Stats.TotalBadges,
				u.Stats.TotalBeers,
			)
		}
		fmt.Fprintf(tw, "\n")
	}

	// Flush buffered output
	if err := tw.Flush(); err != nil {
		log.Fatal(err)
	}
}

// printVenues turns a slice of *untappd.Venue structs into a human-friendly
// output format, and prints it to stdout.
func printVenues(venues []*untappd.Venue) {
	tw := tabWriter()

	// Print field header
	fmt.Fprintln(tw, "ID\tName\tCategory\tPublic\tLocation")

	// Print out each checkin
	for _, v := range venues {
		fmt.Fprintf(tw, "%d\t%s\t%s\t%t\t%s\n",
			v.ID,
			v.Name,
			v.Category,
			v.Public,
			fmt.Sprintf("%s, %s, %s",
				v.Location.City,
				v.Location.State,
				v.Location.Country,
			),
		)
	}

	// Flush buffered output
	if err := tw.Flush(); err != nil {
		log.Fatal(err)
	}
}

// tabWriter returns a *tabwriter.Writer appropriately configured
// for tabular output.
func tabWriter() *tabwriter.Writer {
	return tabwriter.NewWriter(os.Stdout, 0, 8, 2, '\t', 0)
}
<commit_msg>cmd/untappdctl: add number of badges, toasts, and comments to checkins<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"text/tabwriter"

	"github.com/mdlayher/untappd"
)

// printBadges turns a slice of *untappd.Badge structs into a human-friendly
// output format, and prints it to stdout.
func printBadges(badges []*untappd.Badge) {
	tw := tabWriter()

	// Print field header
	fmt.Fprintln(tw, "ID\tName\tEarned\tCheckinID")

	// Function to be invoked for each badge and badge level
	printFn := func(b *untappd.Badge) {
		y, m, d := b.Earned.Date()

		fmt.Fprintf(tw, "%d\t%s\t%s\t%d\n",
			b.ID,
			b.Name,
			fmt.Sprintf("%04d-%02d-%02d", y, m, d),
			b.CheckinID,
		)
	}

	// Print out each badge
	for _, b := range badges {
		printFn(b)

		// Print out each badge level
		for _, bb := range b.Levels {
			printFn(bb)
		}
	}

	// Flush buffered output
	if err := tw.Flush(); err != nil {
		log.Fatal(err)
	}
}

// printBeers turns a slice of *untappd.Beer structs into a human-friendly
// output format, and prints it to stdout.
func printBeers(beers []*untappd.Beer) {
	tw := tabWriter()

	// Print field header
	fmt.Fprintln(tw, "ID\tName\tBrewery\tStyle\tABV\tIBU")

	// Print out each beer
	for _, b := range beers {
		fmt.Fprintf(tw, "%d\t%s\t%s\t%s\t%0.1f\t%03d\n",
			b.ID,
			b.Name,
			b.Brewery.Name,
			b.Style,
			b.ABV,
			b.IBU,
		)
	}

	// Flush buffered output
	if err := tw.Flush(); err != nil {
		log.Fatal(err)
	}
}

// printBreweries turns a slice of *untappd.Brewery structs into a human-friendly
// output format, and prints it to stdout.
func printBreweries(breweries []*untappd.Brewery) {
	tw := tabWriter()

	// Print field header
	fmt.Fprintln(tw, "ID\tName\tLocation")

	// Print out each brewery
	for _, b := range breweries {
		// Use country as default location
		l := b.Country

		// Add extended information if available
		if b.Location.City != "" && b.Location.State != "" {
			l = fmt.Sprintf("%s, %s, %s",
				b.Location.City,
				b.Location.State,
				b.Country,
			)
		}

		fmt.Fprintf(tw, "%d\t%s\t%s\n",
			b.ID,
			b.Name,
			l,
		)
	}

	// Flush buffered output
	if err := tw.Flush(); err != nil {
		log.Fatal(err)
	}
}

// printCheckins turns a slice of *untappd.Checkin structs into a human-friendly
// output format, and prints it to stdout.
func printCheckins(checkins []*untappd.Checkin) {
	tw := tabWriter()

	// Print field header
	fmt.Fprintln(tw, "ID\tName\tBrewery\tRating\tBadges\tToasts\tComments\tComment")

	// Print out each checkin
	for _, c := range checkins {
		fmt.Fprintf(tw, "%d\t%s\t%s\t%0.2f\t%d\t%d\t%d\t%s\n",
			c.ID,
			c.Beer.Name,
			c.Brewery.Name,
			c.UserRating,
			len(c.Badges),
			len(c.Toasts),
			len(c.Comments),
			c.Comment,
		)
	}

	// Flush buffered output
	if err := tw.Flush(); err != nil {
		log.Fatal(err)
	}
}

// printUsers turns a slice of *untappd.User structs into a human-friendly
// output format, and prints it to stdout.  The info parameter allows
// extended information to be printed for user info.
func printUsers(users []*untappd.User, info bool) {
	tw := tabWriter()

	header := "ID\tUserName\tName"
	if info {
		header += "\tCheckins\tBadges\tBeers"
	}

	// Print field header
	fmt.Fprintln(tw, header)

	// Print out each user
	for _, u := range users {
		fmt.Fprintf(tw, "%d\t%s\t%s %s",
			u.UID,
			u.UserName,
			u.FirstName,
			u.LastName,
		)

		if info {
			fmt.Fprintf(tw, "\t%d\t%d\t%d",
				u.Stats.TotalCheckins,
				u.Stats.TotalBadges,
				u.Stats.TotalBeers,
			)
		}
		fmt.Fprintf(tw, "\n")
	}

	// Flush buffered output
	if err := tw.Flush(); err != nil {
		log.Fatal(err)
	}
}

// printVenues turns a slice of *untappd.Venue structs into a human-friendly
// output format, and prints it to stdout.
func printVenues(venues []*untappd.Venue) {
	tw := tabWriter()

	// Print field header
	fmt.Fprintln(tw, "ID\tName\tCategory\tPublic\tLocation")

	// Print out each checkin
	for _, v := range venues {
		fmt.Fprintf(tw, "%d\t%s\t%s\t%t\t%s\n",
			v.ID,
			v.Name,
			v.Category,
			v.Public,
			fmt.Sprintf("%s, %s, %s",
				v.Location.City,
				v.Location.State,
				v.Location.Country,
			),
		)
	}

	// Flush buffered output
	if err := tw.Flush(); err != nil {
		log.Fatal(err)
	}
}

// tabWriter returns a *tabwriter.Writer appropriately configured
// for tabular output.
func tabWriter() *tabwriter.Writer {
	return tabwriter.NewWriter(os.Stdout, 0, 8, 2, '\t', 0)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/writescript/writescript"
)

// main cli tool
func main() {

	//
	// meta
	//
	app := cli.NewApp()
	app.Name = "writescript"
	app.Version = writescript.Version
	app.Usage = "plugin based generator tool backpacked with data"
	app.Author = "Paul Vollmer"
	app.Email = "paul.vollmer@fh-potsdam.de"

	//
	// flags
	//
	app.Flags = []cli.Flag{
		// javascript code
		cli.StringFlag{
			Name:  "plugin, p",
			Value: "",
			Usage: "the generator plugin as file",
		},
		// json data
		cli.StringFlag{
			Name:  "data, d",
			Value: "",
			Usage: "the data as file or json string",
		},
		// settings
		cli.StringFlag{
			Name:  "linebreak, l",
			Value: "\\n",
			Usage: "the linebreak for each row",
		},
		cli.StringFlag{
			Name:  "whitespace, w",
			Value: "\\t",
			Usage: "the level whitespace",
		},
		cli.BoolFlag{
			Name:  "header-off, H",
			Usage: "disables header output",
		},
	}

	//
	// process
	//
	app.Action = func(c *cli.Context) {
		//
		// cli flags
		//
		flagPlugin := c.String("plugin")
		flagData := c.String("data")
		flagLinebreak := c.String("linebreak")
		flagWhitespace := c.String("whitespace")
		flagHeaderOff := c.Bool("header-off")

		// read plugin
		pluginBytes, err := ReadPlugin(flagPlugin)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

		// read data
		dataBytes, err := ReadData(flagData)
		if err != nil {
			fmt.Println("//", err)
			fmt.Println("// try to run...")
		}

		// run the generator
		ws := writescript.WriteScript{}
		err = ws.Process(string(pluginBytes), dataBytes, !flagHeaderOff)
		if err != nil {
			fmt.Println("writescript plugin error!\n", err)
			os.Exit(1)
		}

		if flagLinebreak == "\\n" {
			flagLinebreak = "\n"
		}
		if flagWhitespace == "\\t" {
			flagWhitespace = "\t"
		}
		fmt.Println(ws.Content.GetString(flagLinebreak, flagWhitespace))
	}

	app.Run(os.Args)
}

const (
	SourceTypeUnknown    = 0
	SourceTypeString     = 1
	SourceTypeJavascript = 2
	SourceTypeJSON       = 3
	SourceTypeURL        = 4
	ExtensionJavascript  = ".js"
	ExtensionJSON        = ".json"
)

func SourceIsType(src string) int {
	theType := SourceTypeUnknown

	tmpExt := filepath.Ext(src)
	tmpURL, urlErr := url.Parse(src)

	if urlErr == nil && tmpURL.Scheme == "http" || tmpURL.Scheme == "https" {
		theType = SourceTypeURL
	} else if tmpExt == ExtensionJavascript {
		theType = SourceTypeJavascript
	} else if tmpExt == ExtensionJSON {
		theType = SourceTypeJSON
	} else if src != "" {
		theType = SourceTypeString
	}

	return theType
}

//
// ReadPlugin and return as byte array
//
func ReadPlugin(src string) ([]byte, error) {
	var err error
	var dataReturn []byte

	switch SourceIsType(src) {
	case SourceTypeUnknown:
		dataReturn = []byte("")
		err = errors.New("No Plugin was set")
		break
	case SourceTypeString:
		dataReturn = []byte(src)
		break
	case SourceTypeJavascript:
		dataReturn, err = ioutil.ReadFile(src)
		break
	case SourceTypeJSON:
		dataReturn = []byte("")
		err = errors.New("JSON as Plugin not supported")
		break
	case SourceTypeURL:
		resp, errReq := http.Get(src)
		if errReq != nil {
			err = errReq
		}
		defer resp.Body.Close()
		body, errBody := ioutil.ReadAll(resp.Body)
		if errBody != nil {
			err = errBody
		}
		dataReturn = body
		break
	}

	return dataReturn, err
}

//
// ReadData and return as string. (this must be formatted as json)
//
func ReadData(src string) (string, error) {
	if src == "" {
		return "{}", nil
	}
	dataTmp := ""
	// check if data-flag is a .json file or data as string
	if filepath.Ext(src) == ".json" {
		dataBytes, err := ioutil.ReadFile(src)
		if err != nil {
			return "", err
		}
		dataTmp = string(dataBytes)
	} else {
		dataTmp = src
	}
	return dataTmp, nil
}
<commit_msg>remove unused import<commit_after>package main

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path/filepath"

	"github.com/codegangsta/cli"
	"github.com/writescript/writescript"
)

// main cli tool
func main() {

	//
	// meta
	//
	app := cli.NewApp()
	app.Name = "writescript"
	app.Version = writescript.Version
	app.Usage = "plugin based generator tool backpacked with data"
	app.Author = "Paul Vollmer"
	app.Email = "paul.vollmer@fh-potsdam.de"

	//
	// flags
	//
	app.Flags = []cli.Flag{
		// javascript code
		cli.StringFlag{
			Name:  "plugin, p",
			Value: "",
			Usage: "the generator plugin as file",
		},
		// json data
		cli.StringFlag{
			Name:  "data, d",
			Value: "",
			Usage: "the data as file or json string",
		},
		// settings
		cli.StringFlag{
			Name:  "linebreak, l",
			Value: "\\n",
			Usage: "the linebreak for each row",
		},
		cli.StringFlag{
			Name:  "whitespace, w",
			Value: "\\t",
			Usage: "the level whitespace",
		},
		cli.BoolFlag{
			Name:  "header-off, H",
			Usage: "disables header output",
		},
	}

	//
	// process
	//
	app.Action = func(c *cli.Context) {
		//
		// cli flags
		//
		flagPlugin := c.String("plugin")
		flagData := c.String("data")
		flagLinebreak := c.String("linebreak")
		flagWhitespace := c.String("whitespace")
		flagHeaderOff := c.Bool("header-off")

		// read plugin
		pluginBytes, err := ReadPlugin(flagPlugin)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

		// read data
		dataBytes, err := ReadData(flagData)
		if err != nil {
			fmt.Println("//", err)
			fmt.Println("// try to run...")
		}

		// run the generator
		ws := writescript.WriteScript{}
		err = ws.Process(string(pluginBytes), dataBytes, !flagHeaderOff)
		if err != nil {
			fmt.Println("writescript plugin error!\n", err)
			os.Exit(1)
		}

		if flagLinebreak == "\\n" {
			flagLinebreak = "\n"
		}
		if flagWhitespace == "\\t" {
			flagWhitespace = "\t"
		}
		fmt.Println(ws.Content.GetString(flagLinebreak, flagWhitespace))
	}

	app.Run(os.Args)
}

const (
	SourceTypeUnknown    = 0
	SourceTypeString     = 1
	SourceTypeJavascript = 2
	SourceTypeJSON       = 3
	SourceTypeURL        = 4
	ExtensionJavascript  = ".js"
	ExtensionJSON        = ".json"
)

func SourceIsType(src string) int {
	theType := SourceTypeUnknown

	tmpExt := filepath.Ext(src)
	tmpURL, urlErr := url.Parse(src)

	if urlErr == nil && tmpURL.Scheme == "http" || tmpURL.Scheme == "https" {
		theType = SourceTypeURL
	} else if tmpExt == ExtensionJavascript {
		theType = SourceTypeJavascript
	} else if tmpExt == ExtensionJSON {
		theType = SourceTypeJSON
	} else if src != "" {
		theType = SourceTypeString
	}

	return theType
}

//
// ReadPlugin and return as byte array
//
func ReadPlugin(src string) ([]byte, error) {
	var err error
	var dataReturn []byte

	switch SourceIsType(src) {
	case SourceTypeUnknown:
		dataReturn = []byte("")
		err = errors.New("No Plugin was set")
		break
	case SourceTypeString:
		dataReturn = []byte(src)
		break
	case SourceTypeJavascript:
		dataReturn, err = ioutil.ReadFile(src)
		break
	case SourceTypeJSON:
		dataReturn = []byte("")
		err = errors.New("JSON as Plugin not supported")
		break
	case SourceTypeURL:
		resp, errReq := http.Get(src)
		if errReq != nil {
			err = errReq
		}
		defer resp.Body.Close()
		body, errBody := ioutil.ReadAll(resp.Body)
		if errBody != nil {
			err = errBody
		}
		dataReturn = body
		break
	}

	return dataReturn, err
}

//
// ReadData and return as string. (this must be formatted as json)
//
func ReadData(src string) (string, error) {
	if src == "" {
		return "{}", nil
	}
	dataTmp := ""
	// check if data-flag is a .json file or data as string
	if filepath.Ext(src) == ".json" {
		dataBytes, err := ioutil.ReadFile(src)
		if err != nil {
			return "", err
		}
		dataTmp = string(dataBytes)
	} else {
		dataTmp = src
	}
	return dataTmp, nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Jonathan Chappelow
// Copyright (c) 2016 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"sort"
	"strings"

	"github.com/btcsuite/btclog"
	flags "github.com/btcsuite/go-flags"
	"github.com/decred/dcrd/chaincfg"
	"github.com/decred/dcrutil"
	"github.com/decred/dcrwallet/netparams"
)

const (
	defaultConfigFilename = "dcrdata.conf"
	defaultLogLevel       = "info"
	defaultLogDirname     = "logs"
	defaultLogFilename    = "dcrdata.log"
)

var curDir, _ = os.Getwd()
var activeNet = &netparams.MainNetParams
var activeChain = &chaincfg.MainNetParams

var (
	dcrdHomeDir = dcrutil.AppDataDir("dcrd", false)
	//dcrdataapiHomeDir            = dcrutil.AppDataDir("dcrdataapi", false)
	//defaultDaemonRPCKeyFile  = filepath.Join(dcrdHomeDir, "rpc.key")
	defaultDaemonRPCCertFile = filepath.Join(dcrdHomeDir, "rpc.cert")
	defaultConfigFile        = filepath.Join(curDir, defaultConfigFilename)
	defaultLogDir            = filepath.Join(curDir, defaultLogDirname)
	defaultHost              = "localhost"
	//defaultEmailSubject      = "dcrdataapi transaction notification"

	defaultAPIProto   = "http"
	defaultAPIListen  = "127.0.0.1:6000"
	defaultIndentJSON = "   "

	defaultMonitorMempool     = true
	defaultMempoolMinInterval = 2
	defaultMempoolMaxInterval = 120
	defaultMPTriggerTickets   = 1

	defaultDBFileName = "dcrdata.sqlt.db"
)

type config struct {
	// General application behavior
	ConfigFile  string `short:"C" long:"configfile" description:"Path to configuration file"`
	ShowVersion bool   `short:"V" long:"version" description:"Display version information and exit"`
	TestNet     bool   `long:"testnet" description:"Use the test network (default mainnet)"`
	SimNet      bool   `long:"simnet" description:"Use the simulation test network (default mainnet)"`
	DebugLevel  string `short:"d" long:"debuglevel" description:"Logging level {trace, debug, info, warn, error, critical}"`
	Quiet       bool   `short:"q" long:"quiet" description:"Easy way to set debuglevel to error"`
	LogDir      string `long:"logdir" description:"Directory to log output"`
	CPUProfile  string `long:"cpuprofile" description:"File for CPU profiling."`

	// API
	APIProto   string `long:"apiproto" description:"Protocol for API (http or https)"`
	APIListen  string `long:"apilisten" description:"Listen address for API"`
	IndentJSON string `long:"indentjson" description:"String for JSON indentation (default is \"   \"), when indentation is requested via URL query."`
	UseRealIP  bool   `long:"userealip" description:"Use the RealIP middleware from the pressly/chi/middleware package to get the client's real IP from the X-Forwarded-For or X-Real-IP headers, in that order."`

	// Comamnd execution
	//CmdName string `short:"c" long:"cmdname" description:"Command name to run. Must be on %PATH%."`
	//CmdArgs string `short:"a" long:"cmdargs" description:"Comma-separated list of arguments for command to run. The specifier %n is substituted for block height at execution, and %h is substituted for block hash."`

	// Data I/O
	MonitorMempool     bool   `short:"m" long:"mempool" description:"Monitor mempool for new transactions, and report ticketfee info when new tickets are added."`
	MempoolMinInterval int    `long:"mp-min-interval" description:"The minimum time in seconds between mempool reports, regarless of number of new tickets seen."`
	MempoolMaxInterval int    `long:"mp-max-interval" description:"The maximum time in seconds between mempool reports (within a couple seconds), regarless of number of new tickets seen."`
	MPTriggerTickets   int    `long:"mp-ticket-trigger" description:"The number minimum number of new tickets that must be seen to trigger a new mempool report."`
	DumpAllMPTix       bool   `long:"dumpallmptix" description:"Dump to file the fees of all the tickets in mempool."`
	DBFileName         string `long:"dbfile" description:"SQLite DB file name (default is dcrdata.sqlt.db)."`

	//WatchAddresses []string `short:"w" long:"watchaddress" description:"Watched address (receiving). One per line."`
	//WatchOutpoints []string `short:"o" long:"watchout" description:"Watched outpoint (sending). One per line."`

	// SMTPUser     string `long:"smtpuser" description:"SMTP user name"`
	// SMTPPass     string `long:"smtppass" description:"SMTP password"`
	// SMTPServer   string `long:"smtpserver" description:"SMTP host name"`
	// EmailAddr    string `long:"emailaddr" description:"Destination email address for alerts"`
	// EmailSubject string `long:"emailsubj" description:"Email subject. (default \"dcrdataapi transaction notification\")"`

	OutFolder string `short:"f" long:"outfolder" description:"Folder for file outputs"`

	// RPC client options
	DcrdUser         string `long:"dcrduser" description:"Daemon RPC user name"`
	DcrdPass         string `long:"dcrdpass" description:"Daemon RPC password"`
	DcrdServ         string `long:"dcrdserv" description:"Hostname/IP and port of dcrd RPC server to connect to (default localhost:9109, testnet: localhost:19109, simnet: localhost:19556)"`
	DcrdCert         string `long:"dcrdcert" description:"File containing the dcrd certificate file"`
	DisableDaemonTLS bool   `long:"nodaemontls" description:"Disable TLS for the daemon RPC client -- NOTE: This is only allowed if the RPC client is connecting to localhost"`
}

var (
	defaultConfig = config{
		DebugLevel:         defaultLogLevel,
		ConfigFile:         defaultConfigFile,
		LogDir:             defaultLogDir,
		APIProto:           defaultAPIProto,
		APIListen:          defaultAPIListen,
		IndentJSON:         defaultIndentJSON,
		DcrdCert:           defaultDaemonRPCCertFile,
		MonitorMempool:     defaultMonitorMempool,
		MempoolMinInterval: defaultMempoolMinInterval,
		MempoolMaxInterval: defaultMempoolMaxInterval,
		MPTriggerTickets:   defaultMPTriggerTickets,
		DBFileName:         defaultDBFileName,
		//EmailSubject:       defaultEmailSubject,
	}
)

// cleanAndExpandPath expands environement variables and leading ~ in the
// passed path, cleans the result, and returns it.
func cleanAndExpandPath(path string) string {
	// Expand initial ~ to OS specific home directory.
	if strings.HasPrefix(path, "~") {
		homeDir := filepath.Dir(dcrdHomeDir)
		path = strings.Replace(path, "~", homeDir, 1)
	}

	// NOTE: The os.ExpandEnv doesn't work with Windows cmd.exe-style
	// %VARIABLE%, but they variables can still be expanded via POSIX-style
	// $VARIABLE.
	// So, replace any %VAR% with ${VAR}
	r := regexp.MustCompile(`%(?P<VAR>[^%/\\]*)%`)
	path = r.ReplaceAllString(path, "$${${VAR}}")
	return filepath.Clean(os.ExpandEnv(path))
}

// validLogLevel returns whether or not logLevel is a valid debug log level.
func validLogLevel(logLevel string) bool {
	_, ok := btclog.LevelFromString(logLevel)
	return ok
}

// supportedSubsystems returns a sorted slice of the supported subsystems for
// logging purposes.
func supportedSubsystems() []string {
	// Convert the subsystemLoggers map keys to a slice.
	subsystems := make([]string, 0, len(subsystemLoggers))
	for subsysID := range subsystemLoggers {
		subsystems = append(subsystems, subsysID)
	}

	// Sort the subsytems for stable display.
	sort.Strings(subsystems)
	return subsystems
}

// parseAndSetDebugLevels attempts to parse the specified debug level and set
// the levels accordingly.  An appropriate error is returned if anything is
// invalid.
func parseAndSetDebugLevels(debugLevel string) error {
	// When the specified string doesn't have any delimters, treat it as
	// the log level for all subsystems.
	if !strings.Contains(debugLevel, ",") && !strings.Contains(debugLevel, "=") {
		// Validate debug log level.
		if !validLogLevel(debugLevel) {
			str := "The specified debug level [%v] is invalid"
			return fmt.Errorf(str, debugLevel)
		}

		// Change the logging level for all subsystems.
		setLogLevels(debugLevel)

		return nil
	}

	// Split the specified string into subsystem/level pairs while detecting
	// issues and update the log levels accordingly.
	for _, logLevelPair := range strings.Split(debugLevel, ",") {
		if !strings.Contains(logLevelPair, "=") {
			str := "The specified debug level contains an invalid " +
				"subsystem/level pair [%v]"
			return fmt.Errorf(str, logLevelPair)
		}

		// Extract the specified subsystem and log level.
		fields := strings.Split(logLevelPair, "=")
		subsysID, logLevel := fields[0], fields[1]

		// Validate subsystem.
		if _, exists := subsystemLoggers[subsysID]; !exists {
			str := "The specified subsystem [%v] is invalid -- " +
				"supported subsytems %v"
			return fmt.Errorf(str, subsysID, supportedSubsystems())
		}

		// Validate log level.
		if !validLogLevel(logLevel) {
			str := "The specified debug level [%v] is invalid"
			return fmt.Errorf(str, logLevel)
		}

		setLogLevel(subsysID, logLevel)
	}

	return nil
}

// loadConfig initializes and parses the config using a config file and command
// line options.
func loadConfig() (*config, error) {
	loadConfigError := func(err error) (*config, error) {
		return nil, err
	}

	// Default config.
	cfg := defaultConfig

	// A config file in the current directory takes precedence.
	if _, err := os.Stat(defaultConfigFilename); !os.IsNotExist(err) {
		cfg.ConfigFile = defaultConfigFile
	}

	// Pre-parse the command line options to see if an alternative config
	// file or the version flag was specified.
	preCfg := cfg
	preParser := flags.NewParser(&preCfg, flags.HelpFlag|flags.PassDoubleDash)
	_, err := preParser.Parse()
	if err != nil {
		e, ok := err.(*flags.Error)
		if !ok || e.Type != flags.ErrHelp {
			preParser.WriteHelp(os.Stderr)
		}
		if ok && e.Type == flags.ErrHelp {
			preParser.WriteHelp(os.Stdout)
			os.Exit(0)
		}
		return loadConfigError(err)
	}

	// Show the version and exit if the version flag was specified.
	appName := filepath.Base(os.Args[0])
	appName = strings.TrimSuffix(appName, filepath.Ext(appName))
	if preCfg.ShowVersion {
		fmt.Println(appName, "version", ver.String())
		os.Exit(0)
	}

	// Load additional config from file.
	var configFileError error
	parser := flags.NewParser(&cfg, flags.Default)
	err = flags.NewIniParser(parser).ParseFile(preCfg.ConfigFile)
	if err != nil {
		if _, ok := err.(*os.PathError); !ok {
			fmt.Fprintln(os.Stderr, err)
			parser.WriteHelp(os.Stderr)
			return loadConfigError(err)
		}
		configFileError = err
	}

	// Parse command line options again to ensure they take precedence.
	_, err = parser.Parse()
	if err != nil {
		if e, ok := err.(*flags.Error); !ok || e.Type != flags.ErrHelp {
			parser.WriteHelp(os.Stderr)
		}
		return loadConfigError(err)
	}

	// Warn about missing config file after the final command line parse
	// succeeds.  This prevents the warning on help messages and invalid
	// options.
	if configFileError != nil {
		log.Warnf("%v", configFileError)
		//fmt.Printf("%v\n",configFileError)
		return loadConfigError(configFileError)
	}

	// Choose the active network params based on the selected network.
	// Multiple networks can't be selected simultaneously.
	numNets := 0
	activeNet = &netparams.MainNetParams
	activeChain = &chaincfg.MainNetParams
	if cfg.TestNet {
		activeNet = &netparams.TestNet2Params
		activeChain = &chaincfg.TestNet2Params
		numNets++
	}
	if cfg.SimNet {
		activeNet = &netparams.SimNetParams
		activeChain = &chaincfg.SimNetParams
		numNets++
	}
	if numNets > 1 {
		str := "%s: The testnet and simnet params can't be used " +
			"together -- choose one"
		err := fmt.Errorf(str, "loadConfig")
		fmt.Fprintln(os.Stderr, err)
		parser.WriteHelp(os.Stderr)
		return loadConfigError(err)
	}

	// Set the host names and ports to the default if the
	// user does not specify them.
	if cfg.DcrdServ == "" {
		cfg.DcrdServ = defaultHost + ":" + activeNet.JSONRPCClientPort
	}

	// Put comma-separated comamnd line aguments into slice of strings
	//cfg.CmdArgs = strings.Split(cfg.CmdArgs[0], ",")

	// // Output folder
	cfg.OutFolder = cleanAndExpandPath(cfg.OutFolder)
	cfg.OutFolder = filepath.Join(cfg.OutFolder, activeNet.Name)

	// The HTTP server port can not be beyond a uint16's size in value.
	// if cfg.HttpSvrPort > 0xffff {
	// 	str := "%s: Invalid HTTP port number for HTTP server"
	// 	err := fmt.Errorf(str, "loadConfig")
	// 	fmt.Fprintln(os.Stderr, err)
	// 	parser.WriteHelp(os.Stderr)
	// 	return loadConfigError(err)
	// }

	// Append the network type to the log directory so it is "namespaced"
	// per network.
	cfg.LogDir = cleanAndExpandPath(cfg.LogDir)
	cfg.LogDir = filepath.Join(cfg.LogDir, activeNet.Name)

	// Special show command to list supported subsystems and exit.
	if cfg.DebugLevel == "show" {
		fmt.Println("Supported subsystems", supportedSubsystems())
		os.Exit(0)
	}

	// Initialize log rotation.  After log rotation has been initialized, the
	// logger variables may be used.
	initLogRotator(filepath.Join(cfg.LogDir, defaultLogFilename))

	// Parse, validate, and set debug log level(s).
	if cfg.Quiet {
		cfg.DebugLevel = "error"
	}
	if err := parseAndSetDebugLevels(cfg.DebugLevel); err != nil {
		err = fmt.Errorf("%s: %v", "loadConfig", err.Error())
		fmt.Fprintln(os.Stderr, err)
		parser.WriteHelp(os.Stderr)
		return loadConfigError(err)
	}

	return &cfg, nil
}
<commit_msg>Removed log warning<commit_after>// Copyright (c) 2017 Jonathan Chappelow
// Copyright (c) 2016 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"sort"
	"strings"

	"github.com/btcsuite/btclog"
	flags "github.com/btcsuite/go-flags"
	"github.com/decred/dcrd/chaincfg"
	"github.com/decred/dcrutil"
	"github.com/decred/dcrwallet/netparams"
)

const (
	defaultConfigFilename = "dcrdata.conf"
	defaultLogLevel       = "info"
	defaultLogDirname     = "logs"
	defaultLogFilename    = "dcrdata.log"
)

var curDir, _ = os.Getwd()
var activeNet = &netparams.MainNetParams
var activeChain = &chaincfg.MainNetParams

var (
	dcrdHomeDir = dcrutil.AppDataDir("dcrd", false)
	//dcrdataapiHomeDir            = dcrutil.AppDataDir("dcrdataapi", false)
	//defaultDaemonRPCKeyFile  = filepath.Join(dcrdHomeDir, "rpc.key")
	defaultDaemonRPCCertFile = filepath.Join(dcrdHomeDir, "rpc.cert")
	defaultConfigFile        = filepath.Join(curDir, defaultConfigFilename)
	defaultLogDir            = filepath.Join(curDir, defaultLogDirname)
	defaultHost              = "localhost"
	//defaultEmailSubject      = "dcrdataapi transaction notification"

	defaultAPIProto   = "http"
	defaultAPIListen  = "127.0.0.1:6000"
	defaultIndentJSON = "   "

	defaultMonitorMempool     = true
	defaultMempoolMinInterval = 2
	defaultMempoolMaxInterval = 120
	defaultMPTriggerTickets   = 1

	defaultDBFileName = "dcrdata.sqlt.db"
)

type config struct {
	// General application behavior
	ConfigFile  string `short:"C" long:"configfile" description:"Path to configuration file"`
	ShowVersion bool   `short:"V" long:"version" description:"Display version information and exit"`
	TestNet     bool   `long:"testnet" description:"Use the test network (default mainnet)"`
	SimNet      bool   `long:"simnet" description:"Use the simulation test network (default mainnet)"`
	DebugLevel  string `short:"d" long:"debuglevel" description:"Logging level {trace, debug, info, warn, error, critical}"`
	Quiet       bool   `short:"q" long:"quiet" description:"Easy way to set debuglevel to error"`
	LogDir      string `long:"logdir" description:"Directory to log output"`
	CPUProfile  string `long:"cpuprofile" description:"File for CPU profiling."`

	// API
	APIProto   string `long:"apiproto" description:"Protocol for API (http or https)"`
	APIListen  string `long:"apilisten" description:"Listen address for API"`
	IndentJSON string `long:"indentjson" description:"String for JSON indentation (default is \"   \"), when indentation is requested via URL query."`
	UseRealIP  bool   `long:"userealip" description:"Use the RealIP middleware from the pressly/chi/middleware package to get the client's real IP from the X-Forwarded-For or X-Real-IP headers, in that order."`

	// Comamnd execution
	//CmdName string `short:"c" long:"cmdname" description:"Command name to run. Must be on %PATH%."`
	//CmdArgs string `short:"a" long:"cmdargs" description:"Comma-separated list of arguments for command to run. The specifier %n is substituted for block height at execution, and %h is substituted for block hash."`

	// Data I/O
	MonitorMempool     bool   `short:"m" long:"mempool" description:"Monitor mempool for new transactions, and report ticketfee info when new tickets are added."`
	MempoolMinInterval int    `long:"mp-min-interval" description:"The minimum time in seconds between mempool reports, regarless of number of new tickets seen."`
	MempoolMaxInterval int    `long:"mp-max-interval" description:"The maximum time in seconds between mempool reports (within a couple seconds), regarless of number of new tickets seen."`
	MPTriggerTickets   int    `long:"mp-ticket-trigger" description:"The number minimum number of new tickets that must be seen to trigger a new mempool report."`
	DumpAllMPTix       bool   `long:"dumpallmptix" description:"Dump to file the fees of all the tickets in mempool."`
	DBFileName         string `long:"dbfile" description:"SQLite DB file name (default is dcrdata.sqlt.db)."`

	//WatchAddresses []string `short:"w" long:"watchaddress" description:"Watched address (receiving). One per line."`
	//WatchOutpoints []string `short:"o" long:"watchout" description:"Watched outpoint (sending). One per line."`

	// SMTPUser     string `long:"smtpuser" description:"SMTP user name"`
	// SMTPPass     string `long:"smtppass" description:"SMTP password"`
	// SMTPServer   string `long:"smtpserver" description:"SMTP host name"`
	// EmailAddr    string `long:"emailaddr" description:"Destination email address for alerts"`
	// EmailSubject string `long:"emailsubj" description:"Email subject. (default \"dcrdataapi transaction notification\")"`

	OutFolder string `short:"f" long:"outfolder" description:"Folder for file outputs"`

	// RPC client options
	DcrdUser         string `long:"dcrduser" description:"Daemon RPC user name"`
	DcrdPass         string `long:"dcrdpass" description:"Daemon RPC password"`
	DcrdServ         string `long:"dcrdserv" description:"Hostname/IP and port of dcrd RPC server to connect to (default localhost:9109, testnet: localhost:19109, simnet: localhost:19556)"`
	DcrdCert         string `long:"dcrdcert" description:"File containing the dcrd certificate file"`
	DisableDaemonTLS bool   `long:"nodaemontls" description:"Disable TLS for the daemon RPC client -- NOTE: This is only allowed if the RPC client is connecting to localhost"`
}

var (
	defaultConfig = config{
		DebugLevel:         defaultLogLevel,
		ConfigFile:         defaultConfigFile,
		LogDir:             defaultLogDir,
		APIProto:           defaultAPIProto,
		APIListen:          defaultAPIListen,
		IndentJSON:         defaultIndentJSON,
		DcrdCert:           defaultDaemonRPCCertFile,
		MonitorMempool:     defaultMonitorMempool,
		MempoolMinInterval: defaultMempoolMinInterval,
		MempoolMaxInterval: defaultMempoolMaxInterval,
		MPTriggerTickets:   defaultMPTriggerTickets,
		DBFileName:         defaultDBFileName,
		//EmailSubject:       defaultEmailSubject,
	}
)

// cleanAndExpandPath expands environement variables and leading ~ in the
// passed path, cleans the result, and returns it.
func cleanAndExpandPath(path string) string {
	// Expand initial ~ to OS specific home directory.
	if strings.HasPrefix(path, "~") {
		homeDir := filepath.Dir(dcrdHomeDir)
		path = strings.Replace(path, "~", homeDir, 1)
	}

	// NOTE: The os.ExpandEnv doesn't work with Windows cmd.exe-style
	// %VARIABLE%, but they variables can still be expanded via POSIX-style
	// $VARIABLE.
	// So, replace any %VAR% with ${VAR}
	r := regexp.MustCompile(`%(?P<VAR>[^%/\\]*)%`)
	path = r.ReplaceAllString(path, "$${${VAR}}")
	return filepath.Clean(os.ExpandEnv(path))
}

// validLogLevel returns whether or not logLevel is a valid debug log level.
func validLogLevel(logLevel string) bool {
	_, ok := btclog.LevelFromString(logLevel)
	return ok
}

// supportedSubsystems returns a sorted slice of the supported subsystems for
// logging purposes.
func supportedSubsystems() []string {
	// Convert the subsystemLoggers map keys to a slice.
	subsystems := make([]string, 0, len(subsystemLoggers))
	for subsysID := range subsystemLoggers {
		subsystems = append(subsystems, subsysID)
	}

	// Sort the subsytems for stable display.
	sort.Strings(subsystems)
	return subsystems
}

// parseAndSetDebugLevels attempts to parse the specified debug level and set
// the levels accordingly.  An appropriate error is returned if anything is
// invalid.
func parseAndSetDebugLevels(debugLevel string) error {
	// When the specified string doesn't have any delimters, treat it as
	// the log level for all subsystems.
	if !strings.Contains(debugLevel, ",") && !strings.Contains(debugLevel, "=") {
		// Validate debug log level.
		if !validLogLevel(debugLevel) {
			str := "The specified debug level [%v] is invalid"
			return fmt.Errorf(str, debugLevel)
		}

		// Change the logging level for all subsystems.
		setLogLevels(debugLevel)

		return nil
	}

	// Split the specified string into subsystem/level pairs while detecting
	// issues and update the log levels accordingly.
	for _, logLevelPair := range strings.Split(debugLevel, ",") {
		if !strings.Contains(logLevelPair, "=") {
			str := "The specified debug level contains an invalid " +
				"subsystem/level pair [%v]"
			return fmt.Errorf(str, logLevelPair)
		}

		// Extract the specified subsystem and log level.
		fields := strings.Split(logLevelPair, "=")
		subsysID, logLevel := fields[0], fields[1]

		// Validate subsystem.
		if _, exists := subsystemLoggers[subsysID]; !exists {
			str := "The specified subsystem [%v] is invalid -- " +
				"supported subsytems %v"
			return fmt.Errorf(str, subsysID, supportedSubsystems())
		}

		// Validate log level.
		if !validLogLevel(logLevel) {
			str := "The specified debug level [%v] is invalid"
			return fmt.Errorf(str, logLevel)
		}

		setLogLevel(subsysID, logLevel)
	}

	return nil
}

// loadConfig initializes and parses the config using a config file and command
// line options.
func loadConfig() (*config, error) {
	loadConfigError := func(err error) (*config, error) {
		return nil, err
	}

	// Default config.
	cfg := defaultConfig

	// A config file in the current directory takes precedence.
	if _, err := os.Stat(defaultConfigFilename); !os.IsNotExist(err) {
		cfg.ConfigFile = defaultConfigFile
	}

	// Pre-parse the command line options to see if an alternative config
	// file or the version flag was specified.
	preCfg := cfg
	preParser := flags.NewParser(&preCfg, flags.HelpFlag|flags.PassDoubleDash)
	_, err := preParser.Parse()
	if err != nil {
		e, ok := err.(*flags.Error)
		if !ok || e.Type != flags.ErrHelp {
			preParser.WriteHelp(os.Stderr)
		}
		if ok && e.Type == flags.ErrHelp {
			preParser.WriteHelp(os.Stdout)
			os.Exit(0)
		}
		return loadConfigError(err)
	}

	// Show the version and exit if the version flag was specified.
	appName := filepath.Base(os.Args[0])
	appName = strings.TrimSuffix(appName, filepath.Ext(appName))
	if preCfg.ShowVersion {
		fmt.Println(appName, "version", ver.String())
		os.Exit(0)
	}

	// Load additional config from file.
	var configFileError error
	parser := flags.NewParser(&cfg, flags.Default)
	err = flags.NewIniParser(parser).ParseFile(preCfg.ConfigFile)
	if err != nil {
		if _, ok := err.(*os.PathError); !ok {
			fmt.Fprintln(os.Stderr, err)
			parser.WriteHelp(os.Stderr)
			return loadConfigError(err)
		}
		configFileError = err
	}

	// Parse command line options again to ensure they take precedence.
	_, err = parser.Parse()
	if err != nil {
		if e, ok := err.(*flags.Error); !ok || e.Type != flags.ErrHelp {
			parser.WriteHelp(os.Stderr)
		}
		return loadConfigError(err)
	}

	// Warn about missing config file after the final command line parse
	// succeeds.  This prevents the warning on help messages and invalid
	// options.
	if configFileError != nil {
		//log.Warnf("%v", configFileError)
		//fmt.Printf("%v\n",configFileError)
		return loadConfigError(configFileError)
	}

	// Choose the active network params based on the selected network.
	// Multiple networks can't be selected simultaneously.
	numNets := 0
	activeNet = &netparams.MainNetParams
	activeChain = &chaincfg.MainNetParams
	if cfg.TestNet {
		activeNet = &netparams.TestNet2Params
		activeChain = &chaincfg.TestNet2Params
		numNets++
	}
	if cfg.SimNet {
		activeNet = &netparams.SimNetParams
		activeChain = &chaincfg.SimNetParams
		numNets++
	}
	if numNets > 1 {
		str := "%s: The testnet and simnet params can't be used " +
			"together -- choose one"
		err := fmt.Errorf(str, "loadConfig")
		fmt.Fprintln(os.Stderr, err)
		parser.WriteHelp(os.Stderr)
		return loadConfigError(err)
	}

	// Set the host names and ports to the default if the
	// user does not specify them.
	if cfg.DcrdServ == "" {
		cfg.DcrdServ = defaultHost + ":" + activeNet.JSONRPCClientPort
	}

	// Put comma-separated comamnd line aguments into slice of strings
	//cfg.CmdArgs = strings.Split(cfg.CmdArgs[0], ",")

	// // Output folder
	cfg.OutFolder = cleanAndExpandPath(cfg.OutFolder)
	cfg.OutFolder = filepath.Join(cfg.OutFolder, activeNet.Name)

	// The HTTP server port can not be beyond a uint16's size in value.
	// if cfg.HttpSvrPort > 0xffff {
	// 	str := "%s: Invalid HTTP port number for HTTP server"
	// 	err := fmt.Errorf(str, "loadConfig")
	// 	fmt.Fprintln(os.Stderr, err)
	// 	parser.WriteHelp(os.Stderr)
	// 	return loadConfigError(err)
	// }

	// Append the network type to the log directory so it is "namespaced"
	// per network.
	cfg.LogDir = cleanAndExpandPath(cfg.LogDir)
	cfg.LogDir = filepath.Join(cfg.LogDir, activeNet.Name)

	// Special show command to list supported subsystems and exit.
	if cfg.DebugLevel == "show" {
		fmt.Println("Supported subsystems", supportedSubsystems())
		os.Exit(0)
	}

	// Initialize log rotation.  After log rotation has been initialized, the
	// logger variables may be used.
	initLogRotator(filepath.Join(cfg.LogDir, defaultLogFilename))

	// Parse, validate, and set debug log level(s).
	if cfg.Quiet {
		cfg.DebugLevel = "error"
	}
	if err := parseAndSetDebugLevels(cfg.DebugLevel); err != nil {
		err = fmt.Errorf("%s: %v", "loadConfig", err.Error())
		fmt.Fprintln(os.Stderr, err)
		parser.WriteHelp(os.Stderr)
		return loadConfigError(err)
	}

	return &cfg, nil
}
<|endoftext|>