<commit_before>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ogletest

import (
	"fmt"
	"math"
	"reflect"
)

// Equals returns a matcher that matches any value v such that v == x, with the
// exception that if x is a numeric type, Equals(x) will match equivalent
// numeric values of any type.
func Equals(x interface{}) Matcher {
	v := reflect.ValueOf(x)

	// The == operator is not defined for array or struct types.
	if v.Kind() == reflect.Array || v.Kind() == reflect.Struct {
		panic(fmt.Sprintf("ogletest.Equals: unsupported type", v.Kind()))
	}

	return &equalsMatcher{v}
}

type equalsMatcher struct {
	expectedValue reflect.Value
}

////////////////////////////////////////////////////////////
// Numeric types
////////////////////////////////////////////////////////////

func isSignedInteger(v reflect.Value) bool {
	k := v.Kind()
	return k >= reflect.Int && k <= reflect.Int64
}

func isUnsignedInteger(v reflect.Value) bool {
	k := v.Kind()
	return k >= reflect.Uint && k <= reflect.Uint64
}

func isInteger(v reflect.Value) bool {
	return isSignedInteger(v) || isUnsignedInteger(v)
}

func isFloat(v reflect.Value) bool {
	k := v.Kind()
	return k == reflect.Float32 || k == reflect.Float64
}

func isComplex(v reflect.Value) bool {
	k := v.Kind()
	return k == reflect.Complex64 || k == reflect.Complex128
}

func checkAgainstInt64(e int64, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE

	switch {
	case isSignedInteger(c):
		if c.Int() == e {
			res = MATCH_TRUE
		}

	case isUnsignedInteger(c):
		u := c.Uint()
		if u <= math.MaxInt64 && int64(u) == e {
			res = MATCH_TRUE
		}

	// Turn around the various floating point types so that the checkAgainst*
	// functions for them can deal with precision issues.
	case isFloat(c), isComplex(c):
		return Equals(c.Interface()).Matches(e)

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstUint64(e uint64, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE

	switch {
	case isSignedInteger(c):
		i := c.Int()
		if i >= 0 && uint64(i) == e {
			res = MATCH_TRUE
		}

	case isUnsignedInteger(c):
		if c.Uint() == e {
			res = MATCH_TRUE
		}

	// Turn around the various floating point types so that the checkAgainst*
	// functions for them can deal with precision issues.
	case isFloat(c), isComplex(c):
		return Equals(c.Interface()).Matches(e)

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstFloat32(e float32, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE

	switch {
	case isSignedInteger(c):
		if float32(c.Int()) == e {
			res = MATCH_TRUE
		}

	case isUnsignedInteger(c):
		if float32(c.Uint()) == e {
			res = MATCH_TRUE
		}

	case isFloat(c):
		// Compare using float32 to avoid a false sense of precision; otherwise
		// e.g. Equals(float32(0.1)) won't match float32(0.1).
		if float32(c.Float()) == e {
			res = MATCH_TRUE
		}

	case isComplex(c):
		comp := c.Complex()
		rl := real(comp)
		im := imag(comp)

		// Compare using float32 to avoid a false sense of precision; otherwise
		// e.g. Equals(float32(0.1)) won't match (0.1 + 0i).
		if im == 0 && float32(rl) == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstFloat64(e float64, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE

	ck := c.Kind()

	switch {
	case isSignedInteger(c):
		if float64(c.Int()) == e {
			res = MATCH_TRUE
		}

	case isUnsignedInteger(c):
		if float64(c.Uint()) == e {
			res = MATCH_TRUE
		}

	// If the actual value is lower precision, turn the comparison around so we
	// apply the low-precision rules. Otherwise, e.g. Equals(0.1) may not match
	// float32(0.1).
	case ck == reflect.Float32 || ck == reflect.Complex64:
		return Equals(c.Interface()).Matches(e)

  // Otherwise, compare with double precision.
	case isFloat(c):
		if c.Float() == e {
			res = MATCH_TRUE
		}

	case isComplex(c):
		comp := c.Complex()
		rl := real(comp)
		im := imag(comp)

		if im == 0 && rl == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstComplex64(e complex64, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE
	realPart := real(e)
	imaginaryPart := imag(e)

	switch {
	case isInteger(c) || isFloat(c):
		// If we have no imaginary part, then we should just compare against the
		// real part. Otherwise, we can't be equal.
		if imaginaryPart != 0 {
			res = MATCH_FALSE
			return
		}

		return checkAgainstFloat32(realPart, c)

	case isComplex(c):
		// Compare using complex64 to avoid a false sense of precision; otherwise
		// e.g. Equals(0.1 + 0i) won't match float32(0.1).
		if complex64(c.Complex()) == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstComplex128(e complex128, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE
	realPart := real(e)
	imaginaryPart := imag(e)

	switch {
	case isInteger(c) || isFloat(c):
		// If we have no imaginary part, then we should just compare against the
		// real part. Otherwise, we can't be equal.
		if imaginaryPart != 0 {
			res = MATCH_FALSE
			return
		}

		return checkAgainstFloat64(realPart, c)

	case isComplex(c):
		if c.Complex() == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

////////////////////////////////////////////////////////////
// Other types
////////////////////////////////////////////////////////////

func checkAgainstBool(e bool, c reflect.Value) (res MatchResult, err string) {
	if c.Kind() != reflect.Bool {
		res = MATCH_UNDEFINED
		err = "which is not a bool"
		return
	}

	res = MATCH_FALSE
	if c.Bool() == e {
		res = MATCH_TRUE
	}
	return
}

func checkAgainstUintptr(e uintptr, c reflect.Value) (res MatchResult, err string) {
	if c.Kind() != reflect.Uintptr {
		res = MATCH_UNDEFINED
		err = "which is not a uintptr"
		return
	}

	res = MATCH_FALSE
	if uintptr(c.Uint()) == e {
		res = MATCH_TRUE
	}
	return
}

func checkAgainstChan(e reflect.Value, c reflect.Value) (res MatchResult, err string) {
	// Create a description of e's type, e.g. "chan int".
	typeStr := fmt.Sprintf("%s %s", e.Type().ChanDir(), e.Type().Elem())

	// Make sure c is a chan of the correct type.
	if c.Kind() != reflect.Chan ||
	   c.Type().ChanDir() != e.Type().ChanDir() ||
		 c.Type().Elem() != e.Type().Elem() {
		res = MATCH_UNDEFINED
		err = fmt.Sprintf("which is not a %s", typeStr)
		return
	}

	res = MATCH_FALSE
	if c.Pointer() == e.Pointer() {
		res = MATCH_TRUE
	}
	return
}

func checkAgainstFunc(e reflect.Value, c reflect.Value) (res MatchResult, err string) {
	// Make sure c is a function.
	if c.Kind() != reflect.Func {
		res = MATCH_UNDEFINED
		err = "which is not a function"
		return
	}

	res = MATCH_FALSE
	if c.Pointer() == e.Pointer() {
		res = MATCH_TRUE
	}
	return
}

func checkAgainstMap(e reflect.Value, c reflect.Value) (res MatchResult, err string) {
	// Make sure c is a map.
	if c.Kind() != reflect.Map {
		res = MATCH_UNDEFINED
		err = "which is not a map"
		return
	}

	res = MATCH_FALSE
	if c.Pointer() == e.Pointer() {
		res = MATCH_TRUE
	}
	return
}

func checkAgainstPtr(e reflect.Value, c reflect.Value) (res MatchResult, err string) {
	// Make sure c is a pointer.
	if c.Kind() != reflect.Ptr {
		res = MATCH_UNDEFINED
		err = "which is not a pointer"
		return
	}

	res = MATCH_FALSE
	if c.Pointer() == e.Pointer() {
		res = MATCH_TRUE
	}
	return
}

func checkAgainstUnsafePointer(e reflect.Value, c reflect.Value) (res MatchResult, err string) {
	// Make sure c is a pointer.
	if c.Kind() != reflect.UnsafePointer {
		res = MATCH_UNDEFINED
		err = "which is not a unsafe.Pointer"
		return
	}

	res = MATCH_FALSE
	if c.Pointer() == e.Pointer() {
		res = MATCH_TRUE
	}
	return
}

////////////////////////////////////////////////////////////
// Public implementation
////////////////////////////////////////////////////////////

func (m *equalsMatcher) Matches(candidate interface{}) (MatchResult, string) {
	e := m.expectedValue
	c := reflect.ValueOf(candidate)
	ek := e.Kind()

	switch {
	case ek == reflect.Bool:
		return checkAgainstBool(e.Bool(), c)

	case isSignedInteger(e):
		return checkAgainstInt64(e.Int(), c)

	case isUnsignedInteger(e):
		return checkAgainstUint64(e.Uint(), c)

	case ek == reflect.Uintptr:
		return checkAgainstUintptr(uintptr(e.Uint()), c)

	case ek == reflect.Float32:
		return checkAgainstFloat32(float32(e.Float()), c)

	case ek == reflect.Float64:
		return checkAgainstFloat64(e.Float(), c)

	case ek == reflect.Complex64:
		return checkAgainstComplex64(complex64(e.Complex()), c)

	case ek == reflect.Complex128:
		return checkAgainstComplex128(complex128(e.Complex()), c)

	case ek == reflect.Chan:
		return checkAgainstChan(e, c)

	case ek == reflect.Func:
		return checkAgainstFunc(e, c)

	case ek == reflect.Map:
		return checkAgainstMap(e, c)

	case ek == reflect.Ptr:
		return checkAgainstPtr(e, c)

	case ek == reflect.UnsafePointer:
		return checkAgainstUnsafePointer(e, c)
	}

	return MATCH_UNDEFINED, "TODO"
}

func (m *equalsMatcher) Description() string {
	return fmt.Sprintf("%v", m.expectedValue.Interface())
}
<commit_msg>Fixed some bugs.<commit_after>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ogletest

import (
	"fmt"
	"math"
	"reflect"
)

// Equals returns a matcher that matches any value v such that v == x, with the
// exception that if x is a numeric type, Equals(x) will match equivalent
// numeric values of any type.
func Equals(x interface{}) Matcher {
	v := reflect.ValueOf(x)

	// The == operator is not defined for array or struct types.
	if v.Kind() == reflect.Array || v.Kind() == reflect.Struct {
		panic(fmt.Sprintf("ogletest.Equals: unsupported type", v.Kind()))
	}

	return &equalsMatcher{v}
}

type equalsMatcher struct {
	expectedValue reflect.Value
}

////////////////////////////////////////////////////////////
// Numeric types
////////////////////////////////////////////////////////////

func isSignedInteger(v reflect.Value) bool {
	k := v.Kind()
	return k >= reflect.Int && k <= reflect.Int64
}

func isUnsignedInteger(v reflect.Value) bool {
	k := v.Kind()
	return k >= reflect.Uint && k <= reflect.Uint64
}

func isInteger(v reflect.Value) bool {
	return isSignedInteger(v) || isUnsignedInteger(v)
}

func isFloat(v reflect.Value) bool {
	k := v.Kind()
	return k == reflect.Float32 || k == reflect.Float64
}

func isComplex(v reflect.Value) bool {
	k := v.Kind()
	return k == reflect.Complex64 || k == reflect.Complex128
}

func checkAgainstInt64(e int64, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE

	switch {
	case isSignedInteger(c):
		if c.Int() == e {
			res = MATCH_TRUE
		}

	case isUnsignedInteger(c):
		u := c.Uint()
		if u <= math.MaxInt64 && int64(u) == e {
			res = MATCH_TRUE
		}

	// Turn around the various floating point types so that the checkAgainst*
	// functions for them can deal with precision issues.
	case isFloat(c), isComplex(c):
		return Equals(c.Interface()).Matches(e)

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstUint64(e uint64, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE

	switch {
	case isSignedInteger(c):
		i := c.Int()
		if i >= 0 && uint64(i) == e {
			res = MATCH_TRUE
		}

	case isUnsignedInteger(c):
		if c.Uint() == e {
			res = MATCH_TRUE
		}

	// Turn around the various floating point types so that the checkAgainst*
	// functions for them can deal with precision issues.
	case isFloat(c), isComplex(c):
		return Equals(c.Interface()).Matches(e)

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstFloat32(e float32, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE

	switch {
	case isSignedInteger(c):
		if float32(c.Int()) == e {
			res = MATCH_TRUE
		}

	case isUnsignedInteger(c):
		if float32(c.Uint()) == e {
			res = MATCH_TRUE
		}

	case isFloat(c):
		// Compare using float32 to avoid a false sense of precision; otherwise
		// e.g. Equals(float32(0.1)) won't match float32(0.1).
		if float32(c.Float()) == e {
			res = MATCH_TRUE
		}

	case isComplex(c):
		comp := c.Complex()
		rl := real(comp)
		im := imag(comp)

		// Compare using float32 to avoid a false sense of precision; otherwise
		// e.g. Equals(float32(0.1)) won't match (0.1 + 0i).
		if im == 0 && float32(rl) == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstFloat64(e float64, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE

	ck := c.Kind()

	switch {
	case isSignedInteger(c):
		if float64(c.Int()) == e {
			res = MATCH_TRUE
		}

	case isUnsignedInteger(c):
		if float64(c.Uint()) == e {
			res = MATCH_TRUE
		}

	// If the actual value is lower precision, turn the comparison around so we
	// apply the low-precision rules. Otherwise, e.g. Equals(0.1) may not match
	// float32(0.1).
	case ck == reflect.Float32 || ck == reflect.Complex64:
		return Equals(c.Interface()).Matches(e)

  // Otherwise, compare with double precision.
	case isFloat(c):
		if c.Float() == e {
			res = MATCH_TRUE
		}

	case isComplex(c):
		comp := c.Complex()
		rl := real(comp)
		im := imag(comp)

		if im == 0 && rl == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstComplex64(e complex64, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE
	realPart := real(e)
	imaginaryPart := imag(e)

	switch {
	case isInteger(c) || isFloat(c):
		// If we have no imaginary part, then we should just compare against the
		// real part. Otherwise, we can't be equal.
		if imaginaryPart != 0 {
			res = MATCH_FALSE
			return
		}

		return checkAgainstFloat32(realPart, c)

	case isComplex(c):
		// Compare using complex64 to avoid a false sense of precision; otherwise
		// e.g. Equals(0.1 + 0i) won't match float32(0.1).
		if complex64(c.Complex()) == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstComplex128(e complex128, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE
	realPart := real(e)
	imaginaryPart := imag(e)

	switch {
	case isInteger(c) || isFloat(c):
		// If we have no imaginary part, then we should just compare against the
		// real part. Otherwise, we can't be equal.
		if imaginaryPart != 0 {
			res = MATCH_FALSE
			return
		}

		return checkAgainstFloat64(realPart, c)

	case isComplex(c):
		if c.Complex() == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

////////////////////////////////////////////////////////////
// Other types
////////////////////////////////////////////////////////////

func checkAgainstBool(e bool, c reflect.Value) (res MatchResult, err string) {
	if c.Kind() != reflect.Bool {
		res = MATCH_UNDEFINED
		err = "which is not a bool"
		return
	}

	res = MATCH_FALSE
	if c.Bool() == e {
		res = MATCH_TRUE
	}
	return
}

func checkAgainstUintptr(e uintptr, c reflect.Value) (res MatchResult, err string) {
	if c.Kind() != reflect.Uintptr {
		res = MATCH_UNDEFINED
		err = "which is not a uintptr"
		return
	}

	res = MATCH_FALSE
	if uintptr(c.Uint()) == e {
		res = MATCH_TRUE
	}
	return
}

func checkAgainstChan(e reflect.Value, c reflect.Value) (res MatchResult, err string) {
	// Create a description of e's type, e.g. "chan int".
	typeStr := fmt.Sprintf("%s %s", e.Type().ChanDir(), e.Type().Elem())

	// Make sure c is a chan of the correct type.
	if c.Kind() != reflect.Chan ||
	   c.Type().ChanDir() != e.Type().ChanDir() ||
		 c.Type().Elem() != e.Type().Elem() {
		res = MATCH_UNDEFINED
		err = fmt.Sprintf("which is not a %s", typeStr)
		return
	}

	res = MATCH_FALSE
	if c.Pointer() == e.Pointer() {
		res = MATCH_TRUE
	}
	return
}

func checkAgainstFunc(e reflect.Value, c reflect.Value) (res MatchResult, err string) {
	// Make sure c is a function.
	if c.Kind() != reflect.Func {
		res = MATCH_UNDEFINED
		err = "which is not a function"
		return
	}

	res = MATCH_FALSE
	if c.Pointer() == e.Pointer() {
		res = MATCH_TRUE
	}
	return
}

func checkAgainstMap(e reflect.Value, c reflect.Value) (res MatchResult, err string) {
	// Make sure c is a map.
	if c.Kind() != reflect.Map {
		res = MATCH_UNDEFINED
		err = "which is not a map"
		return
	}

	res = MATCH_FALSE
	if c.Pointer() == e.Pointer() {
		res = MATCH_TRUE
	}
	return
}

func checkAgainstPtr(e reflect.Value, c reflect.Value) (res MatchResult, err string) {
	// Create a description of e's type, e.g. "*int".
	typeStr := fmt.Sprintf("*%v", e.Type().Elem())

	// Make sure c is a pointer of the correct type.
	if c.Kind() != reflect.Ptr ||
		 c.Type().Elem() != e.Type().Elem() {
		res = MATCH_UNDEFINED
		err = fmt.Sprintf("which is not a %s", typeStr)
		return
	}

	res = MATCH_FALSE
	if c.Pointer() == e.Pointer() {
		res = MATCH_TRUE
	}
	return
}

func checkAgainstUnsafePointer(e reflect.Value, c reflect.Value) (res MatchResult, err string) {
	// Make sure c is a pointer.
	if c.Kind() != reflect.UnsafePointer {
		res = MATCH_UNDEFINED
		err = "which is not a unsafe.Pointer"
		return
	}

	res = MATCH_FALSE
	if c.Pointer() == e.Pointer() {
		res = MATCH_TRUE
	}
	return
}

////////////////////////////////////////////////////////////
// Public implementation
////////////////////////////////////////////////////////////

func (m *equalsMatcher) Matches(candidate interface{}) (MatchResult, string) {
	e := m.expectedValue
	c := reflect.ValueOf(candidate)
	ek := e.Kind()

	switch {
	case ek == reflect.Bool:
		return checkAgainstBool(e.Bool(), c)

	case isSignedInteger(e):
		return checkAgainstInt64(e.Int(), c)

	case isUnsignedInteger(e):
		return checkAgainstUint64(e.Uint(), c)

	case ek == reflect.Uintptr:
		return checkAgainstUintptr(uintptr(e.Uint()), c)

	case ek == reflect.Float32:
		return checkAgainstFloat32(float32(e.Float()), c)

	case ek == reflect.Float64:
		return checkAgainstFloat64(e.Float(), c)

	case ek == reflect.Complex64:
		return checkAgainstComplex64(complex64(e.Complex()), c)

	case ek == reflect.Complex128:
		return checkAgainstComplex128(complex128(e.Complex()), c)

	case ek == reflect.Chan:
		return checkAgainstChan(e, c)

	case ek == reflect.Func:
		return checkAgainstFunc(e, c)

	case ek == reflect.Map:
		return checkAgainstMap(e, c)

	case ek == reflect.Ptr:
		return checkAgainstPtr(e, c)

	case ek == reflect.UnsafePointer:
		return checkAgainstUnsafePointer(e, c)
	}

	return MATCH_UNDEFINED, "TODO"
}

func (m *equalsMatcher) Description() string {
	return fmt.Sprintf("%v", m.expectedValue.Interface())
}
<|endoftext|>


<commit_before>// Copyright 2020 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package tcell

import (
	"context"
	"image"

	"github.com/gdamore/tcell"
	"github.com/gdamore/tcell/encoding"
	"github.com/mum4k/termdash/cell"
	"github.com/mum4k/termdash/internal/event/eventqueue"
	"github.com/mum4k/termdash/terminal/terminalapi"
)

// Option is used to provide options.
type Option interface {
	// set sets the provided option.
	set(*Terminal)
}

// option implements Option.
type option func(*Terminal)

// set implements Option.set.
func (o option) set(t *Terminal) {
	o(t)
}

// DefaultColorMode is the default value for the ColorMode option.
const DefaultColorMode = terminalapi.ColorMode256

// ColorMode sets the terminal color mode.
// Defaults to DefaultColorMode.
func ColorMode(cm terminalapi.ColorMode) Option {
	return option(func(t *Terminal) {
		t.colorMode = cm
	})
}

// ClearStyle sets the style to use for tcell when clearing the screen.
// Defaults to white foreground and black background.
func ClearStyle(fg, bg cell.Color) Option {
	return option(func(t *Terminal) {
		t.clearStyle = &cell.Options{
			FgColor: fg,
			BgColor: bg,
		}
	})
}

// Terminal provides input and output to a real terminal. Wraps the
// gdamore/tcell terminal implementation. This object is not thread-safe.
// Implements terminalapi.Terminal.
type Terminal struct {
	// events is a queue of input events.
	events *eventqueue.Unbound

	// done gets closed when Close() is called.
	done chan struct{}

	// the tcell terminal window
	screen tcell.Screen

	// Options.
	colorMode  terminalapi.ColorMode
	clearStyle *cell.Options
}

// newTerminal creates the terminal and applies the options.
func newTerminal(opts ...Option) (*Terminal, error) {
	screen, err := tcell.NewScreen()
	if err != nil {
		return nil, err
	}

	t := &Terminal{
		events:    eventqueue.New(),
		done:      make(chan struct{}),
		colorMode: DefaultColorMode,
		clearStyle: &cell.Options{
			FgColor: cell.ColorWhite,
			BgColor: cell.ColorBlack,
		},
		screen: screen,
	}
	for _, opt := range opts {
		opt.set(t)
	}

	return t, nil
}

// New returns a new tcell based Terminal.
// Call Close() when the terminal isn't required anymore.
func New(opts ...Option) (*Terminal, error) {
	// Enable full character set support for tcell
	encoding.Register()

	t, err := newTerminal(opts...)
	if err != nil {
		return nil, err
	}
	if err = t.screen.Init(); err != nil {
		return nil, err
	}

	clearStyle := cellOptsToStyle(t.clearStyle, t.colorMode)
	t.screen.EnableMouse()
	t.screen.SetStyle(clearStyle)

	go t.pollEvents() // Stops when Close() is called.
	return t, nil
}

// Size implements terminalapi.Terminal.Size.
func (t *Terminal) Size() image.Point {
	w, h := t.screen.Size()
	return image.Point{
		X: w,
		Y: h,
	}
}

// Clear implements terminalapi.Terminal.Clear.
func (t *Terminal) Clear(opts ...cell.Option) error {
	o := cell.NewOptions(opts...)
	st := cellOptsToStyle(o, t.colorMode)
	w, h := t.screen.Size()
	for row := 0; row < h; row++ {
		for col := 0; col < w; col++ {
			t.screen.SetContent(col, row, ' ', nil, st)
		}
	}
	return nil
}

// Flush implements terminalapi.Terminal.Flush.
func (t *Terminal) Flush() error {
	t.screen.Show()
	return nil
}

// SetCursor implements terminalapi.Terminal.SetCursor.
func (t *Terminal) SetCursor(p image.Point) {
	t.screen.ShowCursor(p.X, p.Y)
}

// HideCursor implements terminalapi.Terminal.HideCursor.
func (t *Terminal) HideCursor() {
	t.screen.HideCursor()
}

// SetCell implements terminalapi.Terminal.SetCell.
func (t *Terminal) SetCell(p image.Point, r rune, opts ...cell.Option) error {
	o := cell.NewOptions(opts...)
	st := cellOptsToStyle(o, t.colorMode)
	t.screen.SetContent(p.X, p.Y, r, nil, st)
	return nil
}

// pollEvents polls and enqueues the input events.
func (t *Terminal) pollEvents() {
	for {
		select {
		case <-t.done:
			return
		default:
		}

		events := toTermdashEvents(t.screen.PollEvent())
		for _, ev := range events {
			t.events.Push(ev)
		}
	}
}

// Event implements terminalapi.Terminal.Event.
func (t *Terminal) Event(ctx context.Context) terminalapi.Event {
	ev := t.events.Pull(ctx)
	if ev == nil {
		return nil
	}
	return ev
}

// Close closes the terminal, should be called when the terminal isn't required
// anymore to return the screen to a sane state.
// Implements terminalapi.Terminal.Close.
func (t *Terminal) Close() {
	close(t.done)
	t.screen.Fini()
}
<commit_msg>Use tcell screen.Fill() to clear screen<commit_after>// Copyright 2020 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package tcell

import (
	"context"
	"image"

	"github.com/gdamore/tcell"
	"github.com/gdamore/tcell/encoding"
	"github.com/mum4k/termdash/cell"
	"github.com/mum4k/termdash/internal/event/eventqueue"
	"github.com/mum4k/termdash/terminal/terminalapi"
)

// Option is used to provide options.
type Option interface {
	// set sets the provided option.
	set(*Terminal)
}

// option implements Option.
type option func(*Terminal)

// set implements Option.set.
func (o option) set(t *Terminal) {
	o(t)
}

// DefaultColorMode is the default value for the ColorMode option.
const DefaultColorMode = terminalapi.ColorMode256

// ColorMode sets the terminal color mode.
// Defaults to DefaultColorMode.
func ColorMode(cm terminalapi.ColorMode) Option {
	return option(func(t *Terminal) {
		t.colorMode = cm
	})
}

// ClearStyle sets the style to use for tcell when clearing the screen.
// Defaults to white foreground and black background.
func ClearStyle(fg, bg cell.Color) Option {
	return option(func(t *Terminal) {
		t.clearStyle = &cell.Options{
			FgColor: fg,
			BgColor: bg,
		}
	})
}

// Terminal provides input and output to a real terminal. Wraps the
// gdamore/tcell terminal implementation. This object is not thread-safe.
// Implements terminalapi.Terminal.
type Terminal struct {
	// events is a queue of input events.
	events *eventqueue.Unbound

	// done gets closed when Close() is called.
	done chan struct{}

	// the tcell terminal window
	screen tcell.Screen

	// Options.
	colorMode  terminalapi.ColorMode
	clearStyle *cell.Options
}

// newTerminal creates the terminal and applies the options.
func newTerminal(opts ...Option) (*Terminal, error) {
	screen, err := tcell.NewScreen()
	if err != nil {
		return nil, err
	}

	t := &Terminal{
		events:    eventqueue.New(),
		done:      make(chan struct{}),
		colorMode: DefaultColorMode,
		clearStyle: &cell.Options{
			FgColor: cell.ColorWhite,
			BgColor: cell.ColorBlack,
		},
		screen: screen,
	}
	for _, opt := range opts {
		opt.set(t)
	}

	return t, nil
}

// New returns a new tcell based Terminal.
// Call Close() when the terminal isn't required anymore.
func New(opts ...Option) (*Terminal, error) {
	// Enable full character set support for tcell
	encoding.Register()

	t, err := newTerminal(opts...)
	if err != nil {
		return nil, err
	}
	if err = t.screen.Init(); err != nil {
		return nil, err
	}

	clearStyle := cellOptsToStyle(t.clearStyle, t.colorMode)
	t.screen.EnableMouse()
	t.screen.SetStyle(clearStyle)

	go t.pollEvents() // Stops when Close() is called.
	return t, nil
}

// Size implements terminalapi.Terminal.Size.
func (t *Terminal) Size() image.Point {
	w, h := t.screen.Size()
	return image.Point{
		X: w,
		Y: h,
	}
}

// Clear implements terminalapi.Terminal.Clear.
func (t *Terminal) Clear(opts ...cell.Option) error {
	o := cell.NewOptions(opts...)
	st := cellOptsToStyle(o, t.colorMode)
	t.screen.Fill(' ', st)
	return nil
}

// Flush implements terminalapi.Terminal.Flush.
func (t *Terminal) Flush() error {
	t.screen.Show()
	return nil
}

// SetCursor implements terminalapi.Terminal.SetCursor.
func (t *Terminal) SetCursor(p image.Point) {
	t.screen.ShowCursor(p.X, p.Y)
}

// HideCursor implements terminalapi.Terminal.HideCursor.
func (t *Terminal) HideCursor() {
	t.screen.HideCursor()
}

// SetCell implements terminalapi.Terminal.SetCell.
func (t *Terminal) SetCell(p image.Point, r rune, opts ...cell.Option) error {
	o := cell.NewOptions(opts...)
	st := cellOptsToStyle(o, t.colorMode)
	t.screen.SetContent(p.X, p.Y, r, nil, st)
	return nil
}

// pollEvents polls and enqueues the input events.
func (t *Terminal) pollEvents() {
	for {
		select {
		case <-t.done:
			return
		default:
		}

		events := toTermdashEvents(t.screen.PollEvent())
		for _, ev := range events {
			t.events.Push(ev)
		}
	}
}

// Event implements terminalapi.Terminal.Event.
func (t *Terminal) Event(ctx context.Context) terminalapi.Event {
	ev := t.events.Pull(ctx)
	if ev == nil {
		return nil
	}
	return ev
}

// Close closes the terminal, should be called when the terminal isn't required
// anymore to return the screen to a sane state.
// Implements terminalapi.Terminal.Close.
func (t *Terminal) Close() {
	close(t.done)
	t.screen.Fini()
}
<|endoftext|>


<commit_before>// Generated automatically.  DO NOT HAND-EDIT.

package tmux

import "github.com/gdamore/tcell/v2/terminfo"

func init() {

	// tmux terminal multiplexer
	terminfo.AddTerminfo(&terminfo.Terminfo{
		Name:          "tmux",
		Columns:       80,
		Lines:         24,
		Colors:        8,
		Bell:          "\a",
		Clear:         "\x1b[H\x1b[J",
		EnterCA:       "\x1b[?1049h",
		ExitCA:        "\x1b[?1049l",
		ShowCursor:    "\x1b[34h\x1b[?25h",
		HideCursor:    "\x1b[?25l",
		AttrOff:       "\x1b[m\x0f",
		Underline:     "\x1b[4m",
		Bold:          "\x1b[1m",
		Dim:           "\x1b[2m",
		Italic:        "\x1b[3m",
		Blink:         "\x1b[5m",
		Reverse:       "\x1b[7m",
		EnterKeypad:   "\x1b[?1h\x1b=",
		ExitKeypad:    "\x1b[?1l\x1b>",
		SetFg:         "\x1b[3%p1%dm",
		SetBg:         "\x1b[4%p1%dm",
		SetFgBg:       "\x1b[3%p1%d;4%p2%dm",
		ResetFgBg:     "\x1b[39;49m",
		PadChar:       "\x00",
		AltChars:      "++,,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
		EnterAcs:      "\x0e",
		ExitAcs:       "\x0f",
		EnableAcs:     "\x1b(B\x1b)0",
		StrikeThrough: "\x1b[9m",
		Mouse:         "\x1b[M",
		SetCursor:     "\x1b[%i%p1%d;%p2%dH",
		CursorBack1:   "\b",
		CursorUp1:     "\x1bM",
		KeyUp:         "\x1bOA",
		KeyDown:       "\x1bOB",
		KeyRight:      "\x1bOC",
		KeyLeft:       "\x1bOD",
		KeyInsert:     "\x1b[2~",
		KeyDelete:     "\x1b[3~",
		KeyBackspace:  "\u007f",
		KeyHome:       "\x1b[1~",
		KeyEnd:        "\x1b[4~",
		KeyPgUp:       "\x1b[5~",
		KeyPgDn:       "\x1b[6~",
		KeyF1:         "\x1bOP",
		KeyF2:         "\x1bOQ",
		KeyF3:         "\x1bOR",
		KeyF4:         "\x1bOS",
		KeyF5:         "\x1b[15~",
		KeyF6:         "\x1b[17~",
		KeyF7:         "\x1b[18~",
		KeyF8:         "\x1b[19~",
		KeyF9:         "\x1b[20~",
		KeyF10:        "\x1b[21~",
		KeyF11:        "\x1b[23~",
		KeyF12:        "\x1b[24~",
		KeyBacktab:    "\x1b[Z",
		Modifiers:     1,
		AutoMargin:    true,
	})
}
<commit_msg>fixes #521 tmux-256color missing from bundled terminfo<commit_after>// Generated automatically.  DO NOT HAND-EDIT.

package tmux

import "github.com/gdamore/tcell/v2/terminfo"

func init() {

	// tmux terminal multiplexer
	terminfo.AddTerminfo(&terminfo.Terminfo{
		Name:          "tmux",
		Columns:       80,
		Lines:         24,
		Colors:        8,
		Bell:          "\a",
		Clear:         "\x1b[H\x1b[J",
		EnterCA:       "\x1b[?1049h",
		ExitCA:        "\x1b[?1049l",
		ShowCursor:    "\x1b[34h\x1b[?25h",
		HideCursor:    "\x1b[?25l",
		AttrOff:       "\x1b[m\x0f",
		Underline:     "\x1b[4m",
		Bold:          "\x1b[1m",
		Dim:           "\x1b[2m",
		Italic:        "\x1b[3m",
		Blink:         "\x1b[5m",
		Reverse:       "\x1b[7m",
		EnterKeypad:   "\x1b[?1h\x1b=",
		ExitKeypad:    "\x1b[?1l\x1b>",
		SetFg:         "\x1b[3%p1%dm",
		SetBg:         "\x1b[4%p1%dm",
		SetFgBg:       "\x1b[3%p1%d;4%p2%dm",
		ResetFgBg:     "\x1b[39;49m",
		PadChar:       "\x00",
		AltChars:      "++,,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
		EnterAcs:      "\x0e",
		ExitAcs:       "\x0f",
		EnableAcs:     "\x1b(B\x1b)0",
		StrikeThrough: "\x1b[9m",
		Mouse:         "\x1b[M",
		SetCursor:     "\x1b[%i%p1%d;%p2%dH",
		CursorBack1:   "\b",
		CursorUp1:     "\x1bM",
		KeyUp:         "\x1bOA",
		KeyDown:       "\x1bOB",
		KeyRight:      "\x1bOC",
		KeyLeft:       "\x1bOD",
		KeyInsert:     "\x1b[2~",
		KeyDelete:     "\x1b[3~",
		KeyBackspace:  "\u007f",
		KeyHome:       "\x1b[1~",
		KeyEnd:        "\x1b[4~",
		KeyPgUp:       "\x1b[5~",
		KeyPgDn:       "\x1b[6~",
		KeyF1:         "\x1bOP",
		KeyF2:         "\x1bOQ",
		KeyF3:         "\x1bOR",
		KeyF4:         "\x1bOS",
		KeyF5:         "\x1b[15~",
		KeyF6:         "\x1b[17~",
		KeyF7:         "\x1b[18~",
		KeyF8:         "\x1b[19~",
		KeyF9:         "\x1b[20~",
		KeyF10:        "\x1b[21~",
		KeyF11:        "\x1b[23~",
		KeyF12:        "\x1b[24~",
		KeyBacktab:    "\x1b[Z",
		Modifiers:     1,
		AutoMargin:    true,
	})
	terminfo.AddTerminfo(&terminfo.Terminfo{
		Name:          "tmux-256color",
		Columns:       80,
		Lines:         24,
		Colors:        256,
		Bell:          "\a",
		Clear:         "\x1b[H\x1b[J",
		EnterCA:       "\x1b[?1049h",
		ExitCA:        "\x1b[?1049l",
		ShowCursor:    "\x1b[34h\x1b[?25h",
		HideCursor:    "\x1b[?25l",
		AttrOff:       "\x1b[m\x0f",
		Underline:     "\x1b[4m",
		Bold:          "\x1b[1m",
		Dim:           "\x1b[2m",
		Italic:        "\x1b[3m",
		Blink:         "\x1b[5m",
		Reverse:       "\x1b[7m",
		EnterKeypad:   "\x1b[?1h\x1b=",
		ExitKeypad:    "\x1b[?1l\x1b>",
		SetFg:         "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m",
		SetBg:         "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m",
		SetFgBg:       "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;;%?%p2%{8}%<%t4%p2%d%e%p2%{16}%<%t10%p2%{8}%-%d%e48;5;%p2%d%;m",
		ResetFgBg:     "\x1b[39;49m",
		PadChar:       "\x00",
		AltChars:      "++,,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~",
		EnterAcs:      "\x0e",
		ExitAcs:       "\x0f",
		EnableAcs:     "\x1b(B\x1b)0",
		StrikeThrough: "\x1b[9m",
		Mouse:         "\x1b[M",
		SetCursor:     "\x1b[%i%p1%d;%p2%dH",
		CursorBack1:   "\b",
		CursorUp1:     "\x1bM",
		KeyUp:         "\x1bOA",
		KeyDown:       "\x1bOB",
		KeyRight:      "\x1bOC",
		KeyLeft:       "\x1bOD",
		KeyInsert:     "\x1b[2~",
		KeyDelete:     "\x1b[3~",
		KeyBackspace:  "\u007f",
		KeyHome:       "\x1b[1~",
		KeyEnd:        "\x1b[4~",
		KeyPgUp:       "\x1b[5~",
		KeyPgDn:       "\x1b[6~",
		KeyF1:         "\x1bOP",
		KeyF2:         "\x1bOQ",
		KeyF3:         "\x1bOR",
		KeyF4:         "\x1bOS",
		KeyF5:         "\x1b[15~",
		KeyF6:         "\x1b[17~",
		KeyF7:         "\x1b[18~",
		KeyF8:         "\x1b[19~",
		KeyF9:         "\x1b[20~",
		KeyF10:        "\x1b[21~",
		KeyF11:        "\x1b[23~",
		KeyF12:        "\x1b[24~",
		KeyBacktab:    "\x1b[Z",
		Modifiers:     1,
		AutoMargin:    true,
	})
}
<|endoftext|>


<commit_before>package sloth

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
	"time"
)

// for mock in this package
var timeNow = time.Now

// Make sure Logger always implements io.Writer
var _ io.WriteCloser = (*File)(nil)

// Logger writes specific to Filename
type File struct {
	Filename string
	Every    time.Duration

	file      *os.File
	createdAt time.Time
}

func (f *File) Write(b []byte) (n int, err error) {
	if f.file == nil {
		f.file, err = openNew(f.Filename, false)
		f.createdAt = timeNow()
	}

	if now := timeNow(); f.Every > 0 && now.Sub(f.createdAt) >= f.Every {
		backup(f)
	}
	return f.file.Write(b)
}

func (f *File) Close() error {
	return f.file.Close()
}

func backup(f *File) {
	name := f.file.Name()
	f.Close()

	backupfile, err := openNew(name, true)
	if err != nil {
		return
	}
	defer backupfile.Close()

	f.file, _ = openNew(name, false)
	f.createdAt = timeNow()
	if _, err := io.Copy(backupfile, f.file); err != nil {
		panic(err)
	}
}

func exist(filename string) bool {
	_, err := os.Stat(filename)
	return !os.IsNotExist(err)
}

func openNew(filename string, stamptime bool) (*os.File, error) {
	if !stamptime {
		return os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644)
	}

	dir := filepath.Dir(filename)
	ext := filepath.Ext(filename)
	name := filepath.Base(filename)
	prefix := name[:len(name)-len(ext)]

	if !exist(dir) {
		os.MkdirAll(dir, 0744)
	}

	return os.OpenFile(filepath.Join(dir, fmt.Sprintf("%s_%s%s", prefix, timeNow().Format("20060102_1504"), ext)), os.O_CREATE|os.O_WRONLY, 0644)
}
<commit_msg>Create method Name to return file name<commit_after>package sloth

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
	"time"
)

// for mock in this package
var timeNow = time.Now

// Make sure Logger always implements io.Writer
var _ io.WriteCloser = (*File)(nil)

// Logger writes specific to Filename
type File struct {
	Filename string
	Every    time.Duration

	file      *os.File
	createdAt time.Time
}

func (f *File) Write(b []byte) (n int, err error) {
	if f.file == nil {
		f.file, err = openNew(f.Filename, false)
		f.createdAt = timeNow()
	}

	if now := timeNow(); f.Every > 0 && now.Sub(f.createdAt) >= f.Every {
		backup(f)
	}
	return f.file.Write(b)
}

func (f *File) Close() error {
	return f.file.Close()
}

func (f *File) Name() string { return f.file.Name() }

func backup(f *File) {
	name := f.Name()
	f.Close()

	backupfile, err := openNew(name, true)
	if err != nil {
		return
	}
	defer backupfile.Close()

	f.file, _ = openNew(name, false)
	f.createdAt = timeNow()
	if _, err := io.Copy(backupfile, f.file); err != nil {
		panic(err)
	}
}

func exist(filename string) bool {
	_, err := os.Stat(filename)
	return !os.IsNotExist(err)
}

func openNew(filename string, stamptime bool) (*os.File, error) {
	if !stamptime {
		return os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644)
	}

	dir := filepath.Dir(filename)
	ext := filepath.Ext(filename)
	name := filepath.Base(filename)
	prefix := name[:len(name)-len(ext)]

	if !exist(dir) {
		os.MkdirAll(dir, 0744)
	}

	return os.OpenFile(filepath.Join(dir, fmt.Sprintf("%s_%s%s", prefix, timeNow().Format("20060102_1504"), ext)), os.O_CREATE|os.O_WRONLY, 0644)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"sync"
	"time"

	"github.com/fraenkel/candiedyaml"
	"github.com/gorilla/websocket"
	"github.com/mgutz/ansi"
	"github.com/pivotal-golang/archiver/compressor"
)

type Build struct {
	Guid   string `json:"guid,omitempty"`
	Image  string `json:"image"`
	Path   string `json:"path"`
	Script string `json:"script"`
}

type BuildResult struct {
	Status string `json:"status"`
}

type BuildConfig struct {
	Image  string `yaml:"image"`
	Path   string `yaml:"path"`
	Script string `yaml:"script"`
}

var buildConfig = flag.String(
	"c",
	"build.yml",
	"build configuration file",
)

var buildDir = flag.String(
	"d",
	".",
	"source directory to build",
)

var redgreenAddr = flag.String(
	"redgreenAddr",
	"127.0.0.1:5637",
	"address denoting the redgreen service",
)

func main() {
	flag.Parse()

	build := create(loadConfig())

	buildLog := fmt.Sprintf("ws://%s/builds/%s/log/output", *redgreenAddr, build.Guid)

	conn, res, err := websocket.DefaultDialer.Dial(buildLog, nil)
	if err != nil {
		log.Println("failed to stream output:", err, res)
		return
	}

	streaming := new(sync.WaitGroup)
	streaming.Add(1)

	go stream(conn, streaming)

	upload(build)

	exitCode := poll(build)

	res.Body.Close()
	conn.Close()

	streaming.Wait()

	os.Exit(exitCode)
}

func loadConfig() BuildConfig {
	configFile, err := os.Open(*buildConfig)
	if err != nil {
		log.Fatalln("could not open config file:", err)
	}

	var config BuildConfig

	err = candiedyaml.NewDecoder(configFile).Decode(&config)
	if err != nil {
		log.Fatalln("could not parse config file:", err)
	}

	return config
}

func create(config BuildConfig) Build {
	buffer := &bytes.Buffer{}

	build := Build{
		Image:  config.Image,
		Path:   config.Path,
		Script: config.Script,
	}

	if build.Path == "" {
		build.Path = "."
	}

	err := json.NewEncoder(buffer).Encode(build)
	if err != nil {
		log.Fatalln("encoding build failed:", err)
	}

	response, err := http.Post(
		"http://"+*redgreenAddr+"/builds",
		"application/json",
		buffer,
	)
	if err != nil {
		log.Fatalln("request failed:", err)
	}

	defer response.Body.Close()

	if response.StatusCode != http.StatusCreated {
		log.Println("bad response when creating build:", response)
		response.Write(os.Stderr)
		os.Exit(1)
	}

	err = json.NewDecoder(response.Body).Decode(&build)
	if err != nil {
		log.Fatalln("response decoding failed:", err)
	}

	return build
}

func stream(conn *websocket.Conn, streaming *sync.WaitGroup) {
	defer streaming.Done()

	for {
		_, data, err := conn.ReadMessage()
		if err != nil {
			break
		}

		fmt.Print(string(data))
	}
}

func upload(build Build) {
	src, err := filepath.Abs(*buildDir)
	if err != nil {
		log.Fatalln("could not locate build config:", err)
	}

	compressor := compressor.NewTgz()

	tmpfile, err := ioutil.TempFile("", "smith")
	if err != nil {
		log.Fatalln("creating tempfile failed:", err)
	}

	tmpfile.Close()

	defer os.Remove(tmpfile.Name())

	err = compressor.Compress(src, tmpfile.Name())
	if err != nil {
		log.Fatalln("creating archive failed:", err)
	}

	archive, err := os.Open(tmpfile.Name())
	if err != nil {
		log.Fatalln("could not open archive:", err)
	}

	response, err := http.Post(
		"http://"+*redgreenAddr+"/builds/"+build.Guid+"/bits",
		"application/octet-stream",
		archive,
	)
	if err != nil {
		log.Fatalln("request failed:", err)
	}

	defer response.Body.Close()

	if response.StatusCode != http.StatusCreated {
		log.Println("bad response when uploading bits:", response)
		response.Write(os.Stderr)
		os.Exit(1)
	}
}

func poll(build Build) int {
	for {
		var result BuildResult

		response, err := http.Get("http://" + *redgreenAddr + "/builds/" + build.Guid + "/result")
		if err != nil {
			log.Fatalln("error polling for result:", err)
		}

		err = json.NewDecoder(response.Body).Decode(&result)
		if err != nil {
			response.Body.Close()
			log.Fatalln("error decoding result:", err)
		}

		response.Body.Close()

		var color string
		var exitCode int

		switch result.Status {
		case "succeeded":
			color = "green"
			exitCode = 0
		case "failed":
			color = "red"
			exitCode = 1
		case "errored":
			color = "magenta"
			exitCode = 2
		default:
			time.Sleep(time.Second)
			continue
		}

		fmt.Println(ansi.Color(result.Status, color))
		return exitCode
	}
}
<commit_msg>report upload progress<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"sync"
	"time"

	"github.com/cheggaaa/pb"
	"github.com/fraenkel/candiedyaml"
	"github.com/gorilla/websocket"
	"github.com/mgutz/ansi"
	"github.com/pivotal-golang/archiver/compressor"
)

type Build struct {
	Guid   string `json:"guid,omitempty"`
	Image  string `json:"image"`
	Path   string `json:"path"`
	Script string `json:"script"`
}

type BuildResult struct {
	Status string `json:"status"`
}

type BuildConfig struct {
	Image  string `yaml:"image"`
	Path   string `yaml:"path"`
	Script string `yaml:"script"`
}

var buildConfig = flag.String(
	"c",
	"build.yml",
	"build configuration file",
)

var buildDir = flag.String(
	"d",
	".",
	"source directory to build",
)

var redgreenAddr = flag.String(
	"redgreenAddr",
	"127.0.0.1:5637",
	"address denoting the redgreen service",
)

func main() {
	flag.Parse()

	build := create(loadConfig())

	buildLog := fmt.Sprintf("ws://%s/builds/%s/log/output", *redgreenAddr, build.Guid)

	conn, res, err := websocket.DefaultDialer.Dial(buildLog, nil)
	if err != nil {
		log.Println("failed to stream output:", err, res)
		return
	}

	streaming := new(sync.WaitGroup)
	streaming.Add(1)

	go stream(conn, streaming)

	upload(build)

	exitCode := poll(build)

	res.Body.Close()
	conn.Close()

	streaming.Wait()

	os.Exit(exitCode)
}

func loadConfig() BuildConfig {
	configFile, err := os.Open(*buildConfig)
	if err != nil {
		log.Fatalln("could not open config file:", err)
	}

	var config BuildConfig

	err = candiedyaml.NewDecoder(configFile).Decode(&config)
	if err != nil {
		log.Fatalln("could not parse config file:", err)
	}

	return config
}

func create(config BuildConfig) Build {
	buffer := &bytes.Buffer{}

	build := Build{
		Image:  config.Image,
		Path:   config.Path,
		Script: config.Script,
	}

	if build.Path == "" {
		build.Path = "."
	}

	err := json.NewEncoder(buffer).Encode(build)
	if err != nil {
		log.Fatalln("encoding build failed:", err)
	}

	response, err := http.Post(
		"http://"+*redgreenAddr+"/builds",
		"application/json",
		buffer,
	)
	if err != nil {
		log.Fatalln("request failed:", err)
	}

	defer response.Body.Close()

	if response.StatusCode != http.StatusCreated {
		log.Println("bad response when creating build:", response)
		response.Write(os.Stderr)
		os.Exit(1)
	}

	err = json.NewDecoder(response.Body).Decode(&build)
	if err != nil {
		log.Fatalln("response decoding failed:", err)
	}

	return build
}

func stream(conn *websocket.Conn, streaming *sync.WaitGroup) {
	defer streaming.Done()

	for {
		_, data, err := conn.ReadMessage()
		if err != nil {
			break
		}

		fmt.Print(string(data))
	}
}

func upload(build Build) {
	src, err := filepath.Abs(*buildDir)
	if err != nil {
		log.Fatalln("could not locate build config:", err)
	}

	compressor := compressor.NewTgz()

	tmpfile, err := ioutil.TempFile("", "smith")
	if err != nil {
		log.Fatalln("creating tempfile failed:", err)
	}

	tmpfile.Close()

	defer os.Remove(tmpfile.Name())

	err = compressor.Compress(src, tmpfile.Name())
	if err != nil {
		log.Fatalln("creating archive failed:", err)
	}

	archive, err := os.Open(tmpfile.Name())
	if err != nil {
		log.Fatalln("could not open archive:", err)
	}

	info, err := archive.Stat()
	if err != nil {
		log.Fatalln("could not stat archive:", err)
	}

	progress := pb.New64(info.Size())
	progress.SetUnits(pb.U_BYTES)

	progress.Start()
	defer progress.Finish()

	response, err := http.Post(
		"http://"+*redgreenAddr+"/builds/"+build.Guid+"/bits",
		"application/octet-stream",
		progress.NewProxyReader(archive),
	)
	if err != nil {
		log.Fatalln("request failed:", err)
	}

	defer response.Body.Close()

	if response.StatusCode != http.StatusCreated {
		log.Println("bad response when uploading bits:", response)
		response.Write(os.Stderr)
		os.Exit(1)
	}
}

func poll(build Build) int {
	for {
		var result BuildResult

		response, err := http.Get("http://" + *redgreenAddr + "/builds/" + build.Guid + "/result")
		if err != nil {
			log.Fatalln("error polling for result:", err)
		}

		err = json.NewDecoder(response.Body).Decode(&result)
		if err != nil {
			response.Body.Close()
			log.Fatalln("error decoding result:", err)
		}

		response.Body.Close()

		var color string
		var exitCode int

		switch result.Status {
		case "succeeded":
			color = "green"
			exitCode = 0
		case "failed":
			color = "red"
			exitCode = 1
		case "errored":
			color = "magenta"
			exitCode = 2
		default:
			time.Sleep(time.Second)
			continue
		}

		fmt.Println(ansi.Color(result.Status, color))
		return exitCode
	}
}
<|endoftext|>


<commit_before>// Package smtpd implements an SMTP server with support for STARTTLS, authentication (PLAIN/LOGIN) and optional restrictions on the different stages of the SMTP session.
package smtpd

import (
	"bufio"
	"crypto/tls"
	"fmt"
	"log"
	"net"
	"os"
	"time"
)

// Server defines the parameters for running the SMTP server
type Server struct {
	Addr           string // Address to listen on when using ListenAndServe. (default: "127.0.0.1:10025")
	WelcomeMessage string // Initial server banner. (default: "<hostname> ESMTP ready.")

	ReadTimeout  time.Duration // Socket timeout for read operations. (default: 60s)
	WriteTimeout time.Duration // Socket timeout for write operations. (default: 60s)
	DataTimeout  time.Duration // Socket timeout for DATA command (default: 5m)

	MaxConnections int // Max concurrent connections, use -1 to disable. (default: 100)
	MaxMessageSize int // Max message size in bytes. (default: 10240000)
	MaxRecipients  int // Max RCPT TO calls for each envelope. (default: 100)

	// New e-mails are handed off to this function.
	// Can be left empty for a NOOP server.
	// If an error is returned, it will be reported in the SMTP session.
	Handler func(peer Peer, env Envelope) error

	// Enable various checks during the SMTP session.
	// Can be left empty for no restrictions.
	// If an error is returned, it will be reported in the SMTP session.
	// Use the Error struct for access to error codes.
	ConnectionChecker func(peer Peer) error              // Called upon new connection.
	HeloChecker       func(peer Peer, name string) error // Called after HELO/EHLO.
	SenderChecker     func(peer Peer, addr string) error // Called after MAIL FROM.
	RecipientChecker  func(peer Peer, addr string) error // Called after each RCPT TO.

	// Enable PLAIN/LOGIN authentication, only available after STARTTLS.
	// Can be left empty for no authentication support.
	Authenticator func(peer Peer, username, password string) error

	EnableXCLIENT bool // Enable XCLIENT support (default: false)

	TLSConfig *tls.Config // Enable STARTTLS support.
	ForceTLS  bool        // Force STARTTLS usage.
}

// Protocol represents the protocol used in the SMTP session
type Protocol string

const (
	SMTP  Protocol = "SMTP"
	ESMTP          = "ESMTP"
)

// Peer represents the client connecting to the server
type Peer struct {
	HeloName string   // Server name used in HELO/EHLO command
	Username string   // Username from authentication, if authenticated
	Password string   // Password from authentication, if authenticated
	Protocol Protocol // Protocol used, SMTP or ESMTP
	Addr     net.Addr // Network address
}

// Envelope holds a message
type Envelope struct {
	Sender     string
	Recipients []string
	Data       []byte
}

// Error represents an Error reported in the SMTP session.
type Error struct {
	Code    int    // The integer error code
	Message string // The error message
}

// Error returns a string representation of the SMTP error
func (e Error) Error() string { return fmt.Sprintf("%d %s", e.Code, e.Message) }

type session struct {
	server *Server

	peer     Peer
	envelope *Envelope

	conn net.Conn

	reader  *bufio.Reader
	writer  *bufio.Writer
	scanner *bufio.Scanner

	tls bool
}

func (srv *Server) newSession(c net.Conn) (s *session) {

	s = &session{
		server: srv,
		conn:   c,
		reader: bufio.NewReader(c),
		writer: bufio.NewWriter(c),
		peer:   Peer{Addr: c.RemoteAddr()},
	}

	s.scanner = bufio.NewScanner(s.reader)

	return

}

// ListenAndServe starts the SMTP server and listens on the address provided in Server.Addr
func (srv *Server) ListenAndServe() error {

	srv.configureDefaults()

	l, err := net.Listen("tcp", srv.Addr)
	if err != nil {
		return err
	}

	return srv.Serve(l)
}

// Serve starts the SMTP server and listens on the Listener provided
func (srv *Server) Serve(l net.Listener) error {

	srv.configureDefaults()

	defer l.Close()

	var limiter chan struct{}

	if srv.MaxConnections > 0 {
		limiter = make(chan struct{}, srv.MaxConnections)
	} else {
		limiter = nil
	}

	for {

		conn, e := l.Accept()
		if e != nil {
			if ne, ok := e.(net.Error); ok && ne.Temporary() {
				time.Sleep(time.Second)
				continue
			}
			return e
		}

		session := srv.newSession(conn)

		if limiter != nil {
			go func() {
				select {
				case limiter <- struct{}{}:
					session.serve()
					<-limiter
				default:
					session.reject()
				}
			}()
		} else {
			go session.serve()
		}

	}

}

func (srv *Server) configureDefaults() {

	if srv.MaxMessageSize == 0 {
		srv.MaxMessageSize = 10240000
	}

	if srv.MaxConnections == 0 {
		srv.MaxConnections = 100
	}

	if srv.MaxRecipients == 0 {
		srv.MaxRecipients = 100
	}

	if srv.ReadTimeout == 0 {
		srv.ReadTimeout = time.Second * 60
	}

	if srv.WriteTimeout == 0 {
		srv.WriteTimeout = time.Second * 60
	}

	if srv.DataTimeout == 0 {
		srv.DataTimeout = time.Minute * 5
	}

	if srv.ForceTLS && srv.TLSConfig == nil {
		log.Fatal("Cannot use ForceTLS with no TLSConfig")
	}

	if srv.Addr == "" {
		srv.Addr = "127.0.0.1:10025"
	}

	if srv.WelcomeMessage == "" {

		hostname, err := os.Hostname()

		if err != nil {
			log.Fatal("Couldn't determine hostname: %s", err)
		}

		srv.WelcomeMessage = fmt.Sprintf("%s ESMTP ready.", hostname)

	}

}

func (session *session) serve() {

	defer session.close()

	session.welcome()

	for {

		for session.scanner.Scan() {
			session.handle(session.scanner.Text())
		}

		err := session.scanner.Err()

		if err == bufio.ErrTooLong {

			session.reply(500, "Line too long")

			// Advance reader to the next newline

			session.reader.ReadString('\n')
			session.scanner = bufio.NewScanner(session.reader)

			// Reset and have the client start over.

			session.reset()

			continue
		}

		break
	}

}

func (session *session) reject() {
	session.reply(421, "Too busy. Try again later.")
	session.close()
}

func (session *session) reset() {
	session.envelope = nil
}

func (session *session) welcome() {

	if session.server.ConnectionChecker != nil {
		err := session.server.ConnectionChecker(session.peer)
		if err != nil {
			session.error(err)
			session.close()
			return
		}
	}

	session.reply(220, session.server.WelcomeMessage)

}

func (session *session) reply(code int, message string) {
	fmt.Fprintf(session.writer, "%d %s\r\n", code, message)
	session.flush()
}

func (session *session) flush() {
	session.conn.SetWriteDeadline(time.Now().Add(session.server.WriteTimeout))
	session.writer.Flush()
	session.conn.SetReadDeadline(time.Now().Add(session.server.ReadTimeout))
}

func (session *session) error(err error) {
	if smtpdError, ok := err.(Error); ok {
		session.reply(smtpdError.Code, smtpdError.Message)
	} else {
		session.reply(502, fmt.Sprintf("%s", err))
	}
}

func (session *session) extensions() []string {

	extensions := []string{
		fmt.Sprintf("SIZE %d", session.server.MaxMessageSize),
		"8BITMIME",
		"PIPELINING",
	}

	if session.server.EnableXCLIENT {
		extensions = append(extensions, "XCLIENT")
	}

	if session.server.TLSConfig != nil && !session.tls {
		extensions = append(extensions, "STARTTLS")
	}

	if session.server.Authenticator != nil && session.tls {
		extensions = append(extensions, "AUTH PLAIN LOGIN")
	}

	return extensions

}

func (session *session) deliver() error {
	if session.server.Handler != nil {
		return session.server.Handler(session.peer, *session.envelope)
	}
	return nil
}

func (session *session) close() {
	session.writer.Flush()
	time.Sleep(200 * time.Millisecond)
	session.conn.Close()
}
<commit_msg>Update synopsis.<commit_after>// Package smtpd implements an SMTP server with support for STARTTLS, authentication (PLAIN/LOGIN), XCLIENT and optional restrictions on the different stages of the SMTP session.
package smtpd

import (
	"bufio"
	"crypto/tls"
	"fmt"
	"log"
	"net"
	"os"
	"time"
)

// Server defines the parameters for running the SMTP server
type Server struct {
	Addr           string // Address to listen on when using ListenAndServe. (default: "127.0.0.1:10025")
	WelcomeMessage string // Initial server banner. (default: "<hostname> ESMTP ready.")

	ReadTimeout  time.Duration // Socket timeout for read operations. (default: 60s)
	WriteTimeout time.Duration // Socket timeout for write operations. (default: 60s)
	DataTimeout  time.Duration // Socket timeout for DATA command (default: 5m)

	MaxConnections int // Max concurrent connections, use -1 to disable. (default: 100)
	MaxMessageSize int // Max message size in bytes. (default: 10240000)
	MaxRecipients  int // Max RCPT TO calls for each envelope. (default: 100)

	// New e-mails are handed off to this function.
	// Can be left empty for a NOOP server.
	// If an error is returned, it will be reported in the SMTP session.
	Handler func(peer Peer, env Envelope) error

	// Enable various checks during the SMTP session.
	// Can be left empty for no restrictions.
	// If an error is returned, it will be reported in the SMTP session.
	// Use the Error struct for access to error codes.
	ConnectionChecker func(peer Peer) error              // Called upon new connection.
	HeloChecker       func(peer Peer, name string) error // Called after HELO/EHLO.
	SenderChecker     func(peer Peer, addr string) error // Called after MAIL FROM.
	RecipientChecker  func(peer Peer, addr string) error // Called after each RCPT TO.

	// Enable PLAIN/LOGIN authentication, only available after STARTTLS.
	// Can be left empty for no authentication support.
	Authenticator func(peer Peer, username, password string) error

	EnableXCLIENT bool // Enable XCLIENT support (default: false)

	TLSConfig *tls.Config // Enable STARTTLS support.
	ForceTLS  bool        // Force STARTTLS usage.
}

// Protocol represents the protocol used in the SMTP session
type Protocol string

const (
	SMTP  Protocol = "SMTP"
	ESMTP          = "ESMTP"
)

// Peer represents the client connecting to the server
type Peer struct {
	HeloName string   // Server name used in HELO/EHLO command
	Username string   // Username from authentication, if authenticated
	Password string   // Password from authentication, if authenticated
	Protocol Protocol // Protocol used, SMTP or ESMTP
	Addr     net.Addr // Network address
}

// Envelope holds a message
type Envelope struct {
	Sender     string
	Recipients []string
	Data       []byte
}

// Error represents an Error reported in the SMTP session.
type Error struct {
	Code    int    // The integer error code
	Message string // The error message
}

// Error returns a string representation of the SMTP error
func (e Error) Error() string { return fmt.Sprintf("%d %s", e.Code, e.Message) }

type session struct {
	server *Server

	peer     Peer
	envelope *Envelope

	conn net.Conn

	reader  *bufio.Reader
	writer  *bufio.Writer
	scanner *bufio.Scanner

	tls bool
}

func (srv *Server) newSession(c net.Conn) (s *session) {

	s = &session{
		server: srv,
		conn:   c,
		reader: bufio.NewReader(c),
		writer: bufio.NewWriter(c),
		peer:   Peer{Addr: c.RemoteAddr()},
	}

	s.scanner = bufio.NewScanner(s.reader)

	return

}

// ListenAndServe starts the SMTP server and listens on the address provided in Server.Addr
func (srv *Server) ListenAndServe() error {

	srv.configureDefaults()

	l, err := net.Listen("tcp", srv.Addr)
	if err != nil {
		return err
	}

	return srv.Serve(l)
}

// Serve starts the SMTP server and listens on the Listener provided
func (srv *Server) Serve(l net.Listener) error {

	srv.configureDefaults()

	defer l.Close()

	var limiter chan struct{}

	if srv.MaxConnections > 0 {
		limiter = make(chan struct{}, srv.MaxConnections)
	} else {
		limiter = nil
	}

	for {

		conn, e := l.Accept()
		if e != nil {
			if ne, ok := e.(net.Error); ok && ne.Temporary() {
				time.Sleep(time.Second)
				continue
			}
			return e
		}

		session := srv.newSession(conn)

		if limiter != nil {
			go func() {
				select {
				case limiter <- struct{}{}:
					session.serve()
					<-limiter
				default:
					session.reject()
				}
			}()
		} else {
			go session.serve()
		}

	}

}

func (srv *Server) configureDefaults() {

	if srv.MaxMessageSize == 0 {
		srv.MaxMessageSize = 10240000
	}

	if srv.MaxConnections == 0 {
		srv.MaxConnections = 100
	}

	if srv.MaxRecipients == 0 {
		srv.MaxRecipients = 100
	}

	if srv.ReadTimeout == 0 {
		srv.ReadTimeout = time.Second * 60
	}

	if srv.WriteTimeout == 0 {
		srv.WriteTimeout = time.Second * 60
	}

	if srv.DataTimeout == 0 {
		srv.DataTimeout = time.Minute * 5
	}

	if srv.ForceTLS && srv.TLSConfig == nil {
		log.Fatal("Cannot use ForceTLS with no TLSConfig")
	}

	if srv.Addr == "" {
		srv.Addr = "127.0.0.1:10025"
	}

	if srv.WelcomeMessage == "" {

		hostname, err := os.Hostname()

		if err != nil {
			log.Fatal("Couldn't determine hostname: %s", err)
		}

		srv.WelcomeMessage = fmt.Sprintf("%s ESMTP ready.", hostname)

	}

}

func (session *session) serve() {

	defer session.close()

	session.welcome()

	for {

		for session.scanner.Scan() {
			session.handle(session.scanner.Text())
		}

		err := session.scanner.Err()

		if err == bufio.ErrTooLong {

			session.reply(500, "Line too long")

			// Advance reader to the next newline

			session.reader.ReadString('\n')
			session.scanner = bufio.NewScanner(session.reader)

			// Reset and have the client start over.

			session.reset()

			continue
		}

		break
	}

}

func (session *session) reject() {
	session.reply(421, "Too busy. Try again later.")
	session.close()
}

func (session *session) reset() {
	session.envelope = nil
}

func (session *session) welcome() {

	if session.server.ConnectionChecker != nil {
		err := session.server.ConnectionChecker(session.peer)
		if err != nil {
			session.error(err)
			session.close()
			return
		}
	}

	session.reply(220, session.server.WelcomeMessage)

}

func (session *session) reply(code int, message string) {
	fmt.Fprintf(session.writer, "%d %s\r\n", code, message)
	session.flush()
}

func (session *session) flush() {
	session.conn.SetWriteDeadline(time.Now().Add(session.server.WriteTimeout))
	session.writer.Flush()
	session.conn.SetReadDeadline(time.Now().Add(session.server.ReadTimeout))
}

func (session *session) error(err error) {
	if smtpdError, ok := err.(Error); ok {
		session.reply(smtpdError.Code, smtpdError.Message)
	} else {
		session.reply(502, fmt.Sprintf("%s", err))
	}
}

func (session *session) extensions() []string {

	extensions := []string{
		fmt.Sprintf("SIZE %d", session.server.MaxMessageSize),
		"8BITMIME",
		"PIPELINING",
	}

	if session.server.EnableXCLIENT {
		extensions = append(extensions, "XCLIENT")
	}

	if session.server.TLSConfig != nil && !session.tls {
		extensions = append(extensions, "STARTTLS")
	}

	if session.server.Authenticator != nil && session.tls {
		extensions = append(extensions, "AUTH PLAIN LOGIN")
	}

	return extensions

}

func (session *session) deliver() error {
	if session.server.Handler != nil {
		return session.server.Handler(session.peer, *session.envelope)
	}
	return nil
}

func (session *session) close() {
	session.writer.Flush()
	time.Sleep(200 * time.Millisecond)
	session.conn.Close()
}
<|endoftext|>


<commit_before>package vlc

import "errors"

// Common errors.
var (
	ErrModuleNotInitialized     = errors.New("module not initialized")
	ErrPlayerNotInitialized     = errors.New("player not initialized")
	ErrListPlayerNotInitialized = errors.New("list player not initialized")
	ErrMediaNotInitialized      = errors.New("media not initialized")
	ErrMediaListNotInitialized  = errors.New("media list not initialized")
	ErrMissingEventManager      = errors.New("could not get event manager instance")
	ErrInvalidEventCallback     = errors.New("invalid event callback")
)
<commit_msg>Refactor library errors<commit_after>package vlc

import "errors"

// Module errors.
var (
	ErrModuleNotInitialized = errors.New("module not initialized")
)

// Player errors.
var (
	ErrPlayerNotInitialized     = errors.New("player not initialized")
	ErrListPlayerNotInitialized = errors.New("list player not initialized")
)

// Media errors.
var (
	ErrMediaNotInitialized     = errors.New("media not initialized")
	ErrMediaListNotInitialized = errors.New("media list not initialized")
	ErrMissingMediaStats       = errors.New("could not get media statistics")
	ErrInvalidMediaStats       = errors.New("invalid media statistics")
)

// Event manager errors.
var (
	ErrMissingEventManager  = errors.New("could not get event manager instance")
	ErrInvalidEventCallback = errors.New("invalid event callback")
)
<|endoftext|>


<commit_before>package buffalo

import (
	"database/sql"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"net/http"
	"sort"
	"strings"

	"github.com/gobuffalo/events"
	"github.com/gobuffalo/plush"
	"github.com/gobuffalo/x/defaults"
	"github.com/gobuffalo/x/httpx"
	"github.com/pkg/errors"
)

// HTTPError a typed error returned by http Handlers and used for choosing error handlers
type HTTPError struct {
	Status int   `json:"status"`
	Cause  error `json:"error"`
}

func (h HTTPError) Error() string {
	return h.Cause.Error()
}

// ErrorHandler interface for handling an error for a
// specific status code.
type ErrorHandler func(int, error, Context) error

// ErrorHandlers is used to hold a list of ErrorHandler
// types that can be used to handle specific status codes.
/*
	a.ErrorHandlers[500] = func(status int, err error, c buffalo.Context) error {
		res := c.Response()
		res.WriteHeader(status)
		res.Write([]byte(err.Error()))
		return nil
	}
*/
type ErrorHandlers map[int]ErrorHandler

// Get a registered ErrorHandler for this status code. If
// no ErrorHandler has been registered, a default one will
// be returned.
func (e ErrorHandlers) Get(status int) ErrorHandler {
	if eh, ok := e[status]; ok {
		return eh
	}
	return defaultErrorHandler
}

// PanicHandler recovers from panics gracefully and calls
// the error handling code for a 500 error.
func (a *App) PanicHandler(next Handler) Handler {
	return func(c Context) error {
		defer func() { //catch or finally
			r := recover()
			var err error
			if r != nil { //catch
				switch t := r.(type) {
				case error:
					err = t
				case string:
					err = errors.New(t)
				default:
					err = errors.New(fmt.Sprint(t))
				}
				err = errors.WithStack(err)
				events.EmitError(events.ErrPanic, err,
					map[string]interface{}{
						"context": c,
						"app":     a,
					},
				)
				eh := a.ErrorHandlers.Get(500)
				eh(500, err, c)
			}
		}()
		return next(c)
	}
}

func (a *App) defaultErrorMiddleware(next Handler) Handler {
	return func(c Context) error {
		err := next(c)
		if err == nil {
			return nil
		}
		status := 500
		// unpack root cause and check for HTTPError
		cause := errors.Cause(err)
		switch cause {
		case sql.ErrNoRows:
			status = 404
		default:
			if h, ok := cause.(HTTPError); ok {
				status = h.Status
			}
		}
		payload := events.Payload{
			"context": c,
			"app":     a,
		}
		events.EmitError(events.ErrGeneral, err, payload)

		eh := a.ErrorHandlers.Get(status)
		err = eh(status, err, c)
		if err != nil {
			events.Emit(events.Event{
				Kind:    EvtFailureErr,
				Message: "unable to handle error and giving up",
				Error:   err,
				Payload: payload,
			})
			// things have really hit the fan if we're here!!
			a.Logger.Error(err)
			c.Response().WriteHeader(500)
			c.Response().Write([]byte(err.Error()))
		}
		return nil
	}
}

func productionErrorResponseFor(status int) []byte {
	if status == http.StatusNotFound {
		return []byte(prodNotFoundTmpl)
	}

	return []byte(prodErrorTmpl)
}

// ErrorResponse is a used to display errors as JSON or XML
type ErrorResponse struct {
	XMLName xml.Name `json:"-" xml:"response"`
	Error   string   `json:"error" xml:"error"`
	Trace   string   `json:"trace" xml:"trace"`
	Code    int      `json:"code" xml:"code,attr"`
}

func defaultErrorHandler(status int, origErr error, c Context) error {
	env := c.Value("env")
	ct := defaults.String(httpx.ContentType(c.Request()), "text/html; charset=utf-8")
	c.Response().Header().Set("content-type", ct)

	c.Logger().Error(origErr)
	c.Response().WriteHeader(status)

	if env != nil && env.(string) == "production" {
		responseBody := productionErrorResponseFor(status)
		c.Response().Write(responseBody)
		return nil
	}

	trace := fmt.Sprintf("%+v", origErr)
	switch strings.ToLower(ct) {
	case "application/json", "text/json", "json":
		err := json.NewEncoder(c.Response()).Encode(&ErrorResponse{
			Error: errors.Cause(origErr).Error(),
			Trace: trace,
			Code:  status,
		})
		if err != nil {
			return errors.WithStack(err)
		}
	case "application/xml", "text/xml", "xml":
		err := xml.NewEncoder(c.Response()).Encode(&ErrorResponse{
			Error: errors.Cause(origErr).Error(),
			Trace: trace,
			Code:  status,
		})
		if err != nil {
			return errors.WithStack(err)
		}
	default:
		if err := c.Request().ParseForm(); err != nil {
			trace = fmt.Sprintf("%s\n%s", err.Error(), trace)
		}
		routes := c.Value("routes")
		if cd, ok := c.(*DefaultContext); ok {
			delete(cd.data, "app")
			delete(cd.data, "routes")
		}
		data := map[string]interface{}{
			"routes":      routes,
			"error":       trace,
			"status":      status,
			"data":        c.Data(),
			"params":      c.Params(),
			"posted_form": c.Request().Form,
			"context":     c,
			"headers":     inspectHeaders(c.Request().Header),
			"inspect": func(v interface{}) string {
				return fmt.Sprintf("%+v", v)
			},
		}
		ctx := plush.NewContextWith(data)
		t, err := plush.Render(devErrorTmpl, ctx)
		if err != nil {
			return errors.WithStack(err)
		}
		res := c.Response()
		_, err = res.Write([]byte(t))
		return err
	}
	return nil
}

type inspectHeaders http.Header

func (i inspectHeaders) String() string {

	bb := make([]string, 0, len(i))

	for k, v := range i {
		bb = append(bb, fmt.Sprintf("%s: %s", k, v))
	}
	sort.Strings(bb)
	return strings.Join(bb, "\n\n")
}
<commit_msg>fixes strange issues with pages being downloaded instead of rendered (#1402)<commit_after>package buffalo

import (
	"database/sql"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"net/http"
	"sort"
	"strings"

	"github.com/gobuffalo/events"
	"github.com/gobuffalo/plush"
	"github.com/gobuffalo/x/defaults"
	"github.com/gobuffalo/x/httpx"
	"github.com/pkg/errors"
)

// HTTPError a typed error returned by http Handlers and used for choosing error handlers
type HTTPError struct {
	Status int   `json:"status"`
	Cause  error `json:"error"`
}

func (h HTTPError) Error() string {
	return h.Cause.Error()
}

// ErrorHandler interface for handling an error for a
// specific status code.
type ErrorHandler func(int, error, Context) error

// ErrorHandlers is used to hold a list of ErrorHandler
// types that can be used to handle specific status codes.
/*
	a.ErrorHandlers[500] = func(status int, err error, c buffalo.Context) error {
		res := c.Response()
		res.WriteHeader(status)
		res.Write([]byte(err.Error()))
		return nil
	}
*/
type ErrorHandlers map[int]ErrorHandler

// Get a registered ErrorHandler for this status code. If
// no ErrorHandler has been registered, a default one will
// be returned.
func (e ErrorHandlers) Get(status int) ErrorHandler {
	if eh, ok := e[status]; ok {
		return eh
	}
	return defaultErrorHandler
}

// PanicHandler recovers from panics gracefully and calls
// the error handling code for a 500 error.
func (a *App) PanicHandler(next Handler) Handler {
	return func(c Context) error {
		defer func() { //catch or finally
			r := recover()
			var err error
			if r != nil { //catch
				switch t := r.(type) {
				case error:
					err = t
				case string:
					err = errors.New(t)
				default:
					err = errors.New(fmt.Sprint(t))
				}
				err = errors.WithStack(err)
				events.EmitError(events.ErrPanic, err,
					map[string]interface{}{
						"context": c,
						"app":     a,
					},
				)
				eh := a.ErrorHandlers.Get(500)
				eh(500, err, c)
			}
		}()
		return next(c)
	}
}

func (a *App) defaultErrorMiddleware(next Handler) Handler {
	return func(c Context) error {
		err := next(c)
		if err == nil {
			return nil
		}
		status := 500
		// unpack root cause and check for HTTPError
		cause := errors.Cause(err)
		switch cause {
		case sql.ErrNoRows:
			status = 404
		default:
			if h, ok := cause.(HTTPError); ok {
				status = h.Status
			}
		}
		payload := events.Payload{
			"context": c,
			"app":     a,
		}
		events.EmitError(events.ErrGeneral, err, payload)

		eh := a.ErrorHandlers.Get(status)
		err = eh(status, err, c)
		if err != nil {
			events.Emit(events.Event{
				Kind:    EvtFailureErr,
				Message: "unable to handle error and giving up",
				Error:   err,
				Payload: payload,
			})
			// things have really hit the fan if we're here!!
			a.Logger.Error(err)
			c.Response().WriteHeader(500)
			c.Response().Write([]byte(err.Error()))
		}
		return nil
	}
}

func productionErrorResponseFor(status int) []byte {
	if status == http.StatusNotFound {
		return []byte(prodNotFoundTmpl)
	}

	return []byte(prodErrorTmpl)
}

// ErrorResponse is a used to display errors as JSON or XML
type ErrorResponse struct {
	XMLName xml.Name `json:"-" xml:"response"`
	Error   string   `json:"error" xml:"error"`
	Trace   string   `json:"trace" xml:"trace"`
	Code    int      `json:"code" xml:"code,attr"`
}

const defErrorCT = "text/html; charset=utf-8"

type stackTracer interface {
	StackTrace() errors.StackTrace
}

func defaultErrorHandler(status int, origErr error, c Context) error {
	env := c.Value("env")
	ct := defaults.String(httpx.ContentType(c.Request()), defErrorCT)
	if strings.Contains(ct, "form") {
		ct = defErrorCT
	}
	c.Response().Header().Set("content-type", ct)

	c.Logger().Error(origErr)
	c.Response().WriteHeader(status)

	if env != nil && env.(string) == "production" {
		responseBody := productionErrorResponseFor(status)
		c.Response().Write(responseBody)
		return nil
	}

	trace := fmt.Sprintf("%s\n\n%+v", origErr, origErr)
	if st, ok := origErr.(stackTracer); ok {
		var log []string
		for _, t := range st.StackTrace() {
			log = append(log, fmt.Sprintf("%+v", t))
		}
		trace = fmt.Sprintf("%s\n%s", origErr, strings.Join(log, "\n"))
	}
	switch strings.ToLower(ct) {
	case "application/json", "text/json", "json":
		err := json.NewEncoder(c.Response()).Encode(&ErrorResponse{
			Error: errors.Cause(origErr).Error(),
			Trace: trace,
			Code:  status,
		})
		if err != nil {
			return errors.WithStack(err)
		}
	case "application/xml", "text/xml", "xml":
		err := xml.NewEncoder(c.Response()).Encode(&ErrorResponse{
			Error: errors.Cause(origErr).Error(),
			Trace: trace,
			Code:  status,
		})
		if err != nil {
			return errors.WithStack(err)
		}
	default:
		if err := c.Request().ParseForm(); err != nil {
			trace = fmt.Sprintf("%s\n%s", err.Error(), trace)
		}
		routes := c.Value("routes")
		if cd, ok := c.(*DefaultContext); ok {
			delete(cd.data, "app")
			delete(cd.data, "routes")
		}
		data := map[string]interface{}{
			"routes":      routes,
			"error":       trace,
			"status":      status,
			"data":        c.Data(),
			"params":      c.Params(),
			"posted_form": c.Request().Form,
			"context":     c,
			"headers":     inspectHeaders(c.Request().Header),
			"inspect": func(v interface{}) string {
				return fmt.Sprintf("%+v", v)
			},
		}
		ctx := plush.NewContextWith(data)
		t, err := plush.Render(devErrorTmpl, ctx)
		if err != nil {
			return errors.WithStack(err)
		}
		res := c.Response()
		_, err = res.Write([]byte(t))
		return err
	}
	return nil
}

type inspectHeaders http.Header

func (i inspectHeaders) String() string {

	bb := make([]string, 0, len(i))

	for k, v := range i {
		bb = append(bb, fmt.Sprintf("%s: %s", k, v))
	}
	sort.Strings(bb)
	return strings.Join(bb, "\n\n")
}
<|endoftext|>


<commit_before>package viron

import "fmt"

const ParseErrorFormat = "%s value \"%s\" could not be parsed into %s value"

type ParseError string

func NewParseError(name, value, kind string) ParseError {
    return ParseError(fmt.Sprintf(ParseErrorFormat, name, value, kind))
}

func (err ParseError) Error() string {
    return string(err)
}

type InvalidArgumentError string

func NewInvalidArgumentError(value interface{}) InvalidArgumentError {
    return InvalidArgumentError(fmt.Sprintf("%v is not a non-zero struct pointer", value))
}

func (err InvalidArgumentError) Error() string {
    return string(err)
}

type RequiredFieldError string

func NewRequiredFieldError(name string) RequiredFieldError {
    return RequiredFieldError(fmt.Sprintf("%s is a required environment variable", name))
}

func (err RequiredFieldError) Error() string {
    return string(err)
}
<commit_msg>Moves error format strings into const values<commit_after>package viron

import "fmt"

const (
    ParseErrorFormat           = "%s value \"%s\" could not be parsed into %s value"
    InvalidArgumentErrorFormat = "%v is not a non-zero struct pointer"
    RequiredFieldErrorFormat   = "%s is a required environment variable"
)

type ParseError string

func NewParseError(name, value, kind string) ParseError {
    return ParseError(fmt.Sprintf(ParseErrorFormat, name, value, kind))
}

func (err ParseError) Error() string {
    return string(err)
}

type InvalidArgumentError string

func NewInvalidArgumentError(value interface{}) InvalidArgumentError {
    return InvalidArgumentError(fmt.Sprintf(InvalidArgumentErrorFormat, value))
}

func (err InvalidArgumentError) Error() string {
    return string(err)
}

type RequiredFieldError string

func NewRequiredFieldError(name string) RequiredFieldError {
    return RequiredFieldError(fmt.Sprintf(RequiredFieldErrorFormat, name))
}

func (err RequiredFieldError) Error() string {
    return string(err)
}
<|endoftext|>


<commit_before>package buffalo

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/gobuffalo/plush"
	"github.com/pkg/errors"
)

// HTTPError a typed error returned by http Handlers and used for choosing error handlers
type HTTPError struct {
	Status int   `json:"status"`
	Cause  error `json:"error"`
}

func (h HTTPError) Error() string {
	return h.Cause.Error()
}

// ErrorHandler interface for handling an error for a
// specific status code.
type ErrorHandler func(int, error, Context) error

// ErrorHandlers is used to hold a list of ErrorHandler
// types that can be used to handle specific status codes.
/*
	a.ErrorHandlers[500] = func(status int, err error, c buffalo.Context) error {
		res := c.Response()
		res.WriteHeader(status)
		res.Write([]byte(err.Error()))
		return nil
	}
*/
type ErrorHandlers map[int]ErrorHandler

// Get a registered ErrorHandler for this status code. If
// no ErrorHandler has been registered, a default one will
// be returned.
func (e ErrorHandlers) Get(status int) ErrorHandler {
	if eh, ok := e[status]; ok {
		return eh
	}
	return defaultErrorHandler
}

// PanicHandler recovers from panics gracefully and calls
// the error handling code for a 500 error.
func (a *App) PanicHandler(next Handler) Handler {
	return func(c Context) error {
		defer func() { //catch or finally
			r := recover()
			var err error
			if r != nil { //catch
				switch t := r.(type) {
				case error:
					err = t
				case string:
					err = errors.New(t)
				default:
					err = errors.New(fmt.Sprint(t))
				}
				eh := a.ErrorHandlers.Get(500)
				eh(500, err, c)
			}
		}()
		return next(c)
	}
}

func defaultErrorHandler(status int, err error, c Context) error {
	env := c.Value("env")
	c.Logger().Error(err)
	if env != nil && env.(string) == "production" {
		c.Response().WriteHeader(status)
		c.Response().Write([]byte(prodErrorTmpl))
		return nil
	}
	c.Response().WriteHeader(status)

	msg := fmt.Sprintf("%+v", err)
	ct := c.Request().Header.Get("Content-Type")
	switch strings.ToLower(ct) {
	case "application/json", "text/json", "json":
		err = json.NewEncoder(c.Response()).Encode(map[string]interface{}{
			"error": msg,
			"code":  status,
		})
	case "application/xml", "text/xml", "xml":
	default:
		data := map[string]interface{}{
			"routes": c.Value("routes"),
			"error":  msg,
			"status": status,
			"data":   c.Data(),
		}
		ctx := plush.NewContextWith(data)
		t, err := plush.Render(devErrorTmpl, ctx)
		if err != nil {
			return errors.WithStack(err)
		}
		res := c.Response()
		res.WriteHeader(404)
		_, err = res.Write([]byte(t))
		return err
	}
	return err
}

var devErrorTmpl = `

	<title><%= status %> - ERROR!</title>

<%= status %> - ERROR!

<%= error %>

Context

<%= for (k, v) in data { %>
<%= inspect(k) %>: <%= inspect(v) %>
<% } %>

Routes

			METHOD
			PATH
			NAME
			HANDLER

		<%= for (route) in routes { %>

				<%= route.Method %>
				<%= route.Path %>
				<%= route.PathName %>
				<%= route.HandlerName %>

		<% } %>

`
var prodErrorTmpl = `

We're Sorry!

It looks like something went wrong! Don't worry, we are aware of the problem and are looking into it.

Sorry if this has caused you any problems. Please check back again later.

`
<commit_msg>fixed `http: multiple response.WriteHeader calls`<commit_after>package buffalo

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/gobuffalo/plush"
	"github.com/pkg/errors"
)

// HTTPError a typed error returned by http Handlers and used for choosing error handlers
type HTTPError struct {
	Status int   `json:"status"`
	Cause  error `json:"error"`
}

func (h HTTPError) Error() string {
	return h.Cause.Error()
}

// ErrorHandler interface for handling an error for a
// specific status code.
type ErrorHandler func(int, error, Context) error

// ErrorHandlers is used to hold a list of ErrorHandler
// types that can be used to handle specific status codes.
/*
	a.ErrorHandlers[500] = func(status int, err error, c buffalo.Context) error {
		res := c.Response()
		res.WriteHeader(status)
		res.Write([]byte(err.Error()))
		return nil
	}
*/
type ErrorHandlers map[int]ErrorHandler

// Get a registered ErrorHandler for this status code. If
// no ErrorHandler has been registered, a default one will
// be returned.
func (e ErrorHandlers) Get(status int) ErrorHandler {
	if eh, ok := e[status]; ok {
		return eh
	}
	return defaultErrorHandler
}

// PanicHandler recovers from panics gracefully and calls
// the error handling code for a 500 error.
func (a *App) PanicHandler(next Handler) Handler {
	return func(c Context) error {
		defer func() { //catch or finally
			r := recover()
			var err error
			if r != nil { //catch
				switch t := r.(type) {
				case error:
					err = t
				case string:
					err = errors.New(t)
				default:
					err = errors.New(fmt.Sprint(t))
				}
				eh := a.ErrorHandlers.Get(500)
				eh(500, err, c)
			}
		}()
		return next(c)
	}
}

func defaultErrorHandler(status int, err error, c Context) error {
	env := c.Value("env")
	c.Logger().Error(err)
	if env != nil && env.(string) == "production" {
		c.Response().WriteHeader(status)
		c.Response().Write([]byte(prodErrorTmpl))
		return nil
	}
	c.Response().WriteHeader(status)

	msg := fmt.Sprintf("%+v", err)
	ct := c.Request().Header.Get("Content-Type")
	switch strings.ToLower(ct) {
	case "application/json", "text/json", "json":
		err = json.NewEncoder(c.Response()).Encode(map[string]interface{}{
			"error": msg,
			"code":  status,
		})
	case "application/xml", "text/xml", "xml":
	default:
		data := map[string]interface{}{
			"routes": c.Value("routes"),
			"error":  msg,
			"status": status,
			"data":   c.Data(),
		}
		ctx := plush.NewContextWith(data)
		t, err := plush.Render(devErrorTmpl, ctx)
		if err != nil {
			return errors.WithStack(err)
		}
		res := c.Response()
		_, err = res.Write([]byte(t))
		return err
	}
	return err
}

var devErrorTmpl = `

	<title><%= status %> - ERROR!</title>

<%= status %> - ERROR!

<%= error %>

Context

<%= for (k, v) in data { %>
<%= inspect(k) %>: <%= inspect(v) %>
<% } %>

Routes

			METHOD
			PATH
			NAME
			HANDLER

		<%= for (route) in routes { %>

				<%= route.Method %>
				<%= route.Path %>
				<%= route.PathName %>
				<%= route.HandlerName %>

		<% } %>

`
var prodErrorTmpl = `

We're Sorry!

It looks like something went wrong! Don't worry, we are aware of the problem and are looking into it.

Sorry if this has caused you any problems. Please check back again later.

`
<|endoftext|>


<commit_before>package cloudflare

import (
	"fmt"
	"net/http"
	"strings"
)

// Error messages
const (
	errEmptyCredentials          = "invalid credentials: key & email must not be empty"
	errEmptyAPIToken             = "invalid credentials: API Token must not be empty"
	errMakeRequestError          = "error from makeRequest"
	errUnmarshalError            = "error unmarshalling the JSON response"
	errUnmarshalErrorBody        = "error unmarshalling the JSON response error body"
	errRequestNotSuccessful      = "error reported by API"
	errMissingAccountID          = "account ID is empty and must be provided"
	errOperationStillRunning     = "bulk operation did not finish before timeout"
	errOperationUnexpectedStatus = "bulk operation returned an unexpected status"
	errPagination                = "unexpected pagination in response"
	errManualPagination          = "unexpected pagination parameters in request"
)

// APIRequestError is a type of error raised by API calls made by this library.
type APIRequestError struct {
	StatusCode int
	Errors     []ResponseInfo
}

func (e APIRequestError) Error() string {
	errString := ""
	errString += fmt.Sprintf("HTTP status %d", e.StatusCode)

	if len(e.Errors) > 0 {
		errString += ": "
	}

	errMessages := []string{}
	for _, err := range e.Errors {
		m := ""
		if err.Message != "" {
			m += fmt.Sprintf("%s", err.Message)
		}

		if err.Code != 0 {
			m += fmt.Sprintf(" (%d)", err.Code)
		}

		errMessages = append(errMessages, m)
	}

	return errString + strings.Join(errMessages, ", ")
}

// HTTPStatusCode exposes the HTTP status from the error response encountered.
func (e APIRequestError) HTTPStatusCode() int {
	return e.StatusCode
}

// ErrorMessages exposes the error messages as a slice of strings from the error
// response encountered.
func (e *APIRequestError) ErrorMessages() []string {
	messages := []string{}

	for _, e := range e.Errors {
		messages = append(messages, e.Message)
	}

	return messages
}

// InternalErrorCodes exposes the internal error codes as a slice of int from
// the error response encountered.
func (e *APIRequestError) InternalErrorCodes() []int {
	ec := []int{}

	for _, e := range e.Errors {
		ec = append(ec, e.Code)
	}

	return ec
}

// ServiceError returns a boolean whether or not the raised error was caused by
// an internal service.
func (e *APIRequestError) ServiceError() bool {
	return e.StatusCode >= http.StatusInternalServerError &&
		e.StatusCode < 600
}

// ClientError returns a boolean whether or not the raised error was caused by
// something client side.
func (e *APIRequestError) ClientError() bool {
	return e.StatusCode >= http.StatusBadRequest &&
		e.StatusCode < http.StatusInternalServerError
}

// ClientRateLimited returns a boolean whether or not the raised error was
// caused by too many requests from the client.
func (e *APIRequestError) ClientRateLimited() bool {
	return e.StatusCode == http.StatusTooManyRequests
}

// InternalErrorCodeIs returns a boolean whether or not the desired internal
// error code is present in `e.InternalErrorCodes`.
func (e *APIRequestError) InternalErrorCodeIs(code int) bool {
	for _, errCode := range e.InternalErrorCodes() {
		if errCode == code {
			return true
		}
	}

	return false
}

// ErrorMessageContains returns a boolean whether or not a substring exists in
// any of the `e.ErrorMessages` slice entries.
func (e *APIRequestError) ErrorMessageContains(s string) bool {
	for _, errMsg := range e.ErrorMessages() {
		if strings.Contains(errMsg, s) {
			return true
		}
	}
	return false
}
<commit_msg>fix: wording of errManualPagination<commit_after>package cloudflare

import (
	"fmt"
	"net/http"
	"strings"
)

// Error messages
const (
	errEmptyCredentials          = "invalid credentials: key & email must not be empty"
	errEmptyAPIToken             = "invalid credentials: API Token must not be empty"
	errMakeRequestError          = "error from makeRequest"
	errUnmarshalError            = "error unmarshalling the JSON response"
	errUnmarshalErrorBody        = "error unmarshalling the JSON response error body"
	errRequestNotSuccessful      = "error reported by API"
	errMissingAccountID          = "account ID is empty and must be provided"
	errOperationStillRunning     = "bulk operation did not finish before timeout"
	errOperationUnexpectedStatus = "bulk operation returned an unexpected status"
	errPagination                = "unexpected pagination in response"
	errManualPagination          = "unexpected pagination options passed to functions that handle pagination automatically"
)

// APIRequestError is a type of error raised by API calls made by this library.
type APIRequestError struct {
	StatusCode int
	Errors     []ResponseInfo
}

func (e APIRequestError) Error() string {
	errString := ""
	errString += fmt.Sprintf("HTTP status %d", e.StatusCode)

	if len(e.Errors) > 0 {
		errString += ": "
	}

	errMessages := []string{}
	for _, err := range e.Errors {
		m := ""
		if err.Message != "" {
			m += fmt.Sprintf("%s", err.Message)
		}

		if err.Code != 0 {
			m += fmt.Sprintf(" (%d)", err.Code)
		}

		errMessages = append(errMessages, m)
	}

	return errString + strings.Join(errMessages, ", ")
}

// HTTPStatusCode exposes the HTTP status from the error response encountered.
func (e APIRequestError) HTTPStatusCode() int {
	return e.StatusCode
}

// ErrorMessages exposes the error messages as a slice of strings from the error
// response encountered.
func (e *APIRequestError) ErrorMessages() []string {
	messages := []string{}

	for _, e := range e.Errors {
		messages = append(messages, e.Message)
	}

	return messages
}

// InternalErrorCodes exposes the internal error codes as a slice of int from
// the error response encountered.
func (e *APIRequestError) InternalErrorCodes() []int {
	ec := []int{}

	for _, e := range e.Errors {
		ec = append(ec, e.Code)
	}

	return ec
}

// ServiceError returns a boolean whether or not the raised error was caused by
// an internal service.
func (e *APIRequestError) ServiceError() bool {
	return e.StatusCode >= http.StatusInternalServerError &&
		e.StatusCode < 600
}

// ClientError returns a boolean whether or not the raised error was caused by
// something client side.
func (e *APIRequestError) ClientError() bool {
	return e.StatusCode >= http.StatusBadRequest &&
		e.StatusCode < http.StatusInternalServerError
}

// ClientRateLimited returns a boolean whether or not the raised error was
// caused by too many requests from the client.
func (e *APIRequestError) ClientRateLimited() bool {
	return e.StatusCode == http.StatusTooManyRequests
}

// InternalErrorCodeIs returns a boolean whether or not the desired internal
// error code is present in `e.InternalErrorCodes`.
func (e *APIRequestError) InternalErrorCodeIs(code int) bool {
	for _, errCode := range e.InternalErrorCodes() {
		if errCode == code {
			return true
		}
	}

	return false
}

// ErrorMessageContains returns a boolean whether or not a substring exists in
// any of the `e.ErrorMessages` slice entries.
func (e *APIRequestError) ErrorMessageContains(s string) bool {
	for _, errMsg := range e.ErrorMessages() {
		if strings.Contains(errMsg, s) {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package structmapper

import "errors"

var (
	// ErrTagNameEmpty designates that the passed tag name is empty
	ErrTagNameEmpty = errors.New("Tag name is empty")

	// ErrNotAStruct designates that the passed value is not a struct
	ErrNotAStruct = errors.New("Now a struct")

	// ErrInvalidMap designates that the passed value is not a valid map
	ErrInvalidMap = errors.New("Invalid map")

	// ErrFieldIsInterface designates that a field is an interface
	ErrFieldIsInterface = errors.New("Field is interface")

	// ErrMapIsNil designates that the passed map is nil
	ErrMapIsNil = errors.New("Map is nil")

	// ErrNotAStructPointer designates that the passed value is not a pointer to a struct
	ErrNotAStructPointer = errors.New("Not a struct pointer")
)
<commit_msg>Typo fix in error message<commit_after>package structmapper

import "errors"

var (
	// ErrTagNameEmpty designates that the passed tag name is empty
	ErrTagNameEmpty = errors.New("Tag name is empty")

	// ErrNotAStruct designates that the passed value is not a struct
	ErrNotAStruct = errors.New("Not a struct")

	// ErrInvalidMap designates that the passed value is not a valid map
	ErrInvalidMap = errors.New("Invalid map")

	// ErrFieldIsInterface designates that a field is an interface
	ErrFieldIsInterface = errors.New("Field is interface")

	// ErrMapIsNil designates that the passed map is nil
	ErrMapIsNil = errors.New("Map is nil")

	// ErrNotAStructPointer designates that the passed value is not a pointer to a struct
	ErrNotAStructPointer = errors.New("Not a struct pointer")
)
<|endoftext|>


<commit_before>package messenger

import "encoding/json"

type upstreamEvent struct {
	Object  string          `json:"object"`
	Entries []*MessageEvent `json:"entry"`
}

type Event struct {
	ID   string `json:"id"`
	Time int64  `json:"time"`
}

type rawEvent struct {
	ID   json.Number `json:"id"`
	Time int64       `json:"time"`
}

func (e *Event) UnmarshalJSON(b []byte) error {
	re := &rawEvent{}
	if err := json.Unmarshal(b, re); err != nil {
		return err
	}
	e.ID = re.ID.String()
	e.Time = re.Time
	return nil
}

type MessageOpts struct {
	Sender struct {
		ID string `json:"id"`
	} `json:"sender"`
	Recipient struct {
		ID string `json:"id"`
	} `json:"recipient"`
	Timestamp int64 `json:"timestamp"`
}

type MessageEvent struct {
	Event
	Messaging []struct {
		MessageOpts
		Message  *ReceivedMessage `json:"message,omitempty"`
		Delivery *Delivery        `json:"delivery,omitempty"`
		Postback *Postback        `json:"postback,omitempty"`
		Optin    *Optin           `json:"optin,empty"`
	} `json:"messaging"`
}

type ReceivedMessage struct {
	Message
	ID  string `json:"mid"`
	Seq int    `json:"seq"`
}

type Delivery struct {
	MessageIDS []string `json:"mids"`
	Watermark  int64    `json:"watermark"`
	Seq        int      `json:"seq"`
}

type Postback struct {
	Payload string `json:"payload"`
}

type Optin struct {
	Ref string `json:"ref"`
}
<commit_msg>Embedding struct with it's own unmarshaller caused the parent struct to fail unmarshalling. Fixes #3<commit_after>package messenger

import "encoding/json"

type upstreamEvent struct {
	Object  string          `json:"object"`
	Entries []*MessageEvent `json:"entry"`
}

type FBString string

type Event struct {
	ID   FBString `json:"id"`
	Time int64    `json:"time"`
}

func (sn *FBString) UnmarshalJSON(b []byte) error {
	num := new(json.Number)
	if err := json.Unmarshal(b, num); err != nil {
		return err
	}
	*sn = FBString(num.String())
	return nil
}

type MessageOpts struct {
	Sender struct {
		ID string `json:"id"`
	} `json:"sender"`
	Recipient struct {
		ID string `json:"id"`
	} `json:"recipient"`
	Timestamp int64 `json:"timestamp"`
}

type MessageEvent struct {
	Event
	Messaging []struct {
		MessageOpts
		Message  *ReceivedMessage `json:"message,omitempty"`
		Delivery *Delivery        `json:"delivery,omitempty"`
		Postback *Postback        `json:"postback,omitempty"`
		Optin    *Optin           `json:"optin,empty"`
	} `json:"messaging"`
}

type ReceivedMessage struct {
	Message
	ID  string `json:"mid"`
	Seq int    `json:"seq"`
}

type Delivery struct {
	MessageIDS []string `json:"mids"`
	Watermark  int64    `json:"watermark"`
	Seq        int      `json:"seq"`
}

type Postback struct {
	Payload string `json:"payload"`
}

type Optin struct {
	Ref string `json:"ref"`
}
<|endoftext|>