<commit_before>package air

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"path"
	"runtime"
	"strconv"
	"sync"
	"text/template"
	"time"
)

// Logger is used to log information generated in runtime.
type (
	Logger struct {
		template   *template.Template
		bufferPool *sync.Pool
		mutex      *sync.Mutex
		levels     []string
		air        *Air

		Level  LoggerLevel
		Output io.Writer
	}

	// LoggerLevel is level of the logger.
	LoggerLevel uint8
)

// Logger levels
const (
	DEBUG LoggerLevel = iota
	INFO
	WARN
	ERROR
	FATAL
	OFF
)

// newLogger returns a pointer of a new instance of `Logger`.
func newLogger(a *Air) *Logger {
	l := &Logger{
		bufferPool: &sync.Pool{
			New: func() interface{} {
				return bytes.NewBuffer(make([]byte, 256))
			},
		},
		mutex: &sync.Mutex{},
		levels: []string{
			"DEBUG",
			"INFO",
			"WARN",
			"ERROR",
			"FATAL",
		},
		air:   a,
		Level: OFF,
	}
	l.template, _ = template.New("logger").Parse(a.Config.LogFormat)
	l.Output = os.Stdout
	return l
}

// Print prints log info with provided type i.
func (l *Logger) Print(i ...interface{}) {
	fmt.Fprintln(l.Output, i...)
}

// Printf prints log info in a format with provided type i.
func (l *Logger) Printf(format string, args ...interface{}) {
	f := fmt.Sprintf("%s\n", format)
	fmt.Fprintf(l.Output, f, args...)
}

// Printj prints log info with provided json map.
func (l *Logger) Printj(j JSONMap) {
	json.NewEncoder(l.Output).Encode(j)
}

// Debug prints debug level log info with provided type i.
func (l *Logger) Debug(i ...interface{}) {
	l.log(DEBUG, "", i...)
}

// Debugf prints debug level log info in a format with provided type i.
func (l *Logger) Debugf(format string, args ...interface{}) {
	l.log(DEBUG, format, args...)
}

// Debugj prints debug level log info in a format with provided json map.
func (l *Logger) Debugj(j JSONMap) {
	l.log(DEBUG, "json", j)
}

// Info prints info level log info with provided type i.
func (l *Logger) Info(i ...interface{}) {
	l.log(INFO, "", i...)
}

// Infof prints info level log info in a format with provided type i.
func (l *Logger) Infof(format string, args ...interface{}) {
	l.log(INFO, format, args...)
}

// Infoj prints info level log info in a format with provided json map.
func (l *Logger) Infoj(j JSONMap) {
	l.log(INFO, "json", j)
}

// Warn prints warn level log info with provided type i.
func (l *Logger) Warn(i ...interface{}) {
	l.log(WARN, "", i...)
}

// Warnf prints warn level log info in a format with provided type i.
func (l *Logger) Warnf(format string, args ...interface{}) {
	l.log(WARN, format, args...)
}

// Warnj prints warn level log info in a format with provided json map.
func (l *Logger) Warnj(j JSONMap) {
	l.log(WARN, "json", j)
}

// Error prints error level log info with provided type i.
func (l *Logger) Error(i ...interface{}) {
	l.log(ERROR, "", i...)
}

// Errorf prints error level log info in a format with provided type i.
func (l *Logger) Errorf(format string, args ...interface{}) {
	l.log(ERROR, format, args...)
}

// Errorj prints error level log info in a format with provided json map.
func (l *Logger) Errorj(j JSONMap) {
	l.log(ERROR, "json", j)
}

// Fatal prints fatal level log info with provided type i.
func (l *Logger) Fatal(i ...interface{}) {
	l.log(FATAL, "", i...)
	os.Exit(1)
}

// Fatalf prints fatal level log info in a format with provided type i.
func (l *Logger) Fatalf(format string, args ...interface{}) {
	l.log(FATAL, format, args...)
	os.Exit(1)
}

// Fatalj prints fatal level log info in a format with provided json map.
func (l *Logger) Fatalj(j JSONMap) {
	l.log(FATAL, "json", j)
}

// log prints log info in a format with provided level and args.
func (l *Logger) log(lvl LoggerLevel, format string, args ...interface{}) {
	l.mutex.Lock()
	defer l.mutex.Unlock()
	buf := l.bufferPool.Get().(*bytes.Buffer)
	buf.Reset()
	defer l.bufferPool.Put(buf)
	_, file, line, _ := runtime.Caller(3)

	if lvl >= l.Level {
		message := ""
		if format == "" {
			message = fmt.Sprint(args...)
		} else if format == "json" {
			b, err := json.Marshal(args[0])
			if err != nil {
				panic(err)
			}
			message = string(b)
		} else {
			message = fmt.Sprintf(format, args...)
		}

		if lvl == FATAL {
			panic(message)
		}

		data := make(JSONMap)
		data["app_name"] = l.air.Config.AppName
		data["time_rfc3339"] = time.Now().Format(time.RFC3339)
		data["level"] = l.levels[lvl]
		data["long_file"] = file
		data["short_file"] = path.Base(file)
		data["line"] = strconv.Itoa(line)
		err := l.template.Execute(buf, data)

		if err == nil {
			s := buf.String()
			i := buf.Len() - 1
			if s[i] == '}' {
				// JSON header
				buf.Truncate(i)
				buf.WriteByte(',')
				if format == "json" {
					buf.WriteString(message[1:])
				} else {
					buf.WriteString(`"message":"`)
					buf.WriteString(message)
					buf.WriteString(`"}`)
				}
			} else {
				// Text header
				buf.WriteByte(' ')
				buf.WriteString(message)
			}
			buf.WriteByte('\n')
			l.Output.Write(buf.Bytes())
		}
	}
}
<commit_msg>docs: update comments in logger.go<commit_after>package air

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"path"
	"runtime"
	"strconv"
	"sync"
	"text/template"
	"time"
)

type (
	// Logger is used to log information generated in runtime.
	Logger struct {
		template   *template.Template
		bufferPool *sync.Pool
		mutex      *sync.Mutex
		levels     []string
		air        *Air

		Level  LoggerLevel
		Output io.Writer
	}

	// LoggerLevel is level of the logger.
	LoggerLevel uint8
)

// Logger levels
const (
	DEBUG LoggerLevel = iota
	INFO
	WARN
	ERROR
	FATAL
	OFF
)

// newLogger returns a pointer of a new instance of `Logger`.
func newLogger(a *Air) *Logger {
	l := &Logger{
		bufferPool: &sync.Pool{
			New: func() interface{} {
				return bytes.NewBuffer(make([]byte, 256))
			},
		},
		mutex: &sync.Mutex{},
		levels: []string{
			"DEBUG",
			"INFO",
			"WARN",
			"ERROR",
			"FATAL",
		},
		air:   a,
		Level: OFF,
	}
	l.template, _ = template.New("logger").Parse(a.Config.LogFormat)
	l.Output = os.Stdout
	return l
}

// Print prints log info with provided type i.
func (l *Logger) Print(i ...interface{}) {
	fmt.Fprintln(l.Output, i...)
}

// Printf prints log info in a format with provided type i.
func (l *Logger) Printf(format string, args ...interface{}) {
	f := fmt.Sprintf("%s\n", format)
	fmt.Fprintf(l.Output, f, args...)
}

// Printj prints log info with provided json map.
func (l *Logger) Printj(j JSONMap) {
	json.NewEncoder(l.Output).Encode(j)
}

// Debug prints debug level log info with provided type i.
func (l *Logger) Debug(i ...interface{}) {
	l.log(DEBUG, "", i...)
}

// Debugf prints debug level log info in a format with provided type i.
func (l *Logger) Debugf(format string, args ...interface{}) {
	l.log(DEBUG, format, args...)
}

// Debugj prints debug level log info in a format with provided json map.
func (l *Logger) Debugj(j JSONMap) {
	l.log(DEBUG, "json", j)
}

// Info prints info level log info with provided type i.
func (l *Logger) Info(i ...interface{}) {
	l.log(INFO, "", i...)
}

// Infof prints info level log info in a format with provided type i.
func (l *Logger) Infof(format string, args ...interface{}) {
	l.log(INFO, format, args...)
}

// Infoj prints info level log info in a format with provided json map.
func (l *Logger) Infoj(j JSONMap) {
	l.log(INFO, "json", j)
}

// Warn prints warn level log info with provided type i.
func (l *Logger) Warn(i ...interface{}) {
	l.log(WARN, "", i...)
}

// Warnf prints warn level log info in a format with provided type i.
func (l *Logger) Warnf(format string, args ...interface{}) {
	l.log(WARN, format, args...)
}

// Warnj prints warn level log info in a format with provided json map.
func (l *Logger) Warnj(j JSONMap) {
	l.log(WARN, "json", j)
}

// Error prints error level log info with provided type i.
func (l *Logger) Error(i ...interface{}) {
	l.log(ERROR, "", i...)
}

// Errorf prints error level log info in a format with provided type i.
func (l *Logger) Errorf(format string, args ...interface{}) {
	l.log(ERROR, format, args...)
}

// Errorj prints error level log info in a format with provided json map.
func (l *Logger) Errorj(j JSONMap) {
	l.log(ERROR, "json", j)
}

// Fatal prints fatal level log info with provided type i.
func (l *Logger) Fatal(i ...interface{}) {
	l.log(FATAL, "", i...)
	os.Exit(1)
}

// Fatalf prints fatal level log info in a format with provided type i.
func (l *Logger) Fatalf(format string, args ...interface{}) {
	l.log(FATAL, format, args...)
	os.Exit(1)
}

// Fatalj prints fatal level log info in a format with provided json map.
func (l *Logger) Fatalj(j JSONMap) {
	l.log(FATAL, "json", j)
}

// log prints log info in a format with provided level and args.
func (l *Logger) log(lvl LoggerLevel, format string, args ...interface{}) {
	l.mutex.Lock()
	defer l.mutex.Unlock()
	buf := l.bufferPool.Get().(*bytes.Buffer)
	buf.Reset()
	defer l.bufferPool.Put(buf)
	_, file, line, _ := runtime.Caller(3)

	if lvl >= l.Level {
		message := ""
		if format == "" {
			message = fmt.Sprint(args...)
		} else if format == "json" {
			b, err := json.Marshal(args[0])
			if err != nil {
				panic(err)
			}
			message = string(b)
		} else {
			message = fmt.Sprintf(format, args...)
		}

		if lvl == FATAL {
			panic(message)
		}

		data := make(JSONMap)
		data["app_name"] = l.air.Config.AppName
		data["time_rfc3339"] = time.Now().Format(time.RFC3339)
		data["level"] = l.levels[lvl]
		data["long_file"] = file
		data["short_file"] = path.Base(file)
		data["line"] = strconv.Itoa(line)
		err := l.template.Execute(buf, data)

		if err == nil {
			s := buf.String()
			i := buf.Len() - 1
			if s[i] == '}' {
				// JSON header
				buf.Truncate(i)
				buf.WriteByte(',')
				if format == "json" {
					buf.WriteString(message[1:])
				} else {
					buf.WriteString(`"message":"`)
					buf.WriteString(message)
					buf.WriteString(`"}`)
				}
			} else {
				// Text header
				buf.WriteByte(' ')
				buf.WriteString(message)
			}
			buf.WriteByte('\n')
			l.Output.Write(buf.Bytes())
		}
	}
}
<|endoftext|>


<commit_before>// Package logger provides collection of loggin functions with colored output and stack frames
package logger

import (
	"fmt"
	"io"
	"os"
	"runtime"
	"time"

	"github.com/fatih/color"
	"github.com/shiena/ansicolor"
)

const (
	// FileNameNo indicates to no print filename
	FileNameNo int = iota
	// FileNameShort indicates to print short filename
	FileNameShort
	// FileNameLong indicates to print full filename
	FileNameLong
)

var (
	colored = false
	btrace  = true
	pdebug  = true
	fname   = FileNameNo

	output     = ansicolor.NewAnsiColorWriter(os.Stdout)
	timeFormat = "2006-Jan-2 15:04:05.0000"

	// InfoPrefix is text prefix for info log
	InfoPrefix = "INFO"
	// WarnPrefix is text prefix for warning log
	WarnPrefix = "WARN"
	// ErrPrefix is text prefix for error log
	ErrPrefix = " ERR"
	// DebugPrefix is text prefix for debug log
	DebugPrefix = " DEB"
)

// EnableColored enables colored output
func EnableColored() {
	colored = true
}

// DisableColored disables colored output
func DisableColored() {
	colored = false
}

// EnableBTrace enables backtrace for warnings and errors
func EnableBTrace() {
	btrace = true
}

// DisableBTrace disables backtrace
func DisableBTrace() {
	btrace = false
}

// EnableDebug enables debug logs
func EnableDebug() {
	pdebug = true
}

// DisableDebug disables debug logs
func DisableDebug() {
	pdebug = false
}

// SetFileName sets flag for print ceurrent file name in log
func SetFileName(fn int) {
	switch fn {
	case FileNameLong, FileNameNo, FileNameShort:
		fname = fn
	}
}

// SetOut set writer fo print logs. Default writer is os.Stdout
func SetOut(out io.Writer) {
	output = ansicolor.NewAnsiColorWriter(out)
}

func makeStack() (ret string) {
	st := make([]uintptr, 50)
	cnt := runtime.Callers(4, st)
	st = st[0:cnt]
	for _, r := range st {
		fnc := runtime.FuncForPC(r)
		file, line := fnc.FileLine(r - 1)
		ret += fmt.Sprintf("\t%s:%d\n\t\t%s\n", file, line, fnc.Name())
	}
	return
}

func printLog(colora color.Attribute, prefix string, printTrace bool, message string, v ...interface{}) {
	var f func(format string, a ...interface{}) string
	if colored {
		f = color.New(colora).SprintfFunc()
	} else {
		f = fmt.Sprintf
	}

	var fileName string
	if fname != FileNameNo {
		_, file, line, ok := runtime.Caller(2)
		if !ok {
			file = "???"
			line = 0
		}
		if fname == FileNameShort {
			short := file
			for i := len(file) - 1; i > 0; i-- {
				if file[i] == '/' {
					short = file[i+1:]
					break
				}
			}
			file = short
		}
		fileName = fmt.Sprintf(" %s:%d", file, line)
	}

	var stack string
	if printTrace && btrace {
		stack = makeStack()
		if colored {
			stack = color.MagentaString(stack)
		}
	}
	fmt.Fprint(output, f("%s %s %s\n", time.Now().Format(timeFormat), prefix+fileName, fmt.Sprintf(message, v...)), stack)
}

// Info prints info log (green if colored)
func Info(message string, v ...interface{}) {
	printLog(color.FgGreen, InfoPrefix, false, message, v...)
}

// Warning prints warning log (yellow if colored)
func Warning(message string, v ...interface{}) {
	printLog(color.FgYellow, WarnPrefix, true, message, v...)
}

// Error prints error log (red if colored)
func Error(message string, v ...interface{}) {
	printLog(color.FgRed, ErrPrefix, true, message, v...)
}

// Debug prints debug log (blue if colored)
func Debug(message string, v ...interface{}) {
	if pdebug {
		printLog(color.FgBlue, DebugPrefix, false, message, v...)
	}
}

// Fatal prints error log and finish proccess by os.Exit(1)
func Fatal(message string, v ...interface{}) {
	Error(message, v...)
	os.Exit(1)
}

// ErrorErr prints err as error log and returns true if err!=nil
func ErrorErr(err error) bool {
	if err != nil {
		Error("%v", err)
		return true
	}
	return false
}

// WarningErr prints err as warning log and returns true if err!=nil
func WarningErr(err error) bool {
	if err != nil {
		Warning("%v", err)
		return true
	}
	return false
}

// FatalErr prints err as fatal log
func FatalErr(err error) {
	if err != nil {
		Fatal("%v", err)
	}
}
<commit_msg>add Panic<commit_after>// Package logger provides collection of loggin functions with colored output and stack frames
package logger

import (
	"fmt"
	"io"
	"os"
	"runtime"
	"time"

	"github.com/fatih/color"
	"github.com/shiena/ansicolor"
)

const (
	// FileNameNo indicates to no print filename
	FileNameNo int = iota
	// FileNameShort indicates to print short filename
	FileNameShort
	// FileNameLong indicates to print full filename
	FileNameLong
)

var (
	colored = false
	btrace  = true
	pdebug  = true
	fname   = FileNameNo

	output     = ansicolor.NewAnsiColorWriter(os.Stdout)
	timeFormat = "2006-Jan-2 15:04:05.0000"

	// InfoPrefix is text prefix for info log
	InfoPrefix = "INFO"
	// WarnPrefix is text prefix for warning log
	WarnPrefix = "WARN"
	// ErrPrefix is text prefix for error log
	ErrPrefix = " ERR"
	// DebugPrefix is text prefix for debug log
	DebugPrefix = " DEB"
)

// EnableColored enables colored output
func EnableColored() {
	colored = true
}

// DisableColored disables colored output
func DisableColored() {
	colored = false
}

// EnableBTrace enables backtrace for warnings and errors
func EnableBTrace() {
	btrace = true
}

// DisableBTrace disables backtrace
func DisableBTrace() {
	btrace = false
}

// EnableDebug enables debug logs
func EnableDebug() {
	pdebug = true
}

// DisableDebug disables debug logs
func DisableDebug() {
	pdebug = false
}

// SetFileName sets flag for print ceurrent file name in log
func SetFileName(fn int) {
	switch fn {
	case FileNameLong, FileNameNo, FileNameShort:
		fname = fn
	}
}

// SetOut set writer fo print logs. Default writer is os.Stdout
func SetOut(out io.Writer) {
	output = ansicolor.NewAnsiColorWriter(out)
}

func makeStack() (ret string) {
	st := make([]uintptr, 50)
	cnt := runtime.Callers(4, st)
	st = st[0:cnt]
	for _, r := range st {
		fnc := runtime.FuncForPC(r)
		file, line := fnc.FileLine(r - 1)
		ret += fmt.Sprintf("\t%s:%d\n\t\t%s\n", file, line, fnc.Name())
	}
	return
}

func printLog(colora color.Attribute, prefix string, printTrace bool, message string, v ...interface{}) {
	var f func(format string, a ...interface{}) string
	if colored {
		f = color.New(colora).SprintfFunc()
	} else {
		f = fmt.Sprintf
	}

	var fileName string
	if fname != FileNameNo {
		_, file, line, ok := runtime.Caller(2)
		if !ok {
			file = "???"
			line = 0
		}
		if fname == FileNameShort {
			short := file
			for i := len(file) - 1; i > 0; i-- {
				if file[i] == '/' {
					short = file[i+1:]
					break
				}
			}
			file = short
		}
		fileName = fmt.Sprintf(" %s:%d", file, line)
	}

	var stack string
	if printTrace && btrace {
		stack = makeStack()
		if colored {
			stack = color.MagentaString(stack)
		}
	}
	fmt.Fprint(output, f("%s %s %s\n", time.Now().Format(timeFormat), prefix+fileName, fmt.Sprintf(message, v...)), stack)
}

// Info prints info log (green if colored)
func Info(message string, v ...interface{}) {
	printLog(color.FgGreen, InfoPrefix, false, message, v...)
}

// Warning prints warning log (yellow if colored)
func Warning(message string, v ...interface{}) {
	printLog(color.FgYellow, WarnPrefix, true, message, v...)
}

// Error prints error log (red if colored)
func Error(message string, v ...interface{}) {
	printLog(color.FgRed, ErrPrefix, true, message, v...)
}

// Debug prints debug log (blue if colored)
func Debug(message string, v ...interface{}) {
	if pdebug {
		printLog(color.FgBlue, DebugPrefix, false, message, v...)
	}
}

// Fatal prints error log and finish proccess by os.Exit(1)
func Fatal(message string, v ...interface{}) {
	Error(message, v...)
	os.Exit(1)
}

// Panic prints error log and call panic
func Panic(message string, v ...interface{}) {
	DisableBTrace()
	Error(message, v...)
	panic(fmt.Sprintf(message, v...))
}

// ErrorErr prints err as error log and returns true if err!=nil
func ErrorErr(err error) bool {
	if err != nil {
		Error("%v", err)
		return true
	}
	return false
}

// WarningErr prints err as warning log and returns true if err!=nil
func WarningErr(err error) bool {
	if err != nil {
		Warning("%v", err)
		return true
	}
	return false
}

// FatalErr prints err as fatal log
func FatalErr(err error) {
	if err != nil {
		Fatal("%v", err)
	}
}
<|endoftext|>


<commit_before>// All this package really does is add a little structure and a little color
// to the standard log package

package logsip

import (
	"errors"
	"fmt"
	"os"
	"time"

	"github.com/iamthemuffinman/logsip/isatty"
)

// Level is a type that represents the log level
type Level uint8

var startTime time.Time

const (
	// PanicLevel is the lowest level
	PanicLevel Level = iota
	FatalLevel
	ErrorLevel
	WarnLevel
	InfoLevel
	DebugLevel
)

func init() {
	startTime = time.Now()
}

func sinceStartTime() int {
	return int(time.Since(startTime) / time.Second)
}

func (level Level) String() string {
	switch level {
	case PanicLevel:
		if isatty.IsTerminal(os.Stdout.Fd()) {
			return fmt.Sprintf(prettyPrint("{{.Red}}PANIC[%04d]{{.Default}} "), sinceStartTime())
		}
		return fmt.Sprintf("PANIC[%04d] ", sinceStartTime())
	case FatalLevel:
		if isatty.IsTerminal(os.Stdout.Fd()) {
			return fmt.Sprintf(prettyPrint("{{.Red}}FATAL[%04d]{{.Default}} "), sinceStartTime())
		}
		return fmt.Sprintf("FATAL[%04d] ", sinceStartTime())
	case ErrorLevel:
		if isatty.IsTerminal(os.Stdout.Fd()) {
			return fmt.Sprintf(prettyPrint("{{.Red}}ERROR[%04d]{{.Default}} "), sinceStartTime())
		}
		return fmt.Sprintf("ERROR[%04d] ", sinceStartTime())
	case WarnLevel:
		if isatty.IsTerminal(os.Stdout.Fd()) {
			return fmt.Sprintf(prettyPrint("{{.Yellow}}WARN[%04d]{{.Default}} "), sinceStartTime())
		}
		return fmt.Sprintf("WARN[%04d] ", sinceStartTime())
	case InfoLevel:
		if isatty.IsTerminal(os.Stdout.Fd()) {
			return fmt.Sprintf(prettyPrint("{{.Blue}}INFO[%04d]{{.Default}} "), sinceStartTime())
		}
		return fmt.Sprintf("INFO[%04d] ", sinceStartTime())
	case DebugLevel:
		if isatty.IsTerminal(os.Stdout.Fd()) {
			return fmt.Sprintf(prettyPrint("{{.Purple}}DEBUG[%04d]{{.Default}} "), sinceStartTime())
		}
		return fmt.Sprintf("DEBUG[%04d] ", sinceStartTime())
	}

	return fmt.Sprintf("UNKNOWN ")
}

func parseLevel(level Level) (Level, error) {
	switch level {
	case PanicLevel:
		return PanicLevel, nil
	case FatalLevel:
		return FatalLevel, nil
	case ErrorLevel:
		return ErrorLevel, nil
	case WarnLevel:
		return WarnLevel, nil
	case InfoLevel:
		return InfoLevel, nil
	case DebugLevel:
		return DebugLevel, nil
	}

	return PanicLevel, errors.New("unable to parse log level")
}

// SetLevel is a method to set the log level (i.e Info, Warn, Debug, etc.)
func (logger *Logger) SetLevel(level Level) {
	l, err := parseLevel(level)
	if err != nil {
		fmt.Printf("%v", err)
	}

	logger.mu.Lock()
	defer logger.mu.Unlock()
	logger.Level = l
}

// GetLevel is a method to get the current log level
func (logger *Logger) GetLevel() Level {
	logger.mu.Lock()
	defer logger.mu.Unlock()
	return logger.Level
}

// SetLevel is a function to set the log level (i.e Info, Warn, Debug, etc.)
func SetLevel(level Level) {
	l, err := parseLevel(level)
	if err != nil {
		fmt.Printf("%v", err)
	}

	std.mu.Lock()
	defer std.mu.Unlock()
	std.Level = l
}

// GetLevel is a function to get the current log level
func GetLevel() Level {
	std.mu.Lock()
	defer std.mu.Unlock()
	return std.Level
}
<commit_msg>Detect terminal in global variable instead of each log level<commit_after>// All this package really does is add a little structure and a little color
// to the standard log package

package logsip

import (
	"errors"
	"fmt"
	"os"
	"time"

	"github.com/iamthemuffinman/logsip/isatty"
)

// Level is a type that represents the log level
type Level uint8

var startTime time.Time

// IsTerminal defines whether we have a terminal or not
var IsTerminal = isatty.IsTerminal(os.Stdout.Fd())

const (
	// PanicLevel is the lowest level
	PanicLevel Level = iota
	FatalLevel
	ErrorLevel
	WarnLevel
	InfoLevel
	DebugLevel
)

func init() {
	startTime = time.Now()
}

func sinceStartTime() int {
	return int(time.Since(startTime) / time.Second)
}

func (level Level) String() string {
	switch level {
	case PanicLevel:
		if IsTerminal {
			return fmt.Sprintf(prettyPrint("{{.Red}}PANIC[%04d]{{.Default}} "), sinceStartTime())
		}
		return fmt.Sprintf("PANIC[%04d] ", sinceStartTime())
	case FatalLevel:
		if IsTerminal {
			return fmt.Sprintf(prettyPrint("{{.Red}}FATAL[%04d]{{.Default}} "), sinceStartTime())
		}
		return fmt.Sprintf("FATAL[%04d] ", sinceStartTime())
	case ErrorLevel:
		if IsTerminal {
			return fmt.Sprintf(prettyPrint("{{.Red}}ERROR[%04d]{{.Default}} "), sinceStartTime())
		}
		return fmt.Sprintf("ERROR[%04d] ", sinceStartTime())
	case WarnLevel:
		if IsTerminal {
			return fmt.Sprintf(prettyPrint("{{.Yellow}}WARN[%04d]{{.Default}} "), sinceStartTime())
		}
		return fmt.Sprintf("WARN[%04d] ", sinceStartTime())
	case InfoLevel:
		if IsTerminal {
			return fmt.Sprintf(prettyPrint("{{.Blue}}INFO[%04d]{{.Default}} "), sinceStartTime())
		}
		return fmt.Sprintf("INFO[%04d] ", sinceStartTime())
	case DebugLevel:
		if IsTerminal {
			return fmt.Sprintf(prettyPrint("{{.Purple}}DEBUG[%04d]{{.Default}} "), sinceStartTime())
		}
		return fmt.Sprintf("DEBUG[%04d] ", sinceStartTime())
	}

	return fmt.Sprintf("UNKNOWN ")
}

func parseLevel(level Level) (Level, error) {
	switch level {
	case PanicLevel:
		return PanicLevel, nil
	case FatalLevel:
		return FatalLevel, nil
	case ErrorLevel:
		return ErrorLevel, nil
	case WarnLevel:
		return WarnLevel, nil
	case InfoLevel:
		return InfoLevel, nil
	case DebugLevel:
		return DebugLevel, nil
	}

	return PanicLevel, errors.New("unable to parse log level")
}

// SetLevel is a method to set the log level (i.e Info, Warn, Debug, etc.)
func (logger *Logger) SetLevel(level Level) {
	l, err := parseLevel(level)
	if err != nil {
		fmt.Printf("%v", err)
	}

	logger.mu.Lock()
	defer logger.mu.Unlock()
	logger.Level = l
}

// GetLevel is a method to get the current log level
func (logger *Logger) GetLevel() Level {
	logger.mu.Lock()
	defer logger.mu.Unlock()
	return logger.Level
}

// SetLevel is a function to set the log level (i.e Info, Warn, Debug, etc.)
func SetLevel(level Level) {
	l, err := parseLevel(level)
	if err != nil {
		fmt.Printf("%v", err)
	}

	std.mu.Lock()
	defer std.mu.Unlock()
	std.Level = l
}

// GetLevel is a function to get the current log level
func GetLevel() Level {
	std.mu.Lock()
	defer std.mu.Unlock()
	return std.Level
}
<|endoftext|>


<commit_before>package honeybadger

import (
	"code.google.com/p/go-uuid/uuid"
	"encoding/json"
	"os"
	"regexp"
	"time"
)

type hash map[string]interface{}

type Notice struct {
	APIKey       string
	Error        Error
	Token        string
	ErrorMessage string
	ErrorClass   string
	Hostname     string
	Env          string
	Backtrace    []*Frame
	ProjectRoot  string
}

func (n *Notice) asJSON() *hash {
	return &hash{
		"api_key": n.APIKey,
		"notifier": &hash{
			"name":    "honeybadger",
			"url":     "https://github.com/honeybadger-io/honeybadger-go",
			"version": "0.0.0",
		},
		"error": &hash{
			"token":     n.Token,
			"message":   n.ErrorMessage,
			"class":     n.ErrorClass,
			"backtrace": n.Backtrace,
		},
		"server": &hash{
			"project_root":     n.ProjectRoot,
			"environment_name": n.Env,
			"hostname":         n.Hostname,
			"time":             time.Now().UTC(),
			"pid":              os.Getpid(),
		},
	}
}

func (n *Notice) toJSON() []byte {
	if out, err := json.Marshal(n.asJSON()); err == nil {
		return out
	} else {
		panic(err)
	}
}

func composeStack(stack []*Frame, root string) (frames []*Frame) {
	if root == "" {
		return stack
	}

	re, err := regexp.Compile("^" + regexp.QuoteMeta(root))
	if err != nil {
		return stack
	}

	for _, frame := range stack {
		file := re.ReplaceAllString(frame.File, "[PROJECT_ROOT]")
		frames = append(frames, &Frame{
			File:   file,
			Number: frame.Number,
			Method: frame.Method,
		})
	}
	return
}

func newNotice(config *Configuration, err Error) *Notice {
	notice := Notice{
		APIKey:       config.APIKey,
		Error:        err,
		Token:        uuid.NewRandom().String(),
		ErrorMessage: err.Message,
		ErrorClass:   err.Class,
		Env:          config.Env,
		Hostname:     config.Hostname,
		Backtrace:    composeStack(err.Stack, config.Root),
		ProjectRoot:  config.Root,
	}

	return &notice
}
<commit_msg>Send stats.<commit_after>package honeybadger

import (
	"code.google.com/p/go-uuid/uuid"
	"encoding/json"
	"github.com/shirou/gopsutil/load"
	"github.com/shirou/gopsutil/mem"
	"os"
	"regexp"
	"time"
)

type hash map[string]interface{}

type Notice struct {
	APIKey       string
	Error        Error
	Token        string
	ErrorMessage string
	ErrorClass   string
	Hostname     string
	Env          string
	Backtrace    []*Frame
	ProjectRoot  string
}

func (n *Notice) asJSON() *hash {
	return &hash{
		"api_key": n.APIKey,
		"notifier": &hash{
			"name":    "honeybadger",
			"url":     "https://github.com/honeybadger-io/honeybadger-go",
			"version": "0.0.0",
		},
		"error": &hash{
			"token":     n.Token,
			"message":   n.ErrorMessage,
			"class":     n.ErrorClass,
			"backtrace": n.Backtrace,
		},
		"server": &hash{
			"project_root":     n.ProjectRoot,
			"environment_name": n.Env,
			"hostname":         n.Hostname,
			"time":             time.Now().UTC(),
			"pid":              os.Getpid(),
			"stats":            getStats(),
		},
	}
}

func bytesToKB(bytes uint64) float64 {
	return float64(bytes) / 1024.0
}

func getStats() *hash {
	var m, l *hash

	if stat, err := mem.VirtualMemory(); err == nil {
		m = &hash{
			"total":      bytesToKB(stat.Total),
			"free":       bytesToKB(stat.Free),
			"buffers":    bytesToKB(stat.Buffers),
			"cached":     bytesToKB(stat.Cached),
			"free_total": bytesToKB(stat.Free + stat.Buffers + stat.Cached),
		}
	}

	if stat, err := load.LoadAvg(); err == nil {
		l = &hash{
			"one":     stat.Load1,
			"five":    stat.Load5,
			"fifteen": stat.Load15,
		}
	}

	return &hash{"mem": m, "load": l}
}

func (n *Notice) toJSON() []byte {
	if out, err := json.Marshal(n.asJSON()); err == nil {
		return out
	} else {
		panic(err)
	}
}

func composeStack(stack []*Frame, root string) (frames []*Frame) {
	if root == "" {
		return stack
	}

	re, err := regexp.Compile("^" + regexp.QuoteMeta(root))
	if err != nil {
		return stack
	}

	for _, frame := range stack {
		file := re.ReplaceAllString(frame.File, "[PROJECT_ROOT]")
		frames = append(frames, &Frame{
			File:   file,
			Number: frame.Number,
			Method: frame.Method,
		})
	}
	return
}

func newNotice(config *Configuration, err Error) *Notice {
	notice := Notice{
		APIKey:       config.APIKey,
		Error:        err,
		Token:        uuid.NewRandom().String(),
		ErrorMessage: err.Message,
		ErrorClass:   err.Class,
		Env:          config.Env,
		Hostname:     config.Hostname,
		Backtrace:    composeStack(err.Stack, config.Root),
		ProjectRoot:  config.Root,
	}

	return &notice
}
<|endoftext|>


<commit_before>// Package notify provides an implementation of the Freedesktop Notifications Specification
// using the DBus API.
package notify

import "github.com/godbus/dbus"

// Notification expire timeout
const (
	ExpiresDefault = -1
	ExpiresNever   = 0
)

// Notification Categories
const (
	ClassDevice              = "device"
	ClassDeviceAdded         = "device.added"
	ClassDeviceError         = "device.error"
	ClassDeviceRemoved       = "device.removed"
	ClassEmail               = "email"
	ClassEmailArrived        = "email.arrived"
	ClassEmailBounced        = "email.bounced"
	ClassIm                  = "im"
	ClassImError             = "im.error"
	ClassImReceived          = "im.received"
	ClassNetwork             = "network"
	ClassNetworkConnected    = "network.connected"
	ClassNetworkDisconnected = "network.disconnected"
	ClassNetworkError        = "network.error"
	ClassPresence            = "presence"
	ClassPresenceOffline     = "presence.offline"
	ClassPresenceOnline      = "presence.online"
	ClassTransfer            = "transfer"
	ClassTransferComplete    = "transfer.complete"
	ClassTransferError       = "transfer.error"
)

// Urgency Levels
const (
	UrgencyLow      = 0
	UrgencyNormal   = 1
	UrgencyCritical = 2
)

// Hints
const (
	HintActionIcons   = "action-icons"
	HintCategory      = "category"
	HintDesktopEntry  = "desktop-entry"
	HintImageData     = "image-data"
	HintImagePath     = "image-path"
	HintResident      = "resident"
	HintSoundFile     = "sound-file"
	HintSoundName     = "sound-name"
	HintSuppressSound = "suppress-sound"
	HintTransient     = "transient"
	HintX             = "x"
	HintY             = "y"
	HintUrgency       = "urgency"
)

type Capabilities struct {
	// Supports using icons instead of text for displaying actions.
	ActionIcons bool

	// The server will provide any specified actions to the user.
	Actions bool

	// Supports body text. Some implementations may only show the summary.
	Body bool

	// The server supports hyperlinks in the notifications.
	BodyHyperlinks bool

	// The server supports images in the notifications.
	BodyImages bool

	// Supports markup in the body text.
	BodyMarkup bool

	// The server will render an animation of all the frames in a given image array.
	IconMulti bool

	// Supports display of exactly 1 frame of any given image array.
	IconStatic bool

	// The server supports persistence of notifications. Notifications will be
	// retained until they are acknowledged or removed by the user or recalled by the sender.
	Persistence bool

	// The server supports sounds on notifications.
	Sound bool
}

// GetCapabilities returns the capabilities of the notification server.
func GetCapabilities() (c Capabilities, err error) {
	connection, err := dbus.SessionBus()
	if err != nil {
		return
	}
	obj := connection.Object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")

	call := obj.Call("org.freedesktop.Notifications.GetCapabilities", 0)
	if call.Err != nil {
		return Capabilities{}, call.Err
	}

	s := []string{}
	if err = call.Store(&s); err != nil {
		return
	}
	for _, v := range s {
		switch v {
		case "action-icons":
			c.ActionIcons = true
			break
		case "actions":
			c.Actions = true
			break
		case "body":
			c.Body = true
			break
		case "body-hyperlinks":
			c.BodyHyperlinks = true
			break
		case "body-images":
			c.BodyImages = true
			break
		case "body-markup":
			c.BodyMarkup = true
			break
		case "icon-multi":
			c.IconMulti = true
			break
		case "icon-static":
			c.IconStatic = true
			break
		case "persistence":
			c.Persistence = true
			break
		case "sound":
			c.Sound = true
			break
		}
	}
	return
}

type ServerInformation struct {
	// The name of the notification server daemon
	Name string

	// The vendor of the notification server
	Vendor string

	// Version of the notification server
	Version string

	// Spec version the notification server conforms to
	SpecVersion string
}

// GetServerInformation returns information about the notification server such as its name
// and version.
func GetServerInformation() (i ServerInformation, err error) {
	connection, err := dbus.SessionBus()
	if err != nil {
		return
	}
	obj := connection.Object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")

	call := obj.Call("org.freedesktop.Notifications.GetServerInformation", 0)
	if call.Err != nil {
		return ServerInformation{}, call.Err
	}

	if err = call.Store(&i.Name, &i.Vendor, &i.Version, &i.SpecVersion); err != nil {
		return
	}
	return
}

type Notification struct {
	// The optional name of the application sending the notification. Can be blank.
	AppName string

	// The optional notification ID that this notification replaces.
	ReplacesID uint32

	// The optional program icon of the calling application.
	AppIcon string

	// The summary text briefly describing the notification.
	Summary string

	// The optional detailed body text.
	Body string

	// The actions send a request message back to the notification client when invoked.
	Actions []string

	// Hints are a way to provide extra data to a notification server.
	Hints map[string]interface{}

	// The timeout time in milliseconds since the display of the notification at which
	// the notification should automatically close.
	Timeout int32
}

// NewNotification creates a new notification object with some basic information.
func NewNotification(summary, body string) Notification {
	return Notification{Summary: summary, Body: body, Timeout: ExpiresDefault}
}

// Show sends the information in the notification object to the server to be displayed.
func (n *Notification) Show() (id uint32, err error) {

	// We need to convert the interface type of the map to dbus.Variant as people
	// dont want to have to import the dbus package just to make use of the notification
	// hints.
	hints := map[string]dbus.Variant{}
	if len(n.Hints) != 0 {
		for k, v := range n.Hints {
			hints[k] = dbus.MakeVariant(v)
		}
	}

	connection, err := dbus.SessionBus()
	if err != nil {
		return
	}
	obj := connection.Object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")

	call := obj.Call(
		"org.freedesktop.Notifications.Notify",
		0,
		n.AppName,
		n.ReplacesID,
		n.AppIcon,
		n.Summary,
		n.Body,
		n.Actions,
		hints,
		n.Timeout)
	if call.Err != nil {
		return 0, call.Err
	}

	if err = call.Store(&id); err != nil {
		return
	}
	return
}

// CloseNotification closes the notification if it exists using its id.
func CloseNotification(id uint32) (err error) {
	connection, err := dbus.SessionBus()
	if err != nil {
		return
	}
	obj := connection.Object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")

	call := obj.Call("org.freedesktop.Notifications.CloseNotification", 0, id)
	if call.Err != nil {
		return call.Err
	}
	return
}
<commit_msg>Removed another useless pointer.<commit_after>// Package notify provides an implementation of the Freedesktop Notifications Specification
// using the DBus API.
package notify

import "github.com/godbus/dbus"

// Notification expire timeout
const (
	ExpiresDefault = -1
	ExpiresNever   = 0
)

// Notification Categories
const (
	ClassDevice              = "device"
	ClassDeviceAdded         = "device.added"
	ClassDeviceError         = "device.error"
	ClassDeviceRemoved       = "device.removed"
	ClassEmail               = "email"
	ClassEmailArrived        = "email.arrived"
	ClassEmailBounced        = "email.bounced"
	ClassIm                  = "im"
	ClassImError             = "im.error"
	ClassImReceived          = "im.received"
	ClassNetwork             = "network"
	ClassNetworkConnected    = "network.connected"
	ClassNetworkDisconnected = "network.disconnected"
	ClassNetworkError        = "network.error"
	ClassPresence            = "presence"
	ClassPresenceOffline     = "presence.offline"
	ClassPresenceOnline      = "presence.online"
	ClassTransfer            = "transfer"
	ClassTransferComplete    = "transfer.complete"
	ClassTransferError       = "transfer.error"
)

// Urgency Levels
const (
	UrgencyLow      = 0
	UrgencyNormal   = 1
	UrgencyCritical = 2
)

// Hints
const (
	HintActionIcons   = "action-icons"
	HintCategory      = "category"
	HintDesktopEntry  = "desktop-entry"
	HintImageData     = "image-data"
	HintImagePath     = "image-path"
	HintResident      = "resident"
	HintSoundFile     = "sound-file"
	HintSoundName     = "sound-name"
	HintSuppressSound = "suppress-sound"
	HintTransient     = "transient"
	HintX             = "x"
	HintY             = "y"
	HintUrgency       = "urgency"
)

type Capabilities struct {
	// Supports using icons instead of text for displaying actions.
	ActionIcons bool

	// The server will provide any specified actions to the user.
	Actions bool

	// Supports body text. Some implementations may only show the summary.
	Body bool

	// The server supports hyperlinks in the notifications.
	BodyHyperlinks bool

	// The server supports images in the notifications.
	BodyImages bool

	// Supports markup in the body text.
	BodyMarkup bool

	// The server will render an animation of all the frames in a given image array.
	IconMulti bool

	// Supports display of exactly 1 frame of any given image array.
	IconStatic bool

	// The server supports persistence of notifications. Notifications will be
	// retained until they are acknowledged or removed by the user or recalled by the sender.
	Persistence bool

	// The server supports sounds on notifications.
	Sound bool
}

// GetCapabilities returns the capabilities of the notification server.
func GetCapabilities() (c Capabilities, err error) {
	connection, err := dbus.SessionBus()
	if err != nil {
		return
	}
	obj := connection.Object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")

	call := obj.Call("org.freedesktop.Notifications.GetCapabilities", 0)
	if call.Err != nil {
		return Capabilities{}, call.Err
	}

	s := []string{}
	if err = call.Store(&s); err != nil {
		return
	}
	for _, v := range s {
		switch v {
		case "action-icons":
			c.ActionIcons = true
			break
		case "actions":
			c.Actions = true
			break
		case "body":
			c.Body = true
			break
		case "body-hyperlinks":
			c.BodyHyperlinks = true
			break
		case "body-images":
			c.BodyImages = true
			break
		case "body-markup":
			c.BodyMarkup = true
			break
		case "icon-multi":
			c.IconMulti = true
			break
		case "icon-static":
			c.IconStatic = true
			break
		case "persistence":
			c.Persistence = true
			break
		case "sound":
			c.Sound = true
			break
		}
	}
	return
}

type ServerInformation struct {
	// The name of the notification server daemon
	Name string

	// The vendor of the notification server
	Vendor string

	// Version of the notification server
	Version string

	// Spec version the notification server conforms to
	SpecVersion string
}

// GetServerInformation returns information about the notification server such as its name
// and version.
func GetServerInformation() (i ServerInformation, err error) {
	connection, err := dbus.SessionBus()
	if err != nil {
		return
	}
	obj := connection.Object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")

	call := obj.Call("org.freedesktop.Notifications.GetServerInformation", 0)
	if call.Err != nil {
		return ServerInformation{}, call.Err
	}

	if err = call.Store(&i.Name, &i.Vendor, &i.Version, &i.SpecVersion); err != nil {
		return
	}
	return
}

type Notification struct {
	// The optional name of the application sending the notification. Can be blank.
	AppName string

	// The optional notification ID that this notification replaces.
	ReplacesID uint32

	// The optional program icon of the calling application.
	AppIcon string

	// The summary text briefly describing the notification.
	Summary string

	// The optional detailed body text.
	Body string

	// The actions send a request message back to the notification client when invoked.
	Actions []string

	// Hints are a way to provide extra data to a notification server.
	Hints map[string]interface{}

	// The timeout time in milliseconds since the display of the notification at which
	// the notification should automatically close.
	Timeout int32
}

// NewNotification creates a new notification object with some basic information.
func NewNotification(summary, body string) Notification {
	return Notification{Summary: summary, Body: body, Timeout: ExpiresDefault}
}

// Show sends the information in the notification object to the server to be displayed.
func (n Notification) Show() (id uint32, err error) {

	// We need to convert the interface type of the map to dbus.Variant as people
	// dont want to have to import the dbus package just to make use of the notification
	// hints.
	hints := map[string]dbus.Variant{}
	if len(n.Hints) != 0 {
		for k, v := range n.Hints {
			hints[k] = dbus.MakeVariant(v)
		}
	}

	connection, err := dbus.SessionBus()
	if err != nil {
		return
	}
	obj := connection.Object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")

	call := obj.Call(
		"org.freedesktop.Notifications.Notify",
		0,
		n.AppName,
		n.ReplacesID,
		n.AppIcon,
		n.Summary,
		n.Body,
		n.Actions,
		hints,
		n.Timeout)
	if call.Err != nil {
		return 0, call.Err
	}

	if err = call.Store(&id); err != nil {
		return
	}
	return
}

// CloseNotification closes the notification if it exists using its id.
func CloseNotification(id uint32) (err error) {
	connection, err := dbus.SessionBus()
	if err != nil {
		return
	}
	obj := connection.Object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")

	call := obj.Call("org.freedesktop.Notifications.CloseNotification", 0, id)
	if call.Err != nil {
		return call.Err
	}
	return
}
<|endoftext|>


<commit_before>package skiplist

import (
	"math/rand"
	"sync"
)

const (
	// ListMaxLevel is the Skiplist can have
	ListMaxLevel = 32
	// ListP is the P value for the SkipList
	ListP = 0.25
)

type SkipList interface {
	Search(key int) *Node
	Delete(key int) bool
	Insert(key int, val []byte) *Node
	Iterator() Iterator
}

type List struct {
	sync.RWMutex
	MaxLevel int
	level    int
	length   int
	header   *Node
	footer   *Node
}

var _ SkipList = (*List)(nil)

// Returns a random level used during inserting nodes
func randomLevel(maxLevel int) int {
	newLevel := 1
	for rand.Float64() >= ListP && newLevel < maxLevel && newLevel < ListMaxLevel-1 {
		newLevel++
	}
	return newLevel
}

// New initializes a new skiplist with
// max level of 32 or 2^32 elements
func NewList() *List {
	return NewListWithLevel(ListMaxLevel)
}

// NewWithLevel initializes a new skiplist with a custom
// max level. Level is defaulted to 32 to allow
// for 2^32 max elements
func NewListWithLevel(level int) *List {
	return &List{
		MaxLevel: level,
		header:   &Node{forward: make([]*Node, level)},
		level:    0,
	}
}

func (l *List) Iterator() Iterator {
	return &iterable{curr: l.header}
}

func (l *List) Search(key int) *Node {
	l.RLock()
	defer l.RUnlock()
	x := l.header
	for i := l.level; i >= 0; i-- {
		for x.forward[i] != nil && x.forward[i].key < key {
			x = x.forward[i]
		}
	}
	x = x.forward[0]
	if x != nil && x.key == key {
		return x
	}
	return nil
}

func (l *List) Insert(key int, val []byte) *Node {
	update := make([]*Node, l.MaxLevel)
	x := l.header
	var alreadyChecked *Node
	l.Lock()
	defer l.Unlock()

	for i := l.level; i >= 0; i-- {
		for x.forward[i] != nil &&
			alreadyChecked != x.forward[i] &&
			x.forward[i].key < key {
			x = x.forward[i]
		}
		alreadyChecked = x.forward[i]
		update[i] = x
	}
	x = x.forward[0]
	if x != nil && x.key == key {
		x.val = val
		return x
	}
	newLevel := randomLevel(l.MaxLevel)
	if newLevel > l.level {
		for i := l.level + 1; i < newLevel; i++ {
			update[i] = l.header
		}
		l.level = newLevel
	}
	x = NewNode(newLevel, key, val)
	for i := 0; i < newLevel; i++ {
		x.forward[i] = update[i].forward[i]
		update[i].forward[i] = x
	}
	x.backward = nil
	if update[0] != l.header {
		x.backward = update[0]
	}
	if x.forward[0] != nil {
		x.forward[0].backward = x
	}
	if l.footer == nil || l.footer.key < key {
		l.footer = x
	}
	l.length++
	return x
}

func (l *List) Delete(key int) bool {
	update := make([]*Node, l.MaxLevel)
	x := l.header
	var alreadyChecked *Node
	l.Lock()
	defer l.Unlock()

	for i := l.level; i >= 0; i-- {
		for x.forward[i] != nil &&
			alreadyChecked != x.forward[i] &&
			x.forward[i].key < key {
			x = x.forward[i]
		}
		alreadyChecked = x.forward[i]
		update[i] = x
	}
	x = x.forward[0]
	if x != nil && x.key == key {
		for i := 0; i < l.level; i++ {
			if update[i].forward[i] != x {
				break
			}
			update[i].forward[i] = x.forward[i]
		}
		for l.level > 1 && len(l.header.forward) > l.level && l.header.forward[l.level-1] == nil {
			l.level--
		}
		l.length--
		return true
	}
	return false
}
<commit_msg>Add Size function for skiplist<commit_after>package skiplist

import (
	"math/rand"
	"sync"
)

const (
	// ListMaxLevel is the Skiplist can have
	ListMaxLevel = 32
	// ListP is the P value for the SkipList
	ListP = 0.25
)

type SkipList interface {
	Search(key int) *Node
	Delete(key int) bool
	Insert(key int, val []byte) *Node
	Iterator() Iterator
}

type List struct {
	sync.RWMutex
	MaxLevel int
	level    int
	length   int
	header   *Node
	footer   *Node
}

var _ SkipList = (*List)(nil)

// Returns a random level used during inserting nodes
func randomLevel(maxLevel int) int {
	newLevel := 1
	for rand.Float64() >= ListP && newLevel < maxLevel && newLevel < ListMaxLevel-1 {
		newLevel++
	}
	return newLevel
}

// New initializes a new skiplist with
// max level of 32 or 2^32 elements
func NewList() *List {
	return NewListWithLevel(ListMaxLevel)
}

// NewWithLevel initializes a new skiplist with a custom
// max level. Level is defaulted to 32 to allow
// for 2^32 max elements
func NewListWithLevel(level int) *List {
	return &List{
		MaxLevel: level,
		header:   &Node{forward: make([]*Node, level)},
		level:    0,
	}
}

func (l *List) Iterator() Iterator {
	return &iterable{curr: l.header}
}

// Size returns the length of the list
func (l *List) Size() int {
	return l.length
}

func (l *List) Search(key int) *Node {
	l.RLock()
	defer l.RUnlock()
	x := l.header
	for i := l.level; i >= 0; i-- {
		for x.forward[i] != nil && x.forward[i].key < key {
			x = x.forward[i]
		}
	}
	x = x.forward[0]
	if x != nil && x.key == key {
		return x
	}
	return nil
}

func (l *List) Insert(key int, val []byte) *Node {
	update := make([]*Node, l.MaxLevel)
	x := l.header
	var alreadyChecked *Node
	l.Lock()
	defer l.Unlock()

	for i := l.level; i >= 0; i-- {
		for x.forward[i] != nil &&
			alreadyChecked != x.forward[i] &&
			x.forward[i].key < key {
			x = x.forward[i]
		}
		alreadyChecked = x.forward[i]
		update[i] = x
	}
	x = x.forward[0]
	if x != nil && x.key == key {
		x.val = val
		return x
	}
	newLevel := randomLevel(l.MaxLevel)
	if newLevel > l.level {
		for i := l.level + 1; i < newLevel; i++ {
			update[i] = l.header
		}
		l.level = newLevel
	}
	x = NewNode(newLevel, key, val)
	for i := 0; i < newLevel; i++ {
		x.forward[i] = update[i].forward[i]
		update[i].forward[i] = x
	}
	x.backward = nil
	if update[0] != l.header {
		x.backward = update[0]
	}
	if x.forward[0] != nil {
		x.forward[0].backward = x
	}
	if l.footer == nil || l.footer.key < key {
		l.footer = x
	}
	l.length++
	return x
}

func (l *List) Delete(key int) bool {
	update := make([]*Node, l.MaxLevel)
	x := l.header
	var alreadyChecked *Node
	l.Lock()
	defer l.Unlock()

	for i := l.level; i >= 0; i-- {
		for x.forward[i] != nil &&
			alreadyChecked != x.forward[i] &&
			x.forward[i].key < key {
			x = x.forward[i]
		}
		alreadyChecked = x.forward[i]
		update[i] = x
	}
	x = x.forward[0]
	if x != nil && x.key == key {
		for i := 0; i < l.level; i++ {
			if update[i].forward[i] != x {
				break
			}
			update[i].forward[i] = x.forward[i]
		}
		for l.level > 1 && len(l.header.forward) > l.level && l.header.forward[l.level-1] == nil {
			l.level--
		}
		l.length--
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package udpjson

import (
	"net"
	"packetbeat/common"
	"packetbeat/logp"
	"testing"
	"time"

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

func TestUdpJson(t *testing.T) {
	if testing.Verbose() {
		logp.LogInit(logp.LOG_DEBUG, "", false, true, []string{"udpjson"})
	}

	events := make(chan common.MapStr)
	server := new(Udpjson)

	server.Config = Config{
		Port:    0,
		BindIp:  "127.0.0.1",
		Timeout: 10 * time.Millisecond,
	}
	err := server.Init(true, events)
	assert.Nil(t, err)

	ready := make(chan bool)

	go func() {
		ready <- true
		err := server.Run()
		assert.Nil(t, err, "Error: %v", err)
	}()

	// make sure the goroutine runs first
	<-ready

	logp.Debug("udpjson", server.conn.LocalAddr().String())

	// send a message
	clientConn, err := net.Dial("udp", server.conn.LocalAddr().String())
	assert.Nil(t, err, "Error: %v", err)

	_, err = clientConn.Write([]byte(`{"hello": "udpserver"}`))
	assert.Nil(t, err)

	obj := <-events
	assert.Equal(t, obj["hello"].(string), "udpserver")
	_, ok := obj["@timestamp"].(common.Time)
	assert.True(t, ok)

	_, err = clientConn.Write([]byte(`{"obj2": 4}`))
	assert.Nil(t, err)
	_, ok = obj["@timestamp"].(common.Time)
	assert.True(t, ok)

	obj = <-events
	assert.Equal(t, obj["obj2"].(float64), 4)

	server.Stop()
}
<commit_msg>Fix udpjson test assertion.<commit_after>package udpjson

import (
	"net"
	"packetbeat/common"
	"packetbeat/logp"
	"testing"
	"time"

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

func TestUdpJson(t *testing.T) {
	if testing.Verbose() {
		logp.LogInit(logp.LOG_DEBUG, "", false, true, []string{"udpjson"})
	}

	events := make(chan common.MapStr)
	server := new(Udpjson)

	server.Config = Config{
		Port:    0,
		BindIp:  "127.0.0.1",
		Timeout: 10 * time.Millisecond,
	}
	err := server.Init(true, events)
	assert.Nil(t, err)

	ready := make(chan bool)

	go func() {
		ready <- true
		err := server.Run()
		assert.Nil(t, err, "Error: %v", err)
	}()

	// make sure the goroutine runs first
	<-ready

	logp.Debug("udpjson", server.conn.LocalAddr().String())

	// send a message
	clientConn, err := net.Dial("udp", server.conn.LocalAddr().String())
	assert.Nil(t, err, "Error: %v", err)

	_, err = clientConn.Write([]byte(`{"hello": "udpserver"}`))
	assert.Nil(t, err)

	obj := <-events
	assert.Equal(t, obj["hello"].(string), "udpserver")
	_, ok := obj["@timestamp"].(common.Time)
	assert.True(t, ok)

	_, err = clientConn.Write([]byte(`{"obj2": 4}`))
	assert.Nil(t, err)
	_, ok = obj["@timestamp"].(common.Time)
	assert.True(t, ok)

	obj = <-events
	assert.Equal(t, obj["obj2"].(float64), 4.0)

	server.Stop()
}
<|endoftext|>


<commit_before>package vindinium

import "math/rand"

type Direction string

var DIRS = []Direction{"Stay", "North", "South", "East", "West"}

func randDir() Direction {
	dir := DIRS[rand.Intn(len(DIRS))]

	return dir
}

type Bot interface {
	Move(state *State) Direction
}

type RandomBot struct{}

func (b *RandomBot) Move(state *State) Direction {
	return randDir()
}

type FighterBot struct{}

func (b *FighterBot) Move(state *State) Direction {
	// g := NewGame(state)
	// Do something awesome
	return randDir()
}

// type SlowBot struct{}
//
// func (b *SlowBot) Move(state *State) Direction {
// 	time.Sleep(2 * time.Millisecond)
// 	return randDir()
// }
<commit_msg>Remove slow bot<commit_after>package vindinium

import "math/rand"

type Direction string

var DIRS = []Direction{"Stay", "North", "South", "East", "West"}

func randDir() Direction {
	dir := DIRS[rand.Intn(len(DIRS))]

	return dir
}

type Bot interface {
	Move(state *State) Direction
}

type RandomBot struct{}

func (b *RandomBot) Move(state *State) Direction {
	return randDir()
}

type FighterBot struct{}

func (b *FighterBot) Move(state *State) Direction {
	// g := NewGame(state)
	// Do something awesome
	return randDir()
}
<|endoftext|>


<commit_before>package display

import (
	"bytes"
	"fmt"
	"path"
	"regexp"
	"strconv"
	"strings"
	"unicode/utf8"

	luar "layeh.com/gopher-luar"

	runewidth "github.com/mattn/go-runewidth"
	lua "github.com/yuin/gopher-lua"
	"github.com/zyedidia/micro/internal/buffer"
	"github.com/zyedidia/micro/internal/config"
	ulua "github.com/zyedidia/micro/internal/lua"
	"github.com/zyedidia/micro/internal/screen"
	"github.com/zyedidia/micro/internal/util"
)

// StatusLine represents the information line at the bottom
// of each window
// It gives information such as filename, whether the file has been
// modified, filetype, cursor location
type StatusLine struct {
	Info map[string]func(*buffer.Buffer) string

	win *BufWindow
}

var statusInfo = map[string]func(*buffer.Buffer) string{
	"filename": func(b *buffer.Buffer) string {
		if b.Settings["basename"].(bool) {
			return path.Base(b.GetName())
		}
		return b.GetName()
	},
	"line": func(b *buffer.Buffer) string {
		return strconv.Itoa(b.GetActiveCursor().Y + 1)
	},
	"col": func(b *buffer.Buffer) string {
		return strconv.Itoa(b.GetActiveCursor().X + 1)
	},
	"modified": func(b *buffer.Buffer) string {
		if b.Modified() {
			return "+ "
		}
		return ""
	},
}

func SetStatusInfoFnLua(fn string) {
	luaFn := strings.Split(fn, ".")
	if len(luaFn) <= 1 {
		return
	}
	plName, plFn := luaFn[0], luaFn[1]
	pl := config.FindPlugin(plName)
	if pl == nil {
		return
	}
	statusInfo[fn] = func(b *buffer.Buffer) string {
		if pl == nil || !pl.IsEnabled() {
			return ""
		}
		val, err := pl.Call(plFn, luar.New(ulua.L, b))
		if err == nil {
			if v, ok := val.(lua.LString); !ok {
				screen.TermMessage(plFn, "should return a string")
				return ""
			} else {
				return string(v)
			}
		}
		return ""
	}
}

// NewStatusLine returns a statusline bound to a window
func NewStatusLine(win *BufWindow) *StatusLine {
	s := new(StatusLine)
	s.win = win
	return s
}

// FindOpt finds a given option in the current buffer's settings
func (s *StatusLine) FindOpt(opt string) interface{} {
	if val, ok := s.win.Buf.Settings[opt]; ok {
		return val
	}
	return "null"
}

var formatParser = regexp.MustCompile(`\$\(.+?\)`)

// Display draws the statusline to the screen
func (s *StatusLine) Display() {
	// We'll draw the line at the lowest line in the window
	y := s.win.Height + s.win.Y - 1

	b := s.win.Buf
	// autocomplete suggestions (for the buffer, not for the infowindow)
	if b.HasSuggestions && len(b.Suggestions) > 1 {
		statusLineStyle := config.DefStyle.Reverse(true)
		if style, ok := config.Colorscheme["statusline"]; ok {
			statusLineStyle = style
		}
		keymenuOffset := 0
		if config.GetGlobalOption("keymenu").(bool) {
			keymenuOffset = len(keydisplay)
		}
		x := 0
		for j, sug := range b.Suggestions {
			style := statusLineStyle
			if b.CurSuggestion == j {
				style = style.Reverse(true)
			}
			for _, r := range sug {
				screen.SetContent(x, y-keymenuOffset, r, nil, style)
				x++
				if x >= s.win.Width {
					return
				}
			}
			screen.SetContent(x, y-keymenuOffset, ' ', nil, statusLineStyle)
			x++
			if x >= s.win.Width {
				return
			}
		}

		for x < s.win.Width {
			screen.SetContent(x, y-keymenuOffset, ' ', nil, statusLineStyle)
			x++
		}
		return
	}

	formatter := func(match []byte) []byte {
		name := match[2 : len(match)-1]
		if bytes.HasPrefix(name, []byte("opt")) {
			option := name[4:]
			return []byte(fmt.Sprint(s.FindOpt(string(option))))
		} else if bytes.HasPrefix(name, []byte("bind")) {
			binding := string(name[5:])
			for k, v := range config.Bindings {
				if v == binding {
					return []byte(k)
				}
			}
			return []byte("null")
		} else {
			if fn, ok := statusInfo[string(name)]; ok {
				return []byte(fn(s.win.Buf))
			}
			return []byte{}
		}
	}

	leftText := []byte(s.win.Buf.Settings["statusformatl"].(string))
	leftText = formatParser.ReplaceAllFunc(leftText, formatter)
	rightText := []byte(s.win.Buf.Settings["statusformatr"].(string))
	rightText = formatParser.ReplaceAllFunc(rightText, formatter)

	statusLineStyle := config.DefStyle.Reverse(true)
	if style, ok := config.Colorscheme["statusline"]; ok {
		statusLineStyle = style
	}

	leftLen := util.StringWidth(leftText, utf8.RuneCount(leftText), 1)
	rightLen := util.StringWidth(rightText, utf8.RuneCount(rightText), 1)

	winX := s.win.X
	for x := 0; x < s.win.Width; x++ {
		if x < leftLen {
			r, size := utf8.DecodeRune(leftText)
			leftText = leftText[size:]
			rw := runewidth.RuneWidth(r)
			for j := 0; j < rw; j++ {
				c := r
				if j > 0 {
					c = ' '
					x++
				}
				screen.SetContent(winX+x, y, c, nil, statusLineStyle)
			}
		} else if x >= s.win.Width-rightLen && x < rightLen+s.win.Width-rightLen {
			r, size := utf8.DecodeRune(rightText)
			rightText = rightText[size:]
			rw := runewidth.RuneWidth(r)
			for j := 0; j < rw; j++ {
				c := r
				if j > 0 {
					c = ' '
					x++
				}
				screen.SetContent(winX+x, y, c, nil, statusLineStyle)
			}
		} else {
			screen.SetContent(winX+x, y, ' ', nil, statusLineStyle)
		}
	}
}
<commit_msg>Show that the file is readonly (#1486)<commit_after>package display

import (
	"bytes"
	"fmt"
	"path"
	"regexp"
	"strconv"
	"strings"
	"unicode/utf8"

	luar "layeh.com/gopher-luar"

	runewidth "github.com/mattn/go-runewidth"
	lua "github.com/yuin/gopher-lua"
	"github.com/zyedidia/micro/internal/buffer"
	"github.com/zyedidia/micro/internal/config"
	ulua "github.com/zyedidia/micro/internal/lua"
	"github.com/zyedidia/micro/internal/screen"
	"github.com/zyedidia/micro/internal/util"
)

// StatusLine represents the information line at the bottom
// of each window
// It gives information such as filename, whether the file has been
// modified, filetype, cursor location
type StatusLine struct {
	Info map[string]func(*buffer.Buffer) string

	win *BufWindow
}

var statusInfo = map[string]func(*buffer.Buffer) string{
	"filename": func(b *buffer.Buffer) string {
		if b.Settings["basename"].(bool) {
			return path.Base(b.GetName())
		}
		return b.GetName()
	},
	"line": func(b *buffer.Buffer) string {
		return strconv.Itoa(b.GetActiveCursor().Y + 1)
	},
	"col": func(b *buffer.Buffer) string {
		return strconv.Itoa(b.GetActiveCursor().X + 1)
	},
	"modified": func(b *buffer.Buffer) string {
		if b.Modified() {
			return "+ "
		}
		if b.Type.Readonly {
			return "[ro] "
		}
		return ""
	},
}

func SetStatusInfoFnLua(fn string) {
	luaFn := strings.Split(fn, ".")
	if len(luaFn) <= 1 {
		return
	}
	plName, plFn := luaFn[0], luaFn[1]
	pl := config.FindPlugin(plName)
	if pl == nil {
		return
	}
	statusInfo[fn] = func(b *buffer.Buffer) string {
		if pl == nil || !pl.IsEnabled() {
			return ""
		}
		val, err := pl.Call(plFn, luar.New(ulua.L, b))
		if err == nil {
			if v, ok := val.(lua.LString); !ok {
				screen.TermMessage(plFn, "should return a string")
				return ""
			} else {
				return string(v)
			}
		}
		return ""
	}
}

// NewStatusLine returns a statusline bound to a window
func NewStatusLine(win *BufWindow) *StatusLine {
	s := new(StatusLine)
	s.win = win
	return s
}

// FindOpt finds a given option in the current buffer's settings
func (s *StatusLine) FindOpt(opt string) interface{} {
	if val, ok := s.win.Buf.Settings[opt]; ok {
		return val
	}
	return "null"
}

var formatParser = regexp.MustCompile(`\$\(.+?\)`)

// Display draws the statusline to the screen
func (s *StatusLine) Display() {
	// We'll draw the line at the lowest line in the window
	y := s.win.Height + s.win.Y - 1

	b := s.win.Buf
	// autocomplete suggestions (for the buffer, not for the infowindow)
	if b.HasSuggestions && len(b.Suggestions) > 1 {
		statusLineStyle := config.DefStyle.Reverse(true)
		if style, ok := config.Colorscheme["statusline"]; ok {
			statusLineStyle = style
		}
		keymenuOffset := 0
		if config.GetGlobalOption("keymenu").(bool) {
			keymenuOffset = len(keydisplay)
		}
		x := 0
		for j, sug := range b.Suggestions {
			style := statusLineStyle
			if b.CurSuggestion == j {
				style = style.Reverse(true)
			}
			for _, r := range sug {
				screen.SetContent(x, y-keymenuOffset, r, nil, style)
				x++
				if x >= s.win.Width {
					return
				}
			}
			screen.SetContent(x, y-keymenuOffset, ' ', nil, statusLineStyle)
			x++
			if x >= s.win.Width {
				return
			}
		}

		for x < s.win.Width {
			screen.SetContent(x, y-keymenuOffset, ' ', nil, statusLineStyle)
			x++
		}
		return
	}

	formatter := func(match []byte) []byte {
		name := match[2 : len(match)-1]
		if bytes.HasPrefix(name, []byte("opt")) {
			option := name[4:]
			return []byte(fmt.Sprint(s.FindOpt(string(option))))
		} else if bytes.HasPrefix(name, []byte("bind")) {
			binding := string(name[5:])
			for k, v := range config.Bindings {
				if v == binding {
					return []byte(k)
				}
			}
			return []byte("null")
		} else {
			if fn, ok := statusInfo[string(name)]; ok {
				return []byte(fn(s.win.Buf))
			}
			return []byte{}
		}
	}

	leftText := []byte(s.win.Buf.Settings["statusformatl"].(string))
	leftText = formatParser.ReplaceAllFunc(leftText, formatter)
	rightText := []byte(s.win.Buf.Settings["statusformatr"].(string))
	rightText = formatParser.ReplaceAllFunc(rightText, formatter)

	statusLineStyle := config.DefStyle.Reverse(true)
	if style, ok := config.Colorscheme["statusline"]; ok {
		statusLineStyle = style
	}

	leftLen := util.StringWidth(leftText, utf8.RuneCount(leftText), 1)
	rightLen := util.StringWidth(rightText, utf8.RuneCount(rightText), 1)

	winX := s.win.X
	for x := 0; x < s.win.Width; x++ {
		if x < leftLen {
			r, size := utf8.DecodeRune(leftText)
			leftText = leftText[size:]
			rw := runewidth.RuneWidth(r)
			for j := 0; j < rw; j++ {
				c := r
				if j > 0 {
					c = ' '
					x++
				}
				screen.SetContent(winX+x, y, c, nil, statusLineStyle)
			}
		} else if x >= s.win.Width-rightLen && x < rightLen+s.win.Width-rightLen {
			r, size := utf8.DecodeRune(rightText)
			rightText = rightText[size:]
			rw := runewidth.RuneWidth(r)
			for j := 0; j < rw; j++ {
				c := r
				if j > 0 {
					c = ' '
					x++
				}
				screen.SetContent(winX+x, y, c, nil, statusLineStyle)
			}
		} else {
			screen.SetContent(winX+x, y, ' ', nil, statusLineStyle)
		}
	}
}
<|endoftext|>


<commit_before>package command

import (
	"os"
	"strings"
	"testing"

	"github.com/mitchellh/cli"

	"github.com/hashicorp/terraform/addrs"
	"github.com/hashicorp/terraform/plans"
	"github.com/hashicorp/terraform/states"
)

func TestGraph(t *testing.T) {
	tmp, cwd := testCwd(t)
	defer testFixCwd(t, tmp, cwd)

	ui := new(cli.MockUi)
	c := &GraphCommand{
		Meta: Meta{
			testingOverrides: metaOverridesForProvider(testProvider()),
			Ui:               ui,
		},
	}

	args := []string{
		testFixturePath("graph"),
	}
	if code := c.Run(args); code != 0 {
		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
	}

	output := ui.OutputWriter.String()
	if !strings.Contains(output, "provider.test") {
		t.Fatalf("doesn't look like digraph: %s", output)
	}
}

func TestGraph_multipleArgs(t *testing.T) {
	ui := new(cli.MockUi)
	c := &GraphCommand{
		Meta: Meta{
			testingOverrides: metaOverridesForProvider(testProvider()),
			Ui:               ui,
		},
	}

	args := []string{
		"bad",
		"bad",
	}
	if code := c.Run(args); code != 1 {
		t.Fatalf("bad: \n%s", ui.OutputWriter.String())
	}
}

func TestGraph_noArgs(t *testing.T) {
	cwd, err := os.Getwd()
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	if err := os.Chdir(testFixturePath("graph")); err != nil {
		t.Fatalf("err: %s", err)
	}
	defer os.Chdir(cwd)

	ui := new(cli.MockUi)
	c := &GraphCommand{
		Meta: Meta{
			testingOverrides: metaOverridesForProvider(testProvider()),
			Ui:               ui,
		},
	}

	args := []string{}
	if code := c.Run(args); code != 0 {
		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
	}

	output := ui.OutputWriter.String()
	if !strings.Contains(output, "provider.test") {
		t.Fatalf("doesn't look like digraph: %s", output)
	}
}

func TestGraph_noConfig(t *testing.T) {
	td := tempDir(t)
	os.MkdirAll(td, 0755)
	defer os.RemoveAll(td)
	defer testChdir(t, td)()

	ui := new(cli.MockUi)
	c := &GraphCommand{
		Meta: Meta{
			testingOverrides: metaOverridesForProvider(testProvider()),
			Ui:               ui,
		},
	}

	// Running the graph command without a config should not panic,
	// but this may be an error at some point in the future.
	args := []string{"-type", "apply"}
	if code := c.Run(args); code != 0 {
		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
	}
}

func TestGraph_plan(t *testing.T) {
	tmp, cwd := testCwd(t)
	defer testFixCwd(t, tmp, cwd)

	plan := &plans.Plan{
		Changes: plans.NewChanges(),
	}
	plan.Changes.Resources = append(plan.Changes.Resources, &plans.ResourceInstanceChangeSrc{
		Addr: addrs.Resource{
			Mode: addrs.ManagedResourceMode,
			Type: "test_instance",
			Name: "bar",
		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
		ChangeSrc: plans.ChangeSrc{
			Action: plans.Delete,
			Before: plans.DynamicValue(`{}`),
			After:  plans.DynamicValue(`null`),
		},
		ProviderAddr: addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance),
	})
	_, configSnap := testModuleWithSnapshot(t, "graph")

	planPath := testPlanFile(t, configSnap, states.NewState(), plan)

	ui := new(cli.MockUi)
	c := &GraphCommand{
		Meta: Meta{
			testingOverrides: metaOverridesForProvider(testProvider()),
			Ui:               ui,
		},
	}

	args := []string{
		planPath,
	}
	if code := c.Run(args); code != 0 {
		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
	}

	output := ui.OutputWriter.String()
	if !strings.Contains(output, "provider.test") {
		t.Fatalf("doesn't look like digraph: %s", output)
	}
}
<commit_msg>command: Fix TestGraph_plan<commit_after>package command

import (
	"os"
	"strings"
	"testing"

	"github.com/mitchellh/cli"
	"github.com/zclconf/go-cty/cty"

	"github.com/hashicorp/terraform/addrs"
	"github.com/hashicorp/terraform/plans"
	"github.com/hashicorp/terraform/states"
)

func TestGraph(t *testing.T) {
	tmp, cwd := testCwd(t)
	defer testFixCwd(t, tmp, cwd)

	ui := new(cli.MockUi)
	c := &GraphCommand{
		Meta: Meta{
			testingOverrides: metaOverridesForProvider(testProvider()),
			Ui:               ui,
		},
	}

	args := []string{
		testFixturePath("graph"),
	}
	if code := c.Run(args); code != 0 {
		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
	}

	output := ui.OutputWriter.String()
	if !strings.Contains(output, "provider.test") {
		t.Fatalf("doesn't look like digraph: %s", output)
	}
}

func TestGraph_multipleArgs(t *testing.T) {
	ui := new(cli.MockUi)
	c := &GraphCommand{
		Meta: Meta{
			testingOverrides: metaOverridesForProvider(testProvider()),
			Ui:               ui,
		},
	}

	args := []string{
		"bad",
		"bad",
	}
	if code := c.Run(args); code != 1 {
		t.Fatalf("bad: \n%s", ui.OutputWriter.String())
	}
}

func TestGraph_noArgs(t *testing.T) {
	cwd, err := os.Getwd()
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	if err := os.Chdir(testFixturePath("graph")); err != nil {
		t.Fatalf("err: %s", err)
	}
	defer os.Chdir(cwd)

	ui := new(cli.MockUi)
	c := &GraphCommand{
		Meta: Meta{
			testingOverrides: metaOverridesForProvider(testProvider()),
			Ui:               ui,
		},
	}

	args := []string{}
	if code := c.Run(args); code != 0 {
		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
	}

	output := ui.OutputWriter.String()
	if !strings.Contains(output, "provider.test") {
		t.Fatalf("doesn't look like digraph: %s", output)
	}
}

func TestGraph_noConfig(t *testing.T) {
	td := tempDir(t)
	os.MkdirAll(td, 0755)
	defer os.RemoveAll(td)
	defer testChdir(t, td)()

	ui := new(cli.MockUi)
	c := &GraphCommand{
		Meta: Meta{
			testingOverrides: metaOverridesForProvider(testProvider()),
			Ui:               ui,
		},
	}

	// Running the graph command without a config should not panic,
	// but this may be an error at some point in the future.
	args := []string{"-type", "apply"}
	if code := c.Run(args); code != 0 {
		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
	}
}

func TestGraph_plan(t *testing.T) {
	tmp, cwd := testCwd(t)
	defer testFixCwd(t, tmp, cwd)

	plan := &plans.Plan{
		Changes: plans.NewChanges(),
	}
	plan.Changes.Resources = append(plan.Changes.Resources, &plans.ResourceInstanceChangeSrc{
		Addr: addrs.Resource{
			Mode: addrs.ManagedResourceMode,
			Type: "test_instance",
			Name: "bar",
		}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
		ChangeSrc: plans.ChangeSrc{
			Action: plans.Delete,
			Before: plans.DynamicValue(`{}`),
			After:  plans.DynamicValue(`null`),
		},
		ProviderAddr: addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance),
	})
	emptyConfig, err := plans.NewDynamicValue(cty.EmptyObjectVal, cty.EmptyObject)
	if err != nil {
		t.Fatal(err)
	}
	plan.Backend = plans.Backend{
		// Doesn't actually matter since we aren't going to activate the backend
		// for this command anyway, but we need something here for the plan
		// file writer to succeed.
		Type:   "placeholder",
		Config: emptyConfig,
	}
	_, configSnap := testModuleWithSnapshot(t, "graph")

	planPath := testPlanFile(t, configSnap, states.NewState(), plan)

	ui := new(cli.MockUi)
	c := &GraphCommand{
		Meta: Meta{
			testingOverrides: metaOverridesForProvider(testProvider()),
			Ui:               ui,
		},
	}

	args := []string{
		planPath,
	}
	if code := c.Run(args); code != 0 {
		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
	}

	output := ui.OutputWriter.String()
	if !strings.Contains(output, "provider.test") {
		t.Fatalf("doesn't look like digraph: %s", output)
	}
}
<|endoftext|>


<commit_before>package command

import (
	"fmt"
	"strings"
)

type NodeDrainCommand struct {
	Meta
}

func (c *NodeDrainCommand) Help() string {
	helpText := `
Usage: nomad node-drain [options] <node>

  Toggles node draining on a specified node. It is required
  that either -enable or -disable is specified, but not both.

General Options:

  ` + generalOptionsUsage() + `

Node Drain Options:

  -disable
    Disable draining for the specified node.

  -enable
    Enable draining for the specified node.

  -yes
    Automatic yes to prompts.
`
	return strings.TrimSpace(helpText)
}

func (c *NodeDrainCommand) Synopsis() string {
	return "Toggle drain mode on a given node"
}

func (c *NodeDrainCommand) Run(args []string) int {
	var enable, disable, autoYes bool

	flags := c.Meta.FlagSet("node-drain", FlagSetClient)
	flags.Usage = func() { c.Ui.Output(c.Help()) }
	flags.BoolVar(&enable, "enable", false, "Enable drain mode")
	flags.BoolVar(&disable, "disable", false, "Disable drain mode")
	flags.BoolVar(&autoYes, "yes", false, "Automatic yes to prompts.")

	if err := flags.Parse(args); err != nil {
		return 1
	}

	// Check that we got either enable or disable, but not both.
	if (enable && disable) || (!enable && !disable) {
		c.Ui.Error(c.Help())
		return 1
	}

	// Check that we got a node ID
	args = flags.Args()
	if len(args) != 1 {
		c.Ui.Error(c.Help())
		return 1
	}
	nodeID := args[0]

	// Get the HTTP client
	client, err := c.Meta.Client()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
		return 1
	}

	// Check if node exists
	if len(nodeID) == 1 {
		c.Ui.Error(fmt.Sprintf("Identifier must contain at least two characters."))
		return 1
	}
	if len(nodeID)%2 == 1 {
		// Identifiers must be of even length, so we strip off the last byte
		// to provide a consistent user experience.
		nodeID = nodeID[:len(nodeID)-1]
	}

	// Exact lookup failed, try with prefix based search
	nodes, _, err := client.Nodes().PrefixList(nodeID)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error toggling drain mode: %s", err))
		return 1
	}
	// Return error if no nodes are found
	if len(nodes) == 0 {
		c.Ui.Error(fmt.Sprintf("No node(s) with prefix or id %q found", nodeID))
		return 1
	}
	if len(nodes) > 1 {
		// Format the nodes list that matches the prefix so that the user
		// can create a more specific request
		out := make([]string, len(nodes)+1)
		out[0] = "ID|Datacenter|Name|Class|Drain|Status"
		for i, node := range nodes {
			out[i+1] = fmt.Sprintf("%s|%s|%s|%s|%v|%s",
				node.ID,
				node.Datacenter,
				node.Name,
				node.NodeClass,
				node.Drain,
				node.Status)
		}
		// Dump the output
		c.Ui.Output(fmt.Sprintf("Prefix matched multiple nodes\n\n%s", formatList(out)))
		return 0
	}

	// Prefix lookup matched a single node
	node, _, err := client.Nodes().Info(nodes[0].ID, nil)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error toggling drain mode: %s", err))
		return 1
	}

	// Confirm drain if the node was a prefix match.
	if nodeID != node.ID && !autoYes {
		verb := "enable"
		if disable {
			verb = "disable"
		}
		question := fmt.Sprintf("Are you sure you want to %s drain mode for node %q? [y/N]", verb, node.ID)
		answer, err := c.Ui.Ask(question)
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Failed to parse answer: %v", err))
			return 1
		}

		if answer == "" || strings.ToLower(answer)[0] == 'n' {
			// No case
			c.Ui.Output("Canceling drain toggle")
			return 0
		} else if strings.ToLower(answer)[0] == 'y' {
			// Non exact match yes
			c.Ui.Output("For confirmation, an exact ‘y’ is required.")
			return 0
		} else if answer != "y" {
			c.Ui.Output("No confirmation detected. For confirmation, an exact 'y' is required.")
			return 1
		}
	}

	// Toggle node draining
	if _, err := client.Nodes().ToggleDrain(node.ID, enable, nil); err != nil {
		c.Ui.Error(fmt.Sprintf("Error toggling drain mode: %s", err))
		return 1
	}
	return 0
}
<commit_msg>Fixes the logic for node drain confirmation prompt<commit_after>package command

import (
	"fmt"
	"strings"
)

type NodeDrainCommand struct {
	Meta
}

func (c *NodeDrainCommand) Help() string {
	helpText := `
Usage: nomad node-drain [options] <node>

  Toggles node draining on a specified node. It is required
  that either -enable or -disable is specified, but not both.

General Options:

  ` + generalOptionsUsage() + `

Node Drain Options:

  -disable
    Disable draining for the specified node.

  -enable
    Enable draining for the specified node.

  -yes
    Automatic yes to prompts.
`
	return strings.TrimSpace(helpText)
}

func (c *NodeDrainCommand) Synopsis() string {
	return "Toggle drain mode on a given node"
}

func (c *NodeDrainCommand) Run(args []string) int {
	var enable, disable, autoYes bool

	flags := c.Meta.FlagSet("node-drain", FlagSetClient)
	flags.Usage = func() { c.Ui.Output(c.Help()) }
	flags.BoolVar(&enable, "enable", false, "Enable drain mode")
	flags.BoolVar(&disable, "disable", false, "Disable drain mode")
	flags.BoolVar(&autoYes, "yes", false, "Automatic yes to prompts.")

	if err := flags.Parse(args); err != nil {
		return 1
	}

	// Check that we got either enable or disable, but not both.
	if (enable && disable) || (!enable && !disable) {
		c.Ui.Error(c.Help())
		return 1
	}

	// Check that we got a node ID
	args = flags.Args()
	if len(args) != 1 {
		c.Ui.Error(c.Help())
		return 1
	}
	nodeID := args[0]

	// Get the HTTP client
	client, err := c.Meta.Client()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
		return 1
	}

	// Check if node exists
	if len(nodeID) == 1 {
		c.Ui.Error(fmt.Sprintf("Identifier must contain at least two characters."))
		return 1
	}
	if len(nodeID)%2 == 1 {
		// Identifiers must be of even length, so we strip off the last byte
		// to provide a consistent user experience.
		nodeID = nodeID[:len(nodeID)-1]
	}

	// Exact lookup failed, try with prefix based search
	nodes, _, err := client.Nodes().PrefixList(nodeID)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error toggling drain mode: %s", err))
		return 1
	}
	// Return error if no nodes are found
	if len(nodes) == 0 {
		c.Ui.Error(fmt.Sprintf("No node(s) with prefix or id %q found", nodeID))
		return 1
	}
	if len(nodes) > 1 {
		// Format the nodes list that matches the prefix so that the user
		// can create a more specific request
		out := make([]string, len(nodes)+1)
		out[0] = "ID|Datacenter|Name|Class|Drain|Status"
		for i, node := range nodes {
			out[i+1] = fmt.Sprintf("%s|%s|%s|%s|%v|%s",
				node.ID,
				node.Datacenter,
				node.Name,
				node.NodeClass,
				node.Drain,
				node.Status)
		}
		// Dump the output
		c.Ui.Output(fmt.Sprintf("Prefix matched multiple nodes\n\n%s", formatList(out)))
		return 0
	}

	// Prefix lookup matched a single node
	node, _, err := client.Nodes().Info(nodes[0].ID, nil)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error toggling drain mode: %s", err))
		return 1
	}

	// Confirm drain if the node was a prefix match.
	if nodeID != node.ID && !autoYes {
		verb := "enable"
		if disable {
			verb = "disable"
		}
		question := fmt.Sprintf("Are you sure you want to %s drain mode for node %q? [y/N]", verb, node.ID)
		answer, err := c.Ui.Ask(question)
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Failed to parse answer: %v", err))
			return 1
		}

		if answer == "" || strings.ToLower(answer)[0] == 'n' {
			// No case
			c.Ui.Output("Canceling drain toggle")
			return 0
		} else if strings.ToLower(answer)[0] == 'y' && len(answer) > 1 {
			// Non exact match yes
			c.Ui.Output("For confirmation, an exact ‘y’ is required.")
			return 0
		} else if answer != "y" {
			c.Ui.Output("No confirmation detected. For confirmation, an exact 'y' is required.")
			return 1
		}
	}

	// Toggle node draining
	if _, err := client.Nodes().ToggleDrain(node.ID, enable, nil); err != nil {
		c.Ui.Error(fmt.Sprintf("Error toggling drain mode: %s", err))
		return 1
	}
	return 0
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"io/ioutil"
	"strings"
	"text/template"

	"encoding/base64"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/kms"
)

// Common Functions - Both Deploy/Gen

var kmsEncrypt = func(kid string, text string) (string, error) {
	sess, err := manager.GetSess(job.profile)
	if err != nil {
		Log(err.Error(), level.err)
		return "", err
	}

	svc := kms.New(sess)

	params := &kms.EncryptInput{
		KeyId:     aws.String(kid),
		Plaintext: []byte(text),
	}

	resp, err := svc.Encrypt(params)
	if err != nil {
		Log(err.Error(), level.err)
		return "", err
	}

	return base64.StdEncoding.EncodeToString(resp.CiphertextBlob), nil
}

var kmsDecrypt = func(cipher string) (string, error) {
	sess, err := manager.GetSess(job.profile)
	if err != nil {
		Log(err.Error(), level.err)
		return "", err
	}

	svc := kms.New(sess)

	ciph, err := base64.StdEncoding.DecodeString(cipher)
	if err != nil {
		Log(err.Error(), level.err)
		return "", err
	}

	params := &kms.DecryptInput{
		CiphertextBlob: []byte(ciph),
	}

	resp, err := svc.Decrypt(params)
	if err != nil {
		Log(err.Error(), level.err)
		return "", err
	}

	return string(resp.Plaintext), nil
}

var httpGet = func(url string) (interface{}, error) {
	Log(fmt.Sprintln("Calling Template Function [GET] with arguments:", url), level.debug)
	resp, err := Get(url)
	if err != nil {
		Log(err.Error(), level.err)
		return "", err
	}

	return resp, nil
}

var s3Read = func(url string) (string, error) {
	Log(fmt.Sprintln("Calling Template Function [S3Read] with arguments:", url), level.debug)
	resp, err := S3Read(url)
	if err != nil {
		Log(err.Error(), level.err)
		return "", err
	}
	return resp, nil
}

var lambdaInvoke = func(name string, payload string) (interface{}, error) {
	f := function{name: name}
	if payload != "" {
		f.payload = []byte(payload)
	}

	sess, err := manager.GetSess(job.profile)
	if err != nil {
		Log(err.Error(), level.err)
		return "", err
	}

	if err := f.Invoke(sess); err != nil {
		Log(err.Error(), level.err)
		return "", err
	}

	return f.response, nil
}

// template function maps

var genTimeFunctions = template.FuncMap{
	// simple additon function useful for counters in loops
	"add": func(a int, b int) int {
		Log(fmt.Sprintln("Calling Template Function [add] with arguments:", a, b), level.debug)
		return a + b
	},

	// strip function for removing characters from text
	"strip": func(s string, rmv string) string {
		Log(fmt.Sprintln("Calling Template Function [strip] with arguments:", s, rmv), level.debug)
		return strings.Replace(s, rmv, "", -1)
	},

	// cat function for reading text from a given file under the files folder
	"cat": func(path string) (string, error) {

		Log(fmt.Sprintln("Calling Template Function [cat] with arguments:", path), level.debug)
		b, err := ioutil.ReadFile(path)
		if err != nil {
			Log(err.Error(), level.err)
			return "", err
		}
		return string(b), nil
	},

	// Get get does an HTTP Get request of the given url and returns the output string
	"GET": httpGet,

	// S3Read reads content of file from s3 and returns string contents
	"s3_read": s3Read,

	// invoke - invokes a lambda function
	"invoke": lambdaInvoke,

	// kms-encrypt - Encrypts PlainText using KMS key
	"kms_encrypt": kmsEncrypt,

	// kms-decrypt - Descrypts CipherText
	"kms_decrypt": kmsDecrypt,
}

var deployTimeFunctions = template.FuncMap{
	// Fetching stackoutputs
	"stack_output": func(target string) (string, error) {
		Log(fmt.Sprintf("Deploy-Time function resolving: %s", target), level.debug)
		req := strings.Split(target, "::")

		s := stacks[req[0]]

		if err := s.outputs(); err != nil {
			return "", err
		}

		for _, i := range s.output.Stacks {
			for _, o := range i.Outputs {
				if *o.OutputKey == req[1] {
					return *o.OutputValue, nil
				}
			}
		}

		return "", fmt.Errorf("Stack Output Not found - Stack:%s | Output:%s", req[0], req[1])
	},

	"stack_output_ext": func(target string) (string, error) {
		Log(fmt.Sprintf("Deploy-Time function resolving: %s", target), level.debug)
		req := strings.Split(target, "::")

		sess, err := manager.GetSess(job.profile)
		if err != nil {
			Log(err.Error(), level.err)
			return "", nil
		}

		s := stack{
			stackname: req[0],
			session:   sess,
		}

		if err := s.outputs(); err != nil {
			return "", err
		}

		for _, i := range s.output.Stacks {
			for _, o := range i.Outputs {
				if *o.OutputKey == req[1] {
					return *o.OutputValue, nil
				}
			}
		}

		return "", fmt.Errorf("Stack Output Not found - Stack:%s | Output:%s", req[0], req[1])
	},

	// Get get does an HTTP Get request of the given url and returns the output string
	"GET": httpGet,

	// S3Read reads content of file from s3 and returns string contents
	"s3_read": s3Read,

	// invoke - invokes a lambda function
	"invoke": lambdaInvoke,

	// kms-encrypt - Encrypts PlainText using KMS key
	"kms_encrypt": kmsEncrypt,

	// kms-decrypt - Descrypts CipherText
	"kms_decrypt": kmsDecrypt,
}
<commit_msg>added new functions for string testing, prefix, suffix, contains<commit_after>package commands

import (
	"fmt"
	"io/ioutil"
	"strings"
	"text/template"

	"encoding/base64"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/kms"
)

// Common Functions - Both Deploy/Gen

var kmsEncrypt = func(kid string, text string) (string, error) {
	sess, err := manager.GetSess(job.profile)
	if err != nil {
		Log(err.Error(), level.err)
		return "", err
	}

	svc := kms.New(sess)

	params := &kms.EncryptInput{
		KeyId:     aws.String(kid),
		Plaintext: []byte(text),
	}

	resp, err := svc.Encrypt(params)
	if err != nil {
		Log(err.Error(), level.err)
		return "", err
	}

	return base64.StdEncoding.EncodeToString(resp.CiphertextBlob), nil
}

var kmsDecrypt = func(cipher string) (string, error) {
	sess, err := manager.GetSess(job.profile)
	if err != nil {
		Log(err.Error(), level.err)
		return "", err
	}

	svc := kms.New(sess)

	ciph, err := base64.StdEncoding.DecodeString(cipher)
	if err != nil {
		Log(err.Error(), level.err)
		return "", err
	}

	params := &kms.DecryptInput{
		CiphertextBlob: []byte(ciph),
	}

	resp, err := svc.Decrypt(params)
	if err != nil {
		Log(err.Error(), level.err)
		return "", err
	}

	return string(resp.Plaintext), nil
}

var httpGet = func(url string) (interface{}, error) {
	Log(fmt.Sprintln("Calling Template Function [GET] with arguments:", url), level.debug)
	resp, err := Get(url)
	if err != nil {
		Log(err.Error(), level.err)
		return "", err
	}

	return resp, nil
}

var s3Read = func(url string) (string, error) {
	Log(fmt.Sprintln("Calling Template Function [S3Read] with arguments:", url), level.debug)
	resp, err := S3Read(url)
	if err != nil {
		Log(err.Error(), level.err)
		return "", err
	}
	return resp, nil
}

var lambdaInvoke = func(name string, payload string) (interface{}, error) {
	f := function{name: name}
	if payload != "" {
		f.payload = []byte(payload)
	}

	sess, err := manager.GetSess(job.profile)
	if err != nil {
		Log(err.Error(), level.err)
		return "", err
	}

	if err := f.Invoke(sess); err != nil {
		Log(err.Error(), level.err)
		return "", err
	}

	return f.response, nil
}

var prefix = func(s string, pre string) bool {
	return strings.HasPrefix(s, pre)
}

var suffix = func(s string, suf string) bool {
	return strings.HasSuffix(s, suf)
}

var contains = func(s string, con string) bool {
	return strings.Contains(s, con)
}

// template function maps

var genTimeFunctions = template.FuncMap{
	// simple additon function useful for counters in loops
	"add": func(a int, b int) int {
		Log(fmt.Sprintln("Calling Template Function [add] with arguments:", a, b), level.debug)
		return a + b
	},

	// strip function for removing characters from text
	"strip": func(s string, rmv string) string {
		Log(fmt.Sprintln("Calling Template Function [strip] with arguments:", s, rmv), level.debug)
		return strings.Replace(s, rmv, "", -1)
	},

	// cat function for reading text from a given file under the files folder
	"cat": func(path string) (string, error) {

		Log(fmt.Sprintln("Calling Template Function [cat] with arguments:", path), level.debug)
		b, err := ioutil.ReadFile(path)
		if err != nil {
			Log(err.Error(), level.err)
			return "", err
		}
		return string(b), nil
	},

	// suffix - returns true if string starts with given suffix
	"suffix": suffix,

	// prefix - returns true if string starts with given prefix
	"prefix": prefix,

	// contains - returns true if string contains
	"contains": contains,

	// Get get does an HTTP Get request of the given url and returns the output string
	"GET": httpGet,

	// S3Read reads content of file from s3 and returns string contents
	"s3_read": s3Read,

	// invoke - invokes a lambda function
	"invoke": lambdaInvoke,

	// kms-encrypt - Encrypts PlainText using KMS key
	"kms_encrypt": kmsEncrypt,

	// kms-decrypt - Descrypts CipherText
	"kms_decrypt": kmsDecrypt,
}

var deployTimeFunctions = template.FuncMap{
	// Fetching stackoutputs
	"stack_output": func(target string) (string, error) {
		Log(fmt.Sprintf("Deploy-Time function resolving: %s", target), level.debug)
		req := strings.Split(target, "::")

		s := stacks[req[0]]

		if err := s.outputs(); err != nil {
			return "", err
		}

		for _, i := range s.output.Stacks {
			for _, o := range i.Outputs {
				if *o.OutputKey == req[1] {
					return *o.OutputValue, nil
				}
			}
		}

		return "", fmt.Errorf("Stack Output Not found - Stack:%s | Output:%s", req[0], req[1])
	},

	"stack_output_ext": func(target string) (string, error) {
		Log(fmt.Sprintf("Deploy-Time function resolving: %s", target), level.debug)
		req := strings.Split(target, "::")

		sess, err := manager.GetSess(job.profile)
		if err != nil {
			Log(err.Error(), level.err)
			return "", nil
		}

		s := stack{
			stackname: req[0],
			session:   sess,
		}

		if err := s.outputs(); err != nil {
			return "", err
		}

		for _, i := range s.output.Stacks {
			for _, o := range i.Outputs {
				if *o.OutputKey == req[1] {
					return *o.OutputValue, nil
				}
			}
		}

		return "", fmt.Errorf("Stack Output Not found - Stack:%s | Output:%s", req[0], req[1])
	},

	// suffix - returns true if string starts with given suffix
	"suffix": suffix,

	// prefix - returns true if string starts with given prefix
	"prefix": prefix,

	// contains - returns true if string contains
	"contains": contains,

	// Get get does an HTTP Get request of the given url and returns the output string
	"GET": httpGet,

	// S3Read reads content of file from s3 and returns string contents
	"s3_read": s3Read,

	// invoke - invokes a lambda function
	"invoke": lambdaInvoke,

	// kms-encrypt - Encrypts PlainText using KMS key
	"kms_encrypt": kmsEncrypt,

	// kms-decrypt - Descrypts CipherText
	"kms_decrypt": kmsDecrypt,
}
<|endoftext|>


<commit_before>package imdb

import (
	"encoding/json"
	"log"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/igungor/ilberbot"
)

var (
	// Use upstream api if needed: http://www.imdb.com/xml/find?xml=1&nr=1&tt=on&q=lost
	baseURL      = "http://www.omdbapi.com/"
	imdbTitleURL = "http://www.imdb.com/title/"
	client       = http.Client{Timeout: 10 * time.Second}
)

func init() {
	ilberbot.RegisterCommand("/imdb", imdb)
}

type Response struct {
	ID       string `json:"imdbID"`
	Rating   string `json:"imdbRating"`
	Type     string
	Title    string
	Year     string
	Released string
	Runtime  string
	Genre    string
	Director string
	Writer   string
	Actors   string
	Plot     string
	Language string
	Country  string
}

func imdb(args ...string) string {
	if args == nil {
		log.Println("image: no argument supplied")
		return ""
	}

	arg := strings.Join(args, "+")

	u, _ := url.Parse(baseURL)
	v := u.Query()
	v.Set("t", arg)    // movie title
	v.Set("r", "json") // return type
	u.RawQuery = v.Encode()

	resp, err := http.Get(u.String())
	if err != nil {
		log.Println(err)
		return ""
	}
	defer resp.Body.Close()

	var response Response
	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
		log.Printf("decode error: %v", err)
		return ""
	}

	if response.ID == "" {
		log.Printf("imdb: no title found")
		return ""
	}

	return imdbTitleURL + response.ID
}
<commit_msg>fix wrong response format for imdb api<commit_after>package imdb

import (
	"encoding/json"
	"log"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/igungor/ilberbot"
)

var (
	// Use upstream api if needed: http://www.imdb.com/xml/find?json=1&nr=1&tt=on&q=lost
	baseURL      = "http://www.omdbapi.com/"
	imdbTitleURL = "http://www.imdb.com/title/"
	client       = http.Client{Timeout: 10 * time.Second}
)

func init() {
	ilberbot.RegisterCommand("/imdb", imdb)
}

type Response struct {
	ID       string `json:"imdbID"`
	Rating   string `json:"imdbRating"`
	Type     string
	Title    string
	Year     string
	Released string
	Runtime  string
	Genre    string
	Director string
	Writer   string
	Actors   string
	Plot     string
	Language string
	Country  string
}

func imdb(args ...string) string {
	if args == nil {
		log.Println("image: no argument supplied")
		return ""
	}

	arg := strings.Join(args, "+")

	u, _ := url.Parse(baseURL)
	v := u.Query()
	v.Set("t", arg)    // movie title
	v.Set("r", "json") // return type
	u.RawQuery = v.Encode()

	resp, err := http.Get(u.String())
	if err != nil {
		log.Println(err)
		return ""
	}
	defer resp.Body.Close()

	var response Response
	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
		log.Printf("decode error: %v", err)
		return ""
	}

	if response.ID == "" {
		log.Printf("imdb: no title found")
		return ""
	}

	return imdbTitleURL + response.ID
}
<|endoftext|>