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

package runtime

import "unsafe"

const (
	_ESRCH       = 3
	_EAGAIN      = 35
	_EWOULDBLOCK = _EAGAIN
	_ENOTSUP     = 91

	// From OpenBSD's sys/time.h
	_CLOCK_REALTIME  = 0
	_CLOCK_VIRTUAL   = 1
	_CLOCK_PROF      = 2
	_CLOCK_MONOTONIC = 3
)

const (
	sigset_none = uint32(0)
	sigset_all  = ^uint32(0)
)

// From OpenBSD's <sys/sysctl.h>
const (
	_CTL_HW  = 6
	_HW_NCPU = 3
)

func getncpu() int32 {
	mib := [2]uint32{_CTL_HW, _HW_NCPU}
	out := uint32(0)
	nout := unsafe.Sizeof(out)

	// Fetch hw.ncpu via sysctl.
	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
	if ret >= 0 {
		return int32(out)
	}
	return 1
}

//go:nosplit
func semacreate() uintptr {
	return 1
}

//go:nosplit
func semasleep(ns int64) int32 {
	_g_ := getg()

	// Compute sleep deadline.
	var tsp *timespec
	if ns >= 0 {
		var ts timespec
		var nsec int32
		ns += nanotime()
		ts.set_sec(int64(timediv(ns, 1000000000, &nsec)))
		ts.set_nsec(nsec)
		tsp = &ts
	}

	for {
		v := atomicload(&_g_.m.waitsemacount)
		if v > 0 {
			if cas(&_g_.m.waitsemacount, v, v-1) {
				return 0 // semaphore acquired
			}
			continue
		}

		// Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0.
		//
		// From OpenBSD's __thrsleep(2) manual:
		// "The abort argument, if not NULL, points to an int that will
		// be examined [...] immediately before blocking.  If that int
		// is non-zero then __thrsleep() will immediately return EINTR
		// without blocking."
		ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &_g_.m.waitsemacount)
		if ret == _EWOULDBLOCK {
			return -1
		}
	}
}

//go:nosplit
func semawakeup(mp *m) {
	xadd(&mp.waitsemacount, 1)
	ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1)
	if ret != 0 && ret != _ESRCH {
		// semawakeup can be called on signal stack.
		systemstack(func() {
			print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
		})
	}
}

func newosproc(mp *m, stk unsafe.Pointer) {
	if false {
		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, "/", int32(mp.tls[0]), " ostk=", &mp, "\n")
	}

	mp.tls[0] = uintptr(mp.id) // so 386 asm can find it

	param := tforkt{
		tf_tcb:   unsafe.Pointer(&mp.tls[0]),
		tf_tid:   (*int32)(unsafe.Pointer(&mp.procid)),
		tf_stack: uintptr(stk),
	}

	oset := sigprocmask(_SIG_SETMASK, sigset_all)
	ret := tfork(&param, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart))
	sigprocmask(_SIG_SETMASK, oset)

	if ret < 0 {
		print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
		if ret == -_ENOTSUP {
			print("runtime: is kern.rthreads disabled?\n")
		}
		throw("runtime.newosproc")
	}
}

func osinit() {
	ncpu = getncpu()
}

var urandom_dev = []byte("/dev/urandom\x00")

//go:nosplit
func getRandomData(r []byte) {
	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
	close(fd)
	extendRandom(r, int(n))
}

func goenvs() {
	goenvs_unix()
}

// Called to initialize a new m (including the bootstrap m).
// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
func mpreinit(mp *m) {
	mp.gsignal = malg(32 * 1024)
	mp.gsignal.m = mp
}

// Called to initialize a new m (including the bootstrap m).
// Called on the new thread, can not allocate memory.
func minit() {
	_g_ := getg()

	// m.procid is a uint64, but tfork writes an int32. Fix it up.
	_g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))

	// Initialize signal handling
	signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
	sigprocmask(_SIG_SETMASK, sigset_none)
}

// Called from dropm to undo the effect of an minit.
func unminit() {
	signalstack(nil, 0)
}

func memlimit() uintptr {
	return 0
}

func sigtramp()

type sigactiont struct {
	sa_sigaction uintptr
	sa_mask      uint32
	sa_flags     int32
}

func setsig(i int32, fn uintptr, restart bool) {
	var sa sigactiont
	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
	if restart {
		sa.sa_flags |= _SA_RESTART
	}
	sa.sa_mask = sigset_all
	if fn == funcPC(sighandler) {
		fn = funcPC(sigtramp)
	}
	sa.sa_sigaction = fn
	sigaction(i, &sa, nil)
}

func setsigstack(i int32) {
	throw("setsigstack")
}

func getsig(i int32) uintptr {
	var sa sigactiont
	sigaction(i, nil, &sa)
	if sa.sa_sigaction == funcPC(sigtramp) {
		return funcPC(sighandler)
	}
	return sa.sa_sigaction
}

func signalstack(p *byte, n int32) {
	var st stackt

	st.ss_sp = uintptr(unsafe.Pointer(p))
	st.ss_size = uintptr(n)
	st.ss_flags = 0
	if p == nil {
		st.ss_flags = _SS_DISABLE
	}
	sigaltstack(&st, nil)
}

func unblocksignals() {
	sigprocmask(_SIG_SETMASK, sigset_none)
}
<commit_msg>runtime: remove reference to openbsd kern.rthreads sysctl<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime

import "unsafe"

const (
	_ESRCH       = 3
	_EAGAIN      = 35
	_EWOULDBLOCK = _EAGAIN
	_ENOTSUP     = 91

	// From OpenBSD's sys/time.h
	_CLOCK_REALTIME  = 0
	_CLOCK_VIRTUAL   = 1
	_CLOCK_PROF      = 2
	_CLOCK_MONOTONIC = 3
)

const (
	sigset_none = uint32(0)
	sigset_all  = ^uint32(0)
)

// From OpenBSD's <sys/sysctl.h>
const (
	_CTL_HW  = 6
	_HW_NCPU = 3
)

func getncpu() int32 {
	mib := [2]uint32{_CTL_HW, _HW_NCPU}
	out := uint32(0)
	nout := unsafe.Sizeof(out)

	// Fetch hw.ncpu via sysctl.
	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
	if ret >= 0 {
		return int32(out)
	}
	return 1
}

//go:nosplit
func semacreate() uintptr {
	return 1
}

//go:nosplit
func semasleep(ns int64) int32 {
	_g_ := getg()

	// Compute sleep deadline.
	var tsp *timespec
	if ns >= 0 {
		var ts timespec
		var nsec int32
		ns += nanotime()
		ts.set_sec(int64(timediv(ns, 1000000000, &nsec)))
		ts.set_nsec(nsec)
		tsp = &ts
	}

	for {
		v := atomicload(&_g_.m.waitsemacount)
		if v > 0 {
			if cas(&_g_.m.waitsemacount, v, v-1) {
				return 0 // semaphore acquired
			}
			continue
		}

		// Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0.
		//
		// From OpenBSD's __thrsleep(2) manual:
		// "The abort argument, if not NULL, points to an int that will
		// be examined [...] immediately before blocking.  If that int
		// is non-zero then __thrsleep() will immediately return EINTR
		// without blocking."
		ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &_g_.m.waitsemacount)
		if ret == _EWOULDBLOCK {
			return -1
		}
	}
}

//go:nosplit
func semawakeup(mp *m) {
	xadd(&mp.waitsemacount, 1)
	ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1)
	if ret != 0 && ret != _ESRCH {
		// semawakeup can be called on signal stack.
		systemstack(func() {
			print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
		})
	}
}

func newosproc(mp *m, stk unsafe.Pointer) {
	if false {
		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, "/", int32(mp.tls[0]), " ostk=", &mp, "\n")
	}

	mp.tls[0] = uintptr(mp.id) // so 386 asm can find it

	param := tforkt{
		tf_tcb:   unsafe.Pointer(&mp.tls[0]),
		tf_tid:   (*int32)(unsafe.Pointer(&mp.procid)),
		tf_stack: uintptr(stk),
	}

	oset := sigprocmask(_SIG_SETMASK, sigset_all)
	ret := tfork(&param, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart))
	sigprocmask(_SIG_SETMASK, oset)

	if ret < 0 {
		print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
		throw("runtime.newosproc")
	}
}

func osinit() {
	ncpu = getncpu()
}

var urandom_dev = []byte("/dev/urandom\x00")

//go:nosplit
func getRandomData(r []byte) {
	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
	close(fd)
	extendRandom(r, int(n))
}

func goenvs() {
	goenvs_unix()
}

// Called to initialize a new m (including the bootstrap m).
// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
func mpreinit(mp *m) {
	mp.gsignal = malg(32 * 1024)
	mp.gsignal.m = mp
}

// Called to initialize a new m (including the bootstrap m).
// Called on the new thread, can not allocate memory.
func minit() {
	_g_ := getg()

	// m.procid is a uint64, but tfork writes an int32. Fix it up.
	_g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))

	// Initialize signal handling
	signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
	sigprocmask(_SIG_SETMASK, sigset_none)
}

// Called from dropm to undo the effect of an minit.
func unminit() {
	signalstack(nil, 0)
}

func memlimit() uintptr {
	return 0
}

func sigtramp()

type sigactiont struct {
	sa_sigaction uintptr
	sa_mask      uint32
	sa_flags     int32
}

func setsig(i int32, fn uintptr, restart bool) {
	var sa sigactiont
	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
	if restart {
		sa.sa_flags |= _SA_RESTART
	}
	sa.sa_mask = sigset_all
	if fn == funcPC(sighandler) {
		fn = funcPC(sigtramp)
	}
	sa.sa_sigaction = fn
	sigaction(i, &sa, nil)
}

func setsigstack(i int32) {
	throw("setsigstack")
}

func getsig(i int32) uintptr {
	var sa sigactiont
	sigaction(i, nil, &sa)
	if sa.sa_sigaction == funcPC(sigtramp) {
		return funcPC(sighandler)
	}
	return sa.sa_sigaction
}

func signalstack(p *byte, n int32) {
	var st stackt

	st.ss_sp = uintptr(unsafe.Pointer(p))
	st.ss_size = uintptr(n)
	st.ss_flags = 0
	if p == nil {
		st.ss_flags = _SS_DISABLE
	}
	sigaltstack(&st, nil)
}

func unblocksignals() {
	sigprocmask(_SIG_SETMASK, sigset_none)
}
<|endoftext|>


<commit_before>package config

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/ninjasphere/go-ninja/logger"
	"gopkg.in/alecthomas/kingpin.v1"
)

var log = logger.GetLogger("config")

var config map[string]interface{}

func init() {
	MustRefresh()
}

func GetAll(flatten bool) map[string]interface{} {
	if flatten {
		return config
	} else {
		return unflatten(config)
	}
}

var serial string

func Serial() string {
	if serial == "" {
		cmd := exec.Command("sphere-serial", os.Args[1:]...)

		var out bytes.Buffer
		cmd.Stdout = &out

		err := cmd.Run()
		if err != nil {
			log.Fatalf("Failed to get sphere serial (sphere-serial must be in the PATH) error:%s", err)
		}

		serial = out.String()
	}

	return serial
}

func String(def string, path ...string) string {
	val := get(path...)
	if val == nil {
		return def
	}
	return val.(string)
}

// MustString returns the string property at the path
func MustString(path ...string) string {
	return mustGet(path...).(string)
}

// MustDuration returns the string property at the path, as a time.Duration
func MustDuration(path ...string) time.Duration {
	s := MustString(path...)
	d, err := time.ParseDuration(s)
	if err != nil {
		log.Fatalf("Failed to parse duration '%s': %s", s, err)
	}
	return d
}

// MustStringArray returns the string array property at the path
func MustStringArray(path ...string) []string {
	a := mustGet(path...).([]interface{})
	b := make([]string, len(a))
	for i := range a {
		b[i] = a[i].(string)
	}
	return b
}

// Int returns the integer property at the path, with a default
func Int(def int, path ...string) int {
	val := get(path...)
	if val == nil {
		return def
	}
	return int(val.(float64))
}

// MustInt returns the string property at the path
func MustInt(path ...string) int {
	return int(mustGet(path...).(float64))
}

func MustFloat(path ...string) float64 {
	return mustGet(path...).(float64)
}

// Bool returns the boolean property at the path, with a default
func Bool(def bool, path ...string) bool {
	val := get(path...)
	if val == nil {
		return def
	}
	return val.(bool)
}

// MustBool returns the boolean property at the path
func MustBool(path ...string) bool {
	return mustGet(path...).(bool)
}

var hey = "what's up buddy?"

func HasString(path ...string) bool {
	val, ok := config[strings.Join(path, ".")]
	if !ok {
		return false
	}

	_, ok = val.(string)
	return ok
}

func mustGet(path ...string) interface{} {
	val, ok := config[strings.Join(path, ".")]
	if !ok {
		log.Fatalf("expected value for %v but found nothing", path)
	}
	return val
}

func get(path ...string) interface{} {
	val, ok := config[strings.Join(path, ".")]
	if !ok {
		return nil
	}
	return val
}

func MustRefresh() {

	flat := make(map[string]interface{})

	// cli overrides
	addArgs(flat)

	// load environments (no value args) from cli args
	environments := []string{"default"}
	for name, value := range flat {
		if value == nil {
			environments = append(environments, name)
		} else {
			if ok, boolValue := value.(bool); ok {
				if boolValue {
					environments = append(environments, name)
				}
			}
		}
	}

	log.Infof("Environments: %s", strings.Join(environments, ", "))

	flat["env"] = environments

	userHome := getUserHome()

	// env vars (if starting with "sphere_")
	addEnv(flat)

	// anything that can be parsed as a number, is a number
	parseNumbers(flat)

	installDir := "/opt/ninjablocks"
	if val, ok := flat["installDirectory"]; ok {
		installDir = val.(string)
	}

	flat["installDirectory"] = installDir

	if _, err := os.Stat(installDir); err != nil {
		log.Fatalf("Couldn't load sphere install directory. Override with env var sphere_installDirectory. error:%s", err)
	}

	// credentials file
	addFile("/data/etc/opt/ninja/credentials.json", flat)

	// home directory environment(s) config
	for i := len(environments) - 1; i >= 0; i-- {
		addFile(filepath.Join(userHome, ".sphere", environments[i]+".json"), flat)
	}

	// current directory environment(s) config
	for i := len(environments) - 1; i >= 0; i-- {
		addFile(filepath.Join(".", "config", environments[i]+".json"), flat)
	}

	// common environment(s) config
	for i := len(environments) - 1; i >= 0; i-- {
		addFile(filepath.Join(installDir, "config", environments[i]+".json"), flat)
	}

	// common credentials config
	addFile(filepath.Join(installDir, "config", "credentials.json"), flat)

	//log.Debugf("Loaded config: %v", flat)

	config = flat
}

func addEnv(config map[string]interface{}) {
	for _, v := range os.Environ() {
		split := strings.Split(v, "=")

		name, value := split[0], split[1]

		if strings.HasPrefix(name, "sphere_") {
			name = strings.TrimPrefix(name, "sphere_")
			name = strings.Replace(name, "_", ".", 0)

			if _, ok := config[name]; !ok {
				config[name] = value
			}
		}
	}
}

func addArgs(config map[string]interface{}) {

	parser := kingpin.Tokenize(os.Args[1:]).Tokens

	for token, parser := parser.Peek(), parser.Next(); token.Type != kingpin.TokenEOL; token, parser = parser.Peek(), parser.Next() {

		if token.IsFlag() {
			var value interface{}
			name := token.Value

			next := parser.Peek()
			if next.Type == kingpin.TokenArg {
				if next.Value == "false" {
					value = false
				} else if next.Value == "true" {
					value = true
				} else {
					value = next.Value
				}
			} else {
				value = true
				// It's an environment indicator... like --cloud-production
			}

			config[name] = value
		}

	}

}

func addFile(path string, config map[string]interface{}) error {
	//log.Debugf("Loading config file: %s", path)

	file, e := ioutil.ReadFile(path)
	if e != nil {
		return fmt.Errorf("Failed to load file: %s error: %s", path, e)
	}

	content := make(map[string]interface{})
	e = json.Unmarshal(file, &content)
	if e != nil {
		return fmt.Errorf("Failed to read file: %s error: %s", path, e)
	}

	//spew.Dump(path, content)

	flatten(content, nil, config)
	return nil
}

func flatten(input interface{}, lpath []string, flattened map[string]interface{}) {
	if lpath == nil {
		lpath = []string{}
	}

	if reflect.ValueOf(input).Kind() == reflect.Map {
		for rkey, value := range input.(map[string]interface{}) {
			flatten(value, append(lpath, rkey), flattened)
		}
	} else {
		if _, ok := flattened[strings.Join(lpath, ".")]; !ok {
			flattened[strings.Join(lpath, ".")] = input
		}
	}
}

func unflatten(flat map[string]interface{}) map[string]interface{} {
	out := make(map[string]interface{})
	obj := out

	for key, val := range flat {

		obj = out
		keys := strings.Split(key, ".")

		for i, k := range keys {
			if i == len(keys)-1 {
				obj[k] = val
			} else {
				next, ok := obj[k]
				if !ok {
					next = make(map[string]interface{})
				}
				obj[k] = next
				obj = next.(map[string]interface{})
			}
		}

	}

	return out
}

func parseNumbers(config map[string]interface{}) {
	for name, val := range config {
		stringVal, ok := val.(string)
		if ok {
			floatVal, err := strconv.ParseFloat(stringVal, 64)
			if err == nil {
				config[name] = floatVal
			}
		}
	}
}

func getUserHome() string {
	usr, err := user.Current()
	if err != nil {
		return "/root"
	}
	return usr.HomeDir
}
<commit_msg>Add config.IsPaired<commit_after>package config

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/ninjasphere/go-ninja/logger"
	"gopkg.in/alecthomas/kingpin.v1"
)

var log = logger.GetLogger("config")

var config map[string]interface{}

func init() {
	MustRefresh()
}

func GetAll(flatten bool) map[string]interface{} {
	if flatten {
		return config
	} else {
		return unflatten(config)
	}
}

var serial string

func Serial() string {
	if serial == "" {
		cmd := exec.Command("sphere-serial", os.Args[1:]...)

		var out bytes.Buffer
		cmd.Stdout = &out

		err := cmd.Run()
		if err != nil {
			log.Fatalf("Failed to get sphere serial (sphere-serial must be in the PATH) error:%s", err)
		}

		serial = out.String()
	}

	return serial
}

func IsPaired() bool {
	return HasString("siteId") && HasString("token") && HasString("userId") && HasString("nodeId")
}

func String(def string, path ...string) string {
	val := get(path...)
	if val == nil {
		return def
	}
	return val.(string)
}

// MustString returns the string property at the path
func MustString(path ...string) string {
	return mustGet(path...).(string)
}

// MustDuration returns the string property at the path, as a time.Duration
func MustDuration(path ...string) time.Duration {
	s := MustString(path...)
	d, err := time.ParseDuration(s)
	if err != nil {
		log.Fatalf("Failed to parse duration '%s': %s", s, err)
	}
	return d
}

// MustStringArray returns the string array property at the path
func MustStringArray(path ...string) []string {
	a := mustGet(path...).([]interface{})
	b := make([]string, len(a))
	for i := range a {
		b[i] = a[i].(string)
	}
	return b
}

// Int returns the integer property at the path, with a default
func Int(def int, path ...string) int {
	val := get(path...)
	if val == nil {
		return def
	}
	return int(val.(float64))
}

// MustInt returns the string property at the path
func MustInt(path ...string) int {
	return int(mustGet(path...).(float64))
}

func MustFloat(path ...string) float64 {
	return mustGet(path...).(float64)
}

// Bool returns the boolean property at the path, with a default
func Bool(def bool, path ...string) bool {
	val := get(path...)
	if val == nil {
		return def
	}
	return val.(bool)
}

// MustBool returns the boolean property at the path
func MustBool(path ...string) bool {
	return mustGet(path...).(bool)
}

var hey = "what's up buddy?"

func HasString(path ...string) bool {
	val, ok := config[strings.Join(path, ".")]
	if !ok {
		return false
	}

	_, ok = val.(string)
	return ok
}

func mustGet(path ...string) interface{} {
	val, ok := config[strings.Join(path, ".")]
	if !ok {
		log.Fatalf("expected value for %v but found nothing", path)
	}
	return val
}

func get(path ...string) interface{} {
	val, ok := config[strings.Join(path, ".")]
	if !ok {
		return nil
	}
	return val
}

func MustRefresh() {

	flat := make(map[string]interface{})

	// cli overrides
	addArgs(flat)

	// load environments (no value args) from cli args
	environments := []string{"default"}
	for name, value := range flat {
		if value == nil {
			environments = append(environments, name)
		} else {
			if ok, boolValue := value.(bool); ok {
				if boolValue {
					environments = append(environments, name)
				}
			}
		}
	}

	log.Infof("Environments: %s", strings.Join(environments, ", "))

	flat["env"] = environments

	userHome := getUserHome()

	// env vars (if starting with "sphere_")
	addEnv(flat)

	// anything that can be parsed as a number, is a number
	parseNumbers(flat)

	installDir := "/opt/ninjablocks"
	if val, ok := flat["installDirectory"]; ok {
		installDir = val.(string)
	}

	flat["installDirectory"] = installDir

	if _, err := os.Stat(installDir); err != nil {
		log.Fatalf("Couldn't load sphere install directory. Override with env var sphere_installDirectory. error:%s", err)
	}

	// credentials file
	addFile("/data/etc/opt/ninja/credentials.json", flat)

	// home directory environment(s) config
	for i := len(environments) - 1; i >= 0; i-- {
		addFile(filepath.Join(userHome, ".sphere", environments[i]+".json"), flat)
	}

	// current directory environment(s) config
	for i := len(environments) - 1; i >= 0; i-- {
		addFile(filepath.Join(".", "config", environments[i]+".json"), flat)
	}

	// common environment(s) config
	for i := len(environments) - 1; i >= 0; i-- {
		addFile(filepath.Join(installDir, "config", environments[i]+".json"), flat)
	}

	// common credentials config
	addFile(filepath.Join(installDir, "config", "credentials.json"), flat)

	//log.Debugf("Loaded config: %v", flat)

	config = flat
}

func addEnv(config map[string]interface{}) {
	for _, v := range os.Environ() {
		split := strings.Split(v, "=")

		name, value := split[0], split[1]

		if strings.HasPrefix(name, "sphere_") {
			name = strings.TrimPrefix(name, "sphere_")
			name = strings.Replace(name, "_", ".", 0)

			if _, ok := config[name]; !ok {
				config[name] = value
			}
		}
	}
}

func addArgs(config map[string]interface{}) {

	parser := kingpin.Tokenize(os.Args[1:]).Tokens

	for token, parser := parser.Peek(), parser.Next(); token.Type != kingpin.TokenEOL; token, parser = parser.Peek(), parser.Next() {

		if token.IsFlag() {
			var value interface{}
			name := token.Value

			next := parser.Peek()
			if next.Type == kingpin.TokenArg {
				if next.Value == "false" {
					value = false
				} else if next.Value == "true" {
					value = true
				} else {
					value = next.Value
				}
			} else {
				value = true
				// It's an environment indicator... like --cloud-production
			}

			config[name] = value
		}

	}

}

func addFile(path string, config map[string]interface{}) error {
	//log.Debugf("Loading config file: %s", path)

	file, e := ioutil.ReadFile(path)
	if e != nil {
		return fmt.Errorf("Failed to load file: %s error: %s", path, e)
	}

	content := make(map[string]interface{})
	e = json.Unmarshal(file, &content)
	if e != nil {
		return fmt.Errorf("Failed to read file: %s error: %s", path, e)
	}

	//spew.Dump(path, content)

	flatten(content, nil, config)
	return nil
}

func flatten(input interface{}, lpath []string, flattened map[string]interface{}) {
	if lpath == nil {
		lpath = []string{}
	}

	if reflect.ValueOf(input).Kind() == reflect.Map {
		for rkey, value := range input.(map[string]interface{}) {
			flatten(value, append(lpath, rkey), flattened)
		}
	} else {
		if _, ok := flattened[strings.Join(lpath, ".")]; !ok {
			flattened[strings.Join(lpath, ".")] = input
		}
	}
}

func unflatten(flat map[string]interface{}) map[string]interface{} {
	out := make(map[string]interface{})
	obj := out

	for key, val := range flat {

		obj = out
		keys := strings.Split(key, ".")

		for i, k := range keys {
			if i == len(keys)-1 {
				obj[k] = val
			} else {
				next, ok := obj[k]
				if !ok {
					next = make(map[string]interface{})
				}
				obj[k] = next
				obj = next.(map[string]interface{})
			}
		}

	}

	return out
}

func parseNumbers(config map[string]interface{}) {
	for name, val := range config {
		stringVal, ok := val.(string)
		if ok {
			floatVal, err := strconv.ParseFloat(stringVal, 64)
			if err == nil {
				config[name] = floatVal
			}
		}
	}
}

func getUserHome() string {
	usr, err := user.Current()
	if err != nil {
		return "/root"
	}
	return usr.HomeDir
}
<|endoftext|>


<commit_before>package config

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
	"reflect"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/davecgh/go-spew/spew"
	"github.com/go-fsnotify/fsnotify"

	"github.com/juju/loggo"
	"gopkg.in/alecthomas/kingpin.v1"
)

var (
	config   map[string]interface{}
	log      = loggo.GetLogger("config") // avoid the wrapper as it uses this module and will cause a loop
	dataPath = "/data"
	lock     = &sync.WaitGroup{}
)

func init() {
	// in snappy, we default to using the snappy data path
	snappDataPath := os.Getenv("SNAPP_APP_DATA_PATH")
	if snappDataPath != "" {
		dataPath = snappDataPath
	}

	MustRefresh()

	if Bool(false, "dumpConfig") {
		spew.Dump(GetAll(false))
	}

	go func() {

		watcher, err := fsnotify.NewWatcher()
		if err != nil {
			panic("Failed to create watcher: " + err.Error())
		}
		watcher.Add(dataPath + "/etc/opt/ninja")

		for {
			select {
			case ev := <-watcher.Events:
				log.Infof("Config updated: %s", ev.Name)
				MustRefresh()
			case err := <-watcher.Errors:
				log.Warningf("Config Watcher error: %s", err)
			}
		}

	}()
}

func GetAll(flatten bool) map[string]interface{} {
	if flatten {
		return config
	}
	return unflatten(config)
}

var serial string
var sphereVersion string

func Serial() string {

	if serial == "" {

		if HasString("serial") {
			serial = String("serial")
		} else {

			cmd := exec.Command("sphere-serial", os.Args[1:]...)

			var out bytes.Buffer
			cmd.Stdout = &out

			err := cmd.Run()
			if err == nil {
				serial = out.String()
			} else {

				if runtime.GOOS == "darwin" {
					serial = darwinSerial()
				} else {
					log.Errorf("Failed to get sphere serial (sphere-serial must be in the PATH) error:%s", err)
					panic(err)
				}
			}

		}
	}

	return serial
}

func darwinSerial() string {
	cmd := exec.Command("/bin/sh", "-c", "system_profiler SPHardwareDataType | sed -n 's/.*Serial Number (system).*: /OSX/p'")
	bytes, err := cmd.Output()
	if err != nil {
		log.Errorf("Failed to get darwin serial: %s ", err)
		panic("No darwin serial")
	}

	return string(bytes[0 : len(bytes)-1])
}

func SphereVersion() string {
	if sphereVersion == "" {
		if HasString("sphere-version") {

			sphereVersion = String("sphere-version")

		} else {

			cmd := exec.Command("sphere-version", os.Args[1:]...)

			var out bytes.Buffer
			cmd.Stdout = &out

			err := cmd.Run()
			if err != nil {
				log.Errorf("Failed to get sphere version (sphere-version must be in the PATH) error:%s", err)
				sphereVersion = "[unknown]"
			} else {
				sphereVersion = strings.TrimSpace(out.String())
			}
		}

	}
	return sphereVersion
}

func IsPaired() bool {
	return /*HasString("sphereNetworkKey") && */ HasString("token") && HasString("userId")
}

func NoCloud() bool {
	return Bool(false, "noCloud")
}

func String(def string, path ...string) string {
	val := get(path...)
	if val == nil {
		return def
	}
	return val.(string)
}

// MustString returns the string property at the path
func MustString(path ...string) string {
	return mustGet(path...).(string)
}

// Duration returns the string property at the path, as a time.Duration
func Duration(def time.Duration, path ...string) time.Duration {
	s := String(hey, path...)
	if s == hey {
		return def
	}
	d, err := time.ParseDuration(s)
	if err != nil {
		log.Infof("Failed to parse duration '%s': %s", s, err)
		return def
	}
	return d
}

// MustDuration returns the string property at the path, as a time.Duration
func MustDuration(path ...string) time.Duration {
	s := MustString(path...)
	d, err := time.ParseDuration(s)
	if err != nil {
		log.Infof("Failed to parse duration '%s': %s", s, err)
	}
	return d
}

// MustStringArray returns the string array property at the path
func MustStringArray(path ...string) []string {
	a := mustGet(path...).([]interface{})
	b := make([]string, len(a))
	for i := range a {
		b[i] = a[i].(string)
	}
	return b
}

// Int returns the integer property at the path, with a default
func Int(def int, path ...string) int {
	val := get(path...)
	if val == nil {
		return def
	}
	return int(val.(float64))
}

// MustInt returns the string property at the path
func MustInt(path ...string) int {
	return int(mustGet(path...).(float64))
}

// Float returns the float property at the path, with a default
func Float(def float64, path ...string) float64 {
	val := get(path...)
	if val == nil {
		return def
	}
	return val.(float64)
}

func MustFloat(path ...string) float64 {
	return mustGet(path...).(float64)
}

// Bool returns the boolean property at the path, with a default
func Bool(def bool, path ...string) bool {
	val := get(path...)
	if val == nil {
		return def
	}
	return val.(bool)
}

// MustBool returns the boolean property at the path
func MustBool(path ...string) bool {
	return mustGet(path...).(bool)
}

var hey = "what's up buddy?"

func HasString(path ...string) bool {
	lock.Wait()

	val, ok := config[strings.Join(path, ".")]
	if !ok {
		return false
	}

	_, ok = val.(string)
	return ok
}

func mustGet(path ...string) interface{} {
	lock.Wait()

	val, ok := config[strings.Join(path, ".")]
	if !ok {
		log.Errorf("expected value for %v but found nothing", path)
		panic(fmt.Errorf("expected value for %v but found nothing", path))
	}
	return val
}

func get(path ...string) interface{} {
	lock.Wait()

	val, ok := config[strings.Join(path, ".")]
	if !ok {
		return nil
	}
	return val
}

func MustRefresh() {
	lock.Wait()
	lock.Add(1)

	func() {
		defer lock.Done()

		flat := make(map[string]interface{})

		// cli overrides
		addArgs(flat)

		// env vars (if starting with "sphere_")
		addEnv(flat)

		// initialise the list
		environments := []string{"default"}

		// add environments read from the env variable
		if v, ok := flat["env"]; ok {
			environments = append(environments, strings.Split(v.(string), ",")...)
		}

		// then add any found in cli arguments
		for name, value := range flat {
			if value == nil {
				environments = append(environments, name)
			} else {
				if ok, boolValue := value.(bool); ok {
					if boolValue {
						environments = append(environments, name)
					}
				}
			}
		}

		flat["env"] = environments

		log.Infof("Environments: %s", strings.Join(environments, ", "))

		userHome := getUserHome()

		// anything that can be parsed as a number, is a number
		parseNumbers(flat)

		installDir := "/opt/ninjablocks"
		if val, ok := flat["installDirectory"]; ok {
			installDir = val.(string)
		}

		if _, err := os.Stat(installDir); err != nil {
			// check for installation in snappy, apply different default path
			snappAppPath := os.Getenv("SNAPP_APP_PATH")
			if snappAppPath != "" {
				installDir = snappAppPath
			}
		}

		flat["installDirectory"] = installDir

		if _, err := os.Stat(installDir); err != nil {
			log.Warningf("Couldn't load sphere install directory. Override with env var sphere_installDirectory. error:%s", err)
		}

		// User overrides (json)
		addFile(dataPath+"/config.json", flat)

		files, _ := ioutil.ReadDir(dataPath + "/etc/opt/ninja")
		for _, f := range files {
			if strings.HasSuffix(f.Name(), ".json") {
				addFile(dataPath+"/etc/opt/ninja/"+f.Name(), flat)
			}
		}

		// home directory environment(s) config
		for i := len(environments) - 1; i >= 0; i-- {
			addFile(filepath.Join(userHome, ".sphere", environments[i]+".json"), flat)
		}

		// current directory environment(s) config
		for i := len(environments) - 1; i >= 0; i-- {
			addFile(filepath.Join(".", "config", environments[i]+".json"), flat)
		}

		// common environment(s) config
		for i := len(environments) - 1; i >= 0; i-- {
			addFile(filepath.Join(installDir, "config", environments[i]+".json"), flat)
		}

		//log.Debugf("Loaded config: %v", flat)

		config = flat

	}()

	if nc, ok := config["noCloud"]; ok {
		if nc.(bool) {
			config["userId"] = "nouser"
			config["token"] = "notoken"
			config["sphereNetworkKey"] = "nonetworkkey"
			config["siteId"] = "nomesh" + Serial()
			config["masterNodeId"] = Serial()
		}
	}

}

func addEnv(config map[string]interface{}) {
	prefix := "sphere_"
	for _, v := range os.Environ() {

		re := regexp.MustCompile("([^=]*)=(.*)")
		split := re.FindStringSubmatch(v)
		if split != nil {
			name, value := split[1], split[2]

			if strings.HasPrefix(name, prefix) {
				name = strings.TrimPrefix(name, prefix)
				name = strings.Replace(name, "_", ".", -1)

				if _, ok := config[name]; !ok {
					if value == "true" {
						config[name] = true
					} else if value == "false" {
						config[name] = false
					} else {
						config[name] = value
					}
				}
			}
		}
	}
}

func addArgs(config map[string]interface{}) {

	parser := kingpin.Tokenize(os.Args[1:]).Tokens

	for token, parser := parser.Peek(), parser.Next(); token.Type != kingpin.TokenEOL; token, parser = parser.Peek(), parser.Next() {

		if token.IsFlag() {
			var value interface{}
			name := token.Value

			next := parser.Peek()
			if next.Type == kingpin.TokenArg {
				if next.Value == "false" {
					value = false
				} else if next.Value == "true" {
					value = true
				} else {
					value = next.Value
				}
			} else {
				value = true
				// It's an environment indicator... like --cloud-production
			}

			config[name] = value
		}

	}

}

func addFile(path string, config map[string]interface{}) error {
	//log.Debugf("Loading config file: %s", path)

	file, e := ioutil.ReadFile(path)
	if e != nil {
		return fmt.Errorf("Failed to load file: %s error: %s", path, e)
	}

	content := make(map[string]interface{})
	e = json.Unmarshal(file, &content)
	if e != nil {
		return fmt.Errorf("Failed to read file: %s error: %s", path, e)
	}

	//spew.Dump(path, content)

	flatten(content, nil, config)
	return nil
}

func flatten(input interface{}, lpath []string, flattened map[string]interface{}) {
	if lpath == nil {
		lpath = []string{}
	}

	if reflect.ValueOf(input).Kind() == reflect.Map {
		for rkey, value := range input.(map[string]interface{}) {
			flatten(value, append(lpath, rkey), flattened)
		}
	} else {
		if _, ok := flattened[strings.Join(lpath, ".")]; !ok {
			flattened[strings.Join(lpath, ".")] = input
		}
	}
}

func unflatten(flat map[string]interface{}) map[string]interface{} {
	out := make(map[string]interface{})
	obj := out

	for key, val := range flat {

		obj = out
		keys := strings.Split(key, ".")

		for i, k := range keys {
			if i == len(keys)-1 {
				obj[k] = val
			} else {
				next, ok := obj[k]
				if !ok {
					next = make(map[string]interface{})
				}
				obj[k] = next
				obj = next.(map[string]interface{})
			}
		}

	}

	return out
}

func parseNumbers(config map[string]interface{}) {
	for name, val := range config {
		stringVal, ok := val.(string)
		if ok {
			floatVal, err := strconv.ParseFloat(stringVal, 64)
			if err == nil {
				config[name] = floatVal
			}
		}
	}
}

func getUserHome() string {
	usr, err := user.Current()
	if err != nil {
		return "/root"
	}
	return usr.HomeDir
}

func IsSlave() bool {
	masterNodeId := String("", "masterNodeId")
	serial := Serial()
	return masterNodeId != "" && serial != masterNodeId
}

func IsMaster() bool {
	masterNodeId := String("", "masterNodeId")
	serial := Serial()
	return masterNodeId != "" && serial == masterNodeId
}
<commit_msg>avoids a fork bomb would otherwise occur<commit_after>package config

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
	"reflect"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/davecgh/go-spew/spew"
	"github.com/go-fsnotify/fsnotify"

	"github.com/juju/loggo"
	"gopkg.in/alecthomas/kingpin.v1"
)

var (
	config   map[string]interface{}
	log      = loggo.GetLogger("config") // avoid the wrapper as it uses this module and will cause a loop
	dataPath = "/data"
	lock     = &sync.WaitGroup{}
)

func init() {
	// in snappy, we default to using the snappy data path
	snappDataPath := os.Getenv("SNAPP_APP_DATA_PATH")
	if snappDataPath != "" {
		dataPath = snappDataPath
	}

	MustRefresh()

	if Bool(false, "dumpConfig") {
		spew.Dump(GetAll(false))
	}

	go func() {

		watcher, err := fsnotify.NewWatcher()
		if err != nil {
			panic("Failed to create watcher: " + err.Error())
		}
		watcher.Add(dataPath + "/etc/opt/ninja")

		for {
			select {
			case ev := <-watcher.Events:
				log.Infof("Config updated: %s", ev.Name)
				MustRefresh()
			case err := <-watcher.Errors:
				log.Warningf("Config Watcher error: %s", err)
			}
		}

	}()
}

func GetAll(flatten bool) map[string]interface{} {
	if flatten {
		return config
	}
	return unflatten(config)
}

var serial string
var sphereVersion string

func Serial() string {

	if serial == "" {

		if HasString("serial") {
			serial = String("serial")
		} else {
			// dont use the user space wrapper to avoid fork bomb -> sphere-serial -> sphere-config -> sphere-serial -> sphere-config
			cmd := exec.Command("sphere-go-serial", os.Args[1:]...)

			var out bytes.Buffer
			cmd.Stdout = &out

			err := cmd.Run()
			if err == nil {
				serial = out.String()
			} else {

				if runtime.GOOS == "darwin" {
					serial = darwinSerial()
				} else {
					log.Errorf("Failed to get sphere serial (sphere-serial must be in the PATH) error:%s", err)
					panic(err)
				}
			}

		}
	}

	return serial
}

func darwinSerial() string {
	cmd := exec.Command("/bin/sh", "-c", "system_profiler SPHardwareDataType | sed -n 's/.*Serial Number (system).*: /OSX/p'")
	bytes, err := cmd.Output()
	if err != nil {
		log.Errorf("Failed to get darwin serial: %s ", err)
		panic("No darwin serial")
	}

	return string(bytes[0 : len(bytes)-1])
}

func SphereVersion() string {
	if sphereVersion == "" {
		if HasString("sphere-version") {

			sphereVersion = String("sphere-version")

		} else {

			cmd := exec.Command("sphere-version", os.Args[1:]...)

			var out bytes.Buffer
			cmd.Stdout = &out

			err := cmd.Run()
			if err != nil {
				log.Errorf("Failed to get sphere version (sphere-version must be in the PATH) error:%s", err)
				sphereVersion = "[unknown]"
			} else {
				sphereVersion = strings.TrimSpace(out.String())
			}
		}

	}
	return sphereVersion
}

func IsPaired() bool {
	return /*HasString("sphereNetworkKey") && */ HasString("token") && HasString("userId")
}

func NoCloud() bool {
	return Bool(false, "noCloud")
}

func String(def string, path ...string) string {
	val := get(path...)
	if val == nil {
		return def
	}
	return val.(string)
}

// MustString returns the string property at the path
func MustString(path ...string) string {
	return mustGet(path...).(string)
}

// Duration returns the string property at the path, as a time.Duration
func Duration(def time.Duration, path ...string) time.Duration {
	s := String(hey, path...)
	if s == hey {
		return def
	}
	d, err := time.ParseDuration(s)
	if err != nil {
		log.Infof("Failed to parse duration '%s': %s", s, err)
		return def
	}
	return d
}

// MustDuration returns the string property at the path, as a time.Duration
func MustDuration(path ...string) time.Duration {
	s := MustString(path...)
	d, err := time.ParseDuration(s)
	if err != nil {
		log.Infof("Failed to parse duration '%s': %s", s, err)
	}
	return d
}

// MustStringArray returns the string array property at the path
func MustStringArray(path ...string) []string {
	a := mustGet(path...).([]interface{})
	b := make([]string, len(a))
	for i := range a {
		b[i] = a[i].(string)
	}
	return b
}

// Int returns the integer property at the path, with a default
func Int(def int, path ...string) int {
	val := get(path...)
	if val == nil {
		return def
	}
	return int(val.(float64))
}

// MustInt returns the string property at the path
func MustInt(path ...string) int {
	return int(mustGet(path...).(float64))
}

// Float returns the float property at the path, with a default
func Float(def float64, path ...string) float64 {
	val := get(path...)
	if val == nil {
		return def
	}
	return val.(float64)
}

func MustFloat(path ...string) float64 {
	return mustGet(path...).(float64)
}

// Bool returns the boolean property at the path, with a default
func Bool(def bool, path ...string) bool {
	val := get(path...)
	if val == nil {
		return def
	}
	return val.(bool)
}

// MustBool returns the boolean property at the path
func MustBool(path ...string) bool {
	return mustGet(path...).(bool)
}

var hey = "what's up buddy?"

func HasString(path ...string) bool {
	lock.Wait()

	val, ok := config[strings.Join(path, ".")]
	if !ok {
		return false
	}

	_, ok = val.(string)
	return ok
}

func mustGet(path ...string) interface{} {
	lock.Wait()

	val, ok := config[strings.Join(path, ".")]
	if !ok {
		log.Errorf("expected value for %v but found nothing", path)
		panic(fmt.Errorf("expected value for %v but found nothing", path))
	}
	return val
}

func get(path ...string) interface{} {
	lock.Wait()

	val, ok := config[strings.Join(path, ".")]
	if !ok {
		return nil
	}
	return val
}

func MustRefresh() {
	lock.Wait()
	lock.Add(1)

	func() {
		defer lock.Done()

		flat := make(map[string]interface{})

		// cli overrides
		addArgs(flat)

		// env vars (if starting with "sphere_")
		addEnv(flat)

		// initialise the list
		environments := []string{"default"}

		// add environments read from the env variable
		if v, ok := flat["env"]; ok {
			environments = append(environments, strings.Split(v.(string), ",")...)
		}

		// then add any found in cli arguments
		for name, value := range flat {
			if value == nil {
				environments = append(environments, name)
			} else {
				if ok, boolValue := value.(bool); ok {
					if boolValue {
						environments = append(environments, name)
					}
				}
			}
		}

		flat["env"] = environments

		log.Infof("Environments: %s", strings.Join(environments, ", "))

		userHome := getUserHome()

		// anything that can be parsed as a number, is a number
		parseNumbers(flat)

		installDir := "/opt/ninjablocks"
		if val, ok := flat["installDirectory"]; ok {
			installDir = val.(string)
		}

		if _, err := os.Stat(installDir); err != nil {
			// check for installation in snappy, apply different default path
			snappAppPath := os.Getenv("SNAPP_APP_PATH")
			if snappAppPath != "" {
				installDir = snappAppPath
			}
		}

		flat["installDirectory"] = installDir

		if _, err := os.Stat(installDir); err != nil {
			log.Warningf("Couldn't load sphere install directory. Override with env var sphere_installDirectory. error:%s", err)
		}

		// User overrides (json)
		addFile(dataPath+"/config.json", flat)

		files, _ := ioutil.ReadDir(dataPath + "/etc/opt/ninja")
		for _, f := range files {
			if strings.HasSuffix(f.Name(), ".json") {
				addFile(dataPath+"/etc/opt/ninja/"+f.Name(), flat)
			}
		}

		// home directory environment(s) config
		for i := len(environments) - 1; i >= 0; i-- {
			addFile(filepath.Join(userHome, ".sphere", environments[i]+".json"), flat)
		}

		// current directory environment(s) config
		for i := len(environments) - 1; i >= 0; i-- {
			addFile(filepath.Join(".", "config", environments[i]+".json"), flat)
		}

		// common environment(s) config
		for i := len(environments) - 1; i >= 0; i-- {
			addFile(filepath.Join(installDir, "config", environments[i]+".json"), flat)
		}

		//log.Debugf("Loaded config: %v", flat)

		config = flat

	}()

	if nc, ok := config["noCloud"]; ok {
		if nc.(bool) {
			config["userId"] = "nouser"
			config["token"] = "notoken"
			config["sphereNetworkKey"] = "nonetworkkey"
			config["siteId"] = "nomesh" + Serial()
			config["masterNodeId"] = Serial()
		}
	}

}

func addEnv(config map[string]interface{}) {
	prefix := "sphere_"
	for _, v := range os.Environ() {

		re := regexp.MustCompile("([^=]*)=(.*)")
		split := re.FindStringSubmatch(v)
		if split != nil {
			name, value := split[1], split[2]

			if strings.HasPrefix(name, prefix) {
				name = strings.TrimPrefix(name, prefix)
				name = strings.Replace(name, "_", ".", -1)

				if _, ok := config[name]; !ok {
					if value == "true" {
						config[name] = true
					} else if value == "false" {
						config[name] = false
					} else {
						config[name] = value
					}
				}
			}
		}
	}
}

func addArgs(config map[string]interface{}) {

	parser := kingpin.Tokenize(os.Args[1:]).Tokens

	for token, parser := parser.Peek(), parser.Next(); token.Type != kingpin.TokenEOL; token, parser = parser.Peek(), parser.Next() {

		if token.IsFlag() {
			var value interface{}
			name := token.Value

			next := parser.Peek()
			if next.Type == kingpin.TokenArg {
				if next.Value == "false" {
					value = false
				} else if next.Value == "true" {
					value = true
				} else {
					value = next.Value
				}
			} else {
				value = true
				// It's an environment indicator... like --cloud-production
			}

			config[name] = value
		}

	}

}

func addFile(path string, config map[string]interface{}) error {
	//log.Debugf("Loading config file: %s", path)

	file, e := ioutil.ReadFile(path)
	if e != nil {
		return fmt.Errorf("Failed to load file: %s error: %s", path, e)
	}

	content := make(map[string]interface{})
	e = json.Unmarshal(file, &content)
	if e != nil {
		return fmt.Errorf("Failed to read file: %s error: %s", path, e)
	}

	//spew.Dump(path, content)

	flatten(content, nil, config)
	return nil
}

func flatten(input interface{}, lpath []string, flattened map[string]interface{}) {
	if lpath == nil {
		lpath = []string{}
	}

	if reflect.ValueOf(input).Kind() == reflect.Map {
		for rkey, value := range input.(map[string]interface{}) {
			flatten(value, append(lpath, rkey), flattened)
		}
	} else {
		if _, ok := flattened[strings.Join(lpath, ".")]; !ok {
			flattened[strings.Join(lpath, ".")] = input
		}
	}
}

func unflatten(flat map[string]interface{}) map[string]interface{} {
	out := make(map[string]interface{})
	obj := out

	for key, val := range flat {

		obj = out
		keys := strings.Split(key, ".")

		for i, k := range keys {
			if i == len(keys)-1 {
				obj[k] = val
			} else {
				next, ok := obj[k]
				if !ok {
					next = make(map[string]interface{})
				}
				obj[k] = next
				obj = next.(map[string]interface{})
			}
		}

	}

	return out
}

func parseNumbers(config map[string]interface{}) {
	for name, val := range config {
		stringVal, ok := val.(string)
		if ok {
			floatVal, err := strconv.ParseFloat(stringVal, 64)
			if err == nil {
				config[name] = floatVal
			}
		}
	}
}

func getUserHome() string {
	usr, err := user.Current()
	if err != nil {
		return "/root"
	}
	return usr.HomeDir
}

func IsSlave() bool {
	masterNodeId := String("", "masterNodeId")
	serial := Serial()
	return masterNodeId != "" && serial != masterNodeId
}

func IsMaster() bool {
	masterNodeId := String("", "masterNodeId")
	serial := Serial()
	return masterNodeId != "" && serial == masterNodeId
}
<|endoftext|>


<commit_before>/*
Package log provides logging mechanism including replaceable Logger interface and its default implementation.
*/
package log

import (
	"fmt"
	"log"
	"os"
	"sync"
)

// Level indicates what logging level the output is representing.
// This typically indicates the severity of particular logging event.
type Level uint

var (
	outputLevel = DebugLevel
	logger      = newDefaultLogger()

	// mutex avoids race condition caused by concurrent call to SetLogger(), SetOutputLevel() and logging method.
	mutex sync.RWMutex
)

const (
	// ErrorLevel indicates the error state of events. This must be noted and be fixed.
	// In practical situation, fix may include lowering of the log level.
	ErrorLevel Level = iota

	// WarnLevel represents those events that are not critical, but deserves to note.
	WarnLevel

	// InfoLevel is used to inform what is happening inside the application.
	InfoLevel

	// DebugLevel indicates the output is logged for debugging purpose.
	DebugLevel
)

// String returns the stringified representation of log level.
func (level Level) String() string {
	switch level {
	case DebugLevel:
		return "DEBUG"
	case InfoLevel:
		return "INFO"
	case WarnLevel:
		return "WARN"
	case ErrorLevel:
		return "ERROR"
	}

	return "UNKNOWN"
}

// Logger defines the interface that can be used as logging tool in this application.
// Developer may provide a customized logger via SetLogger to modify behavior.
// By default, instance of defaultLogger is set as default Logger just like http's DefaultClient.
type Logger interface {
	Debug(args ...interface{})
	Debugf(format string, args ...interface{})

	Info(args ...interface{})
	Infof(format string, args ...interface{})

	Warn(args ...interface{})
	Warnf(format string, args ...interface{})

	Error(args ...interface{})
	Errorf(format string, args ...interface{})
}

type defaultLogger struct {
	logger *log.Logger
}

func (l *defaultLogger) Debug(args ...interface{}) {
	l.out(DebugLevel, args...)
}

func (l *defaultLogger) Debugf(format string, args ...interface{}) {
	l.outf(DebugLevel, format, args...)
}

func (l *defaultLogger) Info(args ...interface{}) {
	l.out(InfoLevel, args...)
}

func (l *defaultLogger) Infof(format string, args ...interface{}) {
	l.outf(InfoLevel, format, args...)
}

func (l *defaultLogger) Warn(args ...interface{}) {
	l.out(WarnLevel, args...)
}

func (l *defaultLogger) Warnf(format string, args ...interface{}) {
	l.outf(WarnLevel, format, args...)
}
func (l *defaultLogger) Error(args ...interface{}) {
	l.out(ErrorLevel, args...)
}

func (l *defaultLogger) Errorf(format string, args ...interface{}) {
	l.outf(ErrorLevel, format, args...)
}

func (l *defaultLogger) out(level Level, args ...interface{}) {
	// combine level identifier and given arguments for variadic function call
	leveledArgs := append([]interface{}{"[" + level.String() + "]"}, args...)
	l.logger.Output(4, fmt.Sprintln(leveledArgs...))
}

func (l *defaultLogger) outf(level Level, format string, args ...interface{}) {
	// combine level identifier and given arguments for variadic function call
	leveledArgs := append([]interface{}{level}, args...)
	l.logger.Output(4, fmt.Sprintf("[%s] "+format, leveledArgs...))
}

func newDefaultLogger() Logger {
	return NewWithStandardLogger(log.New(os.Stdout, "sarah ", log.LstdFlags|log.Llongfile))
}

// NewWithStandardLogger creates an instance of defaultLogger with Go's standard log.Logger.
// This can be used when implementing Logger interface is too much of a task, but still a bit of modification to defaultLogger is required.
//
// Returning Logger can be fed to SetLogger to replace old defaultLogger.
func NewWithStandardLogger(l *log.Logger) Logger {
	return &defaultLogger{
		logger: l,
	}
}

// SetLogger receives struct that satisfies Logger interface, and set this as logger.
// From this call forward, any call to logging method proxies arguments to corresponding logging method of given Logger.
// e.g. call to log.Info points to Logger.Info.
//
// This method is "thread-safe."
func SetLogger(l Logger) {
	mutex.Lock()
	defer mutex.Unlock()
	logger = l
}

// SetOutputLevel sets what logging level to output.
// Application may call logging method any time, but Logger only outputs if the corresponding log level is equal to or higher than the level set here.
func SetOutputLevel(level Level) {
	mutex.Lock()
	defer mutex.Unlock()
	outputLevel = level
}

// Debug outputs given arguments via pre-set Logger implementation.
// Logging level must be set to DebugLevel via logger.SetOutputLevel
func Debug(args ...interface{}) {
	mutex.RLock()
	defer mutex.RUnlock()
	if outputLevel >= DebugLevel {
		logger.Debug(args...)
	}
}

// Debugf outputs given arguments with format via pre-set Logger implementation.
// Logging level must be set to DebugLevel via logger.SetOutputLevel
func Debugf(format string, args ...interface{}) {
	mutex.RLock()
	defer mutex.RUnlock()
	if outputLevel >= DebugLevel {
		logger.Debugf(format, args...)
	}
}

// Info outputs given arguments via pre-set Logger implementation.
// Logging level must be set to DebugLevel or InfoLevel via logger.SetOutputLevel
func Info(args ...interface{}) {
	mutex.RLock()
	defer mutex.RUnlock()
	if outputLevel >= InfoLevel {
		logger.Info(args...)
	}
}

// Infof outputs given arguments with format via pre-set Logger implementation.
// Logging level must be set to DebugLevel or InfoLevel via logger.SetOutputLevel
func Infof(format string, args ...interface{}) {
	mutex.RLock()
	defer mutex.RUnlock()
	if outputLevel >= InfoLevel {
		logger.Infof(format, args...)
	}
}

// Warn outputs given arguments via pre-set Logger implementation.
// Logging level must be set to DebugLevel, InfoLevel or WarnLevel via logger.SetOutputLevel
func Warn(args ...interface{}) {
	mutex.RLock()
	defer mutex.RUnlock()
	if outputLevel >= WarnLevel {
		logger.Warn(args...)
	}
}

// Warnf outputs given arguments with format via pre-set Logger implementation.
// Logging level must be set to DebugLevel, InfoLevel or WarnLevel via logger.SetOutputLevel
func Warnf(format string, args ...interface{}) {
	mutex.RLock()
	defer mutex.RUnlock()
	if outputLevel >= WarnLevel {
		logger.Warnf(format, args...)
	}
}

// Error outputs given arguments via pre-set Logger implementation.
func Error(args ...interface{}) {
	mutex.RLock()
	defer mutex.RUnlock()
	if outputLevel >= ErrorLevel {
		logger.Error(args...)
	}
}

// Errorf outputs given arguments with format via pre-set Logger implementation.
func Errorf(format string, args ...interface{}) {
	mutex.RLock()
	defer mutex.RUnlock()
	if outputLevel >= ErrorLevel {
		logger.Errorf(format, args...)
	}
}
<commit_msg>Add document for log package<commit_after>/*
Package log provides logging mechanism including replaceable Logger interface and its default implementation.
Developers may replace default implementation and output level with her desired Logger implementation in a thread-safe manner as below:

	type MyLogger struct {}

	var _ Logger = (*MyLogger)(nil)

	func (*MyLogger) Debug(args ...interface{}) {}

	func (*MyLogger) Debugf(format string, args ...interface{}) {}

	func (*MyLogger) Info(args ...interface{}) {}

	func (*MyLogger) Infof(format string, args ...interface{}) {}

	func (*MyLogger) Warn(args ...interface{}) {}

	func (*MyLogger) Warnf(format string, args ...interface{}) {}

	func (*MyLogger) Error(args ...interface{}) {}

	func (*MyLogger) Errorf(format string, args ...interface{}) {}

	l := &MyLogger{}

	// These methods are thread-safe
	log.SetLogger(l)
	log.SetOutputLevel(log.InfoLevel)

	log.Info("Output via new Logger impl.")
*/
package log

import (
	"fmt"
	"log"
	"os"
	"sync"
)

// Level indicates what logging level the output is representing.
// This typically indicates the severity of a particular logging event.
type Level uint

var (
	outputLevel = DebugLevel
	logger      = newDefaultLogger()

	// mutex avoids race condition caused by concurrent call to SetLogger(), SetOutputLevel() and logging method.
	mutex sync.RWMutex
)

const (
	// ErrorLevel indicates the error state of events. This must be noted and be fixed.
	// In practical situation, fix may include lowering the corresponding event's log level.
	ErrorLevel Level = iota

	// WarnLevel represents those events that are not critical, but deserves to note.
	// Event with this level may not necessarily be considered as an error;
	// however frequent occurrence deserves developer's attention and may be subject to bug-fix.
	WarnLevel

	// InfoLevel is used to inform what is happening inside the application.
	InfoLevel

	// DebugLevel indicates the output is logged for debugging purpose.
	// This level is not suitable for production usage.
	DebugLevel
)

// String returns the stringified representation of log level.
func (level Level) String() string {
	switch level {
	case DebugLevel:
		return "DEBUG"
	case InfoLevel:
		return "INFO"
	case WarnLevel:
		return "WARN"
	case ErrorLevel:
		return "ERROR"
	}

	return "UNKNOWN"
}

// Logger defines the interface that can be used as logging tool in this application.
// Developer may provide a customized logger via SetLogger() to modify behavior.
// By default, instance of defaultLogger is set as default Logger just like http's DefaultClient.
type Logger interface {
	Debug(args ...interface{})
	Debugf(format string, args ...interface{})

	Info(args ...interface{})
	Infof(format string, args ...interface{})

	Warn(args ...interface{})
	Warnf(format string, args ...interface{})

	Error(args ...interface{})
	Errorf(format string, args ...interface{})
}

type defaultLogger struct {
	logger *log.Logger
}

var _ Logger = (*defaultLogger)(nil)

func (l *defaultLogger) Debug(args ...interface{}) {
	l.out(DebugLevel, args...)
}

func (l *defaultLogger) Debugf(format string, args ...interface{}) {
	l.outf(DebugLevel, format, args...)
}

func (l *defaultLogger) Info(args ...interface{}) {
	l.out(InfoLevel, args...)
}

func (l *defaultLogger) Infof(format string, args ...interface{}) {
	l.outf(InfoLevel, format, args...)
}

func (l *defaultLogger) Warn(args ...interface{}) {
	l.out(WarnLevel, args...)
}

func (l *defaultLogger) Warnf(format string, args ...interface{}) {
	l.outf(WarnLevel, format, args...)
}
func (l *defaultLogger) Error(args ...interface{}) {
	l.out(ErrorLevel, args...)
}

func (l *defaultLogger) Errorf(format string, args ...interface{}) {
	l.outf(ErrorLevel, format, args...)
}

func (l *defaultLogger) out(level Level, args ...interface{}) {
	// combine level identifier and given arguments for variadic function call
	leveledArgs := append([]interface{}{"[" + level.String() + "]"}, args...)
	l.logger.Output(4, fmt.Sprintln(leveledArgs...))
}

func (l *defaultLogger) outf(level Level, format string, args ...interface{}) {
	// combine level identifier and given arguments for variadic function call
	leveledArgs := append([]interface{}{level}, args...)
	l.logger.Output(4, fmt.Sprintf("[%s] "+format, leveledArgs...))
}

func newDefaultLogger() Logger {
	return NewWithStandardLogger(log.New(os.Stdout, "sarah ", log.LstdFlags|log.Llongfile))
}

// NewWithStandardLogger creates an instance of defaultLogger with Go's standard log.Logger.
// This can be used when implementing Logger interface is too much of a task, but still a bit of modification to defaultLogger is required.
//
// Returning Logger can be fed to SetLogger() to replace old defaultLogger.
func NewWithStandardLogger(l *log.Logger) Logger {
	return &defaultLogger{
		logger: l,
	}
}

// SetLogger receives struct that satisfies Logger interface, and sets this as logger.
// From this call forward, any call to logging method proxies arguments to corresponding logging method of given Logger.
// e.g. call to log.Info points to Logger.Info.
//
// This method is "thread-safe."
func SetLogger(l Logger) {
	mutex.Lock()
	defer mutex.Unlock()
	logger = l
}

// SetOutputLevel sets what logging level to output.
// Application may call logging method any time, but Logger only outputs if the corresponding log level is equal to or higher than the level set here.
// e.g. When InfoLevel is set, output with Debug() and Debugf() are ignored.
//
// This method is "thread-safe."
//
// DebugLevel is set by default, so this should be explicitly overridden with higher logging level on production environment
// to avoid printing undesired sensitive data.
func SetOutputLevel(level Level) {
	mutex.Lock()
	defer mutex.Unlock()
	outputLevel = level
}

// Debug outputs given arguments via pre-set Logger implementation.
// Logging level must be left with the default setting or be set to DebugLevel via SetOutputLevel().
func Debug(args ...interface{}) {
	mutex.RLock()
	defer mutex.RUnlock()
	if outputLevel >= DebugLevel {
		logger.Debug(args...)
	}
}

// Debugf outputs given arguments with format via pre-set Logger implementation.
// Logging level must be left with the default setting or be set to DebugLevel via SetOutputLevel().
func Debugf(format string, args ...interface{}) {
	mutex.RLock()
	defer mutex.RUnlock()
	if outputLevel >= DebugLevel {
		logger.Debugf(format, args...)
	}
}

// Info outputs given arguments via pre-set Logger implementation.
// Logging level must be set to DebugLevel or InfoLevel via SetOutputLevel().
func Info(args ...interface{}) {
	mutex.RLock()
	defer mutex.RUnlock()
	if outputLevel >= InfoLevel {
		logger.Info(args...)
	}
}

// Infof outputs given arguments with format via pre-set Logger implementation.
// Logging level must be set to DebugLevel or InfoLevel via SetOutputLevel().
func Infof(format string, args ...interface{}) {
	mutex.RLock()
	defer mutex.RUnlock()
	if outputLevel >= InfoLevel {
		logger.Infof(format, args...)
	}
}

// Warn outputs given arguments via pre-set Logger implementation.
// Logging level must be set to DebugLevel, InfoLevel or WarnLevel via SetOutputLevel().
func Warn(args ...interface{}) {
	mutex.RLock()
	defer mutex.RUnlock()
	if outputLevel >= WarnLevel {
		logger.Warn(args...)
	}
}

// Warnf outputs given arguments with format via pre-set Logger implementation.
// Logging level must be set to DebugLevel, InfoLevel or WarnLevel via SetOutputLevel().
func Warnf(format string, args ...interface{}) {
	mutex.RLock()
	defer mutex.RUnlock()
	if outputLevel >= WarnLevel {
		logger.Warnf(format, args...)
	}
}

// Error outputs given arguments via pre-set Logger implementation.
func Error(args ...interface{}) {
	mutex.RLock()
	defer mutex.RUnlock()
	if outputLevel >= ErrorLevel {
		logger.Error(args...)
	}
}

// Errorf outputs given arguments with format via pre-set Logger implementation.
func Errorf(format string, args ...interface{}) {
	mutex.RLock()
	defer mutex.RUnlock()
	if outputLevel >= ErrorLevel {
		logger.Errorf(format, args...)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"regexp"
	"strings"
	"time"
)

var (
	formatRegex  = regexp.MustCompile(`%(time)|%(pid)|%(tid)|%(priority)|%(tag)|%(message)`)
	sformatRegex = regexp.MustCompile(`%(t)|%(i)|%(I)|%(p)|%(a)|%(m)`)
	formatMap    = map[string]string{
		"time":     "t",
		"pid":      "i",
		"tid":      "I",
		"priority": "p",
		"tag":      "a",
		"message":  "m",
	}
	tabRegexps     = regexp.MustCompile(`\\t`)
	newLineRegexps = regexp.MustCompile(`\\n`)
)

// LogcatItem represents a line of logcat log.
type LogcatItem map[string]string

// time return parsed time.
func (item *LogcatItem) time() time.Time {
	t, _ := time.Parse("12-28 18:54:08.043", (*item)["time"])
	return t
}

// Format returns formatted string.
func (item *LogcatItem) Format(format string) string {
	result := format
	result = item.replaceKeyword(result)
	result = item.replaceEscape(result)
	return result
}

// replace keyword to real value. use short format.
// ex) "%t %p" => "12-28 19:01:14.073 GLSUser"
func (item *LogcatItem) replaceKeyword(format string) string {
	matches := sformatRegex.FindAllStringSubmatch(format, len(formatMap))
	formatArgs := make([]interface{}, 0, len(matches))
	// find matched keyword and store value on item
	for _, match := range matches {
		for _, m := range match {
			key, ok := findKey(formatMap, m)
			if ok {
				formatArgs = append(formatArgs, (*item)[key])
				break
			}
		}
	}
	format = sformatRegex.ReplaceAllString(format, "%s")
	return fmt.Sprintf(format, formatArgs...)
}

func (item *LogcatItem) replaceEscape(format string) string {
	result := format
	result = tabRegexps.ReplaceAllString(result, "\t")
	result = newLineRegexps.ReplaceAllString(result, "\n")
	return result
}

func verifyFormat(format string) error {
	// find unavailable keyword.
	const all = -1
	removed := formatRegex.ReplaceAllString(format, "")
	removed = sformatRegex.ReplaceAllString(removed, "")
	keyRegexp := regexp.MustCompile(`%\w+`)
	matches := keyRegexp.FindAllString(removed, all)

	if len(matches) == 0 {
		return nil // no probrem!
	}

	// return error message.
	err := ParameterError{}
	for _, match := range matches {
		errMsg := fmt.Sprintf(Message["msgUnavailableKeyword"], match)
		err.errors = append(err.errors, errMsg)
	}
	return &err
}

// ParameterError has error message of parameter.
type ParameterError struct {
	errors []string
}

// Error returns all error message.
func (e *ParameterError) Error() string {
	if e.errors != nil {
		return strings.Join(e.errors, "\n")
	}
	return ""
}

// convert long keys in format to short keys.
func normalizeFormat(format string) string {
	const all = -1
	for long, short := range formatMap {
		tmp := strings.Replace(format, long, short, all)
		format = tmp
	}
	return format
}

func findKey(m map[string]string, value string) (string, bool) {
	for k, v := range m {
		if v == value {
			return k, true
		}
	}
	return "", false
}
<commit_msg>refrains excessive use of regular expressions.<commit_after>package main

import (
	"fmt"
	"regexp"
	"strings"
	"time"
)

const flagAll = -1

var (
	formatRegex  = regexp.MustCompile(`%(time)|%(pid)|%(tid)|%(priority)|%(tag)|%(message)`)
	sformatRegex = regexp.MustCompile(`%(t)|%(i)|%(I)|%(p)|%(a)|%(m)`)
	formatMap    = map[string]string{
		"time":     "t",
		"pid":      "i",
		"tid":      "I",
		"priority": "p",
		"tag":      "a",
		"message":  "m",
	}
)

// LogcatItem represents a line of logcat log.
type LogcatItem map[string]string

// time return parsed time.
func (item *LogcatItem) time() time.Time {
	t, _ := time.Parse("12-28 18:54:08.043", (*item)["time"])
	return t
}

// Format returns formatted string.
func (item *LogcatItem) Format(format string) string {
	result := format
	result = item.replaceKeyword(result)
	result = item.replaceEscape(result)
	return result
}

// replace keyword to real value. use short format.
// ex) "%t %p" => "12-28 19:01:14.073 GLSUser"
func (item *LogcatItem) replaceKeyword(format string) string {
	matches := sformatRegex.FindAllStringSubmatch(format, len(formatMap))
	formatArgs := make([]interface{}, 0, len(matches))
	// find matched keyword and store value on item
	for _, match := range matches {
		for _, m := range match {
			key, ok := findKey(formatMap, m)
			if ok {
				formatArgs = append(formatArgs, (*item)[key])
				break
			}
		}
	}
	format = sformatRegex.ReplaceAllString(format, "%s")
	return fmt.Sprintf(format, formatArgs...)
}

func (item *LogcatItem) replaceEscape(format string) string {
	result := format
	result = strings.Replace(result, "\\t", "\t", flagAll)
	result = strings.Replace(result, "\\n", "\n", flagAll)
	return result
}

func verifyFormat(format string) error {
	// find unavailable keyword.
	removed := formatRegex.ReplaceAllString(format, "")
	removed = sformatRegex.ReplaceAllString(removed, "")
	keyRegexp := regexp.MustCompile(`%\w+`)
	matches := keyRegexp.FindAllString(removed, flagAll)

	if len(matches) == 0 {
		return nil // no probrem!
	}

	// return error message.
	err := ParameterError{}
	for _, match := range matches {
		errMsg := fmt.Sprintf(Message["msgUnavailableKeyword"], match)
		err.errors = append(err.errors, errMsg)
	}
	return &err
}

// ParameterError has error message of parameter.
type ParameterError struct {
	errors []string
}

// Error returns all error message.
func (e *ParameterError) Error() string {
	if e.errors != nil {
		return strings.Join(e.errors, "\n")
	}
	return ""
}

// convert long keys in format to short keys.
func normalizeFormat(format string) string {
	for long, short := range formatMap {
		tmp := strings.Replace(format, long, short, flagAll)
		format = tmp
	}
	return format
}

func findKey(m map[string]string, value string) (string, bool) {
	for k, v := range m {
		if v == value {
			return k, true
		}
	}
	return "", false
}
<|endoftext|>


<commit_before>// © 2012 the Minima Authors under the MIT license. See AUTHORS for the list of authors.

package main

import (
	"code.google.com/p/min-game/geom"
	"code.google.com/p/min-game/item"
	"code.google.com/p/min-game/ui"
	"code.google.com/p/min-game/uitil"
)

func NewNormalMessage(msg string) *uitil.MessageBox {
	origin := geom.Pt(32, 32)
	dims := geom.Pt(ScreenDims.X, ScreenDims.Y/2)
	box := geom.Rectangle{
		Min: origin,
		Max: origin.Add(dims).Sub(origin.Mul(2)),
	}

	return &uitil.MessageBox{
		Text:   msg,
		Font:   DialogFont,
		Fontsz: 16,
		Fg:     Black,
		Bg:     White,
		Box:    box,
		Pad:    4.0,
	}
}

type InventoryXXX interface {
	Label() string
	Len() int
	Selected(int) bool
	Get(int) *item.Item
	Set(int, *item.Item)
}

func DrawInventory(i InventoryXXX, d ui.Drawer, pad float64, origin geom.Point, fit bool) geom.Point {
	size := d.TextSize(i.Label())

	width, height := 0.0, 0.0
	if fit {
		width = TileSize*float64(i.Len()) + pad*float64(i.Len()+3) + size.X
		height = TileSize + pad*2
	} else {
		width = ScreenDims.X - TileSize - origin.X
		height = ScreenDims.Y - TileSize - origin.Y
	}

	bounds := geom.Rectangle{
		Min: origin,
		Max: origin.Add(geom.Pt(width, height)),
	}

	d.SetColor(Black)
	d.Draw(bounds.Pad(pad), geom.Pt(0, 0))

	d.SetColor(White)
	d.Draw(bounds, geom.Pt(0, 0))

	pt := origin.Add(geom.Pt(pad, pad))

	d.SetColor(Black)
	d.Draw(i.Label(), pt)
	if fit {
		pt.X += size.X + pad
	} else {
		pt.Y += size.Y + pad
	}

	for j := 0; j < i.Len(); j++ {
		a := i.Get(j)
		if i.Selected(j) {
			d.SetColor(Black)
			d.Draw(geom.Rectangle{
				Min: pt.Sub(geom.Pt(2, 2)),
				Max: pt.Add(geom.Pt(34, 34)),
			}, geom.Pt(0, 0))
		}

		if a != nil {
			d.Draw(ui.Sprite{
				Name:   a.Name,
				Bounds: geom.Rect(0, 0, 32, 32),
				Shade:  1.0,
			}, pt)
		}

		pt.X += 32.0 + pad
		if pt.X >= bounds.Dx() {
			pt.X = bounds.Min.X
			pt.Y += TileSize + pad
		}
	}

	return bounds.Max
}
<commit_msg>I forgot to delete even more junked code.<commit_after>// © 2012 the Minima Authors under the MIT license. See AUTHORS for the list of authors.

package main

import (
	"code.google.com/p/min-game/geom"
	"code.google.com/p/min-game/uitil"
)

func NewNormalMessage(msg string) *uitil.MessageBox {
	origin := geom.Pt(32, 32)
	dims := geom.Pt(ScreenDims.X, ScreenDims.Y/2)
	box := geom.Rectangle{
		Min: origin,
		Max: origin.Add(dims).Sub(origin.Mul(2)),
	}

	return &uitil.MessageBox{
		Text:   msg,
		Font:   DialogFont,
		Fontsz: 16,
		Fg:     Black,
		Bg:     White,
		Box:    box,
		Pad:    4.0,
	}
}
<|endoftext|>


<commit_before>// © 2012 the Minima Authors under the MIT license. See AUTHORS for the list of authors.

package main

import (
	"code.google.com/p/min-game/geom"
	"code.google.com/p/min-game/item"
	"code.google.com/p/min-game/ui"
	"code.google.com/p/min-game/uitil"
)

type PauseScreen struct {
	astro   *Player
	closing bool
}

func NewPauseScreen(astro *Player) *PauseScreen {
	return &PauseScreen{astro, false}
}

func (p *PauseScreen) Transparent() bool {
	return true
}

func (p *PauseScreen) Draw(d ui.Drawer) {
	d.SetFont(DialogFont, 16)

	origin := geom.Pt(32, 32)
	pad := 4.0

	pt := p.astro.suit.Draw("Suit: ", d, pad, origin, true)
	held := geom.Pt(pt.X+pad, origin.Y)
	pt = p.astro.pack.Draw("Pack: ", d, pad, geom.Pt(origin.X, pt.Y+pad), true)

	if p.astro.Held != nil {
		hinv := Inventory{[]*item.Item{p.astro.Held}, 0, true}
		hinv.Draw("Held: ", d, pad, held, true)
	}

	if p.astro.pack.Selected >= 0 && p.astro.pack.Get(p.astro.pack.Selected) == nil {
		return
	}
	if p.astro.suit.Selected >= 0 && p.astro.suit.Get(p.astro.suit.Selected) == nil {
		return
	}

	descBounds := geom.Rectangle{
		Min: geom.Pt(origin.X, pt.Y+pad),
		Max: geom.Pt(ScreenDims.X-origin.X, ScreenDims.Y-origin.Y),
	}

	d.SetColor(Black)
	d.Draw(descBounds.Pad(pad), geom.Pt(0, 0))
	d.SetColor(White)
	d.Draw(descBounds, geom.Pt(0, 0))

	d.SetColor(Black)
	desc := ""
	if p.astro.pack.Selected >= 0 {
		desc = p.astro.pack.Get(p.astro.pack.Selected).Desc()
	} else {
		desc = p.astro.suit.Get(p.astro.suit.Selected).Desc()
	}
	uitil.WordWrap(d, desc, descBounds.Rpad(pad))
}

func (p *PauseScreen) Handle(stk *ui.ScreenStack, e ui.Event) error {
	if p.closing {
		return nil
	}

	key, ok := e.(ui.Key)
	if !ok || !key.Down {
		return nil
	}

	switch key.Button {
	case ui.Menu:
		p.closing = true
	case ui.Hands:
		a := p.astro
		if a.pack.Selected >= 0 {
			a.Held, a.pack.Items[a.pack.Selected] = a.pack.Items[a.pack.Selected], a.Held
		}
		if a.suit.Selected >= 0 {
			a.Held, a.suit.Items[a.suit.Selected] = a.suit.Items[a.suit.Selected], a.Held
		}
		return nil
	}

	HandleInvPair(&p.astro.pack, &p.astro.suit, key.Button)
	return nil
}

func (p *PauseScreen) Update(stk *ui.ScreenStack) error {
	if p.closing {
		stk.Pop()
		return nil
	}

	return nil
}
<commit_msg>Draw scrap on the pause screen. Fixes issue 126.<commit_after>// © 2012 the Minima Authors under the MIT license. See AUTHORS for the list of authors.

package main

import (
	"fmt"

	"code.google.com/p/min-game/geom"
	"code.google.com/p/min-game/item"
	"code.google.com/p/min-game/ui"
	"code.google.com/p/min-game/uitil"
)

type PauseScreen struct {
	astro   *Player
	closing bool
}

func NewPauseScreen(astro *Player) *PauseScreen {
	return &PauseScreen{astro, false}
}

func (p *PauseScreen) Transparent() bool {
	return true
}

func (p *PauseScreen) Draw(d ui.Drawer) {
	d.SetFont(DialogFont, 16)

	origin := geom.Pt(32, 32)
	pad := 4.0

	pt := p.astro.suit.Draw("Suit: ", d, pad, origin, true)
	held := geom.Pt(pt.X+pad, origin.Y)
	packPt := geom.Pt(origin.X, pt.Y+pad)
	pt = p.astro.pack.Draw("Pack: ", d, pad, packPt, true)

	scrapPt := geom.Pt(pt.X+pad, packPt.Y)
	scrapText := fmt.Sprintf("Scrap: %d", p.astro.Scrap)
	scrapDims := d.TextSize(scrapText)
	scrapBounds := geom.Rectangle{
		Max: geom.Pt(scrapDims.X+2*pad, TileSize.Y+2*pad),
	}
	d.SetColor(Black)
	d.Draw(scrapBounds.Pad(pad), scrapPt)
	d.SetColor(White)
	d.Draw(scrapBounds, scrapPt)
	d.SetColor(Black)
	d.Draw(scrapText, scrapPt.Add(geom.Pt(pad, pad)))

	if p.astro.Held != nil {
		hinv := Inventory{[]*item.Item{p.astro.Held}, 0, true}
		hinv.Draw("Held: ", d, pad, held, true)
	}

	if p.astro.pack.Selected >= 0 && p.astro.pack.Get(p.astro.pack.Selected) == nil {
		return
	}
	if p.astro.suit.Selected >= 0 && p.astro.suit.Get(p.astro.suit.Selected) == nil {
		return
	}

	descBounds := geom.Rectangle{
		Min: geom.Pt(origin.X, pt.Y+pad),
		Max: geom.Pt(ScreenDims.X-origin.X, ScreenDims.Y-origin.Y),
	}

	d.SetColor(Black)
	d.Draw(descBounds.Pad(pad), geom.Pt(0, 0))
	d.SetColor(White)
	d.Draw(descBounds, geom.Pt(0, 0))

	d.SetColor(Black)
	desc := ""
	if p.astro.pack.Selected >= 0 {
		desc = p.astro.pack.Get(p.astro.pack.Selected).Desc()
	} else {
		desc = p.astro.suit.Get(p.astro.suit.Selected).Desc()
	}
	uitil.WordWrap(d, desc, descBounds.Rpad(pad))
}

func (p *PauseScreen) Handle(stk *ui.ScreenStack, e ui.Event) error {
	if p.closing {
		return nil
	}

	key, ok := e.(ui.Key)
	if !ok || !key.Down {
		return nil
	}

	switch key.Button {
	case ui.Menu:
		p.closing = true
	case ui.Hands:
		a := p.astro
		if a.pack.Selected >= 0 {
			a.Held, a.pack.Items[a.pack.Selected] = a.pack.Items[a.pack.Selected], a.Held
		}
		if a.suit.Selected >= 0 {
			a.Held, a.suit.Items[a.suit.Selected] = a.suit.Items[a.suit.Selected], a.Held
		}
		return nil
	}

	HandleInvPair(&p.astro.pack, &p.astro.suit, key.Button)
	return nil
}

func (p *PauseScreen) Update(stk *ui.ScreenStack) error {
	if p.closing {
		stk.Pop()
		return nil
	}

	return nil
}
<|endoftext|>


<commit_before>// © 2012 the Minima Authors under the MIT license. See AUTHORS for the list of authors.

package main

import (
	"bufio"
	"io"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"unicode/utf8"

	"code.google.com/p/min-game/geom"
	"code.google.com/p/min-game/ui"
	"github.com/mccoyst/pipeline"
)

type TitleScreen struct {
	loading bool

	// GenTxt is the last string from the level generator.
	genTxt string

	// wgenErr receives strings from wgen's stderr.
	wgenErr chan string

	// gameChan receieves the *Game from the reader.
	gameChan chan *Game

	frame int
}

func NewTitleScreen() *TitleScreen {
	t := &TitleScreen{}
	if *worldOnStdin {
		t.loadWorld()
	}
	return t
}

func (t *TitleScreen) Transparent() bool {
	return false
}

func (t *TitleScreen) Draw(d ui.Drawer) {
	if t.loading {
		if t.genTxt == "" {
			t.genTxt = "Reticulating Splines"
		}
		d.SetColor(Lime)
		d.SetFont(DialogFont, 8)
		genSz := d.TextSize(t.genTxt)
		d.Draw(t.genTxt, geom.Pt(0, ScreenDims.Y-genSz.Y))
		return
	}

	d.SetColor(White)
	d.SetFont(TitleFont, 96)
	titleTxt := "MINIMA"
	titleSz := d.TextSize(titleTxt)
	titlePos := geom.Pt(ScreenDims.X/2-titleSz.X/2,
		ScreenDims.Y/2-titleSz.Y)
	wh := d.Draw(titleTxt, titlePos)

	d.SetFont(DialogFont, 16)
	startTxt := "Press " + actionKey() + " to Start"
	startSz := d.TextSize(startTxt)
	startPos := geom.Pt(ScreenDims.X/2-startSz.X/2, titlePos.Y+wh.Y+startSz.Y)
	wh = d.Draw(startTxt, startPos)

	crTxt := "© 2012 The Minima Authors"
	crSz := d.TextSize(crTxt)
	crPos := geom.Pt(ScreenDims.X/2-crSz.X/2, ScreenDims.Y-crSz.Y)
	d.Draw(crTxt, crPos)
}

func (t *TitleScreen) Handle(stk *ui.ScreenStack, e ui.Event) error {
	switch k := e.(type) {
	case ui.Key:
		if k.Down && k.Button == ui.Action {
			t.loadWorld()
		}
	}
	return nil
}

func (t *TitleScreen) Update(stk *ui.ScreenStack) error {
	if !t.loading {
		return nil
	}
	select {
	case s, ok := <-t.wgenErr:
		if !ok {
			t.wgenErr = nil
			break
		}
		t.genTxt = s
	case g := <-t.gameChan:
		for _ = range t.genTxt {
		} // junk it
		t.loading = false
		stk.Push(g)
	default:
	}
	return nil
}

func (t *TitleScreen) loadWorld() {
	t.gameChan = make(chan *Game)
	t.wgenErr = make(chan string, 1)
	t.loading = true

	go func() {
		if *worldOnStdin {
			*worldOnStdin = false
			t.wgenErr <- "Reading the world"
			close(t.wgenErr)
			in := bufio.NewReader(os.Stdin)
			g, err := ReadGame(in)
			if err != nil {
				panic(err)
			}
			t.gameChan <- g
			return
		}
		cmds := []*exec.Cmd{
			gen("wgen"),
			gen("herbgen 25 Gull 10 Guppy 10 Guppy 10 Guppy 10 Guppy 10 Guppy 10 Guppy 10 Guppy 10 Guppy 10 Guppy 10 Guppy 25 Cow 25 Cow 25 Cow 25 Cow 10 Chicken 10 Chicken 10 Chicken 10 Chicken 10 Chicken"),
			gen("itemnear -num 5 -name Uranium"),
		}

		stderrin, stderrout, err := os.Pipe()
		if err != nil {
			panic(err)
		}
		defer stderrin.Close()
		defer stderrout.Close()
		for _, c := range cmds {
			c.Stderr = stderrout
		}
		go readErr(stderrin, t.wgenErr)

		if *debug {
			cmds = append(cmds, exec.Command("wimg", "-e", "-o", "cur.png"))
			cmds = append(cmds, exec.Command("tee", "cur.world"))
		}

		p, err := pipeline.New(cmds...)
		if err != nil {
			panic(err)
		}
		stdout, err := p.Last().StdoutPipe()
		if err != nil {
			panic(err)
		}

		if err := p.Start(); err != nil {
			panic(err)
		}
		in := bufio.NewReader(stdout)
		g, err := ReadGame(in)
		if err != nil {
			panic(err)
		}
		if errs := p.Wait(); len(errs) > 0 {
			s := ""
			for _, e := range errs {
				s += e.Error() + "\n"
			}
			panic(s)
		}
		t.gameChan <- g
	}()
}

// Gen returns a command for an XXXgen program.  The command
// is given by a string, followed by "-seed" and the random seed.
func gen(s string) *exec.Cmd {
	fs := strings.Fields(s)
	cmd := fs[0]
	fs = append([]string{"-seed", strconv.FormatInt(*seed, 10)}, fs[1:]...)
	*seed++
	return exec.Command(cmd, fs...)
}

// ReadErr reads wgen's standard error, picks out
// what it is currently doing and sends the strings
// to the channel.
func readErr(r io.Reader, strs chan<- string) {
	in := bufio.NewReader(io.TeeReader(r, os.Stderr))
	for {
		s, err := readRunes(in, "…\n")
		if err != nil {
			break
		}
		r, sz := utf8.DecodeLastRuneInString(s)
		if r == '\n' {
			continue
		}
		strs <- s[:len(s)-sz]
	}
	strs <- "Reading the world"
	close(strs)
}

// readRunes returns all runes until a delimiter
// is read or an error occurs.  If a delimiter is
// read then it is included in the returned string.
func readRunes(in *bufio.Reader, delims string) (string, error) {
	var err error
	var runes []rune
	for {
		var r rune
		r, _, err = in.ReadRune()
		if err != nil {
			break
		}
		runes = append(runes, r)
		if strings.ContainsRune(delims, r) {
			break
		}
	}
	return string(runes), err
}

func actionKey() string {
	for k, b := range ui.CurrentKeymap {
		if b == ui.Action {
			return k.String()
		}
	}
	panic("Somebody broke the keymap")
}
<commit_msg>Print the pipeline on -debug.<commit_after>// © 2012 the Minima Authors under the MIT license. See AUTHORS for the list of authors.

package main

import (
	"bufio"
	"io"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"unicode/utf8"

	"code.google.com/p/min-game/geom"
	"code.google.com/p/min-game/ui"
	"github.com/mccoyst/pipeline"
)

type TitleScreen struct {
	loading bool

	// GenTxt is the last string from the level generator.
	genTxt string

	// wgenErr receives strings from wgen's stderr.
	wgenErr chan string

	// gameChan receieves the *Game from the reader.
	gameChan chan *Game

	frame int
}

func NewTitleScreen() *TitleScreen {
	t := &TitleScreen{}
	if *worldOnStdin {
		t.loadWorld()
	}
	return t
}

func (t *TitleScreen) Transparent() bool {
	return false
}

func (t *TitleScreen) Draw(d ui.Drawer) {
	if t.loading {
		if t.genTxt == "" {
			t.genTxt = "Reticulating Splines"
		}
		d.SetColor(Lime)
		d.SetFont(DialogFont, 8)
		genSz := d.TextSize(t.genTxt)
		d.Draw(t.genTxt, geom.Pt(0, ScreenDims.Y-genSz.Y))
		return
	}

	d.SetColor(White)
	d.SetFont(TitleFont, 96)
	titleTxt := "MINIMA"
	titleSz := d.TextSize(titleTxt)
	titlePos := geom.Pt(ScreenDims.X/2-titleSz.X/2,
		ScreenDims.Y/2-titleSz.Y)
	wh := d.Draw(titleTxt, titlePos)

	d.SetFont(DialogFont, 16)
	startTxt := "Press " + actionKey() + " to Start"
	startSz := d.TextSize(startTxt)
	startPos := geom.Pt(ScreenDims.X/2-startSz.X/2, titlePos.Y+wh.Y+startSz.Y)
	wh = d.Draw(startTxt, startPos)

	crTxt := "© 2012 The Minima Authors"
	crSz := d.TextSize(crTxt)
	crPos := geom.Pt(ScreenDims.X/2-crSz.X/2, ScreenDims.Y-crSz.Y)
	d.Draw(crTxt, crPos)
}

func (t *TitleScreen) Handle(stk *ui.ScreenStack, e ui.Event) error {
	switch k := e.(type) {
	case ui.Key:
		if k.Down && k.Button == ui.Action {
			t.loadWorld()
		}
	}
	return nil
}

func (t *TitleScreen) Update(stk *ui.ScreenStack) error {
	if !t.loading {
		return nil
	}
	select {
	case s, ok := <-t.wgenErr:
		if !ok {
			t.wgenErr = nil
			break
		}
		t.genTxt = s
	case g := <-t.gameChan:
		for _ = range t.genTxt {
		} // junk it
		t.loading = false
		stk.Push(g)
	default:
	}
	return nil
}

func (t *TitleScreen) loadWorld() {
	t.gameChan = make(chan *Game)
	t.wgenErr = make(chan string, 1)
	t.loading = true

	go func() {
		if *worldOnStdin {
			*worldOnStdin = false
			t.wgenErr <- "Reading the world"
			close(t.wgenErr)
			in := bufio.NewReader(os.Stdin)
			g, err := ReadGame(in)
			if err != nil {
				panic(err)
			}
			t.gameChan <- g
			return
		}
		cmds := []*exec.Cmd{
			gen("wgen"),
			gen("herbgen 25 Gull 10 Guppy 10 Guppy 10 Guppy 10 Guppy 10 Guppy 10 Guppy 10 Guppy 10 Guppy 10 Guppy 10 Guppy 25 Cow 25 Cow 25 Cow 25 Cow 10 Chicken 10 Chicken 10 Chicken 10 Chicken 10 Chicken"),
			gen("itemnear -num 5 -name Uranium"),
		}

		stderrin, stderrout, err := os.Pipe()
		if err != nil {
			panic(err)
		}
		defer stderrin.Close()
		defer stderrout.Close()
		for _, c := range cmds {
			c.Stderr = stderrout
		}
		go readErr(stderrin, t.wgenErr)

		if *debug {
			cmds = append(cmds, exec.Command("wimg", "-e", "-o", "cur.png"))
			cmds = append(cmds, exec.Command("tee", "cur.world"))
		}

		p, err := pipeline.New(cmds...)
		if err != nil {
			panic(err)
		}
		if *debug {
			os.Stderr.Write([]byte("executing: " + p.String() + "\n"))
		}

		stdout, err := p.Last().StdoutPipe()
		if err != nil {
			panic(err)
		}

		if err := p.Start(); err != nil {
			panic(err)
		}
		in := bufio.NewReader(stdout)
		g, err := ReadGame(in)
		if err != nil {
			panic(err)
		}
		if errs := p.Wait(); len(errs) > 0 {
			s := ""
			for _, e := range errs {
				s += e.Error() + "\n"
			}
			panic(s)
		}
		t.gameChan <- g
	}()
}

// Gen returns a command for an XXXgen program.  The command
// is given by a string, followed by "-seed" and the random seed.
func gen(s string) *exec.Cmd {
	fs := strings.Fields(s)
	cmd := fs[0]
	fs = append([]string{"-seed", strconv.FormatInt(*seed, 10)}, fs[1:]...)
	*seed++
	return exec.Command(cmd, fs...)
}

// ReadErr reads wgen's standard error, picks out
// what it is currently doing and sends the strings
// to the channel.
func readErr(r io.Reader, strs chan<- string) {
	in := bufio.NewReader(io.TeeReader(r, os.Stderr))
	for {
		s, err := readRunes(in, "…\n")
		if err != nil {
			break
		}
		r, sz := utf8.DecodeLastRuneInString(s)
		if r == '\n' {
			continue
		}
		strs <- s[:len(s)-sz]
	}
	strs <- "Reading the world"
	close(strs)
}

// readRunes returns all runes until a delimiter
// is read or an error occurs.  If a delimiter is
// read then it is included in the returned string.
func readRunes(in *bufio.Reader, delims string) (string, error) {
	var err error
	var runes []rune
	for {
		var r rune
		r, _, err = in.ReadRune()
		if err != nil {
			break
		}
		runes = append(runes, r)
		if strings.ContainsRune(delims, r) {
			break
		}
	}
	return string(runes), err
}

func actionKey() string {
	for k, b := range ui.CurrentKeymap {
		if b == ui.Action {
			return k.String()
		}
	}
	panic("Somebody broke the keymap")
}
<|endoftext|>


<commit_before>package models

import (
	//"database/sql"
	"encoding/json"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"net/http"
	//"strconv"
	//"time"
	"moviesapp/token"
)

type User struct {
	Id       int    `json:id`
	Name     string `json:name`
	Lastname string `json:lastname`
	Email    string `json:email`
	Password string `json:password`
	Role     string `json:role`
	Created  string `json:created`
	Updated  string `json:Updated`
}

type UserCredentials struct {
	Email    string `json:email`
	Password string `json:password`
}

type ErrorOut struct {
	Error string `json:error`
}

func Login(cred *http.Request) interface{} {

	var usercred UserCredentials
	var user User
	err := json.NewDecoder(cred.Body).Decode(&usercred)
	if err != nil {
		log.Println("Models Users Login json failed: ", err)
		return `{"error": "Server Error"}`
	}
	fmt.Println(usercred)
	err = Db.QueryRow("select * from users where email='"+usercred.Email+"'").Scan(&user.Id, &user.Password, &user.Name, &user.Lastname, &user.Email, &user.Created, &user.Updated, &user.Role)
	if err != nil && err.Error() != "sql: no rows in result set" {
		log.Println("Models users login query Failed: ", err)
	}
	if err != nil && err.Error() == "sql: no rows in result set" {
		log.Println("User Not Found")
		errOut := new(ErrorOut)
		errOut.Error = "Invalid Username or Password"
		return errOut
	}
	if err == nil && user.Password != usercred.Password {
		fmt.Println(user)
		log.Println("Invalid Password:", usercred.Password, user.Password)
		errOut := new(ErrorOut)
		errOut.Error = "Invalid Username or Password"
		return errOut

	} else {
		//do token stuff
		generatedToken, err := token.GenerateToken(user.Role)
		if err != nil {
			log.Println("Token creation failed: ", err)
		}
		return generatedToken
	}

}
<commit_msg>fixed json caps and token is now json output<commit_after>package models

import (
	//"database/sql"
	"encoding/json"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"net/http"
	//"strconv"
	//"time"
	"moviesapp/token"
)

type User struct {
	Id       int    `json:"id"`
	Name     string `json:"name"`
	Lastname string `json:"lastname"`
	Email    string `json:"email"`
	Password string `json:"password"`
	Role     string `json:"role"`
	Created  string `json:"created"`
	Updated  string `json:"updated"`
}

type UserCredentials struct {
	Email    string `json:"email"`
	Password string `json:"password"`
}

type ErrorOut struct {
	Error string `json:"error"`
}

type TokenOut struct {
	Token string `json:"token"`
}

func Login(cred *http.Request) interface{} {

	var usercred UserCredentials
	var user User
	err := json.NewDecoder(cred.Body).Decode(&usercred)
	if err != nil {
		log.Println("Models Users Login json failed: ", err)
		return `{"error": "Server Error"}`
	}
	fmt.Println(usercred)
	err = Db.QueryRow("select * from users where email='"+usercred.Email+"'").Scan(&user.Id, &user.Password, &user.Name, &user.Lastname, &user.Email, &user.Created, &user.Updated, &user.Role)
	if err != nil && err.Error() != "sql: no rows in result set" {
		log.Println("Models users login query Failed: ", err)
	}
	if err != nil && err.Error() == "sql: no rows in result set" {
		log.Println("User Not Found")
		errOut := new(ErrorOut)
		errOut.Error = "Invalid Username or Password"
		return errOut
	}
	if err == nil && user.Password != usercred.Password {
		fmt.Println(user)
		log.Println("Invalid Password:", usercred.Password, user.Password)
		errOut := new(ErrorOut)
		errOut.Error = "Invalid Username or Password"
		return errOut

	} else {
		//do token stuff
		generatedToken, err := token.GenerateToken(user.Role)
		if err != nil {
			log.Println("Token creation failed: ", err)
			errOut := new(ErrorOut)
			errOut.Error = "Invalid Username or Password"
			return errOut
		}
		jsonToken := new(TokenOut)
		jsonToken.Token = generatedToken
		return jsonToken
	}

}
<|endoftext|>