<commit_before>/*
  Go Language Raspberry Pi Interface
  (c) Copyright David Thorpe 2016-2020
  All Rights Reserved
  For Licensing and Usage information, please see LICENSE.md
*/

package base

import (
	"fmt"
	"io"
	"strconv"

	// Frameworks
	"github.com/djthorpe/gopi/v2"
)

////////////////////////////////////////////////////////////////////////////////
// TYPES

// Logger is the base struct for any logger
type Logger struct {
	name   string
	writer io.Writer
	debug  bool
	Unit
}

////////////////////////////////////////////////////////////////////////////////
// IMPLEMENTATION gopi.Logger

func (this *Logger) Init(writer io.Writer, name string, debug bool) error {
	if name == "" {
		return gopi.ErrBadParameter.WithPrefix("name")
	} else if writer == nil {
		return gopi.ErrBadParameter.WithPrefix("writer")
	} else if err := this.Unit.Init(nil); err != nil {
		return err
	} else {
		this.writer = writer
		this.name = name
		this.debug = debug
		return nil
	}
}

func (this *Logger) String() string {
	return "<gopi.Logger name=" + strconv.Quote(this.name) + " debug=" + fmt.Sprint(this.debug) + ">"
}

func (this *Logger) Error(err error) error {
	if this.name != "" {
		err = fmt.Errorf("%s: %w", this.name, err)
	}
	fmt.Fprintln(this.writer, err)
	return err
}

func (this *Logger) Warn(args ...interface{}) {
	if this.debug {
		fmt.Fprintln(this.writer, append([]interface{}{"[WARN]"}, args...)...)
	}
}

func (this *Logger) Info(args ...interface{}) {
	if this.debug {
		fmt.Fprintln(this.writer, append([]interface{}{"[INFO]"}, args...)...)
	}
}

func (this *Logger) Debug(args ...interface{}) {
	if this.debug {
		fmt.Fprintln(this.writer, append([]interface{}{"[DEBUG]"}, args...)...)
	}
}

func (this *Logger) IsDebug() bool {
	return this.debug
}

func (this *Logger) Name() string {
	return this.name
}

func (this *Logger) Clone(name string) gopi.Logger {
	that := &Logger{
		name:   name,
		writer: this.writer,
		debug:  this.debug,
	}
	if err := that.Unit.Init(this); err != nil {
		return nil
	} else {
		return that
	}
}
<commit_msg>Updated logger so that info and warn get displayed<commit_after>/*
  Go Language Raspberry Pi Interface
  (c) Copyright David Thorpe 2016-2020
  All Rights Reserved
  For Licensing and Usage information, please see LICENSE.md
*/

package base

import (
	"fmt"
	"io"
	"strconv"

	// Frameworks
	"github.com/djthorpe/gopi/v2"
)

////////////////////////////////////////////////////////////////////////////////
// TYPES

// Logger is the base struct for any logger
type Logger struct {
	name   string
	writer io.Writer
	debug  bool
	Unit
}

////////////////////////////////////////////////////////////////////////////////
// IMPLEMENTATION gopi.Logger

func (this *Logger) Init(writer io.Writer, name string, debug bool) error {
	if name == "" {
		return gopi.ErrBadParameter.WithPrefix("name")
	} else if writer == nil {
		return gopi.ErrBadParameter.WithPrefix("writer")
	} else if err := this.Unit.Init(nil); err != nil {
		return err
	} else {
		this.writer = writer
		this.name = name
		this.debug = debug
		return nil
	}
}

func (this *Logger) String() string {
	return "<gopi.Logger name=" + strconv.Quote(this.name) + " debug=" + fmt.Sprint(this.debug) + ">"
}

func (this *Logger) Error(err error) error {
	if this.name != "" {
		err = fmt.Errorf("%s: %w", this.name, err)
	}
	fmt.Fprintln(this.writer, "[ERROR]", err)
	return err
}

func (this *Logger) Warn(args ...interface{}) {
	fmt.Fprintln(this.writer, append([]interface{}{"[WARN]"}, args...)...)
}

func (this *Logger) Info(args ...interface{}) {
	fmt.Fprintln(this.writer, append([]interface{}{"[INFO]"}, args...)...)
}

func (this *Logger) Debug(args ...interface{}) {
	if this.debug {
		fmt.Fprintln(this.writer, append([]interface{}{"[DEBUG]"}, args...)...)
	}
}

func (this *Logger) IsDebug() bool {
	return this.debug
}

func (this *Logger) Name() string {
	return this.name
}

func (this *Logger) Clone(name string) gopi.Logger {
	that := &Logger{
		name:   name,
		writer: this.writer,
		debug:  this.debug,
	}
	if err := that.Unit.Init(this); err != nil {
		return nil
	} else {
		return that
	}
}
<|endoftext|>


<commit_before>package internal

import (
	"github.com/maprost/application/generator/genmodel"
	"path"
	"runtime"
)

const (
	techSkill_Go = genmodel.SkillID(iota)
	techSkill_Java
	techSkill_Cpp
	techSkill_Latex
	techSkill_SoftwareDesign
	techSkill_IntelliJ
	techSkill_Ubuntu
	techSkill_PostgresSQL
	techSkill_Docker
	techSkill_Git
	techSkill_Docker
	techSkill_Docker
	techSkill_Docker
)

const (
	softSkillFriendly = genmodel.SkillID(iota)
)

func Profile() genmodel.Profile {
	_, file, _, _ := runtime.Caller(1)

	return genmodel.Profile{
		FirstName:   "maprost",
		LastName:    "",
		Image:       path.Dir(file) + "/images/cv",
		Birthday:    "",
		Email:       "N/A",
		Nationality: "german",
		Phone:       "N/A",
		Websites:    []string{"https://github.com/maprost"},
		Address: genmodel.Address{
			Street:  "",
			Zip:     "",
			City:    "",
			Country: "Germany",
		},
		ProfessionalSkills: map[genmodel.SkillID]genmodel.Skill{
			techSkill_Go:             {Name: "Go", Rating: 8},
			techSkill_Java:           {Name: "Java", Rating: 9},
			techSkill_SoftwareDesign: {Name: "Software Design", Rating: 9},
			techSkill_Cpp:            {Name: "C++", Rating: 5},
			techSkill_Latex:          {Name: "\\LaTeX", Rating: 7},
			techSkill_IntelliJ:       {Name: "IntelliJ", Rating: 6},
			techSkill_Ubuntu:         {Name: "Ubuntu", Rating: 6},
			techSkill_PostgresSQL:    {Name: "Postgres", Rating: 6},
			techSkill_Docker:         {Name: "Docker", Rating: 5},
			techSkill_Git:            {Name: "Git", Rating: 5},
		},
		SoftSkills: map[genmodel.SkillID]genmodel.Skill{
			softSkillFriendly: {Name: "friendly", Rating: 9},
		},
		Interest: []string{"CleanCode", "TDD", "Design Pattern"},
		Hobbies:  []string{"Boardgames"},
		Language: []genmodel.Language{
			{
				Name:  "German",
				Level: "Native",
			},
			{
				Name:  "English",
				Level: "B2",
			},
		},
		Experience: []genmodel.Experience{
			{
				Company:     "Lord Drug",
				JobPosition: "Joker",
				StartTime:   "Jun. 2014",
				EndTime:     "Jul 2026",
				Description: "Bring some fun to the people in my environment and let them laugh.",
				TechStack:   "MP5, Knifes",
			},
		},
		Education: []genmodel.Education{
			{
				School:      "LA School of Nowhere",
				StartTime:   "Aug 2000",
				EndTime:     "Sep 2000",
				Description: "Learn how to survive in a difficult area.",
			},
		},
	}
}
<commit_msg>improve example<commit_after>package internal

import (
	"github.com/maprost/application/generator/genmodel"
	"path"
	"runtime"
)

const (
	techSkill_Go = genmodel.SkillID(iota)
	techSkill_Java
	techSkill_Cpp
	techSkill_Latex
	techSkill_SoftwareDesign
	techSkill_IntelliJ
	techSkill_Ubuntu
	techSkill_PostgresSQL
	techSkill_Docker
	techSkill_Git
)

const (
	softSkillFriendly = genmodel.SkillID(iota)
)

func Profile() genmodel.Profile {
	_, file, _, _ := runtime.Caller(1)

	return genmodel.Profile{
		FirstName:   "maprost",
		LastName:    "",
		Image:       path.Dir(file) + "/images/cv",
		Birthday:    "",
		Email:       "N/A",
		Nationality: "german",
		Phone:       "N/A",
		Websites:    []string{"https://github.com/maprost"},
		Address: genmodel.Address{
			Street:  "",
			Zip:     "",
			City:    "",
			Country: "Germany",
		},
		ProfessionalSkills: map[genmodel.SkillID]genmodel.Skill{
			techSkill_Go:             {Name: "Go", Rating: 8},
			techSkill_Java:           {Name: "Java", Rating: 9},
			techSkill_SoftwareDesign: {Name: "Software Design", Rating: 9},
			techSkill_Cpp:            {Name: "C++", Rating: 5},
			techSkill_Latex:          {Name: "\\LaTeX", Rating: 7},
			techSkill_IntelliJ:       {Name: "IntelliJ", Rating: 6},
			techSkill_Ubuntu:         {Name: "Ubuntu", Rating: 6},
			techSkill_PostgresSQL:    {Name: "Postgres", Rating: 6},
			techSkill_Docker:         {Name: "Docker", Rating: 5},
			techSkill_Git:            {Name: "Git", Rating: 5},
		},
		SoftSkills: map[genmodel.SkillID]genmodel.Skill{
			softSkillFriendly: {Name: "friendly", Rating: 9},
		},
		Interest: []string{"CleanCode", "TDD", "Design Pattern"},
		Hobbies:  []string{"Boardgames"},
		Language: []genmodel.Language{
			{
				Name:  "German",
				Level: "Native",
			},
			{
				Name:  "English",
				Level: "B2",
			},
		},
		Experience: []genmodel.Experience{
			{
				Company:     "Lord Drug",
				JobPosition: "Joker",
				StartTime:   "Jun. 2014",
				EndTime:     "Jul 2026",
				Description: "Bring some fun to the people in my environment and let them laugh.",
				TechStack:   "MP5, Knifes",
			},
		},
		Education: []genmodel.Education{
			{
				School:      "LA School of Nowhere",
				StartTime:   "Aug 2000",
				EndTime:     "Sep 2000",
				Description: "Learn how to survive in a difficult area.",
			},
		},
	}
}
<|endoftext|>


<commit_before>package logrus

import (
	"bytes"
	"fmt"
	"sort"
	"strings"
	"sync"
	"time"
)

const (
	nocolor = 0
	red     = 31
	green   = 32
	yellow  = 33
	blue    = 34
	gray    = 37
)

var (
	baseTimestamp time.Time
)

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

type TextFormatter struct {
	// Set to true to bypass checking for a TTY before outputting colors.
	ForceColors bool

	// Force disabling colors.
	DisableColors bool

	// Disable timestamp logging. useful when output is redirected to logging
	// system that already adds timestamps.
	DisableTimestamp bool

	// Enable logging the full timestamp when a TTY is attached instead of just
	// the time passed since beginning of execution.
	FullTimestamp bool

	// TimestampFormat to use for display when a full timestamp is printed
	TimestampFormat string

	// The fields are sorted by default for a consistent output. For applications
	// that log extremely frequently and don't use the JSON formatter this may not
	// be desired.
	DisableSorting bool

	// QuoteEmptyFields will wrap empty fields in quotes if true
	QuoteEmptyFields bool

	// QuoteCharacter can be set to the override the default quoting character "
	// with something else. For example: ', or `.
	QuoteCharacter string

	// Whether the logger's out is to a terminal
	isTerminal bool

	sync.Once
}

func (f *TextFormatter) init(entry *Entry) {
	if len(f.QuoteCharacter) == 0 {
		f.QuoteCharacter = "\""
	}
	if entry.Logger != nil {
		f.isTerminal = IsTerminal(entry.Logger.Out)
	}
}

func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
	var b *bytes.Buffer
	keys := make([]string, 0, len(entry.Data))
	for k := range entry.Data {
		keys = append(keys, k)
	}

	if !f.DisableSorting {
		sort.Strings(keys)
	}
	if entry.Buffer != nil {
		b = entry.Buffer
	} else {
		b = &bytes.Buffer{}
	}

	prefixFieldClashes(entry.Data)

	f.Do(func() { f.init(entry) })

	isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors

	timestampFormat := f.TimestampFormat
	if timestampFormat == "" {
		timestampFormat = DefaultTimestampFormat
	}
	if isColored {
		f.printColored(b, entry, keys, timestampFormat)
	} else {
		if !f.DisableTimestamp {
			f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat))
		}
		f.appendKeyValue(b, "level", entry.Level.String())
		if entry.Message != "" {
			f.appendKeyValue(b, "msg", entry.Message)
		}
		for _, key := range keys {
			f.appendKeyValue(b, key, entry.Data[key])
		}
	}

	b.WriteByte('\n')
	return b.Bytes(), nil
}

func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) {
	var levelColor int
	switch entry.Level {
	case DebugLevel:
		levelColor = gray
	case WarnLevel:
		levelColor = yellow
	case ErrorLevel, FatalLevel, PanicLevel:
		levelColor = red
	default:
		levelColor = blue
	}

	levelText := strings.ToUpper(entry.Level.String())[0:4]

	if f.DisableTimestamp {
		fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message)
	} else if !f.FullTimestamp {
		fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), entry.Message)
	} else {
		fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
	}
	for _, k := range keys {
		v := entry.Data[k]
		fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k)
		f.appendValue(b, v)
	}
}

func (f *TextFormatter) needsQuoting(text string) bool {
	if f.QuoteEmptyFields && len(text) == 0 {
		return true
	}
	for _, ch := range text {
		if !((ch >= 'a' && ch <= 'z') ||
			(ch >= 'A' && ch <= 'Z') ||
			(ch >= '0' && ch <= '9') ||
			ch == '-' || ch == '.') {
			return true
		}
	}
	return false
}

func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {

	b.WriteString(key)
	b.WriteByte('=')
	f.appendValue(b, value)
	b.WriteByte(' ')
}

func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
	switch value := value.(type) {
	case string:
		if !f.needsQuoting(value) {
			b.WriteString(value)
		} else {
			fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, value, f.QuoteCharacter)
		}
	case error:
		errmsg := value.Error()
		if !f.needsQuoting(errmsg) {
			b.WriteString(errmsg)
		} else {
			fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, errmsg, f.QuoteCharacter)
		}
	default:
		fmt.Fprint(b, value)
	}
}
<commit_msg>Safely format data when printing<commit_after>package logrus

import (
	"bytes"
	"fmt"
	"sort"
	"strings"
	"sync"
	"time"
)

const (
	nocolor = 0
	red     = 31
	green   = 32
	yellow  = 33
	blue    = 34
	gray    = 37
)

var (
	baseTimestamp time.Time
)

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

type TextFormatter struct {
	// Set to true to bypass checking for a TTY before outputting colors.
	ForceColors bool

	// Force disabling colors.
	DisableColors bool

	// Disable timestamp logging. useful when output is redirected to logging
	// system that already adds timestamps.
	DisableTimestamp bool

	// Enable logging the full timestamp when a TTY is attached instead of just
	// the time passed since beginning of execution.
	FullTimestamp bool

	// TimestampFormat to use for display when a full timestamp is printed
	TimestampFormat string

	// The fields are sorted by default for a consistent output. For applications
	// that log extremely frequently and don't use the JSON formatter this may not
	// be desired.
	DisableSorting bool

	// QuoteEmptyFields will wrap empty fields in quotes if true
	QuoteEmptyFields bool

	// QuoteCharacter can be set to the override the default quoting character "
	// with something else. For example: ', or `.
	QuoteCharacter string

	// Whether the logger's out is to a terminal
	isTerminal bool

	sync.Once
}

func (f *TextFormatter) init(entry *Entry) {
	if len(f.QuoteCharacter) == 0 {
		f.QuoteCharacter = "\""
	}
	if entry.Logger != nil {
		f.isTerminal = IsTerminal(entry.Logger.Out)
	}
}

func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
	var b *bytes.Buffer
	keys := make([]string, 0, len(entry.Data))
	for k := range entry.Data {
		keys = append(keys, k)
	}

	if !f.DisableSorting {
		sort.Strings(keys)
	}
	if entry.Buffer != nil {
		b = entry.Buffer
	} else {
		b = &bytes.Buffer{}
	}

	prefixFieldClashes(entry.Data)

	f.Do(func() { f.init(entry) })

	isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors

	timestampFormat := f.TimestampFormat
	if timestampFormat == "" {
		timestampFormat = DefaultTimestampFormat
	}
	if isColored {
		f.printColored(b, entry, keys, timestampFormat)
	} else {
		if !f.DisableTimestamp {
			f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat))
		}
		f.appendKeyValue(b, "level", entry.Level.String())
		if entry.Message != "" {
			f.appendKeyValue(b, "msg", entry.Message)
		}
		for _, key := range keys {
			f.appendKeyValue(b, key, entry.Data[key])
		}
	}

	b.WriteByte('\n')
	return b.Bytes(), nil
}

func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) {
	var levelColor int
	switch entry.Level {
	case DebugLevel:
		levelColor = gray
	case WarnLevel:
		levelColor = yellow
	case ErrorLevel, FatalLevel, PanicLevel:
		levelColor = red
	default:
		levelColor = blue
	}

	levelText := strings.ToUpper(entry.Level.String())[0:4]

	if f.DisableTimestamp {
		fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message)
	} else if !f.FullTimestamp {
		fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), entry.Message)
	} else {
		fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
	}
	for _, k := range keys {
		v := entry.Data[k]
		fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k)
		f.appendValue(b, v)
	}
}

func (f *TextFormatter) needsQuoting(text string) bool {
	if f.QuoteEmptyFields && len(text) == 0 {
		return true
	}
	for _, ch := range text {
		if !((ch >= 'a' && ch <= 'z') ||
			(ch >= 'A' && ch <= 'Z') ||
			(ch >= '0' && ch <= '9') ||
			ch == '-' || ch == '.') {
			return true
		}
	}
	return false
}

func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {

	b.WriteString(key)
	b.WriteByte('=')
	f.appendValue(b, value)
	b.WriteByte(' ')
}

func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
	switch value := value.(type) {
	case string:
		if !f.needsQuoting(value) {
			b.WriteString(value)
		} else {
			fmt.Fprintf(b, "%q", value)
		}
	case error:
		errmsg := value.Error()
		if !f.needsQuoting(errmsg) {
			b.WriteString(errmsg)
		} else {
			fmt.Fprintf(b, "%q", errmsg)
		}
	default:
		fmt.Fprint(b, value)
	}
}
<|endoftext|>


<commit_before>package logrus

import (
	"bytes"
	"fmt"
	"sort"
	"strings"
	"time"
)

const (
	nocolor = 0
	red     = 31
	green   = 32
	yellow  = 33
	blue    = 34
)

var (
	baseTimestamp time.Time
	isTerminal    bool
)

func init() {
	baseTimestamp = time.Now()
	isTerminal = IsTerminal()
}

func miniTS() int {
	return int(time.Since(baseTimestamp) / time.Second)
}

type TextFormatter struct {
	// Set to true to bypass checking for a TTY before outputting colors.
	ForceColors      bool
	DisableColors    bool
	DisableTimestamp bool
}

func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {

	var keys []string
	for k := range entry.Data {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	b := &bytes.Buffer{}

	prefixFieldClashes(entry)

	isColored := (f.ForceColors || isTerminal) && !f.DisableColors

	if isColored {
		printColored(b, entry, keys)
	} else {
		if !f.DisableTimestamp {
			f.appendKeyValue(b, "time", entry.Time.Format(time.RFC3339))
		}
		f.appendKeyValue(b, "level", entry.Level.String())
		f.appendKeyValue(b, "msg", entry.Message)
		for _, key := range keys {
			f.appendKeyValue(b, key, entry.Data[key])
		}
	}

	b.WriteByte('\n')
	return b.Bytes(), nil
}

func printColored(b *bytes.Buffer, entry *Entry, keys []string) {
	var levelColor int
	switch entry.Level {
	case WarnLevel:
		levelColor = yellow
	case ErrorLevel, FatalLevel, PanicLevel:
		levelColor = red
	default:
		levelColor = blue
	}

	levelText := strings.ToUpper(entry.Level.String())[0:4]

	fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
	for _, k := range keys {
		v := entry.Data[k]
		fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%v", levelColor, k, v)
	}
}

func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key, value interface{}) {
	switch value.(type) {
	case string, error:
		fmt.Fprintf(b, "%v=%q ", key, value)
	default:
		fmt.Fprintf(b, "%v=%v ", key, value)
	}
}
<commit_msg>Document new option<commit_after>package logrus

import (
	"bytes"
	"fmt"
	"sort"
	"strings"
	"time"
)

const (
	nocolor = 0
	red     = 31
	green   = 32
	yellow  = 33
	blue    = 34
)

var (
	baseTimestamp time.Time
	isTerminal    bool
)

func init() {
	baseTimestamp = time.Now()
	isTerminal = IsTerminal()
}

func miniTS() int {
	return int(time.Since(baseTimestamp) / time.Second)
}

type TextFormatter struct {
	// Set to true to bypass checking for a TTY before outputting colors.
	ForceColors   bool
	DisableColors bool
	// Set to true to disable timestamp logging (useful when the output
	// is redirected to a logging system already adding a timestamp)
	DisableTimestamp bool
}

func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {

	var keys []string
	for k := range entry.Data {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	b := &bytes.Buffer{}

	prefixFieldClashes(entry)

	isColored := (f.ForceColors || isTerminal) && !f.DisableColors

	if isColored {
		printColored(b, entry, keys)
	} else {
		if !f.DisableTimestamp {
			f.appendKeyValue(b, "time", entry.Time.Format(time.RFC3339))
		}
		f.appendKeyValue(b, "level", entry.Level.String())
		f.appendKeyValue(b, "msg", entry.Message)
		for _, key := range keys {
			f.appendKeyValue(b, key, entry.Data[key])
		}
	}

	b.WriteByte('\n')
	return b.Bytes(), nil
}

func printColored(b *bytes.Buffer, entry *Entry, keys []string) {
	var levelColor int
	switch entry.Level {
	case WarnLevel:
		levelColor = yellow
	case ErrorLevel, FatalLevel, PanicLevel:
		levelColor = red
	default:
		levelColor = blue
	}

	levelText := strings.ToUpper(entry.Level.String())[0:4]

	fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
	for _, k := range keys {
		v := entry.Data[k]
		fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%v", levelColor, k, v)
	}
}

func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key, value interface{}) {
	switch value.(type) {
	case string, error:
		fmt.Fprintf(b, "%v=%q ", key, value)
	default:
		fmt.Fprintf(b, "%v=%v ", key, value)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package thrift

import (
	"fmt"
	"io"
	"io/ioutil"

	"github.com/uber/tchannel-go/typed"
)

// WriteHeaders writes the given key-value pairs using the following encoding:
// len~2 (k~4 v~4)~len
func WriteHeaders(w io.Writer, headers map[string]string) error {
	// TODO(prashant): Since we are not writing length-prefixed data here,
	// we can write out to the buffer, and if it fills up, flush it.
	// Right now, we calculate the size of the required buffer and write it out.

	// Calculate the size of the buffer that we need.
	size := 2
	for k, v := range headers {
		size += 4 /* size of key/value lengths */
		size += len(k) + len(v)
	}

	buf := make([]byte, size)
	writeBuffer := typed.NewWriteBuffer(buf)
	writeBuffer.WriteUint16(uint16(len(headers)))
	for k, v := range headers {
		writeBuffer.WriteLen16String(k)
		writeBuffer.WriteLen16String(v)
	}

	if err := writeBuffer.Err(); err != nil {
		return err
	}

	// Safety check to ensure the bytes written calculation is correct.
	if writeBuffer.BytesWritten() != size {
		return fmt.Errorf("writeHeaders size calculation wrong, expected to write %v bytes, only wrote %v bytes",
			size, writeBuffer.BytesWritten())
	}

	_, err := writeBuffer.FlushTo(w)
	return err
}

// ReadHeaders reads key-value pairs encoded using WriteHeaders.
func ReadHeaders(r io.Reader) (map[string]string, error) {
	// TODO(prashant): Allow typed.ReadBuffer to read directly from the reader.
	bs, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}

	buffer := typed.NewReadBuffer(bs)
	numHeaders := buffer.ReadUint16()
	if numHeaders == 0 {
		return nil, buffer.Err()
	}

	headers := make(map[string]string, numHeaders)
	for i := 0; i < int(numHeaders) && buffer.Err() == nil; i++ {
		k := buffer.ReadLen16String()
		v := buffer.ReadLen16String()
		headers[k] = v
	}
	return headers, buffer.Err()
}
<commit_msg>Update ReadHeaders to use typed.NewReader<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package thrift

import (
	"fmt"
	"io"

	"github.com/uber/tchannel-go/typed"
)

// WriteHeaders writes the given key-value pairs using the following encoding:
// len~2 (k~4 v~4)~len
func WriteHeaders(w io.Writer, headers map[string]string) error {
	// TODO(prashant): Since we are not writing length-prefixed data here,
	// we can write out to the buffer, and if it fills up, flush it.
	// Right now, we calculate the size of the required buffer and write it out.

	// Calculate the size of the buffer that we need.
	size := 2
	for k, v := range headers {
		size += 4 /* size of key/value lengths */
		size += len(k) + len(v)
	}

	buf := make([]byte, size)
	writeBuffer := typed.NewWriteBuffer(buf)
	writeBuffer.WriteUint16(uint16(len(headers)))
	for k, v := range headers {
		writeBuffer.WriteLen16String(k)
		writeBuffer.WriteLen16String(v)
	}

	if err := writeBuffer.Err(); err != nil {
		return err
	}

	// Safety check to ensure the bytes written calculation is correct.
	if writeBuffer.BytesWritten() != size {
		return fmt.Errorf(
			"writeHeaders size calculation wrong, expected to write %v bytes, only wrote %v bytes",
			size, writeBuffer.BytesWritten())
	}

	_, err := writeBuffer.FlushTo(w)
	return err
}

func readHeaders(reader *typed.Reader) (map[string]string, error) {
	numHeaders := reader.ReadUint16()
	if numHeaders == 0 {
		return nil, reader.Err()
	}

	headers := make(map[string]string, numHeaders)
	for i := 0; i < int(numHeaders) && reader.Err() == nil; i++ {
		k := reader.ReadLen16String()
		v := reader.ReadLen16String()
		headers[k] = v
	}

	return headers, reader.Err()
}

// ReadHeaders reads key-value pairs encoded using WriteHeaders.
func ReadHeaders(r io.Reader) (map[string]string, error) {
	reader := typed.NewReader(r)
	m, err := readHeaders(reader)
	reader.Release()

	return m, err
}
<|endoftext|>


<commit_before>package tollbooth

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

	"github.com/didip/tollbooth/limiter"
)

func TestLimitByKeys(t *testing.T) {
	lmt := NewLimiter(1, nil) // Only 1 request per second is allowed.

	httperror := LimitByKeys(lmt, []string{"127.0.0.1", "/"})
	if httperror != nil {
		t.Errorf("First time count should not return error. Error: %v", httperror.Error())
	}

	httperror = LimitByKeys(lmt, []string{"127.0.0.1", "/"})
	if httperror == nil {
		t.Errorf("Second time count should return error because it exceeds 1 request per second.")
	}

	<-time.After(1 * time.Second)
	httperror = LimitByKeys(lmt, []string{"127.0.0.1", "/"})
	if httperror != nil {
		t.Errorf("Third time count should not return error because the 1 second window has passed.")
	}
}

func TestDefaultBuildKeys(t *testing.T) {
	lmt := NewLimiter(1, nil)
	lmt.SetIPLookups([]string{"X-Forwarded-For", "X-Real-IP", "RemoteAddr"})

	request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!"))
	if err != nil {
		t.Errorf("Unable to create new HTTP request. Error: %v", err)
	}

	request.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8")

	sliceKeys := BuildKeys(lmt, request)
	if len(sliceKeys) == 0 {
		t.Fatal("Length of sliceKeys should never be empty.")
	}

	for _, keys := range sliceKeys {
		for i, keyChunk := range keys {
			if i == 0 && keyChunk != request.Header.Get("X-Real-IP") {
				t.Errorf("The first chunk should be remote IP. KeyChunk: %v", keyChunk)
			}
			if i == 1 && keyChunk != request.URL.Path {
				t.Errorf("The second chunk should be request path. KeyChunk: %v", keyChunk)
			}
		}
	}
}

func TestBasicAuthBuildKeys(t *testing.T) {
	lmt := NewLimiter(1, nil)
	lmt.SetBasicAuthUsers([]string{"bro"})

	request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!"))
	if err != nil {
		t.Errorf("Unable to create new HTTP request. Error: %v", err)
	}

	request.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8")

	request.SetBasicAuth("bro", "tato")

	for _, keys := range BuildKeys(lmt, request) {
		if len(keys) != 3 {
			t.Error("Keys should be made of 3 parts.")
		}
		for i, keyChunk := range keys {
			if i == 0 && keyChunk != request.Header.Get("X-Real-IP") {
				t.Errorf("The (%v) chunk should be remote IP. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 1 && keyChunk != request.URL.Path {
				t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 2 && keyChunk != "bro" {
				t.Errorf("The (%v) chunk should be request username. KeyChunk: %v", i+1, keyChunk)
			}
		}
	}
}

func TestCustomHeadersBuildKeys(t *testing.T) {
	lmt := NewLimiter(1, nil)
	lmt.SetHeader("X-Auth-Token", []string{"totally-top-secret", "another-secret"})

	request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!"))
	if err != nil {
		t.Errorf("Unable to create new HTTP request. Error: %v", err)
	}

	request.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8")
	request.Header.Set("X-Auth-Token", "totally-top-secret")

	for _, keys := range BuildKeys(lmt, request) {
		if len(keys) != 4 {
			t.Errorf("Keys should be made of 4 parts. Keys: %v", keys)
		}
		for i, keyChunk := range keys {
			if i == 0 && keyChunk != request.Header.Get("X-Real-IP") {
				t.Errorf("The (%v) chunk should be remote IP. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 1 && keyChunk != request.URL.Path {
				t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 2 && keyChunk != "X-Auth-Token" {
				t.Errorf("The (%v) chunk should be request header. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 3 && (keyChunk != "totally-top-secret" && keyChunk != "another-secret") {
				t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk)
			}
		}
	}
}

func TestRequestMethodBuildKeys(t *testing.T) {
	lmt := NewLimiter(1, nil)
	lmt.SetMethods([]string{"GET"})

	request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!"))
	if err != nil {
		t.Errorf("Unable to create new HTTP request. Error: %v", err)
	}

	request.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8")

	for _, keys := range BuildKeys(lmt, request) {
		if len(keys) != 3 {
			t.Errorf("Keys should be made of 3 parts. Keys: %v", keys)
		}
		for i, keyChunk := range keys {
			if i == 0 && keyChunk != request.Header.Get("X-Real-IP") {
				t.Errorf("The (%v) chunk should be remote IP. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 1 && keyChunk != request.URL.Path {
				t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 2 && keyChunk != "GET" {
				t.Errorf("The (%v) chunk should be request method. KeyChunk: %v", i+1, keyChunk)
			}
		}
	}
}

func TestRequestMethodAndCustomHeadersBuildKeys(t *testing.T) {
	lmt := NewLimiter(1, nil)
	lmt.SetMethods([]string{"GET"})
	lmt.SetHeader("X-Auth-Token", []string{"totally-top-secret", "another-secret"})

	request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!"))
	if err != nil {
		t.Errorf("Unable to create new HTTP request. Error: %v", err)
	}

	request.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8")
	request.Header.Set("X-Auth-Token", "totally-top-secret")

	for _, keys := range BuildKeys(lmt, request) {
		if len(keys) != 5 {
			t.Errorf("Keys should be made of 4 parts. Keys: %v", keys)
		}
		for i, keyChunk := range keys {
			if i == 0 && keyChunk != request.Header.Get("X-Real-IP") {
				t.Errorf("The (%v) chunk should be remote IP. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 1 && keyChunk != request.URL.Path {
				t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 2 && keyChunk != "GET" {
				t.Errorf("The (%v) chunk should be request method. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 3 && keyChunk != "X-Auth-Token" {
				t.Errorf("The (%v) chunk should be request header. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 4 && (keyChunk != "totally-top-secret" && keyChunk != "another-secret") {
				t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk)
			}
		}
	}
}

func TestRequestMethodAndBasicAuthUsersBuildKeys(t *testing.T) {
	lmt := NewLimiter(1, nil)
	lmt.SetMethods([]string{"GET"})
	lmt.SetBasicAuthUsers([]string{"bro"})

	request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!"))
	if err != nil {
		t.Errorf("Unable to create new HTTP request. Error: %v", err)
	}

	request.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8")
	request.SetBasicAuth("bro", "tato")

	for _, keys := range BuildKeys(lmt, request) {
		if len(keys) != 4 {
			t.Errorf("Keys should be made of 4 parts. Keys: %v", keys)
		}
		for i, keyChunk := range keys {
			if i == 0 && keyChunk != request.Header.Get("X-Real-IP") {
				t.Errorf("The (%v) chunk should be remote IP. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 1 && keyChunk != request.URL.Path {
				t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 2 && keyChunk != "GET" {
				t.Errorf("The (%v) chunk should be request method. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 3 && keyChunk != "bro" {
				t.Errorf("The (%v) chunk should be basic auth user. KeyChunk: %v", i+1, keyChunk)
			}
		}
	}
}

func TestRequestMethodCustomHeadersAndBasicAuthUsersBuildKeys(t *testing.T) {
	lmt := NewLimiter(1, nil)
	lmt.SetMethods([]string{"GET"})
	lmt.SetHeader("X-Auth-Token", []string{"totally-top-secret", "another-secret"})
	lmt.SetBasicAuthUsers([]string{"bro"})

	request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!"))
	if err != nil {
		t.Errorf("Unable to create new HTTP request. Error: %v", err)
	}

	request.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8")
	request.Header.Set("X-Auth-Token", "totally-top-secret")
	request.SetBasicAuth("bro", "tato")

	for _, keys := range BuildKeys(lmt, request) {
		if len(keys) != 6 {
			t.Errorf("Keys should be made of 4 parts. Keys: %v", keys)
		}
		for i, keyChunk := range keys {
			if i == 0 && keyChunk != request.Header.Get("X-Real-IP") {
				t.Errorf("The (%v) chunk should be remote IP. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 1 && keyChunk != request.URL.Path {
				t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 2 && keyChunk != "GET" {
				t.Errorf("The (%v) chunk should be request method. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 3 && keyChunk != "X-Auth-Token" {
				t.Errorf("The (%v) chunk should be request header. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 4 && (keyChunk != "totally-top-secret" && keyChunk != "another-secret") {
				t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 5 && keyChunk != "bro" {
				t.Errorf("The (%v) chunk should be basic auth user. KeyChunk: %v", i+1, keyChunk)
			}
		}
	}

}

func TestLimitHandler(t *testing.T) {
	lmt := limiter.New(nil).SetMax(1).SetBurst(1)
	lmt.SetIPLookups([]string{"X-Real-IP", "RemoteAddr", "X-Forwarded-For"})
	lmt.SetMethods([]string{"POST"})

	counter := 0
	lmt.SetOnLimitReached(func(w http.ResponseWriter, r *http.Request) { counter++ })

	handler := LimitHandler(lmt, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`hello world`))
	}))

	req, err := http.NewRequest("POST", "/doesntmatter", nil)
	if err != nil {
		t.Fatal(err)
	}

	req.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8")

	rr := httptest.NewRecorder()
	handler.ServeHTTP(rr, req)
	//Should not be limited
	if status := rr.Code; status != http.StatusOK {
		t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK)
	}

	ch := make(chan int)
	go func() {
		rr := httptest.NewRecorder()
		handler.ServeHTTP(rr, req)
		// Should be limited
		if status := rr.Code; status != http.StatusTooManyRequests {
			t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusTooManyRequests)
		}
		// OnLimitReached should be called
		if counter != 1 {
			t.Errorf("onLimitReached was not called")
		}
		close(ch)
	}()
	<-ch // Block until go func is done.
}
<commit_msg>Fix error reporting text<commit_after>package tollbooth

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

	"github.com/didip/tollbooth/limiter"
)

func TestLimitByKeys(t *testing.T) {
	lmt := NewLimiter(1, nil) // Only 1 request per second is allowed.

	httperror := LimitByKeys(lmt, []string{"127.0.0.1", "/"})
	if httperror != nil {
		t.Errorf("First time count should not return error. Error: %v", httperror.Error())
	}

	httperror = LimitByKeys(lmt, []string{"127.0.0.1", "/"})
	if httperror == nil {
		t.Errorf("Second time count should return error because it exceeds 1 request per second.")
	}

	<-time.After(1 * time.Second)
	httperror = LimitByKeys(lmt, []string{"127.0.0.1", "/"})
	if httperror != nil {
		t.Errorf("Third time count should not return error because the 1 second window has passed.")
	}
}

func TestDefaultBuildKeys(t *testing.T) {
	lmt := NewLimiter(1, nil)
	lmt.SetIPLookups([]string{"X-Forwarded-For", "X-Real-IP", "RemoteAddr"})

	request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!"))
	if err != nil {
		t.Errorf("Unable to create new HTTP request. Error: %v", err)
	}

	request.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8")

	sliceKeys := BuildKeys(lmt, request)
	if len(sliceKeys) == 0 {
		t.Fatal("Length of sliceKeys should never be empty.")
	}

	for _, keys := range sliceKeys {
		for i, keyChunk := range keys {
			if i == 0 && keyChunk != request.Header.Get("X-Real-IP") {
				t.Errorf("The first chunk should be remote IP. KeyChunk: %v", keyChunk)
			}
			if i == 1 && keyChunk != request.URL.Path {
				t.Errorf("The second chunk should be request path. KeyChunk: %v", keyChunk)
			}
		}
	}
}

func TestBasicAuthBuildKeys(t *testing.T) {
	lmt := NewLimiter(1, nil)
	lmt.SetBasicAuthUsers([]string{"bro"})

	request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!"))
	if err != nil {
		t.Errorf("Unable to create new HTTP request. Error: %v", err)
	}

	request.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8")

	request.SetBasicAuth("bro", "tato")

	for _, keys := range BuildKeys(lmt, request) {
		if len(keys) != 3 {
			t.Error("Keys should be made of 3 parts.")
		}
		for i, keyChunk := range keys {
			if i == 0 && keyChunk != request.Header.Get("X-Real-IP") {
				t.Errorf("The (%v) chunk should be remote IP. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 1 && keyChunk != request.URL.Path {
				t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 2 && keyChunk != "bro" {
				t.Errorf("The (%v) chunk should be request username. KeyChunk: %v", i+1, keyChunk)
			}
		}
	}
}

func TestCustomHeadersBuildKeys(t *testing.T) {
	lmt := NewLimiter(1, nil)
	lmt.SetHeader("X-Auth-Token", []string{"totally-top-secret", "another-secret"})

	request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!"))
	if err != nil {
		t.Errorf("Unable to create new HTTP request. Error: %v", err)
	}

	request.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8")
	request.Header.Set("X-Auth-Token", "totally-top-secret")

	for _, keys := range BuildKeys(lmt, request) {
		if len(keys) != 4 {
			t.Errorf("Keys should be made of 4 parts. Keys: %v", keys)
		}
		for i, keyChunk := range keys {
			if i == 0 && keyChunk != request.Header.Get("X-Real-IP") {
				t.Errorf("The (%v) chunk should be remote IP. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 1 && keyChunk != request.URL.Path {
				t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 2 && keyChunk != "X-Auth-Token" {
				t.Errorf("The (%v) chunk should be request header. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 3 && (keyChunk != "totally-top-secret" && keyChunk != "another-secret") {
				t.Errorf("The (%v) chunk should be request header value. KeyChunk: %v", i+1, keyChunk)
			}
		}
	}
}

func TestRequestMethodBuildKeys(t *testing.T) {
	lmt := NewLimiter(1, nil)
	lmt.SetMethods([]string{"GET"})

	request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!"))
	if err != nil {
		t.Errorf("Unable to create new HTTP request. Error: %v", err)
	}

	request.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8")

	for _, keys := range BuildKeys(lmt, request) {
		if len(keys) != 3 {
			t.Errorf("Keys should be made of 3 parts. Keys: %v", keys)
		}
		for i, keyChunk := range keys {
			if i == 0 && keyChunk != request.Header.Get("X-Real-IP") {
				t.Errorf("The (%v) chunk should be remote IP. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 1 && keyChunk != request.URL.Path {
				t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 2 && keyChunk != "GET" {
				t.Errorf("The (%v) chunk should be request method. KeyChunk: %v", i+1, keyChunk)
			}
		}
	}
}

func TestRequestMethodAndCustomHeadersBuildKeys(t *testing.T) {
	lmt := NewLimiter(1, nil)
	lmt.SetMethods([]string{"GET"})
	lmt.SetHeader("X-Auth-Token", []string{"totally-top-secret", "another-secret"})

	request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!"))
	if err != nil {
		t.Errorf("Unable to create new HTTP request. Error: %v", err)
	}

	request.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8")
	request.Header.Set("X-Auth-Token", "totally-top-secret")

	for _, keys := range BuildKeys(lmt, request) {
		if len(keys) != 5 {
			t.Errorf("Keys should be made of 4 parts. Keys: %v", keys)
		}
		for i, keyChunk := range keys {
			if i == 0 && keyChunk != request.Header.Get("X-Real-IP") {
				t.Errorf("The (%v) chunk should be remote IP. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 1 && keyChunk != request.URL.Path {
				t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 2 && keyChunk != "GET" {
				t.Errorf("The (%v) chunk should be request method. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 3 && keyChunk != "X-Auth-Token" {
				t.Errorf("The (%v) chunk should be request header. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 4 && (keyChunk != "totally-top-secret" && keyChunk != "another-secret") {
				t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk)
			}
		}
	}
}

func TestRequestMethodAndBasicAuthUsersBuildKeys(t *testing.T) {
	lmt := NewLimiter(1, nil)
	lmt.SetMethods([]string{"GET"})
	lmt.SetBasicAuthUsers([]string{"bro"})

	request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!"))
	if err != nil {
		t.Errorf("Unable to create new HTTP request. Error: %v", err)
	}

	request.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8")
	request.SetBasicAuth("bro", "tato")

	for _, keys := range BuildKeys(lmt, request) {
		if len(keys) != 4 {
			t.Errorf("Keys should be made of 4 parts. Keys: %v", keys)
		}
		for i, keyChunk := range keys {
			if i == 0 && keyChunk != request.Header.Get("X-Real-IP") {
				t.Errorf("The (%v) chunk should be remote IP. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 1 && keyChunk != request.URL.Path {
				t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 2 && keyChunk != "GET" {
				t.Errorf("The (%v) chunk should be request method. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 3 && keyChunk != "bro" {
				t.Errorf("The (%v) chunk should be basic auth user. KeyChunk: %v", i+1, keyChunk)
			}
		}
	}
}

func TestRequestMethodCustomHeadersAndBasicAuthUsersBuildKeys(t *testing.T) {
	lmt := NewLimiter(1, nil)
	lmt.SetMethods([]string{"GET"})
	lmt.SetHeader("X-Auth-Token", []string{"totally-top-secret", "another-secret"})
	lmt.SetBasicAuthUsers([]string{"bro"})

	request, err := http.NewRequest("GET", "/", strings.NewReader("Hello, world!"))
	if err != nil {
		t.Errorf("Unable to create new HTTP request. Error: %v", err)
	}

	request.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8")
	request.Header.Set("X-Auth-Token", "totally-top-secret")
	request.SetBasicAuth("bro", "tato")

	for _, keys := range BuildKeys(lmt, request) {
		if len(keys) != 6 {
			t.Errorf("Keys should be made of 4 parts. Keys: %v", keys)
		}
		for i, keyChunk := range keys {
			if i == 0 && keyChunk != request.Header.Get("X-Real-IP") {
				t.Errorf("The (%v) chunk should be remote IP. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 1 && keyChunk != request.URL.Path {
				t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 2 && keyChunk != "GET" {
				t.Errorf("The (%v) chunk should be request method. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 3 && keyChunk != "X-Auth-Token" {
				t.Errorf("The (%v) chunk should be request header. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 4 && (keyChunk != "totally-top-secret" && keyChunk != "another-secret") {
				t.Errorf("The (%v) chunk should be request path. KeyChunk: %v", i+1, keyChunk)
			}
			if i == 5 && keyChunk != "bro" {
				t.Errorf("The (%v) chunk should be basic auth user. KeyChunk: %v", i+1, keyChunk)
			}
		}
	}

}

func TestLimitHandler(t *testing.T) {
	lmt := limiter.New(nil).SetMax(1).SetBurst(1)
	lmt.SetIPLookups([]string{"X-Real-IP", "RemoteAddr", "X-Forwarded-For"})
	lmt.SetMethods([]string{"POST"})

	counter := 0
	lmt.SetOnLimitReached(func(w http.ResponseWriter, r *http.Request) { counter++ })

	handler := LimitHandler(lmt, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`hello world`))
	}))

	req, err := http.NewRequest("POST", "/doesntmatter", nil)
	if err != nil {
		t.Fatal(err)
	}

	req.Header.Set("X-Real-IP", "2601:7:1c82:4097:59a0:a80b:2841:b8c8")

	rr := httptest.NewRecorder()
	handler.ServeHTTP(rr, req)
	//Should not be limited
	if status := rr.Code; status != http.StatusOK {
		t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK)
	}

	ch := make(chan int)
	go func() {
		rr := httptest.NewRecorder()
		handler.ServeHTTP(rr, req)
		// Should be limited
		if status := rr.Code; status != http.StatusTooManyRequests {
			t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusTooManyRequests)
		}
		// OnLimitReached should be called
		if counter != 1 {
			t.Errorf("onLimitReached was not called")
		}
		close(ch)
	}()
	<-ch // Block until go func is done.
}
<|endoftext|>


<commit_before>package golang

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"path/filepath"

	"strings"

	"github.com/golang/gddo/gosrc"
	"github.com/peterbourgon/diskv"
	"github.com/sourcegraph/httpcache"
	"github.com/sourcegraph/httpcache/diskcache"
	"sourcegraph.com/sourcegraph/srcgraph/config"
	"sourcegraph.com/sourcegraph/srcgraph/container"
	"sourcegraph.com/sourcegraph/srcgraph/dep2"
	"sourcegraph.com/sourcegraph/srcgraph/task2"
	"sourcegraph.com/sourcegraph/srcgraph/unit"
)

func init() {
	dep2.RegisterLister(&Package{}, dep2.DockerLister{defaultGoVersion})
	dep2.RegisterResolver(goImportPathTargetType, defaultGoVersion)
}

func (v *goVersion) BuildLister(dir string, unit unit.SourceUnit, c *config.Repository, x *task2.Context) (*container.Command, error) {
	goConfig := v.goConfig(c)
	pkg := unit.(*Package)

	dockerfile, err := v.baseDockerfile()
	if err != nil {
		return nil, err
	}

	containerDir := filepath.Join(containerGOPATH, "src", goConfig.BaseImportPath)
	cmd := container.Command{
		Container: container.Container{
			Dockerfile: dockerfile,
			RunOptions: []string{"-v", dir + ":" + containerDir},
			Cmd:        []string{"go", "list", "-e", "-f", `{{join .Imports "\n"}}{{join .TestImports "\n"}}{{join .XTestImports "\n"}}`, pkg.ImportPath},
		},
		Transform: func(orig []byte) ([]byte, error) {
			importPaths := strings.Split(string(orig), "\n")
			var deps []*dep2.RawDependency
			for _, importPath := range importPaths {
				if importPath == "" {
					continue
				}
				deps = append(deps, &dep2.RawDependency{
					TargetType: goImportPathTargetType,
					Target:     goImportPath(importPath),
				})
			}

			return json.Marshal(deps)
		},
	}
	return &cmd, nil
}

// goImportPath represents a Go import path, such as "github.com/user/repo" or
// "net/http".
type goImportPath string

const goImportPathTargetType = "go-import-path"

func (v *goVersion) Resolve(dep *dep2.RawDependency, c *config.Repository, x *task2.Context) (*dep2.ResolvedTarget, error) {
	importPath := dep.Target.(string)
	return v.resolveGoImportDep(importPath, c, x)
}

func (v *goVersion) resolveGoImportDep(importPath string, c *config.Repository, x *task2.Context) (*dep2.ResolvedTarget, error) {
	// Look up in cache.
	resolvedTarget := func() *dep2.ResolvedTarget {
		v.resolveCacheMu.Lock()
		defer v.resolveCacheMu.Unlock()
		return v.resolveCache[importPath]
	}()
	if resolvedTarget != nil {
		return resolvedTarget, nil
	}

	// Check if this importPath is in this repository.
	goConfig := v.goConfig(c)
	if strings.HasPrefix(importPath, goConfig.BaseImportPath) {
		dir, err := filepath.Rel(goConfig.BaseImportPath, importPath)
		if err != nil {
			return nil, err
		}
		toUnit := &Package{Dir: dir, ImportPath: importPath}
		return &dep2.ResolvedTarget{
			// TODO(sqs): this is a URI not a clone URL
			ToRepoCloneURL: string(c.URI),
			ToUnit:         toUnit.Name(),
			ToUnitType:     unit.Type(toUnit),
		}, nil
	}

	// Special-case the cgo package "C".
	if importPath == "C" {
		return nil, nil
	}

	if gosrc.IsGoRepoPath(importPath) {
		toUnit := &Package{ImportPath: importPath, Dir: "src/pkg/" + importPath}
		return &dep2.ResolvedTarget{
			ToRepoCloneURL:  v.RepositoryCloneURL,
			ToVersionString: v.VersionString,
			ToRevSpec:       v.VCSRevision,
			ToUnit:          toUnit.Name(),
			ToUnitType:      unit.Type(toUnit),
		}, nil
	}

	x.Log.Printf("Resolving Go dep: %s", importPath)

	dir, err := gosrc.Get(cachingHTTPClient, string(importPath), "")
	if err != nil {
		return nil, fmt.Errorf("unable to fetch information about Go package %q", importPath)
	}

	// gosrc returns code.google.com URLs ending in a slash. Remove it.
	dir.ProjectURL = strings.TrimSuffix(dir.ProjectURL, "/")

	toUnit := &Package{ImportPath: dir.ImportPath}
	toUnit.Dir, err = filepath.Rel(dir.ProjectRoot, dir.ImportPath)
	if err != nil {
		return nil, err
	}

	resolvedTarget = &dep2.ResolvedTarget{
		ToRepoCloneURL: dir.ProjectURL,
		ToUnit:         toUnit.Name(),
		ToUnitType:     unit.Type(toUnit),
	}

	if gosrc.IsGoRepoPath(dir.ImportPath) {
		resolvedTarget.ToVersionString = v.VersionString
		resolvedTarget.ToRevSpec = v.VCSRevision
		resolvedTarget.ToUnit = "src/pkg/" + resolvedTarget.ToUnit
	}

	// Save in cache.
	v.resolveCacheMu.Lock()
	defer v.resolveCacheMu.Unlock()
	if v.resolveCache == nil {
		v.resolveCache = make(map[string]*dep2.ResolvedTarget)
	}
	v.resolveCache[importPath] = resolvedTarget

	return resolvedTarget, nil
}

var cachingHTTPClient = &http.Client{
	Transport: &httpcache.Transport{
		Cache: diskcache.NewWithDiskv(diskv.New(diskv.Options{
			BasePath:     filepath.Join(os.TempDir(), "sg-golang-toolchain-cache"),
			CacheSizeMax: 5000 * 1024 * 100, // 500 MB
		})),
	},
}
<commit_msg>fix dupe handling<commit_after>package golang

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"path/filepath"

	"strings"

	"github.com/golang/gddo/gosrc"
	"github.com/peterbourgon/diskv"
	"github.com/sourcegraph/httpcache"
	"github.com/sourcegraph/httpcache/diskcache"
	"sourcegraph.com/sourcegraph/srcgraph/config"
	"sourcegraph.com/sourcegraph/srcgraph/container"
	"sourcegraph.com/sourcegraph/srcgraph/dep2"
	"sourcegraph.com/sourcegraph/srcgraph/task2"
	"sourcegraph.com/sourcegraph/srcgraph/unit"
)

func init() {
	dep2.RegisterLister(&Package{}, dep2.DockerLister{defaultGoVersion})
	dep2.RegisterResolver(goImportPathTargetType, defaultGoVersion)
}

func (v *goVersion) BuildLister(dir string, unit unit.SourceUnit, c *config.Repository, x *task2.Context) (*container.Command, error) {
	goConfig := v.goConfig(c)
	pkg := unit.(*Package)

	dockerfile, err := v.baseDockerfile()
	if err != nil {
		return nil, err
	}

	containerDir := filepath.Join(containerGOPATH, "src", goConfig.BaseImportPath)
	cmd := container.Command{
		Container: container.Container{
			Dockerfile: dockerfile,
			RunOptions: []string{"-v", dir + ":" + containerDir},
			Cmd:        []string{"go", "list", "-e", "-f", `{{join .Imports "\n"}}` + "\n" + `{{join .TestImports "\n"}}` + "\n" + `{{join .XTestImports "\n"}}`, pkg.ImportPath},
		},
		Transform: func(orig []byte) ([]byte, error) {
			importPaths := strings.Split(string(orig), "\n")
			seen := make(map[string]struct{})
			var deps []*dep2.RawDependency
			for _, importPath := range importPaths {
				if importPath == "" {
					continue
				}
				if _, seen := seen[importPath]; seen {
					continue
				}
				seen[importPath] = struct{}{}
				deps = append(deps, &dep2.RawDependency{
					TargetType: goImportPathTargetType,
					Target:     goImportPath(importPath),
				})
			}

			return json.Marshal(deps)
		},
	}
	return &cmd, nil
}

// goImportPath represents a Go import path, such as "github.com/user/repo" or
// "net/http".
type goImportPath string

const goImportPathTargetType = "go-import-path"

func (v *goVersion) Resolve(dep *dep2.RawDependency, c *config.Repository, x *task2.Context) (*dep2.ResolvedTarget, error) {
	importPath := dep.Target.(string)
	return v.resolveGoImportDep(importPath, c, x)
}

func (v *goVersion) resolveGoImportDep(importPath string, c *config.Repository, x *task2.Context) (*dep2.ResolvedTarget, error) {
	// Look up in cache.
	resolvedTarget := func() *dep2.ResolvedTarget {
		v.resolveCacheMu.Lock()
		defer v.resolveCacheMu.Unlock()
		return v.resolveCache[importPath]
	}()
	if resolvedTarget != nil {
		return resolvedTarget, nil
	}

	// Check if this importPath is in this repository.
	goConfig := v.goConfig(c)
	if strings.HasPrefix(importPath, goConfig.BaseImportPath) {
		dir, err := filepath.Rel(goConfig.BaseImportPath, importPath)
		if err != nil {
			return nil, err
		}
		toUnit := &Package{Dir: dir, ImportPath: importPath}
		return &dep2.ResolvedTarget{
			// TODO(sqs): this is a URI not a clone URL
			ToRepoCloneURL: string(c.URI),
			ToUnit:         toUnit.Name(),
			ToUnitType:     unit.Type(toUnit),
		}, nil
	}

	// Special-case the cgo package "C".
	if importPath == "C" {
		return nil, nil
	}

	if gosrc.IsGoRepoPath(importPath) {
		toUnit := &Package{ImportPath: importPath, Dir: "src/pkg/" + importPath}
		return &dep2.ResolvedTarget{
			ToRepoCloneURL:  v.RepositoryCloneURL,
			ToVersionString: v.VersionString,
			ToRevSpec:       v.VCSRevision,
			ToUnit:          toUnit.Name(),
			ToUnitType:      unit.Type(toUnit),
		}, nil
	}

	x.Log.Printf("Resolving Go dep: %s", importPath)

	dir, err := gosrc.Get(cachingHTTPClient, string(importPath), "")
	if err != nil {
		return nil, fmt.Errorf("unable to fetch information about Go package %q", importPath)
	}

	// gosrc returns code.google.com URLs ending in a slash. Remove it.
	dir.ProjectURL = strings.TrimSuffix(dir.ProjectURL, "/")

	toUnit := &Package{ImportPath: dir.ImportPath}
	toUnit.Dir, err = filepath.Rel(dir.ProjectRoot, dir.ImportPath)
	if err != nil {
		return nil, err
	}

	resolvedTarget = &dep2.ResolvedTarget{
		ToRepoCloneURL: dir.ProjectURL,
		ToUnit:         toUnit.Name(),
		ToUnitType:     unit.Type(toUnit),
	}

	if gosrc.IsGoRepoPath(dir.ImportPath) {
		resolvedTarget.ToVersionString = v.VersionString
		resolvedTarget.ToRevSpec = v.VCSRevision
		resolvedTarget.ToUnit = "src/pkg/" + resolvedTarget.ToUnit
	}

	// Save in cache.
	v.resolveCacheMu.Lock()
	defer v.resolveCacheMu.Unlock()
	if v.resolveCache == nil {
		v.resolveCache = make(map[string]*dep2.ResolvedTarget)
	}
	v.resolveCache[importPath] = resolvedTarget

	return resolvedTarget, nil
}

var cachingHTTPClient = &http.Client{
	Transport: &httpcache.Transport{
		Cache: diskcache.NewWithDiskv(diskv.New(diskv.Options{
			BasePath:     filepath.Join(os.TempDir(), "sg-golang-toolchain-cache"),
			CacheSizeMax: 5000 * 1024 * 100, // 500 MB
		})),
	},
}
<|endoftext|>


<commit_before>package trivial

import (
	"fmt"
	"os"
	"time"
)

type timer struct {
    action string
    start time.Time
    depth int
    duration time.Duration
    subActions []*timer
}

func (t *timer) String() string {
    this := fmt.Sprintf("%.3fs %*s%s\n", t.duration.Seconds(), t.depth, "", t.action)
    for _, sub := range t.subActions {
        this += sub.String()
    }
    return this
}

var stack []*timer

func Timeit(action string) func() {
        cur := &timer{action: action, start: time.Now(), depth: len(stack)}
        if len(stack) != 0 {
            tip := stack[len(stack)-1]
            tip.subActions = append(tip.subActions, cur)
        }
        stack = append(stack, cur)
	return func() {
            cur.duration = time.Since(cur.start)
            if cur == stack[0] {
                fmt.Fprint(os.Stderr, cur)
                stack = nil
            } else {
                stack = stack[0:len(stack)-1]
            }
	}
}
<commit_msg>go fmt<commit_after>package trivial

import (
	"fmt"
	"os"
	"time"
)

type timer struct {
	action     string
	start      time.Time
	depth      int
	duration   time.Duration
	subActions []*timer
}

func (t *timer) String() string {
	this := fmt.Sprintf("%.3fs %*s%s\n", t.duration.Seconds(), t.depth, "", t.action)
	for _, sub := range t.subActions {
		this += sub.String()
	}
	return this
}

var stack []*timer

func Timeit(action string) func() {
	cur := &timer{action: action, start: time.Now(), depth: len(stack)}
	if len(stack) != 0 {
		tip := stack[len(stack)-1]
		tip.subActions = append(tip.subActions, cur)
	}
	stack = append(stack, cur)
	return func() {
		cur.duration = time.Since(cur.start)
		if cur == stack[0] {
			fmt.Fprint(os.Stderr, cur)
			stack = nil
		} else {
			stack = stack[0 : len(stack)-1]
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 yati 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 main

import (
	"fmt"

	"github.com/andrewsmedina/yati/tsuru/iaas"
	_ "github.com/andrewsmedina/yati/tsuru/iaas/dockermachine"
	"github.com/tsuru/tsuru/cmd"
	"launchpad.net/gnuflag"
)

type install struct {
	fs *gnuflag.FlagSet
}

func (c *install) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "install",
		Usage:   "install",
		Desc:    "",
		MinArgs: 0,
	}
}

func (c *install) Run(context *cmd.Context, client *cmd.Client) error {
	i := iaas.Get("docker-machine")
	m, err := i.CreateMachine(nil)
	if err != nil {
		return err
	}
	fmt.Printf("Machine %s successfully created!", m.Address)
	fmt.Println("Installing MongoDB")
	err = createContainer(m.Address, "mongodb")
	if err != nil {
		fmt.Println("Error installing MongoDB!")
		return err
	}
	fmt.Println("MongoDB successfully installed!")
	return nil
}

type uninstall struct {
	fs *gnuflag.FlagSet
}

func (c *uninstall) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "uninstall",
		Usage:   "uninstall",
		Desc:    "",
		MinArgs: 0,
	}
}

func (c *uninstall) Run(context *cmd.Context, client *cmd.Client) error {
	i := iaas.Get("docker-machine")
	err := i.DeleteMachine(&iaas.Machine{})
	if err != nil {
		return err
	}
	fmt.Println("Machine successfully removed!")
	return nil
}
<commit_msg>break line<commit_after>// Copyright 2016 yati 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 main

import (
	"fmt"

	"github.com/andrewsmedina/yati/tsuru/iaas"
	_ "github.com/andrewsmedina/yati/tsuru/iaas/dockermachine"
	"github.com/tsuru/tsuru/cmd"
	"launchpad.net/gnuflag"
)

type install struct {
	fs *gnuflag.FlagSet
}

func (c *install) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "install",
		Usage:   "install",
		Desc:    "",
		MinArgs: 0,
	}
}

func (c *install) Run(context *cmd.Context, client *cmd.Client) error {
	i := iaas.Get("docker-machine")
	m, err := i.CreateMachine(nil)
	if err != nil {
		return err
	}
	fmt.Printf("Machine %s successfully created!\n", m.Address)
	fmt.Println("Installing MongoDB")
	err = createContainer(m.Address, "mongodb")
	if err != nil {
		fmt.Println("Error installing MongoDB!")
		return err
	}
	fmt.Println("MongoDB successfully installed!")
	return nil
}

type uninstall struct {
	fs *gnuflag.FlagSet
}

func (c *uninstall) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "uninstall",
		Usage:   "uninstall",
		Desc:    "",
		MinArgs: 0,
	}
}

func (c *uninstall) Run(context *cmd.Context, client *cmd.Client) error {
	i := iaas.Get("docker-machine")
	err := i.DeleteMachine(&iaas.Machine{})
	if err != nil {
		return err
	}
	fmt.Println("Machine successfully removed!")
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"strconv"
	"strings"

	"github.com/Randomsock5/tcptunnel/encodes"
)

var (
	addr      string
	port      int
	localAddr string
	localPort int
	password  string
	pac       string
)

func init() {
	flag.StringVar(&addr, "server", "", "Set server address")
	flag.IntVar(&port, "port", 8443, "Set server port")
	flag.StringVar(&localAddr, "loacl", "", "Set loacl address")
	flag.IntVar(&localPort, "localPort", 8088, "Set loacl port")
	flag.StringVar(&pac, "pac", "./pac.txt", "Set pac path")
	flag.StringVar(&password, "password", "asdfghjkl", "Password")
}

func main() {
	flag.Parse()

	if exist(pac) {
		b, err := ioutil.ReadFile(pac)
		if err != nil {
			log.Println("Can not read file: " + pac)
		}

		pacport := localPort + 1
		s := string(b[:])
		if localAddr != "" {
			s = strings.Replace(s, "__PROXY__", "PROXY "+localAddr+":"+strconv.Itoa(localPort)+";", 1)
			log.Println("pac uri: " + localAddr + ":" + strconv.Itoa(pacport) + "/pac")
		} else {
			s = strings.Replace(s, "__PROXY__", "PROXY 127.0.0.1:"+strconv.Itoa(localPort)+";", 1)
			log.Println("pac uri: 127.0.0.1:" + strconv.Itoa(pacport) + "/pac")
		}

		mux := http.NewServeMux()
		mux.HandleFunc("/pac", func(w http.ResponseWriter, r *http.Request) {
			io.WriteString(w, s)
		})
		go http.ListenAndServe(localAddr+":"+strconv.Itoa(pacport), mux)
	} else {
		log.Println("Can not find file: " + pac)
	}

	localServer, err := net.Listen("tcp", localAddr+":"+strconv.Itoa(localPort))
	if err != nil {
		log.Fatal(err)
	}
	defer localServer.Close()

	for {
		conn, err := localServer.Accept()
		if err != nil {
			log.Println(err)
			continue
		}

		go func(c net.Conn) {
			aesconn, err := encodes.Dial(addr+":"+strconv.Itoa(port), password)
			if err != nil {
				log.Println(err)
				return
			}

			go copyAndClose(aesconn, c)
			go copyAndClose(c, aesconn)
		}(conn)
	}
}

func copyAndClose(w, r net.Conn) {
	io.Copy(w, r)
	r.Close()
}

func exist(filepath string) bool {
	_, err := os.Stat(filepath)
	return err == nil || os.IsExist(err)
}
<commit_msg>fix bug<commit_after>package main

import (
	"flag"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"strconv"
	"strings"

	"github.com/Randomsock5/tcptunnel/encodes"
)

var (
	addr      string
	port      int
	localAddr string
	localPort int
	password  string
	pac       string
)

func init() {
	flag.StringVar(&addr, "server", "", "Set server address")
	flag.IntVar(&port, "port", 8443, "Set server port")
	flag.StringVar(&localAddr, "local", "", "Set local address")
	flag.IntVar(&localPort, "localPort", 8088, "Set local port")
	flag.StringVar(&pac, "pac", "./pac.txt", "Set pac path")
	flag.StringVar(&password, "password", "asdfghjkl", "Password")
}

func main() {
	flag.Parse()

	if exist(pac) {
		b, err := ioutil.ReadFile(pac)
		if err != nil {
			log.Println("Can not read file: " + pac)
		}

		pacport := localPort + 1
		s := string(b[:])
		if localAddr != "" {
			s = strings.Replace(s, "__PROXY__", "PROXY "+localAddr+":"+strconv.Itoa(localPort)+";", 1)
			log.Println("pac uri: " + localAddr + ":" + strconv.Itoa(pacport) + "/pac")
		} else {
			s = strings.Replace(s, "__PROXY__", "PROXY 127.0.0.1:"+strconv.Itoa(localPort)+";", 1)
			log.Println("pac uri: 127.0.0.1:" + strconv.Itoa(pacport) + "/pac")
		}

		mux := http.NewServeMux()
		mux.HandleFunc("/pac", func(w http.ResponseWriter, r *http.Request) {
			io.WriteString(w, s)
		})
		go http.ListenAndServe(localAddr+":"+strconv.Itoa(pacport), mux)
	} else {
		log.Println("Can not find file: " + pac)
	}

	localServer, err := net.Listen("tcp", localAddr+":"+strconv.Itoa(localPort))
	if err != nil {
		log.Fatal(err)
	}
	defer localServer.Close()

	for {
		conn, err := localServer.Accept()
		if err != nil {
			log.Println(err)
			continue
		}

		go func(c net.Conn) {
			aesconn, err := encodes.Dial(addr+":"+strconv.Itoa(port), password)
			if err != nil {
				log.Println(err)
				return
			}

			go copyAndClose(aesconn, c)
			go copyAndClose(c, aesconn)
		}(conn)
	}
}

func copyAndClose(w, r net.Conn) {
	io.Copy(w, r)
	r.Close()
}

func exist(filepath string) bool {
	_, err := os.Stat(filepath)
	return err == nil || os.IsExist(err)
}
<|endoftext|>


<commit_before>package types

type DatabaseService struct {
	Service        string  `json:"service"`
	Tag            string  `json:"tag"`
	DatabaseConfig
}

type DatabaseConfig struct {
	Host           string  `json:"addr"`
	Port           uint    `json:"port"`
	User           string  `json:"user"`
	Password       string  `json:"password"`
	Database       string  `json:"database"`
	Driver         string  `json:"driver"`
}<commit_msg>fixed tag in structure<commit_after>package types

type DatabaseService struct {
	Service        string  `json:"service"`
	Tag            string  `json:"tag"`
	DatabaseConfig
}

type DatabaseConfig struct {
	Host           string  `json:"host"`
	Port           uint    `json:"port"`
	User           string  `json:"user"`
	Password       string  `json:"password"`
	Database       string  `json:"database"`
	Driver         string  `json:"driver"`
}<|endoftext|>


<commit_before>package ui

import (
	"bytes"
	"fmt"

	"github.com/fabiofalci/sconsify/sconsify"
	"github.com/jroimartin/gocui"
)

type KeyMapping struct {
	key  interface{}
	h    gocui.KeybindingHandler
	view string
}

var multipleKeysBuffer bytes.Buffer
var multipleKeysNumber int

func keybindings() error {
	keys := make([]*KeyMapping, 0)

	for _, view := range []string{VIEW_TRACKS, VIEW_PLAYLISTS, VIEW_QUEUE} {
		addKeyBinding(&keys, newKeyMapping('p', view, pauseCurrentSelectedTrack))
		addKeyBinding(&keys, newKeyMapping('r', view, setRandomMode))
		addKeyBinding(&keys, newKeyMapping('R', view, setAllRandomMode))
		addKeyBinding(&keys, newKeyMapping('>', view, nextCommand))
		addKeyBinding(&keys, newKeyMapping('<', view, replayCommand))
		addKeyBinding(&keys, newKeyMapping('/', view, enableSearchInputCommand))
		addKeyBinding(&keys, newKeyMapping('j', view, cursorDown))
		addKeyBinding(&keys, newKeyMapping('k', view, cursorUp))
		addKeyBinding(&keys, newKeyMapping('q', view, quit))
	}

	allViews := ""
	addKeyBinding(&keys, newKeyMapping(gocui.KeySpace, VIEW_TRACKS, playCurrentSelectedTrack))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyEnter, VIEW_TRACKS, playCurrentSelectedTrack))
	addKeyBinding(&keys, newKeyMapping('u', VIEW_TRACKS, queueCommand))
	addKeyBinding(&keys, newKeyMapping('d', VIEW_PLAYLISTS, removeFromPlaylistsCommand))
	addKeyBinding(&keys, newKeyMapping('d', VIEW_QUEUE, removeFromQueueCommand))
	addKeyBinding(&keys, newKeyMapping('D', VIEW_QUEUE, removeAllFromQueueCommand))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyEnter, VIEW_STATUS, searchCommand))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyHome, allViews, cursorHome))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyEnd, allViews, cursorEnd))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyPgup, allViews, cursorPgup))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyPgdn, allViews, cursorPgdn))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyArrowDown, allViews, cursorDown))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyArrowUp, allViews, cursorUp))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyArrowLeft, VIEW_TRACKS, mainNextViewLeft))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyArrowLeft, VIEW_QUEUE, nextView))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyArrowRight, VIEW_PLAYLISTS, nextView))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyArrowRight, VIEW_TRACKS, mainNextViewRight))
	addKeyBinding(&keys, newKeyMapping('h', VIEW_TRACKS, mainNextViewLeft))
	addKeyBinding(&keys, newKeyMapping('h', VIEW_QUEUE, nextView))
	addKeyBinding(&keys, newKeyMapping('l', VIEW_PLAYLISTS, nextView))
	addKeyBinding(&keys, newKeyMapping('l', VIEW_TRACKS, mainNextViewRight))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyCtrlC, allViews, quit))
	addKeyBinding(&keys, newKeyMapping('G', allViews, uppergCommand))

	for _, key := range keys {
		// it needs to copy the key because closures copy var references and we don't
		// want to execute always the last action
		keyCopy := key
		if err := gui.g.SetKeybinding(key.view, key.key, 0,
			func(g *gocui.Gui, v *gocui.View) error {
				err := keyCopy.h(g, v)
				resetMultipleKeys()
				return err
			}); err != nil {
			return err
		}
	}

	// multiple keys
	keys = make([]*KeyMapping, 0)

	addKeyBinding(&keys, newKeyMapping('g', allViews,
		func(g *gocui.Gui, v *gocui.View) error {
			return multipleKeysPressed(g, v, 'g')
		}))

	// numbers
	for i := 0; i < 10; i++ {
		numberCopy := i
		addKeyBinding(&keys, newKeyMapping(rune(i+48), allViews,
			func(g *gocui.Gui, v *gocui.View) error {
				return multipleKeysNumberPressed(numberCopy)
			}))
	}

	for _, key := range keys {
		keyCopy := key
		if err := gui.g.SetKeybinding(key.view, key.key, 0,
			func(g *gocui.Gui, v *gocui.View) error {
				return keyCopy.h(g, v)
			}); err != nil {
			return err
		}
	}
	return nil
}

func addKeyBinding(keys *[]*KeyMapping, key *KeyMapping) {
	*keys = append(*keys, key)
}

func newKeyMapping(key interface{}, view string, h gocui.KeybindingHandler) *KeyMapping {
	return &KeyMapping{key: key, h: h, view: view}
}

func resetMultipleKeys() {
	multipleKeysBuffer.Reset()
	multipleKeysNumber = 0
}

func multipleKeysNumberPressed(pressedNumber int) error {
	if multipleKeysNumber == 0 {
		multipleKeysNumber = pressedNumber
	} else {
		multipleKeysNumber = multipleKeysNumber*10 + pressedNumber
	}
	return nil
}

func multipleKeysPressed(g *gocui.Gui, v *gocui.View, pressedKey rune) error {
	multipleKeysBuffer.WriteRune(pressedKey)

	switch multipleKeysBuffer.String() {
	case "gg":
		ggCommand(g, v)
		resetMultipleKeys()
	}

	return nil
}

func playCurrentSelectedTrack(g *gocui.Gui, v *gocui.View) error {
	player.Play()
	return nil
}

func pauseCurrentSelectedTrack(g *gocui.Gui, v *gocui.View) error {
	player.Pause()
	return nil
}

func setRandomMode(g *gocui.Gui, v *gocui.View) error {
	playlists.InvertMode(sconsify.RandomMode)
	gui.updateCurrentStatus()
	return nil
}

func setAllRandomMode(g *gocui.Gui, v *gocui.View) error {
	playlists.InvertMode(sconsify.AllRandomMode)
	gui.updateCurrentStatus()
	return nil
}

func nextCommand(g *gocui.Gui, v *gocui.View) error {
	gui.playNext()
	return nil
}

func replayCommand(g *gocui.Gui, v *gocui.View) error {
	gui.replay()
	return nil
}

func queueCommand(g *gocui.Gui, v *gocui.View) error {
	if playlist, trackIndex := gui.getSelectedPlaylistAndTrack(); playlist != nil {
		track := playlist.Track(trackIndex)
		fmt.Fprintf(gui.queueView, "%v\n", track.GetTitle())
		queue.Add(track)
	}
	return nil
}

func removeAllFromQueueCommand(g *gocui.Gui, v *gocui.View) error {
	queue.RemoveAll()
	gui.updateQueueView()
	return gui.enableTracksView()
}

func removeFromQueueCommand(g *gocui.Gui, v *gocui.View) error {
	if index := gui.getQueueSelectedTrackIndex(); index > -1 {
		queue.Remove(index)
		gui.updateQueueView()
	}
	return nil
}

func removeFromPlaylistsCommand(g *gocui.Gui, v *gocui.View) error {
	if playlist := gui.getSelectedPlaylist(); playlist != nil && playlist.IsSearch() {
		playlists.Remove(playlist.Name())
		gui.updatePlaylistsView()
		gui.updateTracksView()
	}
	return nil
}

func enableSearchInputCommand(g *gocui.Gui, v *gocui.View) error {
	gui.clearStatusView()
	gui.statusView.Editable = true
	gui.g.SetCurrentView(VIEW_STATUS)
	return nil
}

func searchCommand(g *gocui.Gui, v *gocui.View) error {
	// after user hit Enter, the typed command is at position -1
	if query, _ := gui.statusView.Line(-1); query != "" {
		events.Search(query)
	}
	gui.enableSideView()
	gui.clearStatusView()
	gui.statusView.Editable = false
	gui.updateCurrentStatus()
	return nil
}

func quit(g *gocui.Gui, v *gocui.View) error {
	consoleUserInterface.Shutdown()
	// TODO wait for shutdown
	// <-events.ShutdownUpdates()
	return gocui.Quit
}
<commit_msg>Trim typed search<commit_after>package ui

import (
	"bytes"
	"fmt"
	"strings"

	"github.com/fabiofalci/sconsify/sconsify"
	"github.com/jroimartin/gocui"
)

type KeyMapping struct {
	key  interface{}
	h    gocui.KeybindingHandler
	view string
}

var multipleKeysBuffer bytes.Buffer
var multipleKeysNumber int

func keybindings() error {
	keys := make([]*KeyMapping, 0)

	for _, view := range []string{VIEW_TRACKS, VIEW_PLAYLISTS, VIEW_QUEUE} {
		addKeyBinding(&keys, newKeyMapping('p', view, pauseCurrentSelectedTrack))
		addKeyBinding(&keys, newKeyMapping('r', view, setRandomMode))
		addKeyBinding(&keys, newKeyMapping('R', view, setAllRandomMode))
		addKeyBinding(&keys, newKeyMapping('>', view, nextCommand))
		addKeyBinding(&keys, newKeyMapping('<', view, replayCommand))
		addKeyBinding(&keys, newKeyMapping('/', view, enableSearchInputCommand))
		addKeyBinding(&keys, newKeyMapping('j', view, cursorDown))
		addKeyBinding(&keys, newKeyMapping('k', view, cursorUp))
		addKeyBinding(&keys, newKeyMapping('q', view, quit))
	}

	allViews := ""
	addKeyBinding(&keys, newKeyMapping(gocui.KeySpace, VIEW_TRACKS, playCurrentSelectedTrack))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyEnter, VIEW_TRACKS, playCurrentSelectedTrack))
	addKeyBinding(&keys, newKeyMapping('u', VIEW_TRACKS, queueCommand))
	addKeyBinding(&keys, newKeyMapping('d', VIEW_PLAYLISTS, removeFromPlaylistsCommand))
	addKeyBinding(&keys, newKeyMapping('d', VIEW_QUEUE, removeFromQueueCommand))
	addKeyBinding(&keys, newKeyMapping('D', VIEW_QUEUE, removeAllFromQueueCommand))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyEnter, VIEW_STATUS, searchCommand))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyHome, allViews, cursorHome))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyEnd, allViews, cursorEnd))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyPgup, allViews, cursorPgup))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyPgdn, allViews, cursorPgdn))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyArrowDown, allViews, cursorDown))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyArrowUp, allViews, cursorUp))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyArrowLeft, VIEW_TRACKS, mainNextViewLeft))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyArrowLeft, VIEW_QUEUE, nextView))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyArrowRight, VIEW_PLAYLISTS, nextView))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyArrowRight, VIEW_TRACKS, mainNextViewRight))
	addKeyBinding(&keys, newKeyMapping('h', VIEW_TRACKS, mainNextViewLeft))
	addKeyBinding(&keys, newKeyMapping('h', VIEW_QUEUE, nextView))
	addKeyBinding(&keys, newKeyMapping('l', VIEW_PLAYLISTS, nextView))
	addKeyBinding(&keys, newKeyMapping('l', VIEW_TRACKS, mainNextViewRight))
	addKeyBinding(&keys, newKeyMapping(gocui.KeyCtrlC, allViews, quit))
	addKeyBinding(&keys, newKeyMapping('G', allViews, uppergCommand))

	for _, key := range keys {
		// it needs to copy the key because closures copy var references and we don't
		// want to execute always the last action
		keyCopy := key
		if err := gui.g.SetKeybinding(key.view, key.key, 0,
			func(g *gocui.Gui, v *gocui.View) error {
				err := keyCopy.h(g, v)
				resetMultipleKeys()
				return err
			}); err != nil {
			return err
		}
	}

	// multiple keys
	keys = make([]*KeyMapping, 0)

	addKeyBinding(&keys, newKeyMapping('g', allViews,
		func(g *gocui.Gui, v *gocui.View) error {
			return multipleKeysPressed(g, v, 'g')
		}))

	// numbers
	for i := 0; i < 10; i++ {
		numberCopy := i
		addKeyBinding(&keys, newKeyMapping(rune(i+48), allViews,
			func(g *gocui.Gui, v *gocui.View) error {
				return multipleKeysNumberPressed(numberCopy)
			}))
	}

	for _, key := range keys {
		keyCopy := key
		if err := gui.g.SetKeybinding(key.view, key.key, 0,
			func(g *gocui.Gui, v *gocui.View) error {
				return keyCopy.h(g, v)
			}); err != nil {
			return err
		}
	}
	return nil
}

func addKeyBinding(keys *[]*KeyMapping, key *KeyMapping) {
	*keys = append(*keys, key)
}

func newKeyMapping(key interface{}, view string, h gocui.KeybindingHandler) *KeyMapping {
	return &KeyMapping{key: key, h: h, view: view}
}

func resetMultipleKeys() {
	multipleKeysBuffer.Reset()
	multipleKeysNumber = 0
}

func multipleKeysNumberPressed(pressedNumber int) error {
	if multipleKeysNumber == 0 {
		multipleKeysNumber = pressedNumber
	} else {
		multipleKeysNumber = multipleKeysNumber*10 + pressedNumber
	}
	return nil
}

func multipleKeysPressed(g *gocui.Gui, v *gocui.View, pressedKey rune) error {
	multipleKeysBuffer.WriteRune(pressedKey)

	switch multipleKeysBuffer.String() {
	case "gg":
		ggCommand(g, v)
		resetMultipleKeys()
	}

	return nil
}

func playCurrentSelectedTrack(g *gocui.Gui, v *gocui.View) error {
	player.Play()
	return nil
}

func pauseCurrentSelectedTrack(g *gocui.Gui, v *gocui.View) error {
	player.Pause()
	return nil
}

func setRandomMode(g *gocui.Gui, v *gocui.View) error {
	playlists.InvertMode(sconsify.RandomMode)
	gui.updateCurrentStatus()
	return nil
}

func setAllRandomMode(g *gocui.Gui, v *gocui.View) error {
	playlists.InvertMode(sconsify.AllRandomMode)
	gui.updateCurrentStatus()
	return nil
}

func nextCommand(g *gocui.Gui, v *gocui.View) error {
	gui.playNext()
	return nil
}

func replayCommand(g *gocui.Gui, v *gocui.View) error {
	gui.replay()
	return nil
}

func queueCommand(g *gocui.Gui, v *gocui.View) error {
	if playlist, trackIndex := gui.getSelectedPlaylistAndTrack(); playlist != nil {
		track := playlist.Track(trackIndex)
		fmt.Fprintf(gui.queueView, "%v\n", track.GetTitle())
		queue.Add(track)
	}
	return nil
}

func removeAllFromQueueCommand(g *gocui.Gui, v *gocui.View) error {
	queue.RemoveAll()
	gui.updateQueueView()
	return gui.enableTracksView()
}

func removeFromQueueCommand(g *gocui.Gui, v *gocui.View) error {
	if index := gui.getQueueSelectedTrackIndex(); index > -1 {
		queue.Remove(index)
		gui.updateQueueView()
	}
	return nil
}

func removeFromPlaylistsCommand(g *gocui.Gui, v *gocui.View) error {
	if playlist := gui.getSelectedPlaylist(); playlist != nil && playlist.IsSearch() {
		playlists.Remove(playlist.Name())
		gui.updatePlaylistsView()
		gui.updateTracksView()
	}
	return nil
}

func enableSearchInputCommand(g *gocui.Gui, v *gocui.View) error {
	gui.clearStatusView()
	gui.statusView.Editable = true
	gui.g.SetCurrentView(VIEW_STATUS)
	return nil
}

func searchCommand(g *gocui.Gui, v *gocui.View) error {
	// after user hit Enter, the typed command is at position -1
	query, _ := gui.statusView.Line(-1)
	query = strings.Trim(query, " ")
	if query != "" {
		events.Search(query)
	}
	gui.enableSideView()
	gui.clearStatusView()
	gui.statusView.Editable = false
	gui.updateCurrentStatus()
	return nil
}

func quit(g *gocui.Gui, v *gocui.View) error {
	consoleUserInterface.Shutdown()
	// TODO wait for shutdown
	// <-events.ShutdownUpdates()
	return gocui.Quit
}
<|endoftext|>


<commit_before>package cmd

import (
	"os/exec"

	"github.com/markbates/buffalo/buffalo/cmd/generate"
	"github.com/markbates/gentronics"
)

func newAppGenerator() *gentronics.Generator {
	g := gentronics.New()
	g.Add(gentronics.NewFile("main.go", nMain))
	g.Add(gentronics.NewFile("Procfile", nProcfile))
	g.Add(gentronics.NewFile("Procfile.development", nProcfileDev))
	g.Add(gentronics.NewFile(".buffalo.dev.yml", nRefresh))
	g.Add(gentronics.NewFile("actions/app.go", nApp))
	g.Add(gentronics.NewFile("actions/home.go", nHomeHandler))
	g.Add(gentronics.NewFile("actions/home_test.go", nHomeHandlerTest))
	g.Add(gentronics.NewFile("actions/render.go", nRender))
	g.Add(gentronics.NewFile("grifts/routes.go", nGriftRoutes))
	g.Add(gentronics.NewFile("templates/index.html", nIndexHTML))
	g.Add(gentronics.NewFile("templates/application.html", nApplicationHTML))
	g.Add(gentronics.NewFile("assets/application.js", ""))
	g.Add(gentronics.NewFile("assets/application.css", nApplicationCSS))
	g.Add(gentronics.NewFile(".gitignore", nGitignore))
	g.Add(gentronics.NewCommand(goGet("github.com/markbates/refresh/...")))
	g.Add(gentronics.NewCommand(goInstall("github.com/markbates/refresh")))
	g.Add(gentronics.NewCommand(goGet("github.com/markbates/grift/...")))
	g.Add(gentronics.NewCommand(goInstall("github.com/markbates/grift")))
	g.Add(generate.NewJQueryGenerator())
	g.Add(generate.NewBootstrapGenerator())
	g.Add(newSodaGenerator())
	g.Add(gentronics.NewCommand(appGoGet()))
	g.Add(generate.Fmt)
	return g
}

func appGoGet() *exec.Cmd {
	appArgs := []string{"get", "-t"}
	if verbose {
		appArgs = append(appArgs, "-v")
	}
	appArgs = append(appArgs, "./...")
	return exec.Command("go", appArgs...)
}

const nMain = `package main

import (
	"log"
	"net/http"

	"{{.actionsPath}}"
)

func main() {
	log.Fatal(http.ListenAndServe(":3000", actions.App()))
}

`
const nApp = `package actions

import (
	"net/http"

	"github.com/markbates/buffalo"
	{{if .withPop -}}
	"github.com/markbates/buffalo/middleware"
	"{{.modelsPath}}"
	{{end -}}
)

// App is where all routes and middleware for buffalo
// should be defined. This is the nerve center of your
// application.
func App() http.Handler {
	a := buffalo.Automatic(buffalo.Options{
		Env: "development",
	})

	{{if .withPop -}}
	a.Use(middleware.PopTransaction(models.DB))
	{{end -}}

	a.ServeFiles("/assets", assetsPath())
	a.GET("/", HomeHandler)

	return a
}
`

const nRender = `package actions

import (
	"net/http"
	"path"
	"runtime"

	"github.com/markbates/buffalo/render"
)

var r *render.Engine

func init() {
	r = render.New(render.Options{
		TemplatesPath: fromHere("../templates"),
		HTMLLayout:    "application.html",
	})
}

func assetsPath() http.Dir {
	return http.Dir(fromHere("../assets"))
}

func fromHere(p string) string {
	_, filename, _, _ := runtime.Caller(1)
	return path.Join(path.Dir(filename), p)
}
`

const nHomeHandler = `package actions

import "github.com/markbates/buffalo"

// HomeHandler is a default handler to serve up
// a home page.
func HomeHandler(c buffalo.Context) error {
	return c.Render(200, r.HTML("index.html"))
}
`

const nHomeHandlerTest = `package actions_test

import (
	"testing"

	"{{.actionsPath}}"
	"github.com/markbates/willie"
	"github.com/stretchr/testify/require"
)

func Test_HomeHandler(t *testing.T) {
	r := require.New(t)

	w := willie.New(actions.App())
	res := w.Request("/").Get()

	r.Equal(200, res.Code)
	r.Contains(res.Body.String(), "Welcome to Buffalo!")
}
`

const nIndexHTML = `<h1>Welcome to Buffalo!</h1>`

const nApplicationHTML = `<html>
<head>
  <meta charset="utf-8">
  <title>Buffalo - {{ .titleName }}</title>
  {{if .withBootstrap -}}
  <link rel="stylesheet" href="/assets/bootstrap.css" type="text/css" media="all" />
  {{end -}}
  <link rel="stylesheet" href="/assets/application.css" type="text/css" media="all" />
</head>
<body>

  {{"{{"}} yield {{"}}"}}

  {{if .withJQuery -}}
  <script src="/assets/jquery.js" type="text/javascript" charset="utf-8"></script>
  {{end -}}
  {{if .withBootstrap -}}
  <script src="/assets/bootstrap.js" type="text/javascript" charset="utf-8"></script>
  {{end -}}
  <script src="/assets/application.js" type="text/javascript" charset="utf-8"></script>
</body>
</html>
`

const nApplicationCSS = `body {
  font-family: helvetica;
}
`

const nGitignore = `vendor/
**/*.log
**/*.sqlite
bin/
node_modules/
{{ .name }}
`

const nGriftRoutes = `package grifts

import (
	"os"

	"github.com/markbates/buffalo"
	. "github.com/markbates/grift/grift"
	"{{.actionsPath}}"
	"github.com/olekukonko/tablewriter"
)

var _ = Add("routes", func(c *Context) error {
	a := actions.App().(*buffalo.App)
	routes := a.Routes()

	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"Method", "Path", "Handler"})
	for _, r := range routes {
		table.Append([]string{r.Method, r.Path, r.HandlerName})
	}
	table.SetCenterSeparator("|")
	table.SetAlignment(tablewriter.ALIGN_LEFT)
	table.Render()
	return nil
})`

const nRefresh = `app_root: .
ignored_folders:
- vendor
- log
- tmp
included_extensions:
- .go
- .html
build_path: /tmp
build_delay: 200ns
binary_name: {{.name}}-build
command_flags: []
enable_colors: true
log_name: buffalo
`

const nProcfile = `web: go run main.go`
const nProcfileDev = `web: buffalo dev`
<commit_msg>Procfile should use the project name by default closes #44<commit_after>package cmd

import (
	"os/exec"

	"github.com/markbates/buffalo/buffalo/cmd/generate"
	"github.com/markbates/gentronics"
)

func newAppGenerator() *gentronics.Generator {
	g := gentronics.New()
	g.Add(gentronics.NewFile("main.go", nMain))
	g.Add(gentronics.NewFile("Procfile", nProcfile))
	g.Add(gentronics.NewFile("Procfile.development", nProcfileDev))
	g.Add(gentronics.NewFile(".buffalo.dev.yml", nRefresh))
	g.Add(gentronics.NewFile("actions/app.go", nApp))
	g.Add(gentronics.NewFile("actions/home.go", nHomeHandler))
	g.Add(gentronics.NewFile("actions/home_test.go", nHomeHandlerTest))
	g.Add(gentronics.NewFile("actions/render.go", nRender))
	g.Add(gentronics.NewFile("grifts/routes.go", nGriftRoutes))
	g.Add(gentronics.NewFile("templates/index.html", nIndexHTML))
	g.Add(gentronics.NewFile("templates/application.html", nApplicationHTML))
	g.Add(gentronics.NewFile("assets/application.js", ""))
	g.Add(gentronics.NewFile("assets/application.css", nApplicationCSS))
	g.Add(gentronics.NewFile(".gitignore", nGitignore))
	g.Add(gentronics.NewCommand(goGet("github.com/markbates/refresh/...")))
	g.Add(gentronics.NewCommand(goInstall("github.com/markbates/refresh")))
	g.Add(gentronics.NewCommand(goGet("github.com/markbates/grift/...")))
	g.Add(gentronics.NewCommand(goInstall("github.com/markbates/grift")))
	g.Add(generate.NewJQueryGenerator())
	g.Add(generate.NewBootstrapGenerator())
	g.Add(newSodaGenerator())
	g.Add(gentronics.NewCommand(appGoGet()))
	g.Add(generate.Fmt)
	return g
}

func appGoGet() *exec.Cmd {
	appArgs := []string{"get", "-t"}
	if verbose {
		appArgs = append(appArgs, "-v")
	}
	appArgs = append(appArgs, "./...")
	return exec.Command("go", appArgs...)
}

const nMain = `package main

import (
	"log"
	"net/http"

	"{{.actionsPath}}"
)

func main() {
	log.Fatal(http.ListenAndServe(":3000", actions.App()))
}

`
const nApp = `package actions

import (
	"net/http"

	"github.com/markbates/buffalo"
	{{if .withPop -}}
	"github.com/markbates/buffalo/middleware"
	"{{.modelsPath}}"
	{{end -}}
)

// App is where all routes and middleware for buffalo
// should be defined. This is the nerve center of your
// application.
func App() http.Handler {
	a := buffalo.Automatic(buffalo.Options{
		Env: "development",
	})

	{{if .withPop -}}
	a.Use(middleware.PopTransaction(models.DB))
	{{end -}}

	a.ServeFiles("/assets", assetsPath())
	a.GET("/", HomeHandler)

	return a
}
`

const nRender = `package actions

import (
	"net/http"
	"path"
	"runtime"

	"github.com/markbates/buffalo/render"
)

var r *render.Engine

func init() {
	r = render.New(render.Options{
		TemplatesPath: fromHere("../templates"),
		HTMLLayout:    "application.html",
	})
}

func assetsPath() http.Dir {
	return http.Dir(fromHere("../assets"))
}

func fromHere(p string) string {
	_, filename, _, _ := runtime.Caller(1)
	return path.Join(path.Dir(filename), p)
}
`

const nHomeHandler = `package actions

import "github.com/markbates/buffalo"

// HomeHandler is a default handler to serve up
// a home page.
func HomeHandler(c buffalo.Context) error {
	return c.Render(200, r.HTML("index.html"))
}
`

const nHomeHandlerTest = `package actions_test

import (
	"testing"

	"{{.actionsPath}}"
	"github.com/markbates/willie"
	"github.com/stretchr/testify/require"
)

func Test_HomeHandler(t *testing.T) {
	r := require.New(t)

	w := willie.New(actions.App())
	res := w.Request("/").Get()

	r.Equal(200, res.Code)
	r.Contains(res.Body.String(), "Welcome to Buffalo!")
}
`

const nIndexHTML = `<h1>Welcome to Buffalo!</h1>`

const nApplicationHTML = `<html>
<head>
  <meta charset="utf-8">
  <title>Buffalo - {{ .titleName }}</title>
  {{if .withBootstrap -}}
  <link rel="stylesheet" href="/assets/bootstrap.css" type="text/css" media="all" />
  {{end -}}
  <link rel="stylesheet" href="/assets/application.css" type="text/css" media="all" />
</head>
<body>

  {{"{{"}} yield {{"}}"}}

  {{if .withJQuery -}}
  <script src="/assets/jquery.js" type="text/javascript" charset="utf-8"></script>
  {{end -}}
  {{if .withBootstrap -}}
  <script src="/assets/bootstrap.js" type="text/javascript" charset="utf-8"></script>
  {{end -}}
  <script src="/assets/application.js" type="text/javascript" charset="utf-8"></script>
</body>
</html>
`

const nApplicationCSS = `body {
  font-family: helvetica;
}
`

const nGitignore = `vendor/
**/*.log
**/*.sqlite
bin/
node_modules/
{{ .name }}
`

const nGriftRoutes = `package grifts

import (
	"os"

	"github.com/markbates/buffalo"
	. "github.com/markbates/grift/grift"
	"{{.actionsPath}}"
	"github.com/olekukonko/tablewriter"
)

var _ = Add("routes", func(c *Context) error {
	a := actions.App().(*buffalo.App)
	routes := a.Routes()

	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"Method", "Path", "Handler"})
	for _, r := range routes {
		table.Append([]string{r.Method, r.Path, r.HandlerName})
	}
	table.SetCenterSeparator("|")
	table.SetAlignment(tablewriter.ALIGN_LEFT)
	table.Render()
	return nil
})`

const nRefresh = `app_root: .
ignored_folders:
- vendor
- log
- tmp
included_extensions:
- .go
- .html
build_path: /tmp
build_delay: 200ns
binary_name: {{.name}}-build
command_flags: []
enable_colors: true
log_name: buffalo
`

const nProcfile = `web: {{.name}}`
const nProcfileDev = `web: buffalo dev`
<|endoftext|>