<commit_before>package consul

import (
	"fmt"
	"log"
	"net/url"
	"strings"

	"github.com/gliderlabs/registrator/bridge"
	consulapi "github.com/hashicorp/consul/api"
)

const DefaultInterval = "10s"

func init() {
	bridge.Register(new(Factory), "consul")
}

func (r *ConsulAdapter) interpolateService(script string, service *bridge.Service) string {
	withIp := strings.Replace(script, "$SERVICE_IP", service.Origin.HostIP, -1)
	withPort := strings.Replace(withIp, "$SERVICE_PORT", service.Origin.HostPort, -1)
	return withPort
}

type Factory struct{}

func (f *Factory) New(uri *url.URL) bridge.RegistryAdapter {
	config := consulapi.DefaultConfig()
	if uri.Host != "" {
		config.Address = uri.Host
	}
	client, err := consulapi.NewClient(config)
	if err != nil {
		log.Fatal("consul: ", uri.Scheme)
	}
	return &ConsulAdapter{client: client}
}

type ConsulAdapter struct {
	client *consulapi.Client
}

// Ping will try to connect to consul by attempting to retrieve the current leader.
func (r *ConsulAdapter) Ping() error {
	status := r.client.Status()
	leader, err := status.Leader()
	if err != nil {
		return err
	}
	log.Println("consul: current leader ", leader)

	return nil
}

func (r *ConsulAdapter) Register(service *bridge.Service) error {
	registration := new(consulapi.AgentServiceRegistration)
	registration.ID = service.ID
	registration.Name = service.Name
	registration.Port = service.Port
	registration.Tags = service.Tags
	registration.Address = service.IP
	registration.Check = r.buildCheck(service)
	return r.client.Agent().ServiceRegister(registration)
}

func (r *ConsulAdapter) buildCheck(service *bridge.Service) *consulapi.AgentServiceCheck {
	check := new(consulapi.AgentServiceCheck)
	if path := service.Attrs["check_http"]; path != "" {
		check.HTTP = fmt.Sprintf("http://%s:%d%s", service.IP, service.Port, path)
		if timeout := service.Attrs["check_timeout"]; timeout != "" {
			check.Timeout = timeout
		}
	} else if cmd := service.Attrs["check_cmd"]; cmd != "" {
		check.Script = fmt.Sprintf("check-cmd %s %s %s", service.Origin.ContainerID[:12], service.Origin.ExposedPort, cmd)
	} else if script := service.Attrs["check_script"]; script != "" {
		check.Script = r.interpolateService(script, service)
	} else if ttl := service.Attrs["check_ttl"]; ttl != "" {
		check.TTL = ttl
	} else {
		return nil
	}
	if check.Script != "" || check.HTTP != "" {
		if interval := service.Attrs["check_interval"]; interval != "" {
			check.Interval = interval
		} else {
			check.Interval = DefaultInterval
		}
	}
	return check
}

func (r *ConsulAdapter) Deregister(service *bridge.Service) error {
	return r.client.Agent().ServiceDeregister(service.ID)
}

func (r *ConsulAdapter) Refresh(service *bridge.Service) error {
	return nil
}
<commit_msg>Added support for storing service attributes in the Consul KV store. Use by adding a 'servicePrefix=somepath' URL parameter to the consul:// URL<commit_after>package consul

import (
	"fmt"
	"log"
	"net/url"
	"strings"

	"github.com/gliderlabs/registrator/bridge"
	consulapi "github.com/hashicorp/consul/api"
)

const DefaultInterval = "10s"

func init() {
	bridge.Register(new(Factory), "consul")
}

func (r *ConsulAdapter) interpolateService(script string, service *bridge.Service) string {
	withIp := strings.Replace(script, "$SERVICE_IP", service.Origin.HostIP, -1)
	withPort := strings.Replace(withIp, "$SERVICE_PORT", service.Origin.HostPort, -1)
	return withPort
}

type Factory struct{}

func (f *Factory) New(uri *url.URL) bridge.RegistryAdapter {
	config := consulapi.DefaultConfig()
	if uri.Host != "" {
		config.Address = uri.Host
	}
	servicePrefix := uri.Query()["prefix"]

	client, err := consulapi.NewClient(config)
	if err != nil {
		log.Fatal("consul: ", uri.Scheme)
	}
	return &ConsulAdapter{client: client, servicePrefix: servicePrefix[0]}
}

type ConsulAdapter struct {
	client        *consulapi.Client
	servicePrefix string
}

// Ping will try to connect to consul by attempting to retrieve the current leader.
func (r *ConsulAdapter) Ping() error {
	status := r.client.Status()
	leader, err := status.Leader()
	if err != nil {
		return err
	}
	log.Println("consul: current leader ", leader)

	return nil
}

func (r *ConsulAdapter) Register(service *bridge.Service) error {
	registration := new(consulapi.AgentServiceRegistration)
	registration.ID = service.ID
	registration.Name = service.Name
	registration.Port = service.Port
	registration.Tags = service.Tags
	registration.Address = service.IP
	registration.Check = r.buildCheck(service)
	if r.servicePrefix != "" {
		kv := r.client.KV()
		for k, v := range service.Attrs {
			pair := &consulapi.KVPair{Key: r.servicePrefix + "/" + service.ID + "/" + k, Value: []byte(v)}
			_, err := kv.Put(pair, nil)
			if err != nil {
				panic(err)
			}
		}
	}
	return r.client.Agent().ServiceRegister(registration)
}

func (r *ConsulAdapter) buildCheck(service *bridge.Service) *consulapi.AgentServiceCheck {
	check := new(consulapi.AgentServiceCheck)
	if path := service.Attrs["check_http"]; path != "" {
		check.HTTP = fmt.Sprintf("http://%s:%d%s", service.IP, service.Port, path)
		if timeout := service.Attrs["check_timeout"]; timeout != "" {
			check.Timeout = timeout
		}
	} else if cmd := service.Attrs["check_cmd"]; cmd != "" {
		check.Script = fmt.Sprintf("check-cmd %s %s %s", service.Origin.ContainerID[:12], service.Origin.ExposedPort, cmd)
	} else if script := service.Attrs["check_script"]; script != "" {
		check.Script = r.interpolateService(script, service)
	} else if ttl := service.Attrs["check_ttl"]; ttl != "" {
		check.TTL = ttl
	} else {
		return nil
	}
	if check.Script != "" || check.HTTP != "" {
		if interval := service.Attrs["check_interval"]; interval != "" {
			check.Interval = interval
		} else {
			check.Interval = DefaultInterval
		}
	}
	return check
}

func (r *ConsulAdapter) Deregister(service *bridge.Service) error {
	//	pair := &consulapi.KVPair{Key: "service_attribute" + "/" + service.Name + "/" + k, Value: []byte(v)}
	success := r.client.Agent().ServiceDeregister(service.ID)
	r.client.KV().DeleteTree("service_attribute"+"/"+service.ID, nil)
	return success
}

func (r *ConsulAdapter) Refresh(service *bridge.Service) error {
	return nil
}
<|endoftext|>


<commit_before>package config

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"path/filepath"

	"github.com/sivel/overseer/monitor"
	"github.com/sivel/overseer/notifier"
)

type Config struct {
}

func getNotifiers(configPath string) []notifier.Notifier {
	notifierPath := filepath.Join(configPath, "notifiers")
	files, err := ioutil.ReadDir(notifierPath)
	if err != nil {
		log.Fatalf("%s", err)
	}
	var notifiers []notifier.Notifier
	for _, f := range files {
		var tmp interface{}
		text, err := ioutil.ReadFile(filepath.Join(notifierPath, f.Name()))
		if err != nil {
			continue
		}
		err = json.Unmarshal(text, &tmp)
		if err != nil {
			continue
		}
		nConf := tmp.(map[string]interface{})
		if notifierType, ok := nConf["type"]; ok {
			nc, err := notifier.GetNotifier(notifierType.(string))
			if err != nil {
				continue
			}
			conf := nc(nConf)
			notifiers = append(notifiers, conf)
		}
	}
	return notifiers
}

func getMonitors(configPath string) []monitor.Monitor {
	monitorPath := filepath.Join(configPath, "monitors")
	files, err := ioutil.ReadDir(monitorPath)
	if err != nil {
		log.Fatalf("%s", err)
	}
	var monitors []monitor.Monitor
	for _, f := range files {
		var tmp interface{}
		text, err := ioutil.ReadFile(filepath.Join(monitorPath, f.Name()))
		if err != nil {
			continue
		}
		err = json.Unmarshal(text, &tmp)
		if err != nil {
			continue
		}
		mConf := tmp.(map[string]interface{})
		if monitorType, ok := mConf["type"]; ok {
			mc, err := monitor.GetMonitor(monitorType.(string))
			if err != nil {
				continue
			}
			conf := mc(mConf)
			monitors = append(monitors, conf)
		}
	}
	return monitors
}

func ParseConfig() ([]monitor.Monitor, []notifier.Notifier) {
	var config Config
	configPath, _ := filepath.Abs("/etc/overseer")
	configFile := filepath.Join(configPath, "overseer.json")
	text, err := ioutil.ReadFile(configFile)
	if err == nil {
		json.Unmarshal(text, &config)
	}
	notifiers := getNotifiers(configPath)
	monitors := getMonitors(configPath)
	return monitors, notifiers
}
<commit_msg>Ignore non .json files<commit_after>package config

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"path/filepath"
	"strings"

	"github.com/sivel/overseer/monitor"
	"github.com/sivel/overseer/notifier"
)

type Config struct {
}

func getNotifiers(configPath string) []notifier.Notifier {
	notifierPath := filepath.Join(configPath, "notifiers")
	files, err := ioutil.ReadDir(notifierPath)
	if err != nil {
		log.Fatalf("%s", err)
	}
	var notifiers []notifier.Notifier
	for _, f := range files {
		if !strings.HasSuffix(f.Name(), ".json") {
			continue
		}
		var tmp interface{}
		text, err := ioutil.ReadFile(filepath.Join(notifierPath, f.Name()))
		if err != nil {
			continue
		}
		err = json.Unmarshal(text, &tmp)
		if err != nil {
			continue
		}
		nConf := tmp.(map[string]interface{})
		if notifierType, ok := nConf["type"]; ok {
			nc, err := notifier.GetNotifier(notifierType.(string))
			if err != nil {
				continue
			}
			conf := nc(nConf)
			notifiers = append(notifiers, conf)
		}
	}
	return notifiers
}

func getMonitors(configPath string) []monitor.Monitor {
	monitorPath := filepath.Join(configPath, "monitors")
	files, err := ioutil.ReadDir(monitorPath)
	if err != nil {
		log.Fatalf("%s", err)
	}
	var monitors []monitor.Monitor
	for _, f := range files {
		if !strings.HasSuffix(f.Name(), ".json") {
			continue
		}
		var tmp interface{}
		text, err := ioutil.ReadFile(filepath.Join(monitorPath, f.Name()))
		if err != nil {
			continue
		}
		err = json.Unmarshal(text, &tmp)
		if err != nil {
			continue
		}
		mConf := tmp.(map[string]interface{})
		if monitorType, ok := mConf["type"]; ok {
			mc, err := monitor.GetMonitor(monitorType.(string))
			if err != nil {
				continue
			}
			conf := mc(mConf)
			monitors = append(monitors, conf)
		}
	}
	return monitors
}

func ParseConfig() ([]monitor.Monitor, []notifier.Notifier) {
	var config Config
	configPath, _ := filepath.Abs("/etc/overseer")
	configFile := filepath.Join(configPath, "overseer.json")
	text, err := ioutil.ReadFile(configFile)
	if err == nil {
		json.Unmarshal(text, &config)
	}
	notifiers := getNotifiers(configPath)
	monitors := getMonitors(configPath)
	return monitors, notifiers
}
<|endoftext|>


<commit_before>package config

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"os"
	"path"
	"time"
)

type cacheEntry struct {
	ModTime  time.Time
	Contents interface{}
}

type Config struct {
	ConfigDir string
	Cache     map[string]cacheEntry
}

type Context struct {
	Network string
	Target  string
	Source  string
}

var C Config

func lookupvar(key, path string) interface{} {
	var f interface{}
	i, err := os.Stat(path)
	if err != nil {
		return nil
	}

	_, ok := C.Cache[path]
	if C.Cache[path].ModTime.Before(i.ModTime()) || !ok {
		log.Println("Stale cache for", path)
		data, err := ioutil.ReadFile(path)
		if err != nil {
			return nil
		}

		err = json.Unmarshal(data, &f)
		if err != nil {
			log.Println("Cannot parse", path)
			return nil
		}

		log.Println("Updating cache for", path)
		C.Cache[path] = cacheEntry{
			ModTime:  i.ModTime(),
			Contents: f,
		}

		return f.(map[string]interface{})[key]
	} else {
		log.Println("Found cache for", path)
		return C.Cache[path].Contents.(map[string]interface{})[key]
	}
}

func (c *Config) Lookup(context Context, key string) interface{} {
	var fpath string
	var value interface{}
	if context.Network != "" {
		if context.Source != "" {
			if context.Target != "" {
				fpath = path.Join(c.ConfigDir, context.Network, context.Source, context.Target+".json")

				log.Println("Context:", context, "Looking up", key, "in", fpath)
				value = lookupvar(key, fpath)
				if value != nil {
					log.Println("Context:", context, "Found", key, value)
					return value
				}
			}

			fpath = path.Join(c.ConfigDir, context.Network, context.Source+".json")

			log.Println("Context:", context, "Looking up", key, "in", fpath)
			value = lookupvar(key, fpath)
			if value != nil {
				log.Println("Context:", context, "Found", key, value)
				return value
			}
		}

		fpath = path.Join(c.ConfigDir, context.Network+".json")

		log.Println("Context:", context, "Looking up", key, "in", fpath)
		value = lookupvar(key, fpath)
		if value != nil {
			log.Println("Context:", context, "Found", key, value)
			return value
		}
	}

	fpath = path.Join(c.ConfigDir, "common.json")

	log.Println("Context:", context, "Looking up", key, "in", fpath)
	value = lookupvar(key, fpath)
	if value != nil {
		log.Println("Context:", context, "Found", key, value)
		return value
	} else {
		log.Println("Key", key, "not found")
		return nil
	}
}
<commit_msg>Forgot about cache initalization<commit_after>package config

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"os"
	"path"
	"time"
)

type cacheEntry struct {
	ModTime  time.Time
	Contents interface{}
}

type Config struct {
	ConfigDir string
	Cache     map[string]cacheEntry
}

type Context struct {
	Network string
	Target  string
	Source  string
}

var C Config

func init() {
	log.Println("Initializing configuration cache")
	C.Cache = make(map[string]cacheEntry)
}

func lookupvar(key, path string) interface{} {
	var f interface{}
	i, err := os.Stat(path)
	if err != nil {
		return nil
	}

	_, ok := C.Cache[path]
	if C.Cache[path].ModTime.Before(i.ModTime()) || !ok {
		log.Println("Stale cache for", path)
		data, err := ioutil.ReadFile(path)
		if err != nil {
			return nil
		}

		err = json.Unmarshal(data, &f)
		if err != nil {
			log.Println("Cannot parse", path)
			return nil
		}

		log.Println("Updating cache for", path)
		C.Cache[path] = cacheEntry{
			ModTime:  i.ModTime(),
			Contents: f,
		}

		return f.(map[string]interface{})[key]
	} else {
		log.Println("Found cache for", path)
		return C.Cache[path].Contents.(map[string]interface{})[key]
	}
}

func (c *Config) Lookup(context Context, key string) interface{} {
	var fpath string
	var value interface{}
	if context.Network != "" {
		if context.Source != "" {
			if context.Target != "" {
				fpath = path.Join(c.ConfigDir, context.Network, context.Source, context.Target+".json")

				log.Println("Context:", context, "Looking up", key, "in", fpath)
				value = lookupvar(key, fpath)
				if value != nil {
					log.Println("Context:", context, "Found", key, value)
					return value
				}
			}

			fpath = path.Join(c.ConfigDir, context.Network, context.Source+".json")

			log.Println("Context:", context, "Looking up", key, "in", fpath)
			value = lookupvar(key, fpath)
			if value != nil {
				log.Println("Context:", context, "Found", key, value)
				return value
			}
		}

		fpath = path.Join(c.ConfigDir, context.Network+".json")

		log.Println("Context:", context, "Looking up", key, "in", fpath)
		value = lookupvar(key, fpath)
		if value != nil {
			log.Println("Context:", context, "Found", key, value)
			return value
		}
	}

	fpath = path.Join(c.ConfigDir, "common.json")

	log.Println("Context:", context, "Looking up", key, "in", fpath)
	value = lookupvar(key, fpath)
	if value != nil {
		log.Println("Context:", context, "Found", key, value)
		return value
	} else {
		log.Println("Key", key, "not found")
		return nil
	}
}
<|endoftext|>


<commit_before>package argo

import (
	"testing"
)

func TestAPI(t *testing.T) {
}
<commit_msg>Testing of the API<commit_after>package argo

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/stretchr/testify/assert"
)

type mockResource struct{}

func (m mockResource) List(*Request) (Response, *APIError) {
	return nil, nil
}

func (m mockResource) Post(*Request) (Response, *APIError) {
	return nil, nil
}

func (m mockResource) Get(*Request) (Response, *APIError) {
	return nil, nil
}

func (m mockResource) Patch(*Request) (Response, *APIError) {
	return nil, nil
}

func (m mockResource) Delete(*Request) (Response, *APIError) {
	return nil, nil
}

func TestAPI(t *testing.T) {
	assert := assert.New(t)

	// Start a server with no resources
	api := New()
	ts := httptest.NewServer(api)
	defer ts.Close()

	// API root returns routes
	resp, err := http.Get(ts.URL)
	assert.Nil(err)
	assert.Equal(http.StatusOK, resp.StatusCode)

	// A resource can be added after the server is started
	api.AddRest("nothing", mockResource{})

	resp, err = http.Get(ts.URL + "/nothing")
	assert.Nil(err)
	assert.Equal(http.StatusNoContent, resp.StatusCode)

	// Since no parameters were given, detail requests will 404
	resp, err = http.Get(ts.URL + "/nothing/1")
	assert.Nil(err)
	assert.Equal(http.StatusNotFound, resp.StatusCode)

	// Add a resource with parameters
	api.AddRest("things", mockResource{}, "id")
	resp, err = http.Get(ts.URL + "/things")
	assert.Nil(err)
	assert.Equal(http.StatusNoContent, resp.StatusCode)

	resp, err = http.Get(ts.URL + "/things/1")
	assert.Nil(err)
	assert.Equal(http.StatusNoContent, resp.StatusCode)
}
<|endoftext|>


<commit_before>package config

import (
	"io/ioutil"
	"os"
	"regexp"
	"strconv"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/rancherio/os/util"
	"gopkg.in/yaml.v2"
)

const (
	VERSION            = "0.0.1"
	CONSOLE_CONTAINER  = "console"
	DOCKER_BIN         = "/usr/bin/docker"
	DOCKER_SYSTEM_HOST = "unix:///var/run/system-docker.sock"
	DOCKER_HOST        = "unix:///var/run/docker.sock"
	IMAGES_PATH        = "/"
	IMAGES_PATTERN     = "images*.tar"
	SYS_INIT           = "/sbin/init-sys"
	USER_INIT          = "/sbin/init-user"
	MODULES_ARCHIVE    = "/modules.tar"
	DEBUG              = false
)

var (
	ConfigFile = "/var/lib/rancher/conf/rancher.yml"
)

type InitFunc func(*Config) error

type ContainerConfig struct {
	Id             string `yaml:"id,omitempty"`
	Cmd            string `yaml:"run,omitempty"`
	MigrateVolumes bool   `yaml:"migrate_volumes,omitempty"`
}

type Config struct {
	Debug            bool              `yaml:"debug,omitempty"`
	Disable          []string          `yaml:"disable,omitempty"`
	Dns              []string          `yaml:"dns,flow,omitempty"`
	Rescue           bool              `yaml:"rescue,omitempty"`
	RescueContainer  *ContainerConfig  `yaml:"rescue_container,omitempty"`
	State            ConfigState       `yaml:"state,omitempty"`
	Userdocker       UserDockerInfo    `yaml:"userdocker,omitempty"`
	SystemContainers []ContainerConfig `yaml:"system_containers,omitempty"`
	SystemDockerArgs []string          `yaml:"system_docker_args,flow,omitempty"`
	Modules          []string          `yaml:"modules,omitempty"`
	CloudInit        CloudInit         `yaml:"cloud_init"`
}

type UserDockerInfo struct {
	UseTLS        bool   `yaml:"use_tls"`
	TLSServerCert string `yaml:"tls_server_cert"`
	TLSServerKey  string `yaml:"tls_server_key"`
	TLSCACert     string `yaml:"tls_ca_cert"`
}

type ConfigState struct {
	FsType   string `yaml:"fstype"`
	Dev      string `yaml:"dev"`
	Required bool   `yaml:"required"`
}

type CloudInit struct {
	Datasources []string `yaml:"datasources"`
}

func (c *Config) Merge(newConfig Config) (bool, error) {
	//Efficient? Nope, but computers are fast
	newConfig.ClearReadOnly()
	content, err := newConfig.Dump()
	if err != nil {
		return false, err
	}

	log.Debugf("Input \n%s", string(content))

	err = yaml.Unmarshal([]byte(content), c)
	return true, err
}

func (c *Config) ClearReadOnly() {
	c.SystemContainers = []ContainerConfig{}
	c.RescueContainer = nil
}

func (c *Config) Dump() (string, error) {
	content, err := yaml.Marshal(c)
	if err != nil {
		return "", err
	} else {
		return string(content), err
	}
}

func (c Config) Save() error {
	c.ClearReadOnly()
	content, err := c.Dump()
	if err != nil {
		return err
	}

	return ioutil.WriteFile(ConfigFile, []byte(content), 400)
}

func LoadConfig() (*Config, error) {
	cfg := NewConfig()
	if err := cfg.Reload(); err != nil {
		return nil, err
	}

	if cfg.Debug {
		log.SetLevel(log.DebugLevel)
	}

	return cfg, nil
}

func (c *Config) readArgs() error {
	log.Debug("Reading config args")
	parts := make([]string, len(os.Args))

	for _, arg := range os.Args[1:] {
		if strings.HasPrefix(arg, "--") {
			arg = arg[2:]
		}

		arg = strings.Replace(arg, "-", ".", -1)
		parts = append(parts, arg)
	}

	cmdLine := strings.Join(parts, " ")
	if len(cmdLine) == 0 {
		return nil
	}

	log.Debugf("Config Args %s", cmdLine)

	cmdLineObj := parseCmdline(strings.TrimSpace(cmdLine))

	return c.merge(cmdLineObj)
}

func (c *Config) merge(values map[string]interface{}) error {
	// Lazy way to assign values to *Config
	override, err := yaml.Marshal(values)
	if err != nil {
		return err
	}
	return yaml.Unmarshal(override, c)
}

func (c *Config) readFile() error {
	content, err := ioutil.ReadFile(ConfigFile)
	if os.IsNotExist(err) {
		return nil
	}

	data := make(map[string]interface{})
	err = yaml.Unmarshal(content, data)
	if err != nil {
		return err
	}

	return c.merge(data)
}

func (c *Config) readCmdline() error {
	log.Debug("Reading config cmdline")
	cmdLine, err := ioutil.ReadFile("/proc/cmdline")
	if err != nil {
		return err
	}

	if len(cmdLine) == 0 {
		return nil
	}

	log.Debugf("Config cmdline %s", cmdLine)

	cmdLineObj := parseCmdline(strings.TrimSpace(string(cmdLine)))
	return c.merge(cmdLineObj)
}

func DummyMarshall(value string) interface{} {
	if strings.HasPrefix(value, "[") && strings.HasSuffix(value, "]") {
		return strings.Split(value[1:len(value)-1], ",")
	}

	if value == "true" {
		return true
	} else if value == "false" {
		return false
	} else if ok, _ := regexp.MatchString("^[0-9]+$", value); ok {
		i, err := strconv.Atoi(value)
		if err != nil {
			panic(err)
		}
		return i
	}

	return value
}

func parseCmdline(cmdLine string) map[string]interface{} {
	result := make(map[string]interface{})

outer:
	for _, part := range strings.Split(cmdLine, " ") {
		if !strings.HasPrefix(part, "rancher.") {
			continue
		}

		var value string
		kv := strings.SplitN(part, "=", 2)

		if len(kv) == 1 {
			value = "true"
		} else {
			value = kv[1]
		}

		current := result
		keys := strings.Split(kv[0], ".")[1:]
		for i, key := range keys {
			if i == len(keys)-1 {
				current[key] = DummyMarshall(value)
			} else {
				if obj, ok := current[key]; ok {
					if newCurrent, ok := obj.(map[string]interface{}); ok {
						current = newCurrent
					} else {
						continue outer
					}
				} else {
					newCurrent := make(map[string]interface{})
					current[key] = newCurrent
					current = newCurrent
				}
			}
		}
	}

	log.Debugf("Input obj %s", result)
	return result
}

func (c *Config) Reload() error {
	return util.ShortCircuit(
		c.readFile,
		c.readCmdline,
		c.readArgs,
	)
}

func (c *Config) GetContainerById(id string) *ContainerConfig {
	for _, c := range c.SystemContainers {
		if c.Id == id {
			return &c
		}
	}

	return nil
}

func RunInitFuncs(cfg *Config, initFuncs []InitFunc) error {
	for i, initFunc := range initFuncs {
		log.Debugf("[%d/%d] Starting", i+1, len(initFuncs))
		if err := initFunc(cfg); err != nil {
			log.Errorf("Failed [%d/%d] %d%%", i+1, len(initFuncs), ((i + 1) * 100 / len(initFuncs)))
			return err
		}
		log.Debugf("[%d/%d] Done %d%%", i+1, len(initFuncs), ((i + 1) * 100 / len(initFuncs)))
	}
	return nil
}
<commit_msg>Save ssh keys<commit_after>package config

import (
	"io/ioutil"
	"os"
	"regexp"
	"strconv"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/rancherio/os/util"
	"gopkg.in/yaml.v2"
)

const (
	VERSION            = "0.0.1"
	CONSOLE_CONTAINER  = "console"
	DOCKER_BIN         = "/usr/bin/docker"
	DOCKER_SYSTEM_HOST = "unix:///var/run/system-docker.sock"
	DOCKER_HOST        = "unix:///var/run/docker.sock"
	IMAGES_PATH        = "/"
	IMAGES_PATTERN     = "images*.tar"
	SYS_INIT           = "/sbin/init-sys"
	USER_INIT          = "/sbin/init-user"
	MODULES_ARCHIVE    = "/modules.tar"
	DEBUG              = false
)

var (
	ConfigFile = "/var/lib/rancher/conf/rancher.yml"
)

type InitFunc func(*Config) error

type ContainerConfig struct {
	Id             string `yaml:"id,omitempty"`
	Cmd            string `yaml:"run,omitempty"`
	MigrateVolumes bool   `yaml:"migrate_volumes,omitempty"`
}

type Config struct {
	Debug            bool              `yaml:"debug,omitempty"`
	Disable          []string          `yaml:"disable,omitempty"`
	Dns              []string          `yaml:"dns,flow,omitempty"`
	Rescue           bool              `yaml:"rescue,omitempty"`
	RescueContainer  *ContainerConfig  `yaml:"rescue_container,omitempty"`
	State            ConfigState       `yaml:"state,omitempty"`
	Userdocker       UserDockerInfo    `yaml:"userdocker,omitempty"`
	SystemContainers []ContainerConfig `yaml:"system_containers,omitempty"`
	SystemDockerArgs []string          `yaml:"system_docker_args,flow,omitempty"`
	Modules          []string          `yaml:"modules,omitempty"`
	CloudInit        CloudInit         `yaml:"cloud_init"`
	SshInfo          SshInfo           `yaml:"ssh"`
}

type UserDockerInfo struct {
	UseTLS        bool   `yaml:"use_tls"`
	TLSServerCert string `yaml:"tls_server_cert"`
	TLSServerKey  string `yaml:"tls_server_key"`
	TLSCACert     string `yaml:"tls_ca_cert"`
}

type SshInfo struct {
	Keys map[string]string
}

type ConfigState struct {
	FsType   string `yaml:"fstype"`
	Dev      string `yaml:"dev"`
	Required bool   `yaml:"required"`
}

type CloudInit struct {
	Datasources []string `yaml:"datasources"`
}

func (c *Config) Merge(newConfig Config) (bool, error) {
	//Efficient? Nope, but computers are fast
	newConfig.ClearReadOnly()
	content, err := newConfig.Dump()
	if err != nil {
		return false, err
	}

	log.Debugf("Input \n%s", string(content))

	err = yaml.Unmarshal([]byte(content), c)
	return true, err
}

func (c *Config) ClearReadOnly() {
	c.SystemContainers = []ContainerConfig{}
	c.RescueContainer = nil
}

func (c *Config) Dump() (string, error) {
	content, err := yaml.Marshal(c)
	if err != nil {
		return "", err
	} else {
		return string(content), err
	}
}

func (c Config) Save() error {
	c.ClearReadOnly()
	content, err := c.Dump()
	if err != nil {
		return err
	}

	return ioutil.WriteFile(ConfigFile, []byte(content), 400)
}

func LoadConfig() (*Config, error) {
	cfg := NewConfig()
	if err := cfg.Reload(); err != nil {
		return nil, err
	}

	if cfg.Debug {
		log.SetLevel(log.DebugLevel)
	}

	return cfg, nil
}

func (c *Config) readArgs() error {
	log.Debug("Reading config args")
	parts := make([]string, len(os.Args))

	for _, arg := range os.Args[1:] {
		if strings.HasPrefix(arg, "--") {
			arg = arg[2:]
		}

		arg = strings.Replace(arg, "-", ".", -1)
		parts = append(parts, arg)
	}

	cmdLine := strings.Join(parts, " ")
	if len(cmdLine) == 0 {
		return nil
	}

	log.Debugf("Config Args %s", cmdLine)

	cmdLineObj := parseCmdline(strings.TrimSpace(cmdLine))

	return c.merge(cmdLineObj)
}

func (c *Config) merge(values map[string]interface{}) error {
	// Lazy way to assign values to *Config
	override, err := yaml.Marshal(values)
	if err != nil {
		return err
	}
	return yaml.Unmarshal(override, c)
}

func (c *Config) readFile() error {
	content, err := ioutil.ReadFile(ConfigFile)
	if os.IsNotExist(err) {
		return nil
	} else if err != nil {
		return err
	}

	data := make(map[string]interface{})
	err = yaml.Unmarshal(content, data)
	if err != nil {
		return err
	}

	return c.merge(data)
}

func (c *Config) readCmdline() error {
	log.Debug("Reading config cmdline")
	cmdLine, err := ioutil.ReadFile("/proc/cmdline")
	if err != nil {
		return err
	}

	if len(cmdLine) == 0 {
		return nil
	}

	log.Debugf("Config cmdline %s", cmdLine)

	cmdLineObj := parseCmdline(strings.TrimSpace(string(cmdLine)))
	return c.merge(cmdLineObj)
}

func DummyMarshall(value string) interface{} {
	if strings.HasPrefix(value, "[") && strings.HasSuffix(value, "]") {
		return strings.Split(value[1:len(value)-1], ",")
	}

	if value == "true" {
		return true
	} else if value == "false" {
		return false
	} else if ok, _ := regexp.MatchString("^[0-9]+$", value); ok {
		i, err := strconv.Atoi(value)
		if err != nil {
			panic(err)
		}
		return i
	}

	return value
}

func parseCmdline(cmdLine string) map[string]interface{} {
	result := make(map[string]interface{})

outer:
	for _, part := range strings.Split(cmdLine, " ") {
		if !strings.HasPrefix(part, "rancher.") {
			continue
		}

		var value string
		kv := strings.SplitN(part, "=", 2)

		if len(kv) == 1 {
			value = "true"
		} else {
			value = kv[1]
		}

		current := result
		keys := strings.Split(kv[0], ".")[1:]
		for i, key := range keys {
			if i == len(keys)-1 {
				current[key] = DummyMarshall(value)
			} else {
				if obj, ok := current[key]; ok {
					if newCurrent, ok := obj.(map[string]interface{}); ok {
						current = newCurrent
					} else {
						continue outer
					}
				} else {
					newCurrent := make(map[string]interface{})
					current[key] = newCurrent
					current = newCurrent
				}
			}
		}
	}

	log.Debugf("Input obj %s", result)
	return result
}

func (c *Config) Reload() error {
	return util.ShortCircuit(
		c.readFile,
		c.readCmdline,
		c.readArgs,
	)
}

func (c *Config) GetContainerById(id string) *ContainerConfig {
	for _, c := range c.SystemContainers {
		if c.Id == id {
			return &c
		}
	}

	return nil
}

func RunInitFuncs(cfg *Config, initFuncs []InitFunc) error {
	for i, initFunc := range initFuncs {
		log.Debugf("[%d/%d] Starting", i+1, len(initFuncs))
		if err := initFunc(cfg); err != nil {
			log.Errorf("Failed [%d/%d] %d%%", i+1, len(initFuncs), ((i + 1) * 100 / len(initFuncs)))
			return err
		}
		log.Debugf("[%d/%d] Done %d%%", i+1, len(initFuncs), ((i + 1) * 100 / len(initFuncs)))
	}
	return nil
}
<|endoftext|>


<commit_before>package b2

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strings"
	"testing"
)

func Test_createB2_HasAuth(t *testing.T) {
	reqChan := make(chan *http.Request, 1)
	s, c := setupMockJsonServer(200, "", reqChan)
	defer s.Close()

	client := &client{Protocol: "http", Client: c}

	createB2("1", "1", client)

	// get the request that the mock server received
	req := <-reqChan

	username, password, ok := req.BasicAuth()
	if !ok {
		t.Fatal("Expected ok to be true, instead got false")
	}
	if username != "1" {
		t.Errorf(`Expected username to be "1", instead got %s`, username)
	}
	if password != "1" {
		t.Errorf(`Expected password to be "1", instead got %s`, password)
	}
}

func Test_parseCreateB2Response(t *testing.T) {
	// success
	resp := createTestResponse(200, `{"accountId":"1","authorizationToken":"1","apiUrl":"/","downloadUrl":"/"}`)

	b := &B2{AccountID: "1", ApplicationKey: "key"}
	b, err := b.parseCreateB2Response(resp)
	if err != nil {
		t.Fatalf("Expected err to be nil, instead got %+v", err)
	}

	if b.AccountID != "1" {
		t.Errorf(`Expected AccountID to be "1", instead got %s`, b.AccountID)
	}
	if b.AuthorizationToken != "1" {
		t.Errorf(`Expected AuthorizationToken to be "1", instead got %s`, b.AuthorizationToken)
	}
	if b.ApiUrl != "/" {
		t.Errorf(`Expected ApiUrl to be "/", instead got %s`, b.ApiUrl)
	}
	if b.DownloadUrl != "/" {
		t.Errorf(`Expected DownloadUrl to be "/", instead got %s`, b.DownloadUrl)
	}

	// errors
	resps := createTestErrorResponses()
	for i, resp := range resps {
		b := &B2{AccountID: "1", ApplicationKey: "key"}
		b, err := b.parseCreateB2Response(resp)
		testErrorResponse(err, 400+i, t)
		if b != nil {
			t.Errorf("Expected b to be nil, instead got %+v", b)
		}
	}
}

func Test_B2_CreateRequest(t *testing.T) {
	b2 := &B2{client: &client{Protocol: "https"}} // set client protocol to default

	methods := []string{
		"GET", "POST", "KITTENS",
		"POST", "BAD METHOD",
	}
	urls := []string{
		"http://example.com", "kittens://example.com", "aoeu://example.com",
		"invalid-url", "http://example.com",
	}
	reqBody := struct {
		a int `json:"a"`
	}{a: 1}

	for i := 0; i < 3; i++ {
		req, err := b2.CreateRequest(methods[i], urls[i], reqBody)
		if err != nil {
			t.Fatalf("Expected err to be nil, instead got %+v", err)
		}
		if req.URL.Scheme != "https" {
			t.Errorf(`Expected url protocol to be "https", instead got %s`, req.URL.Scheme)
		}
		if req.Body == nil {
			t.Error("Expected req.Body to not be nil")
		}
	}
	for i := 3; i < 5; i++ {
		req, err := b2.CreateRequest(methods[i], urls[i], reqBody)
		if req != nil {
			t.Errorf("Expected req to be nil, instead got %+v", req)
		}
		if err == nil {
			t.Fatal("Expected err to exist")
		}
	}
}

func Test_replaceProtocol(t *testing.T) {
	b2s := []B2{
		B2{client: &client{Protocol: "https"}},
		B2{client: &client{Protocol: "http"}},
		B2{client: &client{Protocol: "kittens"}},
	}
	urls := []string{
		"http://localhost", "https://localhost", "http://localhost", "kittens://localhost",
		"https://www.backblaze.com/", "https://www.backblaze.com/",
		"http://www.backblaze.com/", "kittens://www.backblaze.com/",
		"non/url/",
	}

	for i, b := range b2s {
		index, i2, index2 := i+1, i+4, i+5 // make offsets
		// localhost
		url, err := b.replaceProtocol(urls[i])
		if err != nil {
			t.Errorf("Expected no error, instead got %+v", err)
		}
		if url != urls[index] {
			t.Errorf("Expected url to be %s, instead got %s", urls[index], url)
		}

		// www.backblaze.com
		url, err = b.replaceProtocol(urls[i2])
		if err != nil {
			t.Errorf("Expected no error, instead got %+v", err)
		}
		if url != urls[index2] {
			t.Errorf("Expected url to be %s, instead got %s", urls[index2], url)
		}
	}

	url, err := b2s[0].replaceProtocol(urls[len(urls)-1])
	if err == nil {
		t.Errorf("Expected error, instead got nil, url returned was %s", url)
	}
}

func Test_GetBzInfoHeaders(t *testing.T) {
	headers := map[string][]string{
		"Content-Type":      []string{"kittens"},
		"X-Bz-Info-kittens": []string{"yes"},
		"X-Bz-Info-thing":   []string{"one"},
	}
	resp := &http.Response{Header: headers}

	bzHeaders := GetBzInfoHeaders(resp)

	if len(bzHeaders) != 2 {
		t.Fatalf("Expected length of headers to be 2, instead got %d", len(bzHeaders))
	}
	if h, ok := bzHeaders["Content-Type"]; ok {
		t.Errorf("Expected no Content-Type, instead recieved %s", h)
	}
	if h := bzHeaders["kittens"]; h != "yes" {
		t.Errorf(`Expected kittens to be "yes", instead got %s`, h)
	}
	if h := bzHeaders["thing"]; h != "one" {
		t.Errorf(`Expected thing to be "one", instead got %s`, h)
	}
}

// TODO remove
func setupRequest(code int, body string) (*httptest.Server, http.Client) {
	return setupMockJsonServer(code, body, nil)
}

// TODO remove
func setupMockJsonServer(code int, body string, reqChan chan<- *http.Request) (*httptest.Server, http.Client) {
	headers := map[string]string{"Content-Type": "application/json"}
	return setupMockServer(code, body, headers, reqChan)
}

// TODO remove
func setupMockServer(code int, body string, headers map[string]string, reqChan chan<- *http.Request) (*httptest.Server, http.Client) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if reqChan != nil {
			reqChan <- r
		}

		for k, v := range headers {
			w.Header().Set(k, v)
		}

		w.WriteHeader(code)
		fmt.Fprintln(w, body)
	}))

	tr := &http.Transport{
		Proxy: func(req *http.Request) (*url.URL, error) {
			return url.Parse(server.URL)
		},
	}

	return server, http.Client{Transport: tr}
}

func createTestResponse(statusCode int, body string) *http.Response {
	return &http.Response{
		StatusCode: statusCode,
		Body:       ioutil.NopCloser(strings.NewReader(body))}
}

func createTestErrorResponses() []*http.Response {
	return []*http.Response{
		createTestResponse(400, `{"status":400,"code":"nope","message":"nope nope"}`),
		createTestResponse(401, `{"status":401,"code":"nope","message":"nope nope"}`),
	}
}

// TODO replace with non-200 *http.Response creator
func errorResponses() ([]int, []string) {
	codes := []int{400, 401}
	bodies := []string{
		`{"status":400,"code":"nope","message":"nope nope"}`,
		`{"status":401,"code":"nope","message":"nope nope"}`,
	}
	return codes, bodies
}

func testErrorResponse(err error, code int, t *testing.T) {
	if err == nil {
		t.Error("Expected error, no error received")
	} else if err.Error() != fmt.Sprintf("Status: %d, Code: nope, Message: nope nope", code) {
		t.Errorf(`Expected "Status: %d, Code: nope, Message: nope nope", instead got %s`, code, err)
	}
}

func makeTestB2(c http.Client) *B2 {
	return &B2{
		AccountID:          "id",
		AuthorizationToken: "token",
		ApiUrl:             "https://api900.backblaze.com",
		DownloadUrl:        "https://f900.backblaze.com",
		client:             &client{Protocol: "http", Client: c},
	}
}
<commit_msg>Rename test to match Struct_MethodName format used elsewhere<commit_after>package b2

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strings"
	"testing"
)

func Test_createB2_HasAuth(t *testing.T) {
	reqChan := make(chan *http.Request, 1)
	s, c := setupMockJsonServer(200, "", reqChan)
	defer s.Close()

	client := &client{Protocol: "http", Client: c}

	createB2("1", "1", client)

	// get the request that the mock server received
	req := <-reqChan

	username, password, ok := req.BasicAuth()
	if !ok {
		t.Fatal("Expected ok to be true, instead got false")
	}
	if username != "1" {
		t.Errorf(`Expected username to be "1", instead got %s`, username)
	}
	if password != "1" {
		t.Errorf(`Expected password to be "1", instead got %s`, password)
	}
}

func Test_B2_parseCreateB2Response(t *testing.T) {
	// success
	resp := createTestResponse(200, `{"accountId":"1","authorizationToken":"1","apiUrl":"/","downloadUrl":"/"}`)

	b := &B2{AccountID: "1", ApplicationKey: "key"}
	b, err := b.parseCreateB2Response(resp)
	if err != nil {
		t.Fatalf("Expected err to be nil, instead got %+v", err)
	}

	if b.AccountID != "1" {
		t.Errorf(`Expected AccountID to be "1", instead got %s`, b.AccountID)
	}
	if b.AuthorizationToken != "1" {
		t.Errorf(`Expected AuthorizationToken to be "1", instead got %s`, b.AuthorizationToken)
	}
	if b.ApiUrl != "/" {
		t.Errorf(`Expected ApiUrl to be "/", instead got %s`, b.ApiUrl)
	}
	if b.DownloadUrl != "/" {
		t.Errorf(`Expected DownloadUrl to be "/", instead got %s`, b.DownloadUrl)
	}

	// errors
	resps := createTestErrorResponses()
	for i, resp := range resps {
		b := &B2{AccountID: "1", ApplicationKey: "key"}
		b, err := b.parseCreateB2Response(resp)
		testErrorResponse(err, 400+i, t)
		if b != nil {
			t.Errorf("Expected b to be nil, instead got %+v", b)
		}
	}
}

func Test_B2_CreateRequest(t *testing.T) {
	b2 := &B2{client: &client{Protocol: "https"}} // set client protocol to default

	methods := []string{
		"GET", "POST", "KITTENS",
		"POST", "BAD METHOD",
	}
	urls := []string{
		"http://example.com", "kittens://example.com", "aoeu://example.com",
		"invalid-url", "http://example.com",
	}
	reqBody := struct {
		a int `json:"a"`
	}{a: 1}

	for i := 0; i < 3; i++ {
		req, err := b2.CreateRequest(methods[i], urls[i], reqBody)
		if err != nil {
			t.Fatalf("Expected err to be nil, instead got %+v", err)
		}
		if req.URL.Scheme != "https" {
			t.Errorf(`Expected url protocol to be "https", instead got %s`, req.URL.Scheme)
		}
		if req.Body == nil {
			t.Error("Expected req.Body to not be nil")
		}
	}
	for i := 3; i < 5; i++ {
		req, err := b2.CreateRequest(methods[i], urls[i], reqBody)
		if req != nil {
			t.Errorf("Expected req to be nil, instead got %+v", req)
		}
		if err == nil {
			t.Fatal("Expected err to exist")
		}
	}
}

func Test_replaceProtocol(t *testing.T) {
	b2s := []B2{
		B2{client: &client{Protocol: "https"}},
		B2{client: &client{Protocol: "http"}},
		B2{client: &client{Protocol: "kittens"}},
	}
	urls := []string{
		"http://localhost", "https://localhost", "http://localhost", "kittens://localhost",
		"https://www.backblaze.com/", "https://www.backblaze.com/",
		"http://www.backblaze.com/", "kittens://www.backblaze.com/",
		"non/url/",
	}

	for i, b := range b2s {
		index, i2, index2 := i+1, i+4, i+5 // make offsets
		// localhost
		url, err := b.replaceProtocol(urls[i])
		if err != nil {
			t.Errorf("Expected no error, instead got %+v", err)
		}
		if url != urls[index] {
			t.Errorf("Expected url to be %s, instead got %s", urls[index], url)
		}

		// www.backblaze.com
		url, err = b.replaceProtocol(urls[i2])
		if err != nil {
			t.Errorf("Expected no error, instead got %+v", err)
		}
		if url != urls[index2] {
			t.Errorf("Expected url to be %s, instead got %s", urls[index2], url)
		}
	}

	url, err := b2s[0].replaceProtocol(urls[len(urls)-1])
	if err == nil {
		t.Errorf("Expected error, instead got nil, url returned was %s", url)
	}
}

func Test_GetBzInfoHeaders(t *testing.T) {
	headers := map[string][]string{
		"Content-Type":      []string{"kittens"},
		"X-Bz-Info-kittens": []string{"yes"},
		"X-Bz-Info-thing":   []string{"one"},
	}
	resp := &http.Response{Header: headers}

	bzHeaders := GetBzInfoHeaders(resp)

	if len(bzHeaders) != 2 {
		t.Fatalf("Expected length of headers to be 2, instead got %d", len(bzHeaders))
	}
	if h, ok := bzHeaders["Content-Type"]; ok {
		t.Errorf("Expected no Content-Type, instead recieved %s", h)
	}
	if h := bzHeaders["kittens"]; h != "yes" {
		t.Errorf(`Expected kittens to be "yes", instead got %s`, h)
	}
	if h := bzHeaders["thing"]; h != "one" {
		t.Errorf(`Expected thing to be "one", instead got %s`, h)
	}
}

// TODO remove
func setupRequest(code int, body string) (*httptest.Server, http.Client) {
	return setupMockJsonServer(code, body, nil)
}

// TODO remove
func setupMockJsonServer(code int, body string, reqChan chan<- *http.Request) (*httptest.Server, http.Client) {
	headers := map[string]string{"Content-Type": "application/json"}
	return setupMockServer(code, body, headers, reqChan)
}

// TODO remove
func setupMockServer(code int, body string, headers map[string]string, reqChan chan<- *http.Request) (*httptest.Server, http.Client) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if reqChan != nil {
			reqChan <- r
		}

		for k, v := range headers {
			w.Header().Set(k, v)
		}

		w.WriteHeader(code)
		fmt.Fprintln(w, body)
	}))

	tr := &http.Transport{
		Proxy: func(req *http.Request) (*url.URL, error) {
			return url.Parse(server.URL)
		},
	}

	return server, http.Client{Transport: tr}
}

func createTestResponse(statusCode int, body string) *http.Response {
	return &http.Response{
		StatusCode: statusCode,
		Body:       ioutil.NopCloser(strings.NewReader(body))}
}

func createTestErrorResponses() []*http.Response {
	return []*http.Response{
		createTestResponse(400, `{"status":400,"code":"nope","message":"nope nope"}`),
		createTestResponse(401, `{"status":401,"code":"nope","message":"nope nope"}`),
	}
}

// TODO replace with non-200 *http.Response creator
func errorResponses() ([]int, []string) {
	codes := []int{400, 401}
	bodies := []string{
		`{"status":400,"code":"nope","message":"nope nope"}`,
		`{"status":401,"code":"nope","message":"nope nope"}`,
	}
	return codes, bodies
}

func testErrorResponse(err error, code int, t *testing.T) {
	if err == nil {
		t.Error("Expected error, no error received")
	} else if err.Error() != fmt.Sprintf("Status: %d, Code: nope, Message: nope nope", code) {
		t.Errorf(`Expected "Status: %d, Code: nope, Message: nope nope", instead got %s`, code, err)
	}
}

func makeTestB2(c http.Client) *B2 {
	return &B2{
		AccountID:          "id",
		AuthorizationToken: "token",
		ApiUrl:             "https://api900.backblaze.com",
		DownloadUrl:        "https://f900.backblaze.com",
		client:             &client{Protocol: "http", Client: c},
	}
}
<|endoftext|>


<commit_before>package config

import (
	"github.com/achilleasa/usrv/config/provider"
	"github.com/achilleasa/usrv/config/store"
)

var (
	// Store is a global configuration store instance that is used to configure
	// the various usrv components.
	Store store.Store
)

// SetDefaults updates the global store instance with the default values for a
// particular configuration path.
func SetDefaults(path string, cfg map[string]string) error {
	_, err := Store.SetKeys(0, path, cfg)
	return err
}

func init() {
	// Register built-in providers
	Store.RegisterValueProvider(provider.NewEnvVars())
}
<commit_msg>Add documentation for config package<commit_after>// Package config exposes a global configuration store instance and provides
// helpers for setting default configuration values.
//
// Including this package will automatically register the built-in configuration
// providers. For more information please see the provider sub-package.
package config

import (
	"github.com/achilleasa/usrv/config/provider"
	"github.com/achilleasa/usrv/config/store"
)

// Store is a global configuration store instance that is used to configure
// the various usrv components. Including the config package automatically
// registers the built-in configuration providers with this store.
var Store store.Store

// SetDefaults updates the global store instance with the default values for a
// particular configuration path.
func SetDefaults(path string, cfg map[string]string) error {
	_, err := Store.SetKeys(0, path, cfg)
	return err
}

func init() {
	// Register built-in providers
	Store.RegisterValueProvider(provider.NewEnvVars())
}
<|endoftext|>


<commit_before>// Package config contains the model and loader of the goreleaser configuration
// file.
package config

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strings"

	"github.com/apex/log"
	yaml "gopkg.in/yaml.v2"
)

// Repo represents any kind of repo (github, gitlab, etc)
type Repo struct {
	Owner string `yaml:",omitempty"`
	Name  string `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// String of the repo, e.g. owner/name
func (r Repo) String() string {
	return r.Owner + "/" + r.Name
}

// Homebrew contains the brew section
type Homebrew struct {
	GitHub       Repo     `yaml:",omitempty"`
	Folder       string   `yaml:",omitempty"`
	Caveats      string   `yaml:",omitempty"`
	Plist        string   `yaml:",omitempty"`
	Install      string   `yaml:",omitempty"`
	Dependencies []string `yaml:",omitempty"`
	Conflicts    []string `yaml:",omitempty"`
	Description  string   `yaml:",omitempty"`
	Homepage     string   `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Hooks define actions to run before and/or after something
type Hooks struct {
	Pre  string `yaml:",omitempty"`
	Post string `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// IgnoredBuild represents a build ignored by the user
type IgnoredBuild struct {
	Goos, Goarch, Goarm string

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Build contains the build configuration section
type Build struct {
	Goos    []string       `yaml:",omitempty"`
	Goarch  []string       `yaml:",omitempty"`
	Goarm   []string       `yaml:",omitempty"`
	Ignore  []IgnoredBuild `yaml:",omitempty"`
	Main    string         `yaml:",omitempty"`
	Ldflags string         `yaml:",omitempty"`
	Flags   string         `yaml:",omitempty"`
	Binary  string         `yaml:",omitempty"`
	Hooks   Hooks          `yaml:",omitempty"`
	Env     []string       `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// FormatOverride is used to specify a custom format for a specific GOOS.
type FormatOverride struct {
	Goos   string `yaml:",omitempty"`
	Format string `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Archive config used for the archive
type Archive struct {
	Format          string            `yaml:",omitempty"`
	FormatOverrides []FormatOverride  `yaml:"format_overrides,omitempty"`
	NameTemplate    string            `yaml:"name_template,omitempty"`
	Replacements    map[string]string `yaml:",omitempty"`
	Files           []string          `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Release config used for the GitHub release
type Release struct {
	GitHub Repo `yaml:",omitempty"`
	Draft  bool `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// FPM config
type FPM struct {
	Formats      []string `yaml:",omitempty"`
	Dependencies []string `yaml:",omitempty"`
	Conflicts    []string `yaml:",omitempty"`
	Vendor       string   `yaml:",omitempty"`
	Homepage     string   `yaml:",omitempty"`
	Maintainer   string   `yaml:",omitempty"`
	Description  string   `yaml:",omitempty"`
	License      string   `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Snapshot config
type Snapshot struct {
	NameTemplate string `yaml:"name_template,omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Project includes all project configuration
type Project struct {
	ProjectName string   `yaml:"project_name,omitempty"`
	Release     Release  `yaml:",omitempty"`
	Brew        Homebrew `yaml:",omitempty"`
	Builds      []Build  `yaml:",omitempty"`
	Archive     Archive  `yaml:",omitempty"`
	FPM         FPM      `yaml:",omitempty"`
	Snapshot    Snapshot `yaml:",omitempty"`

	// this is a hack ¯\_(ツ)_/¯
	SingleBuild Build `yaml:"build,omitempty"`

	// test only property indicating the path to the dist folder
	Dist string `yaml:"-"`

	Parallelism int `yaml:"-"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Load config file
func Load(file string) (config Project, err error) {
	f, err := os.Open(file)
	if err != nil {
		return
	}
	log.WithField("file", file).Info("loading config file")
	return LoadReader(f)
}

// LoadReader config via io.Reader
func LoadReader(fd io.Reader) (config Project, err error) {
	data, err := ioutil.ReadAll(fd)
	if err != nil {
		return config, err
	}
	err = yaml.Unmarshal(data, &config)
	log.WithField("config", config).Debug("loaded config file")

	err = checkOverflows(config)
	return
}

func checkOverflows(config Project) error {
	var checker = &overflowChecker{}
	checker.check(config.XXX, "")
	checker.check(config.Archive.XXX, "archive")
	for i, ov := range config.Archive.FormatOverrides {
		checker.check(ov.XXX, fmt.Sprintf("archive.format_overrides[%d]", i))
	}
	checker.check(config.Brew.XXX, "brew")
	checker.check(config.Brew.GitHub.XXX, "brew.github")
	for i, build := range config.Builds {
		checker.check(build.XXX, fmt.Sprintf("builds[%d]", i))
		checker.check(build.Hooks.XXX, fmt.Sprintf("builds[%d].hooks", i))
		for j, ignored := range build.Ignore {
			checker.check(ignored.XXX, fmt.Sprintf("builds[%d].ignored_builds[%d]", i, j))
		}
	}
	checker.check(config.FPM.XXX, "fpm")
	checker.check(config.Release.XXX, "release")
	checker.check(config.Release.GitHub.XXX, "release.github")
	checker.check(config.SingleBuild.XXX, "build")
	checker.check(config.SingleBuild.Hooks.XXX, "builds.hooks")
	for i, ignored := range config.SingleBuild.Ignore {
		checker.check(ignored.XXX, fmt.Sprintf("builds.ignored_builds[%d]", i))
	}
	checker.check(config.Snapshot.XXX, "snapshot")
	return checker.err()
}

type overflowChecker struct {
	fields []string
}

func (o *overflowChecker) check(m map[string]interface{}, ctx string) {
	for k := range m {
		var key = fmt.Sprintf("%s.%s", ctx, k)
		if ctx == "" {
			key = k
		}
		o.fields = append(o.fields, key)
	}
}

func (o *overflowChecker) err() error {
	if len(o.fields) == 0 {
		return nil
	}
	return fmt.Errorf(
		"unknown fields in the config file: %s",
		strings.Join(o.fields, ", "),
	)
}
<commit_msg>cleanup<commit_after>// Package config contains the model and loader of the goreleaser configuration
// file.
package config

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strings"

	"github.com/apex/log"
	yaml "gopkg.in/yaml.v2"
)

// Repo represents any kind of repo (github, gitlab, etc)
type Repo struct {
	Owner string `yaml:",omitempty"`
	Name  string `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// String of the repo, e.g. owner/name
func (r Repo) String() string {
	return r.Owner + "/" + r.Name
}

// Homebrew contains the brew section
type Homebrew struct {
	GitHub       Repo     `yaml:",omitempty"`
	Folder       string   `yaml:",omitempty"`
	Caveats      string   `yaml:",omitempty"`
	Plist        string   `yaml:",omitempty"`
	Install      string   `yaml:",omitempty"`
	Dependencies []string `yaml:",omitempty"`
	Conflicts    []string `yaml:",omitempty"`
	Description  string   `yaml:",omitempty"`
	Homepage     string   `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Hooks define actions to run before and/or after something
type Hooks struct {
	Pre  string `yaml:",omitempty"`
	Post string `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// IgnoredBuild represents a build ignored by the user
type IgnoredBuild struct {
	Goos, Goarch, Goarm string

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Build contains the build configuration section
type Build struct {
	Goos    []string       `yaml:",omitempty"`
	Goarch  []string       `yaml:",omitempty"`
	Goarm   []string       `yaml:",omitempty"`
	Ignore  []IgnoredBuild `yaml:",omitempty"`
	Main    string         `yaml:",omitempty"`
	Ldflags string         `yaml:",omitempty"`
	Flags   string         `yaml:",omitempty"`
	Binary  string         `yaml:",omitempty"`
	Hooks   Hooks          `yaml:",omitempty"`
	Env     []string       `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// FormatOverride is used to specify a custom format for a specific GOOS.
type FormatOverride struct {
	Goos   string `yaml:",omitempty"`
	Format string `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Archive config used for the archive
type Archive struct {
	Format          string            `yaml:",omitempty"`
	FormatOverrides []FormatOverride  `yaml:"format_overrides,omitempty"`
	NameTemplate    string            `yaml:"name_template,omitempty"`
	Replacements    map[string]string `yaml:",omitempty"`
	Files           []string          `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Release config used for the GitHub release
type Release struct {
	GitHub Repo `yaml:",omitempty"`
	Draft  bool `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// FPM config
type FPM struct {
	Formats      []string `yaml:",omitempty"`
	Dependencies []string `yaml:",omitempty"`
	Conflicts    []string `yaml:",omitempty"`
	Vendor       string   `yaml:",omitempty"`
	Homepage     string   `yaml:",omitempty"`
	Maintainer   string   `yaml:",omitempty"`
	Description  string   `yaml:",omitempty"`
	License      string   `yaml:",omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Snapshot config
type Snapshot struct {
	NameTemplate string `yaml:"name_template,omitempty"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Project includes all project configuration
type Project struct {
	ProjectName string   `yaml:"project_name,omitempty"`
	Release     Release  `yaml:",omitempty"`
	Brew        Homebrew `yaml:",omitempty"`
	Builds      []Build  `yaml:",omitempty"`
	Archive     Archive  `yaml:",omitempty"`
	FPM         FPM      `yaml:",omitempty"`
	Snapshot    Snapshot `yaml:",omitempty"`

	// this is a hack ¯\_(ツ)_/¯
	SingleBuild Build `yaml:"build,omitempty"`

	// test only property indicating the path to the dist folder
	Dist string `yaml:"-"`

	// Capture all undefined fields and should be empty after loading
	XXX map[string]interface{} `yaml:",inline"`
}

// Load config file
func Load(file string) (config Project, err error) {
	f, err := os.Open(file)
	if err != nil {
		return
	}
	log.WithField("file", file).Info("loading config file")
	return LoadReader(f)
}

// LoadReader config via io.Reader
func LoadReader(fd io.Reader) (config Project, err error) {
	data, err := ioutil.ReadAll(fd)
	if err != nil {
		return config, err
	}
	err = yaml.Unmarshal(data, &config)
	log.WithField("config", config).Debug("loaded config file")

	err = checkOverflows(config)
	return
}

func checkOverflows(config Project) error {
	var checker = &overflowChecker{}
	checker.check(config.XXX, "")
	checker.check(config.Archive.XXX, "archive")
	for i, ov := range config.Archive.FormatOverrides {
		checker.check(ov.XXX, fmt.Sprintf("archive.format_overrides[%d]", i))
	}
	checker.check(config.Brew.XXX, "brew")
	checker.check(config.Brew.GitHub.XXX, "brew.github")
	for i, build := range config.Builds {
		checker.check(build.XXX, fmt.Sprintf("builds[%d]", i))
		checker.check(build.Hooks.XXX, fmt.Sprintf("builds[%d].hooks", i))
		for j, ignored := range build.Ignore {
			checker.check(ignored.XXX, fmt.Sprintf("builds[%d].ignored_builds[%d]", i, j))
		}
	}
	checker.check(config.FPM.XXX, "fpm")
	checker.check(config.Release.XXX, "release")
	checker.check(config.Release.GitHub.XXX, "release.github")
	checker.check(config.SingleBuild.XXX, "build")
	checker.check(config.SingleBuild.Hooks.XXX, "builds.hooks")
	for i, ignored := range config.SingleBuild.Ignore {
		checker.check(ignored.XXX, fmt.Sprintf("builds.ignored_builds[%d]", i))
	}
	checker.check(config.Snapshot.XXX, "snapshot")
	return checker.err()
}

type overflowChecker struct {
	fields []string
}

func (o *overflowChecker) check(m map[string]interface{}, ctx string) {
	for k := range m {
		var key = fmt.Sprintf("%s.%s", ctx, k)
		if ctx == "" {
			key = k
		}
		o.fields = append(o.fields, key)
	}
}

func (o *overflowChecker) err() error {
	if len(o.fields) == 0 {
		return nil
	}
	return fmt.Errorf(
		"unknown fields in the config file: %s",
		strings.Join(o.fields, ", "),
	)
}
<|endoftext|>


<commit_before>// Package config collects together all configuration settings
// NOTE: Subject to change, do not rely on this package from outside git-lfs source
package config

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"sync"

	"github.com/git-lfs/git-lfs/fs"
	"github.com/git-lfs/git-lfs/git"
	"github.com/git-lfs/git-lfs/tools"
	"github.com/rubyist/tracerx"
)

var (
	ShowConfigWarnings     = false
	defaultRemote          = "origin"
	gitConfigWarningPrefix = "lfs."
)

type Configuration struct {
	// Os provides a `*Environment` used to access to the system's
	// environment through os.Getenv. It is the point of entry for all
	// system environment configuration.
	Os Environment

	// Git provides a `*Environment` used to access to the various levels of
	// `.gitconfig`'s. It is the point of entry for all Git environment
	// configuration.
	Git Environment

	currentRemote *string

	// gitConfig can fetch or modify the current Git config and track the Git
	// version.
	gitConfig *git.Configuration

	fs         *fs.Filesystem
	gitDir     *string
	workDir    string
	loading    sync.Mutex // guards initialization of gitConfig and remotes
	loadingGit sync.Mutex // guards initialization of local git and working dirs
	remotes    []string
	extensions map[string]Extension
}

func New() *Configuration {
	return NewIn("", "")
}

func NewIn(workdir, gitdir string) *Configuration {
	gitConf := git.NewConfig(workdir, gitdir)
	c := &Configuration{
		Os:        EnvironmentOf(NewOsFetcher()),
		gitConfig: gitConf,
	}

	if len(gitConf.WorkDir) > 0 {
		c.gitDir = &gitConf.GitDir
		c.workDir = gitConf.WorkDir
	}

	c.Git = &delayedEnvironment{
		callback: func() Environment {
			sources, err := gitConf.Sources(filepath.Join(c.LocalWorkingDir(), ".lfsconfig"))
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error reading git config: %s\n", err)
			}
			return c.readGitConfig(sources...)
		},
	}
	return c
}

func (c *Configuration) readGitConfig(gitconfigs ...*git.ConfigurationSource) Environment {
	gf, extensions, uniqRemotes := readGitConfig(gitconfigs...)
	c.extensions = extensions
	c.remotes = make([]string, 0, len(uniqRemotes))
	for remote, isOrigin := range uniqRemotes {
		if isOrigin {
			continue
		}
		c.remotes = append(c.remotes, remote)
	}

	return EnvironmentOf(gf)
}

// Values is a convenience type used to call the NewFromValues function. It
// specifies `Git` and `Env` maps to use as mock values, instead of calling out
// to real `.gitconfig`s and the `os.Getenv` function.
type Values struct {
	// Git and Os are the stand-in maps used to provide values for their
	// respective environments.
	Git, Os map[string][]string
}

// NewFrom returns a new `*config.Configuration` that reads both its Git
// and Enviornment-level values from the ones provided instead of the actual
// `.gitconfig` file or `os.Getenv`, respectively.
//
// This method should only be used during testing.
func NewFrom(v Values) *Configuration {
	c := &Configuration{
		Os:        EnvironmentOf(mapFetcher(v.Os)),
		gitConfig: git.NewConfig("", ""),
	}
	c.Git = &delayedEnvironment{
		callback: func() Environment {
			source := &git.ConfigurationSource{
				Lines: make([]string, 0, len(v.Git)),
			}

			for key, values := range v.Git {
				for _, value := range values {
					fmt.Printf("Config: %s=%s\n", key, value)
					source.Lines = append(source.Lines, fmt.Sprintf("%s=%s", key, value))
				}
			}

			return c.readGitConfig(source)
		},
	}
	return c
}

// BasicTransfersOnly returns whether to only allow "basic" HTTP transfers.
// Default is false, including if the lfs.basictransfersonly is invalid
func (c *Configuration) BasicTransfersOnly() bool {
	return c.Git.Bool("lfs.basictransfersonly", false)
}

// TusTransfersAllowed returns whether to only use "tus.io" HTTP transfers.
// Default is false, including if the lfs.tustransfers is invalid
func (c *Configuration) TusTransfersAllowed() bool {
	return c.Git.Bool("lfs.tustransfers", false)
}

func (c *Configuration) FetchIncludePaths() []string {
	patterns, _ := c.Git.Get("lfs.fetchinclude")
	return tools.CleanPaths(patterns, ",")
}

func (c *Configuration) FetchExcludePaths() []string {
	patterns, _ := c.Git.Get("lfs.fetchexclude")
	return tools.CleanPaths(patterns, ",")
}

func (c *Configuration) IsDefaultRemote() bool {
	return c.Remote() == defaultRemote
}

func (c *Configuration) Remote() string {
	c.loadingGit.Lock()
	defer c.loadingGit.Unlock()
	if c.currentRemote == nil {
		r, err := c.GitConfig().DefaultRemote()
		if err == nil && len(r) > 0 {
			c.currentRemote = &r
		} else {
			if err != nil {
				tracerx.Printf("Error getting default remote: %+v", err)
			}
			c.currentRemote = &defaultRemote
		}
	}
	return *c.currentRemote
}

func (c *Configuration) SetValidRemote(name string) error {
	if err := git.ValidateRemote(name); err != nil {
		return err
	}
	c.SetRemote(name)
	return nil
}

func (c *Configuration) SetRemote(name string) {
	c.currentRemote = &name
}

func (c *Configuration) Remotes() []string {
	c.loadGitConfig()
	return c.remotes
}

func (c *Configuration) Extensions() map[string]Extension {
	c.loadGitConfig()
	return c.extensions
}

// SortedExtensions gets the list of extensions ordered by Priority
func (c *Configuration) SortedExtensions() ([]Extension, error) {
	return SortExtensions(c.Extensions())
}

func (c *Configuration) SkipDownloadErrors() bool {
	return c.Os.Bool("GIT_LFS_SKIP_DOWNLOAD_ERRORS", false) || c.Git.Bool("lfs.skipdownloaderrors", false)
}

func (c *Configuration) SetLockableFilesReadOnly() bool {
	return c.Os.Bool("GIT_LFS_SET_LOCKABLE_READONLY", true) && c.Git.Bool("lfs.setlockablereadonly", true)
}

func (c *Configuration) HookDir() string {
	if git.IsGitVersionAtLeast("2.9.0") {
		hp, ok := c.Git.Get("core.hooksPath")
		if ok {
			return hp
		}
	}
	return filepath.Join(c.LocalGitDir(), "hooks")
}

func (c *Configuration) InRepo() bool {
	return len(c.LocalGitDir()) > 0
}

func (c *Configuration) LocalWorkingDir() string {
	c.loadGitDirs()
	return c.workDir
}

func (c *Configuration) LocalGitDir() string {
	c.loadGitDirs()
	return *c.gitDir
}

func (c *Configuration) loadGitDirs() {
	c.loadingGit.Lock()
	defer c.loadingGit.Unlock()

	if c.gitDir != nil {
		return
	}

	gitdir, workdir, err := git.GitAndRootDirs()
	if err != nil {
		errMsg := err.Error()
		tracerx.Printf("Error running 'git rev-parse': %s", errMsg)
		if !strings.Contains(errMsg, "Not a git repository") {
			fmt.Fprintf(os.Stderr, "Error: %s\n", errMsg)
		}
		c.gitDir = &gitdir
	}

	gitdir = tools.ResolveSymlinks(gitdir)
	c.gitDir = &gitdir
	c.workDir = tools.ResolveSymlinks(workdir)
}

func (c *Configuration) LocalGitStorageDir() string {
	return c.Filesystem().GitStorageDir
}

func (c *Configuration) LocalReferenceDir() string {
	return c.Filesystem().ReferenceDir
}

func (c *Configuration) LFSStorageDir() string {
	return c.Filesystem().LFSStorageDir
}

func (c *Configuration) LFSObjectDir() string {
	return c.Filesystem().LFSObjectDir()
}

func (c *Configuration) LFSObjectExists(oid string, size int64) bool {
	return c.Filesystem().ObjectExists(oid, size)
}

func (c *Configuration) EachLFSObject(fn func(fs.Object) error) error {
	return c.Filesystem().EachObject(fn)
}

func (c *Configuration) LocalLogDir() string {
	return c.Filesystem().LogDir()
}

func (c *Configuration) TempDir() string {
	return c.Filesystem().TempDir()
}

func (c *Configuration) Filesystem() *fs.Filesystem {
	c.loadGitDirs()
	c.loading.Lock()
	defer c.loading.Unlock()

	if c.fs == nil {
		lfsdir, _ := c.Git.Get("lfs.storage")
		c.fs = fs.New(c.LocalGitDir(), c.LocalWorkingDir(), lfsdir)
	}

	return c.fs
}

func (c *Configuration) Cleanup() error {
	c.loading.Lock()
	defer c.loading.Unlock()
	return c.fs.Cleanup()
}

func (c *Configuration) OSEnv() Environment {
	return c.Os
}

func (c *Configuration) GitEnv() Environment {
	return c.Git
}

func (c *Configuration) GitConfig() *git.Configuration {
	return c.gitConfig
}

func (c *Configuration) FindGitGlobalKey(key string) string {
	return c.gitConfig.FindGlobal(key)
}

func (c *Configuration) FindGitSystemKey(key string) string {
	return c.gitConfig.FindSystem(key)
}

func (c *Configuration) FindGitLocalKey(key string) string {
	return c.gitConfig.FindLocal(key)
}

func (c *Configuration) SetGitGlobalKey(key, val string) (string, error) {
	return c.gitConfig.SetGlobal(key, val)
}

func (c *Configuration) SetGitSystemKey(key, val string) (string, error) {
	return c.gitConfig.SetSystem(key, val)
}

func (c *Configuration) SetGitLocalKey(key, val string) (string, error) {
	return c.gitConfig.SetLocal(key, val)
}

func (c *Configuration) UnsetGitGlobalSection(key string) (string, error) {
	return c.gitConfig.UnsetGlobalSection(key)
}

func (c *Configuration) UnsetGitSystemSection(key string) (string, error) {
	return c.gitConfig.UnsetSystemSection(key)
}

func (c *Configuration) UnsetGitLocalSection(key string) (string, error) {
	return c.gitConfig.UnsetLocalSection(key)
}

func (c *Configuration) UnsetGitLocalKey(key string) (string, error) {
	return c.gitConfig.UnsetLocalKey(key)
}

// loadGitConfig is a temporary measure to support legacy behavior dependent on
// accessing properties set by ReadGitConfig, namely:
//  - `c.extensions`
//  - `c.uniqRemotes`
//  - `c.gitConfig`
//
// Since the *gitEnvironment is responsible for setting these values on the
// (*config.Configuration) instance, we must call that method, if it exists.
//
// loadGitConfig returns a bool returning whether or not `loadGitConfig` was
// called AND the method did not return early.
func (c *Configuration) loadGitConfig() {
	if g, ok := c.Git.(*delayedEnvironment); ok {
		g.Load()
	}
}

// CurrentCommitter returns the name/email that would be used to author a commit
// with this configuration. In particular, the "user.name" and "user.email"
// configuration values are used
func (c *Configuration) CurrentCommitter() (name, email string) {
	name, _ = c.Git.Get("user.name")
	email, _ = c.Git.Get("user.email")
	return
}
<commit_msg>config: re-implement DefaultRemote() in *Configuration with the Git env<commit_after>// Package config collects together all configuration settings
// NOTE: Subject to change, do not rely on this package from outside git-lfs source
package config

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"sync"

	"github.com/git-lfs/git-lfs/fs"
	"github.com/git-lfs/git-lfs/git"
	"github.com/git-lfs/git-lfs/tools"
	"github.com/rubyist/tracerx"
)

var (
	ShowConfigWarnings     = false
	defaultRemote          = "origin"
	gitConfigWarningPrefix = "lfs."
)

type Configuration struct {
	// Os provides a `*Environment` used to access to the system's
	// environment through os.Getenv. It is the point of entry for all
	// system environment configuration.
	Os Environment

	// Git provides a `*Environment` used to access to the various levels of
	// `.gitconfig`'s. It is the point of entry for all Git environment
	// configuration.
	Git Environment

	currentRemote *string

	// gitConfig can fetch or modify the current Git config and track the Git
	// version.
	gitConfig *git.Configuration

	ref        *git.Ref
	fs         *fs.Filesystem
	gitDir     *string
	workDir    string
	loading    sync.Mutex // guards initialization of gitConfig and remotes
	loadingGit sync.Mutex // guards initialization of local git and working dirs
	remotes    []string
	extensions map[string]Extension
}

func New() *Configuration {
	return NewIn("", "")
}

func NewIn(workdir, gitdir string) *Configuration {
	gitConf := git.NewConfig(workdir, gitdir)
	c := &Configuration{
		Os:        EnvironmentOf(NewOsFetcher()),
		gitConfig: gitConf,
	}

	if len(gitConf.WorkDir) > 0 {
		c.gitDir = &gitConf.GitDir
		c.workDir = gitConf.WorkDir
	}

	c.Git = &delayedEnvironment{
		callback: func() Environment {
			sources, err := gitConf.Sources(filepath.Join(c.LocalWorkingDir(), ".lfsconfig"))
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error reading git config: %s\n", err)
			}
			return c.readGitConfig(sources...)
		},
	}
	return c
}

func (c *Configuration) readGitConfig(gitconfigs ...*git.ConfigurationSource) Environment {
	gf, extensions, uniqRemotes := readGitConfig(gitconfigs...)
	c.extensions = extensions
	c.remotes = make([]string, 0, len(uniqRemotes))
	for remote, isOrigin := range uniqRemotes {
		if isOrigin {
			continue
		}
		c.remotes = append(c.remotes, remote)
	}

	return EnvironmentOf(gf)
}

// Values is a convenience type used to call the NewFromValues function. It
// specifies `Git` and `Env` maps to use as mock values, instead of calling out
// to real `.gitconfig`s and the `os.Getenv` function.
type Values struct {
	// Git and Os are the stand-in maps used to provide values for their
	// respective environments.
	Git, Os map[string][]string
}

// NewFrom returns a new `*config.Configuration` that reads both its Git
// and Enviornment-level values from the ones provided instead of the actual
// `.gitconfig` file or `os.Getenv`, respectively.
//
// This method should only be used during testing.
func NewFrom(v Values) *Configuration {
	c := &Configuration{
		Os:        EnvironmentOf(mapFetcher(v.Os)),
		gitConfig: git.NewConfig("", ""),
	}
	c.Git = &delayedEnvironment{
		callback: func() Environment {
			source := &git.ConfigurationSource{
				Lines: make([]string, 0, len(v.Git)),
			}

			for key, values := range v.Git {
				for _, value := range values {
					fmt.Printf("Config: %s=%s\n", key, value)
					source.Lines = append(source.Lines, fmt.Sprintf("%s=%s", key, value))
				}
			}

			return c.readGitConfig(source)
		},
	}
	return c
}

// BasicTransfersOnly returns whether to only allow "basic" HTTP transfers.
// Default is false, including if the lfs.basictransfersonly is invalid
func (c *Configuration) BasicTransfersOnly() bool {
	return c.Git.Bool("lfs.basictransfersonly", false)
}

// TusTransfersAllowed returns whether to only use "tus.io" HTTP transfers.
// Default is false, including if the lfs.tustransfers is invalid
func (c *Configuration) TusTransfersAllowed() bool {
	return c.Git.Bool("lfs.tustransfers", false)
}

func (c *Configuration) FetchIncludePaths() []string {
	patterns, _ := c.Git.Get("lfs.fetchinclude")
	return tools.CleanPaths(patterns, ",")
}

func (c *Configuration) FetchExcludePaths() []string {
	patterns, _ := c.Git.Get("lfs.fetchexclude")
	return tools.CleanPaths(patterns, ",")
}

func (c *Configuration) CurrentRef() *git.Ref {
	c.loading.Lock()
	defer c.loading.Unlock()
	if c.ref == nil {
		r, err := git.CurrentRef()
		if err != nil {
			tracerx.Printf("Error loading current ref: %s", err)
			c.ref = &git.Ref{}
		} else {
			c.ref = r
		}
	}
	return c.ref
}

func (c *Configuration) IsDefaultRemote() bool {
	return c.Remote() == defaultRemote
}

func (c *Configuration) Remote() string {
	ref := c.CurrentRef()

	c.loading.Lock()
	defer c.loading.Unlock()

	if c.currentRemote == nil {
		if len(ref.Name) == 0 {
			c.currentRemote = &defaultRemote
			return defaultRemote
		}

		if remote, ok := c.Git.Get(fmt.Sprintf("branch.%s.remote", ref.Name)); ok {
			// try tracking remote
			c.currentRemote = &remote
		} else if remotes := c.Remotes(); len(remotes) == 1 {
			// use only remote if there is only 1
			c.currentRemote = &remotes[0]
		} else {
			// fall back to default :(
			c.currentRemote = &defaultRemote
		}
	}
	return *c.currentRemote
}

func (c *Configuration) SetValidRemote(name string) error {
	if err := git.ValidateRemote(name); err != nil {
		return err
	}
	c.SetRemote(name)
	return nil
}

func (c *Configuration) SetRemote(name string) {
	c.currentRemote = &name
}

func (c *Configuration) Remotes() []string {
	c.loadGitConfig()
	return c.remotes
}

func (c *Configuration) Extensions() map[string]Extension {
	c.loadGitConfig()
	return c.extensions
}

// SortedExtensions gets the list of extensions ordered by Priority
func (c *Configuration) SortedExtensions() ([]Extension, error) {
	return SortExtensions(c.Extensions())
}

func (c *Configuration) SkipDownloadErrors() bool {
	return c.Os.Bool("GIT_LFS_SKIP_DOWNLOAD_ERRORS", false) || c.Git.Bool("lfs.skipdownloaderrors", false)
}

func (c *Configuration) SetLockableFilesReadOnly() bool {
	return c.Os.Bool("GIT_LFS_SET_LOCKABLE_READONLY", true) && c.Git.Bool("lfs.setlockablereadonly", true)
}

func (c *Configuration) HookDir() string {
	if git.IsGitVersionAtLeast("2.9.0") {
		hp, ok := c.Git.Get("core.hooksPath")
		if ok {
			return hp
		}
	}
	return filepath.Join(c.LocalGitDir(), "hooks")
}

func (c *Configuration) InRepo() bool {
	return len(c.LocalGitDir()) > 0
}

func (c *Configuration) LocalWorkingDir() string {
	c.loadGitDirs()
	return c.workDir
}

func (c *Configuration) LocalGitDir() string {
	c.loadGitDirs()
	return *c.gitDir
}

func (c *Configuration) loadGitDirs() {
	c.loadingGit.Lock()
	defer c.loadingGit.Unlock()

	if c.gitDir != nil {
		return
	}

	gitdir, workdir, err := git.GitAndRootDirs()
	if err != nil {
		errMsg := err.Error()
		tracerx.Printf("Error running 'git rev-parse': %s", errMsg)
		if !strings.Contains(errMsg, "Not a git repository") {
			fmt.Fprintf(os.Stderr, "Error: %s\n", errMsg)
		}
		c.gitDir = &gitdir
	}

	gitdir = tools.ResolveSymlinks(gitdir)
	c.gitDir = &gitdir
	c.workDir = tools.ResolveSymlinks(workdir)
}

func (c *Configuration) LocalGitStorageDir() string {
	return c.Filesystem().GitStorageDir
}

func (c *Configuration) LocalReferenceDir() string {
	return c.Filesystem().ReferenceDir
}

func (c *Configuration) LFSStorageDir() string {
	return c.Filesystem().LFSStorageDir
}

func (c *Configuration) LFSObjectDir() string {
	return c.Filesystem().LFSObjectDir()
}

func (c *Configuration) LFSObjectExists(oid string, size int64) bool {
	return c.Filesystem().ObjectExists(oid, size)
}

func (c *Configuration) EachLFSObject(fn func(fs.Object) error) error {
	return c.Filesystem().EachObject(fn)
}

func (c *Configuration) LocalLogDir() string {
	return c.Filesystem().LogDir()
}

func (c *Configuration) TempDir() string {
	return c.Filesystem().TempDir()
}

func (c *Configuration) Filesystem() *fs.Filesystem {
	c.loadGitDirs()
	c.loading.Lock()
	defer c.loading.Unlock()

	if c.fs == nil {
		lfsdir, _ := c.Git.Get("lfs.storage")
		c.fs = fs.New(c.LocalGitDir(), c.LocalWorkingDir(), lfsdir)
	}

	return c.fs
}

func (c *Configuration) Cleanup() error {
	c.loading.Lock()
	defer c.loading.Unlock()
	return c.fs.Cleanup()
}

func (c *Configuration) OSEnv() Environment {
	return c.Os
}

func (c *Configuration) GitEnv() Environment {
	return c.Git
}

func (c *Configuration) GitConfig() *git.Configuration {
	return c.gitConfig
}

func (c *Configuration) FindGitGlobalKey(key string) string {
	return c.gitConfig.FindGlobal(key)
}

func (c *Configuration) FindGitSystemKey(key string) string {
	return c.gitConfig.FindSystem(key)
}

func (c *Configuration) FindGitLocalKey(key string) string {
	return c.gitConfig.FindLocal(key)
}

func (c *Configuration) SetGitGlobalKey(key, val string) (string, error) {
	return c.gitConfig.SetGlobal(key, val)
}

func (c *Configuration) SetGitSystemKey(key, val string) (string, error) {
	return c.gitConfig.SetSystem(key, val)
}

func (c *Configuration) SetGitLocalKey(key, val string) (string, error) {
	return c.gitConfig.SetLocal(key, val)
}

func (c *Configuration) UnsetGitGlobalSection(key string) (string, error) {
	return c.gitConfig.UnsetGlobalSection(key)
}

func (c *Configuration) UnsetGitSystemSection(key string) (string, error) {
	return c.gitConfig.UnsetSystemSection(key)
}

func (c *Configuration) UnsetGitLocalSection(key string) (string, error) {
	return c.gitConfig.UnsetLocalSection(key)
}

func (c *Configuration) UnsetGitLocalKey(key string) (string, error) {
	return c.gitConfig.UnsetLocalKey(key)
}

// loadGitConfig is a temporary measure to support legacy behavior dependent on
// accessing properties set by ReadGitConfig, namely:
//  - `c.extensions`
//  - `c.uniqRemotes`
//  - `c.gitConfig`
//
// Since the *gitEnvironment is responsible for setting these values on the
// (*config.Configuration) instance, we must call that method, if it exists.
//
// loadGitConfig returns a bool returning whether or not `loadGitConfig` was
// called AND the method did not return early.
func (c *Configuration) loadGitConfig() {
	if g, ok := c.Git.(*delayedEnvironment); ok {
		g.Load()
	}
}

// CurrentCommitter returns the name/email that would be used to author a commit
// with this configuration. In particular, the "user.name" and "user.email"
// configuration values are used
func (c *Configuration) CurrentCommitter() (name, email string) {
	name, _ = c.Git.Get("user.name")
	email, _ = c.Git.Get("user.email")
	return
}
<|endoftext|>


<commit_before>package config

import (
	"errors"
	"fmt"

	"gopkg.in/validator.v2"
)

type Config struct {
	Host         string `validate:"nonzero"`
	Port         int    `validate:"nonzero"`
	User         string `validate:"nonzero"`
	Password     string //blank Password is allowed
	ReadOnlyUser string `validate:"nonzero"`
	DBName       string //blank DBName is allowed
}

func (c Config) Validate() error {
	err := validator.Validate(c)
	var errString string
	if err != nil {
		errString = formatErrorString(err)
	}

	if len(errString) > 0 {
		return errors.New(fmt.Sprintf("Validation errors: %s\n", errString))
	}
	return nil
}

func formatErrorString(err error) string {
	errs := err.(validator.ErrorMap)
	var errsString string
	for fieldName, validationMessage := range errs {
		errsString += fmt.Sprintf("%s : %s\n", fieldName, validationMessage)
	}
	return errsString
}
<commit_msg>Use yaml construct tags in config<commit_after>package config

import (
	"errors"
	"fmt"

	"gopkg.in/validator.v2"
)

type Config struct {
	Host         string `yaml:"Host" validate:"nonzero"`
	Port         int    `yaml:"Port" validate:"nonzero"`
	User         string `yaml:"User" validate:"nonzero"`
	Password     string `yaml:"Password"` //blank Password is allowed
	ReadOnlyUser string `yaml:"ReadOnlyUser" validate:"nonzero"`
	DBName       string `yaml:"DBName"` //blank DBName is allowed
}

func (c Config) Validate() error {
	err := validator.Validate(c)
	var errString string
	if err != nil {
		errString = formatErrorString(err)
	}

	if len(errString) > 0 {
		return errors.New(fmt.Sprintf("Validation errors: %s\n", errString))
	}
	return nil
}

func formatErrorString(err error) string {
	errs := err.(validator.ErrorMap)
	var errsString string
	for fieldName, validationMessage := range errs {
		errsString += fmt.Sprintf("%s : %s\n", fieldName, validationMessage)
	}
	return errsString
}
<|endoftext|>


<commit_before>//
package config

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"sync"

	"github.com/ghodss/yaml"
	"github.com/mitchellh/go-homedir"
	"github.com/nanobox-io/nanobox-golang-stylish"
)

const (
	OS          = runtime.GOOS
	ARCH        = runtime.GOARCH
	LOGTAP_PORT = ":6361"
	MIST_PORT   = ":1445"
	SERVER_PORT = ":1757"
	VERSION     = "0.16.9"
)

type (
	exiter func(int)
)

var (
	err   error //
	mutex *sync.Mutex

	//
	AppDir     string // the path to the application (~/.nanobox/apps/<app>)
	AppsDir    string // ~/.nanobox/apps
	CWDir      string // the current working directory
	EnginesDir string // ~/.nanobox/engines
	Home       string // the users home directory (~)
	IP         string // the guest vm's private network ip (generated from app name)
	Root       string // nanobox's root directory path (~/.nanobox)
	UpdateFile string // the path to the .update file (~/.nanobox/.update)

	//
	Nanofile NanofileConfig // parsed nanofile options
	VMfile   VMfileConfig   // parsed nanofile options

	//
	ServerURI string // nanobox-server host:port combo (IP:1757)
	ServerURL string // nanobox-server host:port combo (IP:1757) (http)
	MistURI   string // mist's host:port combo (IP:1445)
	LogtapURI string // logtap's host:port combo (IP:6361)

	// flags
	Background bool   //
	Devmode    bool   //
	Force      bool   //
	Verbose    bool   //
	Silent     bool   //
	LogLevel   string //

	//
	Exit exiter = os.Exit
)

//
func init() {

	// default log level
	LogLevel = "info"

	// set the current working directory first, as it's used in other steps of the
	// configuration process
	if p, err := os.Getwd(); err != nil {
		Log.Fatal("[config/config] os.Getwd() failed", err.Error())
	} else {
		CWDir = filepath.ToSlash(p)
	}

	// set Home based off the users homedir (~)
	if p, err := homedir.Dir(); err != nil {
		Log.Fatal("[config/config] homedir.Dir() failed", err.Error())
	} else {
		Home = filepath.ToSlash(p)
	}

	// set nanobox's root directory;
	Root = filepath.ToSlash(filepath.Join(Home, ".nanobox"))

	// check for a ~/.nanobox dir and create one if it's not found
	if _, err := os.Stat(Root); err != nil {
		fmt.Printf(stylish.Bullet("Creating %s directory", Root))
		if err := os.Mkdir(Root, 0755); err != nil {
			Log.Fatal("[config/config] os.Mkdir() failed", err.Error())
		}
	}

	// check for a ~/.nanobox/.update file and create one if it's not found
	UpdateFile = filepath.ToSlash(filepath.Join(Root, ".update"))
	if _, err := os.Stat(UpdateFile); err != nil {
		f, err := os.Create(UpdateFile)
		if err != nil {
			Log.Fatal("[config/config] os.Create() failed", err.Error())
		}
		defer f.Close()
	}

	// check for a ~/.nanobox/engines dir and create one if it's not found
	EnginesDir = filepath.ToSlash(filepath.Join(Root, "engines"))
	if _, err := os.Stat(EnginesDir); err != nil {
		if err := os.Mkdir(EnginesDir, 0755); err != nil {
			Log.Fatal("[config/config] os.Mkdir() failed", err.Error())
		}
	}

	// check for a ~/.nanobox/apps dir and create one if it's not found
	AppsDir = filepath.ToSlash(filepath.Join(Root, "apps"))
	if _, err := os.Stat(AppsDir); err != nil {
		if err := os.Mkdir(AppsDir, 0755); err != nil {
			Log.Fatal("[config/config] os.Mkdir() failed", err.Error())
		}
	}

	// the .nanofile needs to be parsed right away so that its config options are
	// available as soon as possible
	Nanofile = ParseNanofile()

	//
	ServerURI = Nanofile.IP + SERVER_PORT
	ServerURL = "http://" + ServerURI
	MistURI = Nanofile.IP + MIST_PORT
	LogtapURI = Nanofile.IP + LOGTAP_PORT

	// set the 'App' first so it can be used in subsequent configurations; the 'App'
	// is set to the name of the cwd; this can be overriden from a .nanofile
	AppDir = filepath.ToSlash(filepath.Join(AppsDir, Nanofile.Name))
}

// ParseConfig
func ParseConfig(path string, v interface{}) error {

	//
	fp, err := filepath.Abs(path)
	if err != nil {
		return err
	}

	//
	f, err := ioutil.ReadFile(fp)
	if err != nil {
		return err
	}

	//
	return yaml.Unmarshal(f, v)
}

// writeConfig
func writeConfig(path string, v interface{}) error {

	// take a config objects path and create (and truncate) the file, preparing it
	// to receive new configurations
	f, err := os.Create(path)
	if err != nil {
		Fatal("[config/config] os.Create() failed", err.Error())
	}
	defer f.Close()

	// marshal the config object
	b, err := yaml.Marshal(v)
	if err != nil {
		Fatal("[config/config] yaml.Marshal() failed", err.Error())
	}

	// mutex.Lock()

	// write it back to the file
	if _, err := f.Write(b); err != nil {
		return err
	}

	// mutex.Unlock()

	return nil
}
<commit_msg>bump to 0.16.10<commit_after>//
package config

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"sync"

	"github.com/ghodss/yaml"
	"github.com/mitchellh/go-homedir"
	"github.com/nanobox-io/nanobox-golang-stylish"
)

const (
	OS          = runtime.GOOS
	ARCH        = runtime.GOARCH
	LOGTAP_PORT = ":6361"
	MIST_PORT   = ":1445"
	SERVER_PORT = ":1757"
	VERSION     = "0.16.10"
)

type (
	exiter func(int)
)

var (
	err   error //
	mutex *sync.Mutex

	//
	AppDir     string // the path to the application (~/.nanobox/apps/<app>)
	AppsDir    string // ~/.nanobox/apps
	CWDir      string // the current working directory
	EnginesDir string // ~/.nanobox/engines
	Home       string // the users home directory (~)
	IP         string // the guest vm's private network ip (generated from app name)
	Root       string // nanobox's root directory path (~/.nanobox)
	UpdateFile string // the path to the .update file (~/.nanobox/.update)

	//
	Nanofile NanofileConfig // parsed nanofile options
	VMfile   VMfileConfig   // parsed nanofile options

	//
	ServerURI string // nanobox-server host:port combo (IP:1757)
	ServerURL string // nanobox-server host:port combo (IP:1757) (http)
	MistURI   string // mist's host:port combo (IP:1445)
	LogtapURI string // logtap's host:port combo (IP:6361)

	// flags
	Background bool   //
	Devmode    bool   //
	Force      bool   //
	Verbose    bool   //
	Silent     bool   //
	LogLevel   string //

	//
	Exit exiter = os.Exit
)

//
func init() {

	// default log level
	LogLevel = "info"

	// set the current working directory first, as it's used in other steps of the
	// configuration process
	if p, err := os.Getwd(); err != nil {
		Log.Fatal("[config/config] os.Getwd() failed", err.Error())
	} else {
		CWDir = filepath.ToSlash(p)
	}

	// set Home based off the users homedir (~)
	if p, err := homedir.Dir(); err != nil {
		Log.Fatal("[config/config] homedir.Dir() failed", err.Error())
	} else {
		Home = filepath.ToSlash(p)
	}

	// set nanobox's root directory;
	Root = filepath.ToSlash(filepath.Join(Home, ".nanobox"))

	// check for a ~/.nanobox dir and create one if it's not found
	if _, err := os.Stat(Root); err != nil {
		fmt.Printf(stylish.Bullet("Creating %s directory", Root))
		if err := os.Mkdir(Root, 0755); err != nil {
			Log.Fatal("[config/config] os.Mkdir() failed", err.Error())
		}
	}

	// check for a ~/.nanobox/.update file and create one if it's not found
	UpdateFile = filepath.ToSlash(filepath.Join(Root, ".update"))
	if _, err := os.Stat(UpdateFile); err != nil {
		f, err := os.Create(UpdateFile)
		if err != nil {
			Log.Fatal("[config/config] os.Create() failed", err.Error())
		}
		defer f.Close()
	}

	// check for a ~/.nanobox/engines dir and create one if it's not found
	EnginesDir = filepath.ToSlash(filepath.Join(Root, "engines"))
	if _, err := os.Stat(EnginesDir); err != nil {
		if err := os.Mkdir(EnginesDir, 0755); err != nil {
			Log.Fatal("[config/config] os.Mkdir() failed", err.Error())
		}
	}

	// check for a ~/.nanobox/apps dir and create one if it's not found
	AppsDir = filepath.ToSlash(filepath.Join(Root, "apps"))
	if _, err := os.Stat(AppsDir); err != nil {
		if err := os.Mkdir(AppsDir, 0755); err != nil {
			Log.Fatal("[config/config] os.Mkdir() failed", err.Error())
		}
	}

	// the .nanofile needs to be parsed right away so that its config options are
	// available as soon as possible
	Nanofile = ParseNanofile()

	//
	ServerURI = Nanofile.IP + SERVER_PORT
	ServerURL = "http://" + ServerURI
	MistURI = Nanofile.IP + MIST_PORT
	LogtapURI = Nanofile.IP + LOGTAP_PORT

	// set the 'App' first so it can be used in subsequent configurations; the 'App'
	// is set to the name of the cwd; this can be overriden from a .nanofile
	AppDir = filepath.ToSlash(filepath.Join(AppsDir, Nanofile.Name))
}

// ParseConfig
func ParseConfig(path string, v interface{}) error {

	//
	fp, err := filepath.Abs(path)
	if err != nil {
		return err
	}

	//
	f, err := ioutil.ReadFile(fp)
	if err != nil {
		return err
	}

	//
	return yaml.Unmarshal(f, v)
}

// writeConfig
func writeConfig(path string, v interface{}) error {

	// take a config objects path and create (and truncate) the file, preparing it
	// to receive new configurations
	f, err := os.Create(path)
	if err != nil {
		Fatal("[config/config] os.Create() failed", err.Error())
	}
	defer f.Close()

	// marshal the config object
	b, err := yaml.Marshal(v)
	if err != nil {
		Fatal("[config/config] yaml.Marshal() failed", err.Error())
	}

	// mutex.Lock()

	// write it back to the file
	if _, err := f.Write(b); err != nil {
		return err
	}

	// mutex.Unlock()

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"regexp"
)

var (
	_file        string
	_regex       string
	_print       string
	_ignorecase  bool
	_stoponfirst bool
)

func init() {
	flag.StringVar(&_file, "f", "", "file to search in")
	flag.StringVar(&_regex, "r", "", "search regex")
	flag.StringVar(&_print, "p", "", "instead of whole match print this (can contain $0..$N to refer to groups)")
	flag.BoolVar(&_ignorecase, "c", false, "ignore case (prepends (?i) to regex)")
	flag.BoolVar(&_stoponfirst, "s", false, "stop when first match is found")
	flag.Parse()
}

func main() {
	if _file == "" || _regex == "" {
		flag.Usage()
		return
	}
	if _ignorecase {
		_regex = "(?i)" + _regex
	}
	re, err := regexp.Compile(_regex)
	if err != nil {
		fmt.Println(err)
		return
	}
	fd, err := os.OpenFile(_file, os.O_RDONLY, 0600)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer fd.Close()
	c, err := ioutil.ReadAll(fd)
	if err != nil {
		fmt.Println(err)
		return
	}
	var dst []byte
	if _print != "" {
		dst = make([]byte, 0, 1*1024)
	}
	for {
		m := re.FindSubmatchIndex(c)
		if m == nil {
			break
		}
		if _print != "" {
			dst = dst[:0]
			fmt.Println(string(re.ExpandString(dst, _print, string(c), m)))
		} else {
			fmt.Println(string(c[m[0]:m[1]]))
		}
		if _stoponfirst {
			break
		}
		c = c[m[1]:]
	}
}
<commit_msg>added multiline mode<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"regexp"
)

var (
	_file        string
	_regex       string
	_print       string
	_ignorecase  bool
	_stoponfirst bool
)

func init() {
	flag.StringVar(&_file, "f", "", "file to search in")
	flag.StringVar(&_regex, "r", "", "search regex")
	flag.StringVar(&_print, "p", "", "instead of whole match print this (can contain $0..$N to refer to groups)")
	flag.BoolVar(&_ignorecase, "c", false, "ignore case (prepends (?i) to regex)")
	flag.BoolVar(&_stoponfirst, "s", false, "stop when first match is found")
	flag.Parse()
}

func main() {
	if _file == "" || _regex == "" {
		flag.Usage()
		return
	}
	if _ignorecase {
		_regex = "(?mi)" + _regex
	} else {
		_regex = "(?m)" + _regex
	}
	re, err := regexp.Compile(_regex)
	if err != nil {
		fmt.Println(err)
		return
	}
	fd, err := os.OpenFile(_file, os.O_RDONLY, 0600)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer fd.Close()
	c, err := ioutil.ReadAll(fd)
	if err != nil {
		fmt.Println(err)
		return
	}
	var dst []byte
	if _print != "" {
		dst = make([]byte, 0, 1*1024)
	}
	for {
		m := re.FindSubmatchIndex(c)
		if m == nil {
			break
		}
		if _print != "" {
			dst = dst[:0]
			fmt.Println(string(re.ExpandString(dst, _print, string(c), m)))
		} else {
			fmt.Println(string(c[m[0]:m[1]]))
		}
		if _stoponfirst {
			break
		}
		c = c[m[1]:]
	}
}
<|endoftext|>


<commit_before>package proxy

import (
	"errors"
	"net"
	"net/http"
	"testing"

	"github.com/flynn/flynn/Godeps/_workspace/src/golang.org/x/net/context"
	"github.com/flynn/flynn/pkg/connutil"
)

func TestServeConnClientGone(t *testing.T) {
	control, conn := net.Pipe()
	cnConn := connutil.CloseNotifyConn(conn)

	clientGone := false
	dialer = dialerFunc(func(_, _ string) (net.Conn, error) {
		if clientGone {
			err := errors.New("dial after client gone")
			t.Error(err)
			return nil, err
		}

		if err := control.Close(); err != nil {
			t.Fatal(err)
		}
		<-cnConn.(http.CloseNotifier).CloseNotify()

		clientGone = true
		return nil, &dialErr{}
	})

	fn := func() []string { return []string{"127.0.0.1:0", "127.0.0.1:0"} }
	prox := NewReverseProxy(fn, nil, false)

	prox.ServeConn(context.Background(), cnConn)
}

type dialerFunc func(string, string) (net.Conn, error)

func (f dialerFunc) Dial(network, addr string) (net.Conn, error) {
	return f(network, addr)
}
<commit_msg>router/proxy: Remove broken test<commit_after><|endoftext|>