<commit_before>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

// The version package implements version parsing.
// It also acts as guardian of the current client Juju version number.
package version

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"

	"labix.org/v2/mgo/bson"
)

// The presence and format of this constant is very important.
// The debian/rules build recipe uses this value for the version
// number of the release package.
const version = "1.13.2"

// CurrentNumber returns the version number.
func CurrentNumber() Number {
	return MustParse(version)
}

// CurrentSeries returns the current Ubuntu release name.
func CurrentSeries() string {
	return readSeries("/etc/lsb-release")
}

// CurrentArch returns the architecture of the machine.
func CurrentArch() string {
	return ubuntuArch(runtime.GOARCH)
}

// Current gives the current version of the system.  If the file
// "FORCE-VERSION" is present in the same directory as the running
// binary, it will override this.
var Current = Binary{
	Number: CurrentNumber(),
	Series: CurrentSeries(),
	Arch:   CurrentArch(),
}

func init() {
	toolsDir := filepath.Dir(os.Args[0])
	v, err := ioutil.ReadFile(filepath.Join(toolsDir, "FORCE-VERSION"))
	if err != nil {
		if os.IsNotExist(err) {
			return
		}
		panic(fmt.Errorf("version: cannot read forced version: %v", err))
	}
	Current.Number = MustParse(strings.TrimSpace(string(v)))
}

// Number represents a juju version.  When bugs are fixed the patch
// number is incremented; when new features are added the minor number
// is incremented and patch is reset; and when compatibility is broken
// the major version is incremented and minor and patch are reset.  The
// build number is automatically assigned and has no well defined
// sequence.  If the build number is greater than zero or the minor
// version is odd, it indicates that the release is still in
// development.
type Number struct {
	Major int
	Minor int
	Patch int
	Build int
}

// Zero is occasionally convenient and readable.
// Please don't change its value.
var Zero = Number{}

// Binary specifies a binary version of juju.
type Binary struct {
	Number
	Series string
	Arch   string
}

func (v Binary) String() string {
	return fmt.Sprintf("%v-%s-%s", v.Number, v.Series, v.Arch)
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Binary) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Binary) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := ParseBinary(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

func (v Binary) MarshalJSON() ([]byte, error) {
	return json.Marshal(v.String())
}

func (vp *Binary) UnmarshalJSON(data []byte) error {
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}
	v, err := ParseBinary(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

var (
	binaryPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?-([^-]+)-([^-]+)$`)
	numberPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?$`)
)

// MustParse parses a version and panics if it does
// not parse correctly.
func MustParse(s string) Number {
	v, err := Parse(s)
	if err != nil {
		panic(err)
	}
	return v
}

// MustParseBinary parses a binary version and panics if it does
// not parse correctly.
func MustParseBinary(s string) Binary {
	v, err := ParseBinary(s)
	if err != nil {
		panic(err)
	}
	return v
}

// ParseBinary parses a binary version of the form "1.2.3-series-arch".
func ParseBinary(s string) (Binary, error) {
	m := binaryPat.FindStringSubmatch(s)
	if m == nil {
		return Binary{}, fmt.Errorf("invalid binary version %q", s)
	}
	var v Binary
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	v.Series = m[5]
	v.Arch = m[6]
	return v, nil
}

// Parse parses the version, which is of the form 1.2.3
// giving the major, minor and release versions
// respectively.
func Parse(s string) (Number, error) {
	m := numberPat.FindStringSubmatch(s)
	if m == nil {
		return Number{}, fmt.Errorf("invalid version %q", s)
	}
	var v Number
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	return v, nil
}

// atoi is the same as strconv.Atoi but assumes that
// the string has been verified to be a valid integer.
func atoi(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}

func (v Number) String() string {
	s := fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
	if v.Build > 0 {
		s += fmt.Sprintf(".%d", v.Build)
	}
	return s
}

// Less returns whether v is semantically earlier in the
// version sequence than w.
func (v Number) Less(w Number) bool {
	switch {
	case v.Major != w.Major:
		return v.Major < w.Major
	case v.Minor != w.Minor:
		return v.Minor < w.Minor
	case v.Patch != w.Patch:
		return v.Patch < w.Patch
	case v.Build != w.Build:
		return v.Build < w.Build
	}
	return false
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Number) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Number) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := Parse(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

func (v Number) MarshalJSON() ([]byte, error) {
	return json.Marshal(v.String())
}

func (vp *Number) UnmarshalJSON(data []byte) error {
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}
	v, err := Parse(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

func isOdd(x int) bool {
	return x%2 != 0
}

// IsDev returns whether the version represents a development
// version. A version with an odd-numbered minor component or
// a nonzero build component is considered to be a development
// version.
func (v Number) IsDev() bool {
	return isOdd(v.Minor) || v.Build > 0
}

func readSeries(releaseFile string) string {
	data, err := ioutil.ReadFile(releaseFile)
	if err != nil {
		return "unknown"
	}
	for _, line := range strings.Split(string(data), "\n") {
		const p = "DISTRIB_CODENAME="
		if strings.HasPrefix(line, p) {
			return strings.Trim(line[len(p):], "\t '\"")
		}
	}
	return "unknown"
}

func ubuntuArch(arch string) string {
	if arch == "386" {
		arch = "i386"
	}
	return arch
}
<commit_msg>version: set development version to 1.13.3<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

// The version package implements version parsing.
// It also acts as guardian of the current client Juju version number.
package version

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"

	"labix.org/v2/mgo/bson"
)

// The presence and format of this constant is very important.
// The debian/rules build recipe uses this value for the version
// number of the release package.
const version = "1.13.3"

// CurrentNumber returns the version number.
func CurrentNumber() Number {
	return MustParse(version)
}

// CurrentSeries returns the current Ubuntu release name.
func CurrentSeries() string {
	return readSeries("/etc/lsb-release")
}

// CurrentArch returns the architecture of the machine.
func CurrentArch() string {
	return ubuntuArch(runtime.GOARCH)
}

// Current gives the current version of the system.  If the file
// "FORCE-VERSION" is present in the same directory as the running
// binary, it will override this.
var Current = Binary{
	Number: CurrentNumber(),
	Series: CurrentSeries(),
	Arch:   CurrentArch(),
}

func init() {
	toolsDir := filepath.Dir(os.Args[0])
	v, err := ioutil.ReadFile(filepath.Join(toolsDir, "FORCE-VERSION"))
	if err != nil {
		if os.IsNotExist(err) {
			return
		}
		panic(fmt.Errorf("version: cannot read forced version: %v", err))
	}
	Current.Number = MustParse(strings.TrimSpace(string(v)))
}

// Number represents a juju version.  When bugs are fixed the patch
// number is incremented; when new features are added the minor number
// is incremented and patch is reset; and when compatibility is broken
// the major version is incremented and minor and patch are reset.  The
// build number is automatically assigned and has no well defined
// sequence.  If the build number is greater than zero or the minor
// version is odd, it indicates that the release is still in
// development.
type Number struct {
	Major int
	Minor int
	Patch int
	Build int
}

// Zero is occasionally convenient and readable.
// Please don't change its value.
var Zero = Number{}

// Binary specifies a binary version of juju.
type Binary struct {
	Number
	Series string
	Arch   string
}

func (v Binary) String() string {
	return fmt.Sprintf("%v-%s-%s", v.Number, v.Series, v.Arch)
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Binary) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Binary) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := ParseBinary(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

func (v Binary) MarshalJSON() ([]byte, error) {
	return json.Marshal(v.String())
}

func (vp *Binary) UnmarshalJSON(data []byte) error {
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}
	v, err := ParseBinary(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

var (
	binaryPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?-([^-]+)-([^-]+)$`)
	numberPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?$`)
)

// MustParse parses a version and panics if it does
// not parse correctly.
func MustParse(s string) Number {
	v, err := Parse(s)
	if err != nil {
		panic(err)
	}
	return v
}

// MustParseBinary parses a binary version and panics if it does
// not parse correctly.
func MustParseBinary(s string) Binary {
	v, err := ParseBinary(s)
	if err != nil {
		panic(err)
	}
	return v
}

// ParseBinary parses a binary version of the form "1.2.3-series-arch".
func ParseBinary(s string) (Binary, error) {
	m := binaryPat.FindStringSubmatch(s)
	if m == nil {
		return Binary{}, fmt.Errorf("invalid binary version %q", s)
	}
	var v Binary
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	v.Series = m[5]
	v.Arch = m[6]
	return v, nil
}

// Parse parses the version, which is of the form 1.2.3
// giving the major, minor and release versions
// respectively.
func Parse(s string) (Number, error) {
	m := numberPat.FindStringSubmatch(s)
	if m == nil {
		return Number{}, fmt.Errorf("invalid version %q", s)
	}
	var v Number
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	return v, nil
}

// atoi is the same as strconv.Atoi but assumes that
// the string has been verified to be a valid integer.
func atoi(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}

func (v Number) String() string {
	s := fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
	if v.Build > 0 {
		s += fmt.Sprintf(".%d", v.Build)
	}
	return s
}

// Less returns whether v is semantically earlier in the
// version sequence than w.
func (v Number) Less(w Number) bool {
	switch {
	case v.Major != w.Major:
		return v.Major < w.Major
	case v.Minor != w.Minor:
		return v.Minor < w.Minor
	case v.Patch != w.Patch:
		return v.Patch < w.Patch
	case v.Build != w.Build:
		return v.Build < w.Build
	}
	return false
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Number) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Number) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := Parse(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

func (v Number) MarshalJSON() ([]byte, error) {
	return json.Marshal(v.String())
}

func (vp *Number) UnmarshalJSON(data []byte) error {
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}
	v, err := Parse(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

func isOdd(x int) bool {
	return x%2 != 0
}

// IsDev returns whether the version represents a development
// version. A version with an odd-numbered minor component or
// a nonzero build component is considered to be a development
// version.
func (v Number) IsDev() bool {
	return isOdd(v.Minor) || v.Build > 0
}

func readSeries(releaseFile string) string {
	data, err := ioutil.ReadFile(releaseFile)
	if err != nil {
		return "unknown"
	}
	for _, line := range strings.Split(string(data), "\n") {
		const p = "DISTRIB_CODENAME="
		if strings.HasPrefix(line, p) {
			return strings.Trim(line[len(p):], "\t '\"")
		}
	}
	return "unknown"
}

func ubuntuArch(arch string) string {
	if arch == "386" {
		arch = "i386"
	}
	return arch
}
<|endoftext|>


<commit_before>package version

import (
	"fmt"

	"github.com/github/hub/git"
	"github.com/github/hub/utils"
)

var Version = "2.2.5"

func FullVersion() string {
	gitVersion, err := git.Version()
	utils.Check(err)
	return fmt.Sprintf("%s\nhub version %s", gitVersion, Version)
}
<commit_msg>hub 2.2.6<commit_after>package version

import (
	"fmt"

	"github.com/github/hub/git"
	"github.com/github/hub/utils"
)

var Version = "2.2.6"

func FullVersion() string {
	gitVersion, err := git.Version()
	utils.Check(err)
	return fmt.Sprintf("%s\nhub version %s", gitVersion, Version)
}
<|endoftext|>


<commit_before>package version

import "fmt"

// Version represents the current version of Delve.
type Version struct {
	Major    string
	Minor    string
	Patch    string
	Metadata string
	Build    string
}

var (
	// DelveVersion is the current version of Delve.
	DelveVersion = Version{Major: "0", Minor: "12", Patch: "0", Metadata: ""}
)

func (v Version) String() string {
	return fmt.Sprintf("Version: %s.%s.%s-%s\nBuild: %s", v.Major, v.Minor, v.Patch, v.Metadata, v.Build)
}
<commit_msg>version: Fix version output format<commit_after>package version

import "fmt"

// Version represents the current version of Delve.
type Version struct {
	Major    string
	Minor    string
	Patch    string
	Metadata string
	Build    string
}

var (
	// DelveVersion is the current version of Delve.
	DelveVersion = Version{Major: "0", Minor: "12", Patch: "0", Metadata: ""}
)

func (v Version) String() string {
	ver := fmt.Sprintf("Version: %s.%s.%s", v.Major, v.Minor, v.Patch)
	if v.Metadata != "" {
		ver += "-" + v.Metadata
	}
	return fmt.Sprintf("%s\nBuild: %s", ver, v.Build)
}
<|endoftext|>


<commit_before>package version

var (
	// Package is filled at linking time
	Package = "github.com/containerd/containerd"

	// Version holds the complete version number. Filled in at linking time.
	Version = "1.0.0-alpha3+unknown"

	// Revision is filled with the VCS (e.g. git) revision being used to build
	// the program at linking time.
	Revision = ""
)
<commit_msg>release: prepare for 1.0.0-alpha4<commit_after>package version

var (
	// Package is filled at linking time
	Package = "github.com/containerd/containerd"

	// Version holds the complete version number. Filled in at linking time.
	Version = "1.0.0-alpha4+unknown"

	// Revision is filled with the VCS (e.g. git) revision being used to build
	// the program at linking time.
	Revision = ""
)
<|endoftext|>


<commit_before>package version

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 5
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 15
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 1

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = "-dev"
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<commit_msg>bump main branch to v5.16.0-dev<commit_after>package version

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 5
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 16
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 0

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = "-dev"
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<|endoftext|>


<commit_before>package eventbus

import (
	"errors"
	"fmt"
	"reflect"
	"sync"
	"sync/atomic"

	"github.com/libp2p/go-libp2p-core/event"
)

///////////////////////
// BUS

// basicBus is a type-based event delivery system
type basicBus struct {
	lk    sync.Mutex
	nodes map[reflect.Type]*node
}

var _ event.Bus = (*basicBus)(nil)

type emitter struct {
	n       *node
	typ     reflect.Type
	closed  int32
	dropper func(reflect.Type)
}

func (e *emitter) Emit(evt interface{}) {
	if atomic.LoadInt32(&e.closed) != 0 {
		panic("emitter is closed")
	}
	e.n.emit(evt)
}

func (e *emitter) Close() error {
	if !atomic.CompareAndSwapInt32(&e.closed, 0, 1) {
		panic("closed an emitter more than once")
	}
	if atomic.AddInt32(&e.n.nEmitters, -1) == 0 {
		e.dropper(e.typ)
	}
	return nil
}

func NewBus() event.Bus {
	return &basicBus{
		nodes: map[reflect.Type]*node{},
	}
}

func (b *basicBus) withNode(typ reflect.Type, cb func(*node), async func(*node)) error {
	b.lk.Lock()

	n, ok := b.nodes[typ]
	if !ok {
		n = newNode(typ)
		b.nodes[typ] = n
	}

	n.lk.Lock()
	b.lk.Unlock()

	cb(n)

	go func() {
		defer n.lk.Unlock()
		async(n)
	}()

	return nil
}

func (b *basicBus) tryDropNode(typ reflect.Type) {
	b.lk.Lock()
	n, ok := b.nodes[typ]
	if !ok { // already dropped
		b.lk.Unlock()
		return
	}

	n.lk.Lock()
	if atomic.LoadInt32(&n.nEmitters) > 0 || len(n.sinks) > 0 {
		n.lk.Unlock()
		b.lk.Unlock()
		return // still in use
	}
	n.lk.Unlock()

	delete(b.nodes, typ)
	b.lk.Unlock()
}

type sub struct {
	ch      chan interface{}
	nodes   []*node
	dropper func(reflect.Type)
}

func (s *sub) Out() <-chan interface{} {
	return s.ch
}

func (s *sub) Close() error {
	close(s.ch)
	for _, n := range s.nodes {
		n.lk.Lock()
		for i := 0; i < len(n.sinks); i++ {
			if n.sinks[i] == s.ch {
				n.sinks[i], n.sinks[len(n.sinks)-1] = n.sinks[len(n.sinks)-1], nil
				n.sinks = n.sinks[:len(n.sinks)-1]
				break
			}
		}
		tryDrop := len(n.sinks) == 0 && atomic.LoadInt32(&n.nEmitters) == 0
		n.lk.Unlock()
		if tryDrop {
			s.dropper(n.typ)
		}
	}
	return nil
}

var _ event.Subscription = (*sub)(nil)

// Subscribe creates new subscription. Failing to drain the channel will cause
// publishers to get blocked. CancelFunc is guaranteed to return after last send
// to the channel
func (b *basicBus) Subscribe(evtTypes interface{}, opts ...event.SubscriptionOpt) (_ event.Subscription, err error) {
	settings := subSettings(subSettingsDefault)
	for _, opt := range opts {
		if err := opt(&settings); err != nil {
			return nil, err
		}
	}

	types, ok := evtTypes.([]interface{})
	if !ok {
		types = []interface{}{evtTypes}
	}

	out := &sub{
		ch:    make(chan interface{}, settings.buffer),
		nodes: make([]*node, len(types)),

		dropper: b.tryDropNode,
	}

	for i, etyp := range types {
		typ := reflect.TypeOf(etyp)

		if typ.Kind() != reflect.Ptr {
			return nil, errors.New("subscribe called with non-pointer type")
		}

		err = b.withNode(typ.Elem(), func(n *node) {
			n.sinks = append(n.sinks, out.ch)
			out.nodes[i] = n
		}, func(n *node) {
			if n.keepLast {
				l := n.last.Load()
				if l == nil {
					return
				}
				out.ch <- l
			}
		})
	}

	return out, nil
}

// Emitter creates new emitter
//
// eventType accepts typed nil pointers, and uses the type information to
// select output type
//
// Example:
// emit, err := eventbus.Emitter(new(EventT))
// defer emit.Close() // MUST call this after being done with the emitter
//
// emit(EventT{})
func (b *basicBus) Emitter(evtType interface{}, opts ...event.EmitterOpt) (e event.Emitter, err error) {
	var settings emitterSettings

	for _, opt := range opts {
		if err := opt(&settings); err != nil {
			return nil, err
		}
	}

	typ := reflect.TypeOf(evtType)
	if typ.Kind() != reflect.Ptr {
		return nil, errors.New("emitter called with non-pointer type")
	}
	typ = typ.Elem()

	err = b.withNode(typ, func(n *node) {
		atomic.AddInt32(&n.nEmitters, 1)
		n.keepLast = n.keepLast || settings.makeStateful
		e = &emitter{n: n, typ: typ, dropper: b.tryDropNode}
	}, func(_ *node) {})
	return
}

///////////////////////
// NODE

type node struct {
	// Note: make sure to NEVER lock basicBus.lk when this lock is held
	lk sync.RWMutex

	typ reflect.Type

	// emitter ref count
	nEmitters int32

	keepLast bool
	last     atomic.Value

	sinks []chan interface{}
}

func newNode(typ reflect.Type) *node {
	return &node{
		typ: typ,
	}
}

func (n *node) emit(event interface{}) {
	eval := reflect.ValueOf(event)
	if eval.Type() != n.typ {
		panic(fmt.Sprintf("Emit called with wrong type. expected: %s, got: %s", n.typ, eval.Type()))
	}

	n.lk.RLock()
	if n.keepLast {
		n.last.Store(event)
	}

	for _, ch := range n.sinks {
		ch <- event
	}
	n.lk.RUnlock()
}
<commit_msg>nit: avoid ValueOf<commit_after>package eventbus

import (
	"errors"
	"fmt"
	"reflect"
	"sync"
	"sync/atomic"

	"github.com/libp2p/go-libp2p-core/event"
)

///////////////////////
// BUS

// basicBus is a type-based event delivery system
type basicBus struct {
	lk    sync.Mutex
	nodes map[reflect.Type]*node
}

var _ event.Bus = (*basicBus)(nil)

type emitter struct {
	n       *node
	typ     reflect.Type
	closed  int32
	dropper func(reflect.Type)
}

func (e *emitter) Emit(evt interface{}) {
	if atomic.LoadInt32(&e.closed) != 0 {
		panic("emitter is closed")
	}
	e.n.emit(evt)
}

func (e *emitter) Close() error {
	if !atomic.CompareAndSwapInt32(&e.closed, 0, 1) {
		panic("closed an emitter more than once")
	}
	if atomic.AddInt32(&e.n.nEmitters, -1) == 0 {
		e.dropper(e.typ)
	}
	return nil
}

func NewBus() event.Bus {
	return &basicBus{
		nodes: map[reflect.Type]*node{},
	}
}

func (b *basicBus) withNode(typ reflect.Type, cb func(*node), async func(*node)) error {
	b.lk.Lock()

	n, ok := b.nodes[typ]
	if !ok {
		n = newNode(typ)
		b.nodes[typ] = n
	}

	n.lk.Lock()
	b.lk.Unlock()

	cb(n)

	go func() {
		defer n.lk.Unlock()
		async(n)
	}()

	return nil
}

func (b *basicBus) tryDropNode(typ reflect.Type) {
	b.lk.Lock()
	n, ok := b.nodes[typ]
	if !ok { // already dropped
		b.lk.Unlock()
		return
	}

	n.lk.Lock()
	if atomic.LoadInt32(&n.nEmitters) > 0 || len(n.sinks) > 0 {
		n.lk.Unlock()
		b.lk.Unlock()
		return // still in use
	}
	n.lk.Unlock()

	delete(b.nodes, typ)
	b.lk.Unlock()
}

type sub struct {
	ch      chan interface{}
	nodes   []*node
	dropper func(reflect.Type)
}

func (s *sub) Out() <-chan interface{} {
	return s.ch
}

func (s *sub) Close() error {
	close(s.ch)
	for _, n := range s.nodes {
		n.lk.Lock()
		for i := 0; i < len(n.sinks); i++ {
			if n.sinks[i] == s.ch {
				n.sinks[i], n.sinks[len(n.sinks)-1] = n.sinks[len(n.sinks)-1], nil
				n.sinks = n.sinks[:len(n.sinks)-1]
				break
			}
		}
		tryDrop := len(n.sinks) == 0 && atomic.LoadInt32(&n.nEmitters) == 0
		n.lk.Unlock()
		if tryDrop {
			s.dropper(n.typ)
		}
	}
	return nil
}

var _ event.Subscription = (*sub)(nil)

// Subscribe creates new subscription. Failing to drain the channel will cause
// publishers to get blocked. CancelFunc is guaranteed to return after last send
// to the channel
func (b *basicBus) Subscribe(evtTypes interface{}, opts ...event.SubscriptionOpt) (_ event.Subscription, err error) {
	settings := subSettings(subSettingsDefault)
	for _, opt := range opts {
		if err := opt(&settings); err != nil {
			return nil, err
		}
	}

	types, ok := evtTypes.([]interface{})
	if !ok {
		types = []interface{}{evtTypes}
	}

	out := &sub{
		ch:    make(chan interface{}, settings.buffer),
		nodes: make([]*node, len(types)),

		dropper: b.tryDropNode,
	}

	for i, etyp := range types {
		typ := reflect.TypeOf(etyp)

		if typ.Kind() != reflect.Ptr {
			return nil, errors.New("subscribe called with non-pointer type")
		}

		err = b.withNode(typ.Elem(), func(n *node) {
			n.sinks = append(n.sinks, out.ch)
			out.nodes[i] = n
		}, func(n *node) {
			if n.keepLast {
				l := n.last.Load()
				if l == nil {
					return
				}
				out.ch <- l
			}
		})
	}

	return out, nil
}

// Emitter creates new emitter
//
// eventType accepts typed nil pointers, and uses the type information to
// select output type
//
// Example:
// emit, err := eventbus.Emitter(new(EventT))
// defer emit.Close() // MUST call this after being done with the emitter
//
// emit(EventT{})
func (b *basicBus) Emitter(evtType interface{}, opts ...event.EmitterOpt) (e event.Emitter, err error) {
	var settings emitterSettings

	for _, opt := range opts {
		if err := opt(&settings); err != nil {
			return nil, err
		}
	}

	typ := reflect.TypeOf(evtType)
	if typ.Kind() != reflect.Ptr {
		return nil, errors.New("emitter called with non-pointer type")
	}
	typ = typ.Elem()

	err = b.withNode(typ, func(n *node) {
		atomic.AddInt32(&n.nEmitters, 1)
		n.keepLast = n.keepLast || settings.makeStateful
		e = &emitter{n: n, typ: typ, dropper: b.tryDropNode}
	}, func(_ *node) {})
	return
}

///////////////////////
// NODE

type node struct {
	// Note: make sure to NEVER lock basicBus.lk when this lock is held
	lk sync.RWMutex

	typ reflect.Type

	// emitter ref count
	nEmitters int32

	keepLast bool
	last     atomic.Value

	sinks []chan interface{}
}

func newNode(typ reflect.Type) *node {
	return &node{
		typ: typ,
	}
}

func (n *node) emit(event interface{}) {
	typ := reflect.TypeOf(event)
	if typ != n.typ {
		panic(fmt.Sprintf("Emit called with wrong type. expected: %s, got: %s", n.typ, typ))
	}

	n.lk.RLock()
	if n.keepLast {
		n.last.Store(event)
	}

	for _, ch := range n.sinks {
		ch <- event
	}
	n.lk.RUnlock()
}
<|endoftext|>


<commit_before>package corerepo

import (
	"errors"
	"time"

	humanize "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/dustin/go-humanize"
	context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
	key "github.com/ipfs/go-ipfs/blocks/key"
	"github.com/ipfs/go-ipfs/core"
	repo "github.com/ipfs/go-ipfs/repo"
	logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
)

var log = logging.Logger("corerepo")

var ErrMaxStorageExceeded = errors.New("Maximum storage limit exceeded. Maybe unpin some files?")

type KeyRemoved struct {
	Key key.Key
}

type GC struct {
	Node       *core.IpfsNode
	Repo       repo.Repo
	StorageMax uint64
	StorageGC  uint64
	SlackGB    uint64
	Storage    uint64
}

func NewGC(n *core.IpfsNode) (*GC, error) {
	r := n.Repo
	cfg, err := r.Config()
	if err != nil {
		return nil, err
	}

	// check if cfg has these fields initialized
	// TODO: there should be a general check for all of the cfg fields
	// maybe distinguish between user config file and default struct?
	if cfg.Datastore.StorageMax == "" {
		r.SetConfigKey("Datastore.StorageMax", "10GB")
		cfg.Datastore.StorageMax = "10GB"
	}
	if cfg.Datastore.StorageGCWatermark == 0 {
		r.SetConfigKey("Datastore.StorageGCWatermark", 90)
		cfg.Datastore.StorageGCWatermark = 90
	}

	storageMax, err := humanize.ParseBytes(cfg.Datastore.StorageMax)
	if err != nil {
		return nil, err
	}
	storageGC := storageMax * uint64(cfg.Datastore.StorageGCWatermark) / 100

	// calculate the slack space between StorageMax and StorageGCWatermark
	// used to limit GC duration
	slackGB := (storageMax - storageGC) / 10e9
	if slackGB < 1 {
		slackGB = 1
	}

	return &GC{
		Node:       n,
		Repo:       r,
		StorageMax: storageMax,
		StorageGC:  storageGC,
		SlackGB:    slackGB,
	}, nil
}

func GarbageCollect(n *core.IpfsNode, ctx context.Context) error {
	ctx, cancel := context.WithCancel(ctx)
	defer cancel() // in case error occurs during operation
	keychan, err := n.Blockstore.AllKeysChan(ctx)
	if err != nil {
		return err
	}
	for k := range keychan { // rely on AllKeysChan to close chan
		if !n.Pinning.IsPinned(k) {
			if err := n.Blockstore.DeleteBlock(k); err != nil {
				return err
			}
		}
	}
	return nil
}

func GarbageCollectAsync(n *core.IpfsNode, ctx context.Context) (<-chan *KeyRemoved, error) {

	keychan, err := n.Blockstore.AllKeysChan(ctx)
	if err != nil {
		return nil, err
	}

	output := make(chan *KeyRemoved)
	go func() {
		defer close(output)
		for {
			select {
			case k, ok := <-keychan:
				if !ok {
					return
				}
				if !n.Pinning.IsPinned(k) {
					err := n.Blockstore.DeleteBlock(k)
					if err != nil {
						log.Debugf("Error removing key from blockstore: %s", err)
						continue
					}
					select {
					case output <- &KeyRemoved{k}:
					case <-ctx.Done():
					}
				}
			case <-ctx.Done():
				return
			}
		}
	}()
	return output, nil
}

func PeriodicGC(ctx context.Context, node *core.IpfsNode) error {
	cfg, err := node.Repo.Config()
	if err != nil {
		return err
	}

	if cfg.Datastore.GCPeriod == "" {
		node.Repo.SetConfigKey("Datastore.GCPeriod", "1h")
		cfg.Datastore.GCPeriod = "1h"
	}

	period, err := time.ParseDuration(cfg.Datastore.GCPeriod)
	if err != nil {
		return err
	}
	if int64(period) == 0 {
		// if duration is 0, it means GC is disabled.
		return nil
	}

	gc, err := NewGC(node)
	if err != nil {
		return err
	}

	for {
		select {
		case <-ctx.Done():
			return nil
		case <-time.After(period):
			// the private func maybeGC doesn't compute storageMax, storageGC, slackGC so that they are not re-computed for every cycle
			if err := gc.maybeGC(ctx, 0); err != nil {
				return err
			}
		}
	}
}

func ConditionalGC(ctx context.Context, node *core.IpfsNode, offset uint64) error {
	gc, err := NewGC(node)
	if err != nil {
		return err
	}
	return gc.maybeGC(ctx, offset)
}

func (gc *GC) maybeGC(ctx context.Context, offset uint64) error {
	storage, err := gc.Repo.GetStorageUsage()
	if err != nil {
		return err
	}

	if storage+offset > gc.StorageMax {
		err := ErrMaxStorageExceeded
		log.Error(err)
		return err
	}

	if storage+offset > gc.StorageGC {
		// Do GC here
		log.Info("Starting repo GC...")
		defer log.EventBegin(ctx, "repoGC").Done()
		// 1 minute is sufficient for ~1GB unlink() blocks each of 100kb in SSD
		_ctx, cancel := context.WithTimeout(ctx, time.Duration(gc.SlackGB)*time.Minute)
		defer cancel()

		if err := GarbageCollect(gc.Node, _ctx); err != nil {
			return err
		}
		newStorage, err := gc.Repo.GetStorageUsage()
		if err != nil {
			return err
		}
		log.Infof("Repo GC done. Released %s\n", humanize.Bytes(uint64(storage-newStorage)))
		return nil
	}
	return nil
}
<commit_msg>Fix maybeGC trigger condition<commit_after>package corerepo

import (
	"errors"
	"time"

	humanize "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/dustin/go-humanize"
	context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
	key "github.com/ipfs/go-ipfs/blocks/key"
	"github.com/ipfs/go-ipfs/core"
	repo "github.com/ipfs/go-ipfs/repo"
	logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
)

var log = logging.Logger("corerepo")

var ErrMaxStorageExceeded = errors.New("Maximum storage limit exceeded. Maybe unpin some files?")

type KeyRemoved struct {
	Key key.Key
}

type GC struct {
	Node       *core.IpfsNode
	Repo       repo.Repo
	StorageMax uint64
	StorageGC  uint64
	SlackGB    uint64
	Storage    uint64
}

func NewGC(n *core.IpfsNode) (*GC, error) {
	r := n.Repo
	cfg, err := r.Config()
	if err != nil {
		return nil, err
	}

	// check if cfg has these fields initialized
	// TODO: there should be a general check for all of the cfg fields
	// maybe distinguish between user config file and default struct?
	if cfg.Datastore.StorageMax == "" {
		r.SetConfigKey("Datastore.StorageMax", "10GB")
		cfg.Datastore.StorageMax = "10GB"
	}
	if cfg.Datastore.StorageGCWatermark == 0 {
		r.SetConfigKey("Datastore.StorageGCWatermark", 90)
		cfg.Datastore.StorageGCWatermark = 90
	}

	storageMax, err := humanize.ParseBytes(cfg.Datastore.StorageMax)
	if err != nil {
		return nil, err
	}
	storageGC := storageMax * uint64(cfg.Datastore.StorageGCWatermark) / 100

	// calculate the slack space between StorageMax and StorageGCWatermark
	// used to limit GC duration
	slackGB := (storageMax - storageGC) / 10e9
	if slackGB < 1 {
		slackGB = 1
	}

	return &GC{
		Node:       n,
		Repo:       r,
		StorageMax: storageMax,
		StorageGC:  storageGC,
		SlackGB:    slackGB,
	}, nil
}

func GarbageCollect(n *core.IpfsNode, ctx context.Context) error {
	ctx, cancel := context.WithCancel(ctx)
	defer cancel() // in case error occurs during operation
	keychan, err := n.Blockstore.AllKeysChan(ctx)
	if err != nil {
		return err
	}
	for k := range keychan { // rely on AllKeysChan to close chan
		if !n.Pinning.IsPinned(k) {
			if err := n.Blockstore.DeleteBlock(k); err != nil {
				return err
			}
		}
	}
	return nil
}

func GarbageCollectAsync(n *core.IpfsNode, ctx context.Context) (<-chan *KeyRemoved, error) {

	keychan, err := n.Blockstore.AllKeysChan(ctx)
	if err != nil {
		return nil, err
	}

	output := make(chan *KeyRemoved)
	go func() {
		defer close(output)
		for {
			select {
			case k, ok := <-keychan:
				if !ok {
					return
				}
				if !n.Pinning.IsPinned(k) {
					err := n.Blockstore.DeleteBlock(k)
					if err != nil {
						log.Debugf("Error removing key from blockstore: %s", err)
						continue
					}
					select {
					case output <- &KeyRemoved{k}:
					case <-ctx.Done():
					}
				}
			case <-ctx.Done():
				return
			}
		}
	}()
	return output, nil
}

func PeriodicGC(ctx context.Context, node *core.IpfsNode) error {
	cfg, err := node.Repo.Config()
	if err != nil {
		return err
	}

	if cfg.Datastore.GCPeriod == "" {
		node.Repo.SetConfigKey("Datastore.GCPeriod", "1h")
		cfg.Datastore.GCPeriod = "1h"
	}

	period, err := time.ParseDuration(cfg.Datastore.GCPeriod)
	if err != nil {
		return err
	}
	if int64(period) == 0 {
		// if duration is 0, it means GC is disabled.
		return nil
	}

	gc, err := NewGC(node)
	if err != nil {
		return err
	}

	for {
		select {
		case <-ctx.Done():
			return nil
		case <-time.After(period):
			// the private func maybeGC doesn't compute storageMax, storageGC, slackGC so that they are not re-computed for every cycle
			if err := gc.maybeGC(ctx, 0); err != nil {
				return err
			}
		}
	}
}

func ConditionalGC(ctx context.Context, node *core.IpfsNode, offset uint64) error {
	gc, err := NewGC(node)
	if err != nil {
		return err
	}
	return gc.maybeGC(ctx, offset)
}

func (gc *GC) maybeGC(ctx context.Context, offset uint64) error {
	storage, err := gc.Repo.GetStorageUsage()
	if err != nil {
		return err
	}

	if storage+offset > gc.StorageGC {
		if storage+offset > gc.StorageMax {
			log.Warningf("pre-GC: %s", ErrMaxStorageExceeded)
		}

		// Do GC here
		log.Info("Watermark exceeded. Starting repo GC...")
		defer log.EventBegin(ctx, "repoGC").Done()
		// 1 minute is sufficient for ~1GB unlink() blocks each of 100kb in SSD
		_ctx, cancel := context.WithTimeout(ctx, time.Duration(gc.SlackGB)*time.Minute)
		defer cancel()

		if err := GarbageCollect(gc.Node, _ctx); err != nil {
			return err
		}
		newStorage, err := gc.Repo.GetStorageUsage()
		if err != nil {
			return err
		}
		log.Infof("Repo GC done. Released %s\n", humanize.Bytes(uint64(storage-newStorage)))
		if newStorage > gc.StorageGC {
			log.Warningf("post-GC: Watermark still exceeded")
			if newStorage > gc.StorageMax {
				err := ErrMaxStorageExceeded
				log.Error(err)
				return err
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package server

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"strconv"

	"github.com/gorilla/mux"
	"github.com/kolide/kolide-ose/datastore"
	"golang.org/x/net/context"
)

var (
	// errBadRoute is used for mux errors
	errBadRoute = errors.New("bad route")
)

type invalidArgumentError struct {
	field    string
	required bool
}

// invalidArgumentError is returned when one or more arguments are invalid.
func (e invalidArgumentError) Error() string {
	req := "optional"
	if e.required {
		req = "required"
	}
	return fmt.Sprintf("%s argument invalid or missing: %s", req, e.field)
}

func encodeResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
	if e, ok := response.(errorer); ok && e.error() != nil {
		encodeError(ctx, e.error(), w)
		return nil
	}
	return json.NewEncoder(w).Encode(response)
}

// erroer interface is implemented by response structs to encode business logic errors
type errorer interface {
	error() error
}

// encode errors from business-logic
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
	switch err {
	case datastore.ErrNotFound:
		w.WriteHeader(http.StatusNotFound)
	case datastore.ErrExists:
		w.WriteHeader(http.StatusConflict)
	default:
		w.WriteHeader(typeErrsStatus(err))
	}
	json.NewEncoder(w).Encode(map[string]interface{}{
		"error": err.Error(),
	})
}

const unprocessableEntity int = 422

func typeErrsStatus(err error) int {
	switch err.(type) {
	case invalidArgumentError:
		return unprocessableEntity
	case authError:
		return http.StatusUnauthorized
	case forbiddenError:
		return http.StatusForbidden
	default:
		return http.StatusInternalServerError
	}
}

func idFromRequest(r *http.Request, name string) (uint, error) {
	vars := mux.Vars(r)
	id, ok := vars[name]
	if !ok {
		return 0, errBadRoute
	}
	uid, err := strconv.Atoi(id)
	if err != nil {
		return 0, err
	}
	return uint(uid), nil
}

func decodeNoParamsRequest(ctx context.Context, r *http.Request) (interface{}, error) {
	return nil, nil
}
<commit_msg>pretty-print JSON response. (#147)<commit_after>package server

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"strconv"

	"github.com/gorilla/mux"
	"github.com/kolide/kolide-ose/datastore"
	"golang.org/x/net/context"
)

var (
	// errBadRoute is used for mux errors
	errBadRoute = errors.New("bad route")
)

type invalidArgumentError struct {
	field    string
	required bool
}

// invalidArgumentError is returned when one or more arguments are invalid.
func (e invalidArgumentError) Error() string {
	req := "optional"
	if e.required {
		req = "required"
	}
	return fmt.Sprintf("%s argument invalid or missing: %s", req, e.field)
}

func encodeResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
	if e, ok := response.(errorer); ok && e.error() != nil {
		encodeError(ctx, e.error(), w)
		return nil
	}
	enc := json.NewEncoder(w)
	enc.SetIndent("", "  ")
	return enc.Encode(response)
}

// erroer interface is implemented by response structs to encode business logic errors
type errorer interface {
	error() error
}

// encode errors from business-logic
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
	switch err {
	case datastore.ErrNotFound:
		w.WriteHeader(http.StatusNotFound)
	case datastore.ErrExists:
		w.WriteHeader(http.StatusConflict)
	default:
		w.WriteHeader(typeErrsStatus(err))
	}
	enc := json.NewEncoder(w)
	enc.SetIndent("", "  ")
	enc.Encode(map[string]interface{}{
		"error": err.Error(),
	})
}

const unprocessableEntity int = 422

func typeErrsStatus(err error) int {
	switch err.(type) {
	case invalidArgumentError:
		return unprocessableEntity
	case authError:
		return http.StatusUnauthorized
	case forbiddenError:
		return http.StatusForbidden
	default:
		return http.StatusInternalServerError
	}
}

func idFromRequest(r *http.Request, name string) (uint, error) {
	vars := mux.Vars(r)
	id, ok := vars[name]
	if !ok {
		return 0, errBadRoute
	}
	uid, err := strconv.Atoi(id)
	if err != nil {
		return 0, err
	}
	return uint(uid), nil
}

func decodeNoParamsRequest(ctx context.Context, r *http.Request) (interface{}, error) {
	return nil, nil
}
<|endoftext|>


<commit_before>// Copyright 2016 The Tcell Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use 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 views

import (
	"github.com/gdamore/tcell"
)

// BoxLayout is a container Widget that lays out its child widgets in
// either a horizontal row or a vertical column.
type BoxLayout struct {
	view    View
	orient  Orientation
	style   tcell.Style // backing style
	cells   []*boxLayoutCell
	width   int
	height  int
	changed bool

	WidgetWatchers
}

type boxLayoutCell struct {
	widget Widget
	fill   float64 // fill factor - 0.0 means no expansion
	pad    int     // count of padding spaces (stretch)
	frac   float64 // calculated residual spacing, used internally
	view   *ViewPort
}

func (b *BoxLayout) hLayout() {
	w, h := b.view.Size()

	totf := 0.0
	for _, c := range b.cells {
		x, y := c.widget.Size()
		totf += c.fill
		b.width += x
		if y > b.height {
			b.height = y
		}
		c.pad = 0
		c.frac = 0
	}

	extra := w - b.width
	if extra < 0 {
		extra = 0
	}
	resid := extra
	if totf == 0 {
		resid = 0
	}

	for _, c := range b.cells {
		if c.fill > 0 {
			c.frac = float64(extra) * c.fill / totf
			c.pad = int(c.frac)
			c.frac -= float64(c.pad)
			resid -= c.pad
		}
	}

	// Distribute any left over padding.  We try to give it to the
	// the cells with the highest residual fraction.  It should be
	// the case that no single cell gets more than one more cell.
	for resid > 0 {
		var best *boxLayoutCell
		for _, c := range b.cells {
			if c.fill == 0 {
				continue
			}
			if best == nil || c.frac > best.frac {
				best = c
			}
		}
		best.pad++
		best.frac = 0
		resid--
	}

	x, y, xinc := 0, 0, 0
	for _, c := range b.cells {
		cw, _ := c.widget.Size()

		xinc = cw + c.pad
		cw += c.pad

		c.view.Resize(x, y, cw, h)
		c.widget.Resize()
		x += xinc
	}
}

func (b *BoxLayout) vLayout() {
	w, h := b.view.Size()

	totf := 0.0
	for _, c := range b.cells {
		x, y := c.widget.Size()
		b.height += y
		totf += c.fill
		if x > b.width {
			b.width = x
		}
		c.pad = 0
		c.frac = 0
	}

	extra := h - b.height
	if extra < 0 {
		extra = 0
	}

	resid := extra
	if totf == 0 {
		resid = 0
	}

	for _, c := range b.cells {
		if c.fill > 0 {
			c.frac = float64(extra) * c.fill / totf
			c.pad = int(c.frac)
			c.frac -= float64(c.pad)
			resid -= c.pad
		}
	}

	// Distribute any left over padding.  We try to give it to the
	// the cells with the highest residual fraction.  It should be
	// the case that no single cell gets more than one more cell.
	for resid > 0 {
		var best *boxLayoutCell
		for _, c := range b.cells {
			if c.fill == 0 {
				continue
			}
			if best == nil || c.frac > best.frac {
				best = c
			}
		}
		best.pad++
		best.frac = 0
		resid--
	}

	x, y, yinc := 0, 0, 0
	for _, c := range b.cells {
		_, ch := c.widget.Size()

		yinc = ch + c.pad
		ch += c.pad
		c.view.Resize(x, y, w, ch)
		c.widget.Resize()
		y += yinc
	}
}

func (b *BoxLayout) layout() {
	if b.view == nil {
		return
	}
	b.width, b.height = 0, 0
	switch b.orient {
	case Horizontal:
		b.hLayout()
	case Vertical:
		b.vLayout()
	default:
		panic("Bad orientation")
	}
	b.changed = false
}

// Resize adjusts the layout when the underlying View changes size.
func (b *BoxLayout) Resize() {
	b.layout()

	// Now also let the children know we resized.
	for i := range b.cells {
		b.cells[i].widget.Resize()
	}
	b.PostEventWidgetResize(b)
}

// Draw is called to update the displayed content.
func (b *BoxLayout) Draw() {

	if b.view == nil {
		return
	}
	if b.changed {
		b.layout()
	}
	b.view.Fill('*', b.style)
	w, h := b.view.Size()
	for y := 0; y < h; y++ {
		for x := 0; x < w; x++ {
			b.view.SetContent(x, y, ' ', nil, b.style)
		}
	}
	for i := range b.cells {
		b.cells[i].widget.Draw()
	}
}

// Size returns the preferred size in character cells (width, height).
func (b *BoxLayout) Size() (int, int) {
	return b.width, b.height
}

// SetView sets the View object used for the text bar.
func (b *BoxLayout) SetView(view View) {
	b.changed = true
	b.view = view
	for _, c := range b.cells {
		c.view.SetView(view)
	}
}

// HandleEvent implements a tcell.EventHandler.  The only events
// we care about are Widget change events from our children. We
// watch for those so that if the child changes, we can arrange
// to update our layout.
func (b *BoxLayout) HandleEvent(ev tcell.Event) bool {
	switch ev.(type) {
	case *EventWidgetContent:
		// This can only have come from one of our children.
		b.changed = true
		b.PostEventWidgetContent(b)
		return true
	}
	for _, c := range b.cells {
		if c.widget.HandleEvent(ev) {
			return true
		}
	}
	return false
}

// AddWidget adds a widget to the end of the BoxLayout.
func (b *BoxLayout) AddWidget(widget Widget, fill float64) {
	c := &boxLayoutCell{
		widget: widget,
		fill:   fill,
		view:   NewViewPort(b.view, 0, 0, 0, 0),
	}
	widget.SetView(c.view)
	b.cells = append(b.cells, c)
	b.changed = true
	widget.Watch(b)
	b.layout()
	b.PostEventWidgetContent(b)
}

// InsertWidget inserts a widget at the given offset.  Offset 0 is the
// front.  If the index is longer than the number of widgets, then it
// just gets appended to the end.
func (b *BoxLayout) InsertWidget(index int, widget Widget, fill float64) {
	c := &boxLayoutCell{
		widget: widget,
		fill:   fill,
		view:   NewViewPort(b.view, 0, 0, 0, 0),
	}
	c.widget.SetView(c.view)
	if index < 0 {
		index = 0
	}
	if index > len(b.cells) {
		index = len(b.cells)
	}
	b.cells = append(b.cells, c)
	copy(b.cells[index+1:], b.cells[index:])
	b.cells[index] = c
	widget.Watch(b)
	b.layout()
	b.PostEventWidgetContent(b)
}

// RemoveWidget removes a Widget from the layout.
func (b *BoxLayout) RemoveWidget(widget Widget) {
	changed := false
	for i := 0; i < len(b.cells); i++ {
		if b.cells[i].widget == widget {
			b.cells = append(b.cells[:i], b.cells[i+1:]...)
			changed = true
		}
	}
	if !changed {
		return
	}
	b.changed = true
	widget.Unwatch(b)
	b.layout()
	b.PostEventWidgetContent(b)
}

// Widgets returns the list of Widgets for this BoxLayout.
func (b *BoxLayout) Widgets() []Widget {
	w := make([]Widget, 0, len(b.cells))
	for _, c := range b.cells {
		w = append(w, c.widget)
	}
	return w
}

// SetOrientation sets the orientation as either Horizontal or Vertical.
func (b *BoxLayout) SetOrientation(orient Orientation) {
	if b.orient != orient {
		b.orient = orient
		b.changed = true
		b.PostEventWidgetContent(b)
	}
}

// SetStyle sets the style used.
func (b *BoxLayout) SetStyle(style tcell.Style) {
	b.style = style
	b.PostEventWidgetContent(b)
}

// NewBoxLayout creates an empty BoxLayout.
func NewBoxLayout(orient Orientation) *BoxLayout {
	return &BoxLayout{orient: orient}
}
<commit_msg>fixes #238 views: BoxLayout.Draw does unnecessary filling<commit_after>// Copyright 2016 The Tcell Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use 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 views

import (
	"github.com/gdamore/tcell"
)

// BoxLayout is a container Widget that lays out its child widgets in
// either a horizontal row or a vertical column.
type BoxLayout struct {
	view    View
	orient  Orientation
	style   tcell.Style // backing style
	cells   []*boxLayoutCell
	width   int
	height  int
	changed bool

	WidgetWatchers
}

type boxLayoutCell struct {
	widget Widget
	fill   float64 // fill factor - 0.0 means no expansion
	pad    int     // count of padding spaces (stretch)
	frac   float64 // calculated residual spacing, used internally
	view   *ViewPort
}

func (b *BoxLayout) hLayout() {
	w, h := b.view.Size()

	totf := 0.0
	for _, c := range b.cells {
		x, y := c.widget.Size()
		totf += c.fill
		b.width += x
		if y > b.height {
			b.height = y
		}
		c.pad = 0
		c.frac = 0
	}

	extra := w - b.width
	if extra < 0 {
		extra = 0
	}
	resid := extra
	if totf == 0 {
		resid = 0
	}

	for _, c := range b.cells {
		if c.fill > 0 {
			c.frac = float64(extra) * c.fill / totf
			c.pad = int(c.frac)
			c.frac -= float64(c.pad)
			resid -= c.pad
		}
	}

	// Distribute any left over padding.  We try to give it to the
	// the cells with the highest residual fraction.  It should be
	// the case that no single cell gets more than one more cell.
	for resid > 0 {
		var best *boxLayoutCell
		for _, c := range b.cells {
			if c.fill == 0 {
				continue
			}
			if best == nil || c.frac > best.frac {
				best = c
			}
		}
		best.pad++
		best.frac = 0
		resid--
	}

	x, y, xinc := 0, 0, 0
	for _, c := range b.cells {
		cw, _ := c.widget.Size()

		xinc = cw + c.pad
		cw += c.pad

		c.view.Resize(x, y, cw, h)
		c.widget.Resize()
		x += xinc
	}
}

func (b *BoxLayout) vLayout() {
	w, h := b.view.Size()

	totf := 0.0
	for _, c := range b.cells {
		x, y := c.widget.Size()
		b.height += y
		totf += c.fill
		if x > b.width {
			b.width = x
		}
		c.pad = 0
		c.frac = 0
	}

	extra := h - b.height
	if extra < 0 {
		extra = 0
	}

	resid := extra
	if totf == 0 {
		resid = 0
	}

	for _, c := range b.cells {
		if c.fill > 0 {
			c.frac = float64(extra) * c.fill / totf
			c.pad = int(c.frac)
			c.frac -= float64(c.pad)
			resid -= c.pad
		}
	}

	// Distribute any left over padding.  We try to give it to the
	// the cells with the highest residual fraction.  It should be
	// the case that no single cell gets more than one more cell.
	for resid > 0 {
		var best *boxLayoutCell
		for _, c := range b.cells {
			if c.fill == 0 {
				continue
			}
			if best == nil || c.frac > best.frac {
				best = c
			}
		}
		best.pad++
		best.frac = 0
		resid--
	}

	x, y, yinc := 0, 0, 0
	for _, c := range b.cells {
		_, ch := c.widget.Size()

		yinc = ch + c.pad
		ch += c.pad
		c.view.Resize(x, y, w, ch)
		c.widget.Resize()
		y += yinc
	}
}

func (b *BoxLayout) layout() {
	if b.view == nil {
		return
	}
	b.width, b.height = 0, 0
	switch b.orient {
	case Horizontal:
		b.hLayout()
	case Vertical:
		b.vLayout()
	default:
		panic("Bad orientation")
	}
	b.changed = false
}

// Resize adjusts the layout when the underlying View changes size.
func (b *BoxLayout) Resize() {
	b.layout()

	// Now also let the children know we resized.
	for i := range b.cells {
		b.cells[i].widget.Resize()
	}
	b.PostEventWidgetResize(b)
}

// Draw is called to update the displayed content.
func (b *BoxLayout) Draw() {

	if b.view == nil {
		return
	}
	if b.changed {
		b.layout()
	}
	b.view.Fill(' ', b.style)
	for i := range b.cells {
		b.cells[i].widget.Draw()
	}
}

// Size returns the preferred size in character cells (width, height).
func (b *BoxLayout) Size() (int, int) {
	return b.width, b.height
}

// SetView sets the View object used for the text bar.
func (b *BoxLayout) SetView(view View) {
	b.changed = true
	b.view = view
	for _, c := range b.cells {
		c.view.SetView(view)
	}
}

// HandleEvent implements a tcell.EventHandler.  The only events
// we care about are Widget change events from our children. We
// watch for those so that if the child changes, we can arrange
// to update our layout.
func (b *BoxLayout) HandleEvent(ev tcell.Event) bool {
	switch ev.(type) {
	case *EventWidgetContent:
		// This can only have come from one of our children.
		b.changed = true
		b.PostEventWidgetContent(b)
		return true
	}
	for _, c := range b.cells {
		if c.widget.HandleEvent(ev) {
			return true
		}
	}
	return false
}

// AddWidget adds a widget to the end of the BoxLayout.
func (b *BoxLayout) AddWidget(widget Widget, fill float64) {
	c := &boxLayoutCell{
		widget: widget,
		fill:   fill,
		view:   NewViewPort(b.view, 0, 0, 0, 0),
	}
	widget.SetView(c.view)
	b.cells = append(b.cells, c)
	b.changed = true
	widget.Watch(b)
	b.layout()
	b.PostEventWidgetContent(b)
}

// InsertWidget inserts a widget at the given offset.  Offset 0 is the
// front.  If the index is longer than the number of widgets, then it
// just gets appended to the end.
func (b *BoxLayout) InsertWidget(index int, widget Widget, fill float64) {
	c := &boxLayoutCell{
		widget: widget,
		fill:   fill,
		view:   NewViewPort(b.view, 0, 0, 0, 0),
	}
	c.widget.SetView(c.view)
	if index < 0 {
		index = 0
	}
	if index > len(b.cells) {
		index = len(b.cells)
	}
	b.cells = append(b.cells, c)
	copy(b.cells[index+1:], b.cells[index:])
	b.cells[index] = c
	widget.Watch(b)
	b.layout()
	b.PostEventWidgetContent(b)
}

// RemoveWidget removes a Widget from the layout.
func (b *BoxLayout) RemoveWidget(widget Widget) {
	changed := false
	for i := 0; i < len(b.cells); i++ {
		if b.cells[i].widget == widget {
			b.cells = append(b.cells[:i], b.cells[i+1:]...)
			changed = true
		}
	}
	if !changed {
		return
	}
	b.changed = true
	widget.Unwatch(b)
	b.layout()
	b.PostEventWidgetContent(b)
}

// Widgets returns the list of Widgets for this BoxLayout.
func (b *BoxLayout) Widgets() []Widget {
	w := make([]Widget, 0, len(b.cells))
	for _, c := range b.cells {
		w = append(w, c.widget)
	}
	return w
}

// SetOrientation sets the orientation as either Horizontal or Vertical.
func (b *BoxLayout) SetOrientation(orient Orientation) {
	if b.orient != orient {
		b.orient = orient
		b.changed = true
		b.PostEventWidgetContent(b)
	}
}

// SetStyle sets the style used.
func (b *BoxLayout) SetStyle(style tcell.Style) {
	b.style = style
	b.PostEventWidgetContent(b)
}

// NewBoxLayout creates an empty BoxLayout.
func NewBoxLayout(orient Orientation) *BoxLayout {
	return &BoxLayout{orient: orient}
}
<|endoftext|>


<commit_before>package hoverfly

import (
	"encoding/base64"
	"github.com/SpectoLabs/hoverfly/core/cache"
	"github.com/SpectoLabs/hoverfly/core/matching"
	"github.com/SpectoLabs/hoverfly/core/models"
	. "github.com/SpectoLabs/hoverfly/core/util"
	"github.com/SpectoLabs/hoverfly/core/views"
	. "github.com/onsi/gomega"
	"io/ioutil"
	"os"
	"testing"
)

func TestIsURLHTTP(t *testing.T) {
	url := "http://somehost.com"

	b := isURL(url)
	Expect(b).To(BeTrue())
}

func TestIsURLEmpty(t *testing.T) {
	b := isURL("")
	Expect(b).To(BeFalse())
}

func TestIsURLHTTPS(t *testing.T) {
	url := "https://somehost.com"

	b := isURL(url)
	Expect(b).To(BeTrue())
}

func TestIsURLWrong(t *testing.T) {
	url := "somehost.com"

	b := isURL(url)
	Expect(b).To(BeFalse())
}

func TestIsURLWrongTLD(t *testing.T) {
	url := "http://somehost."

	b := isURL(url)
	Expect(b).To(BeFalse())
}

func TestFileExists(t *testing.T) {
	fp := "examples/exports/readthedocs.json"

	ex, err := exists(fp)
	Expect(err).To(BeNil())
	Expect(ex).To(BeTrue())
}

func TestFileDoesNotExist(t *testing.T) {
	fp := "shouldnotbehere.yaml"

	ex, err := exists(fp)
	Expect(err).To(BeNil())
	Expect(ex).To(BeFalse())
}

func TestImportFromDisk(t *testing.T) {
	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()
	defer dbClient.RequestCache.DeleteData()

	err := dbClient.Import("examples/exports/readthedocs.json")
	Expect(err).To(BeNil())

	recordsCount, err := dbClient.RequestCache.RecordsCount()
	Expect(err).To(BeNil())

	Expect(recordsCount).To(Equal(5))
}

func TestImportFromDiskBlankPath(t *testing.T) {
	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()
	defer dbClient.RequestCache.DeleteData()

	err := dbClient.ImportFromDisk("")
	Expect(err).ToNot(BeNil())
}

func TestImportFromDiskWrongJson(t *testing.T) {
	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()
	defer dbClient.RequestCache.DeleteData()

	err := dbClient.ImportFromDisk("examples/exports/README.md")
	Expect(err).ToNot(BeNil())
}

func TestImportFromURL(t *testing.T) {
	// reading file and preparing json payload
	pairFile, err := os.Open("examples/exports/readthedocs.json")
	Expect(err).To(BeNil())
	pairFileBytes, err := ioutil.ReadAll(pairFile)
	Expect(err).To(BeNil())

	// pretending this is the endpoint with given json
	server, dbClient := testTools(200, string(pairFileBytes))
	defer server.Close()
	defer dbClient.RequestCache.DeleteData()

	// importing payloads
	err = dbClient.Import("http://thiswillbeintercepted.json")
	Expect(err).To(BeNil())

	recordsCount, err := dbClient.RequestCache.RecordsCount()
	Expect(err).To(BeNil())
	Expect(recordsCount).To(Equal(5))
}

func TestImportFromURLHTTPFail(t *testing.T) {
	// this tests simulates unreachable server
	server, dbClient := testTools(200, `this shouldn't matter anyway`)
	// closing it immediately
	server.Close()
	defer dbClient.RequestCache.DeleteData()

	err := dbClient.ImportFromURL("somepath")
	Expect(err).ToNot(BeNil())
}

func TestImportFromURLMalformedJSON(t *testing.T) {
	// testing behaviour when there is no json on the other end
	server, dbClient := testTools(200, `i am not json :(`)
	defer server.Close()
	defer dbClient.RequestCache.DeleteData()

	// importing payloads
	err := dbClient.Import("http://thiswillbeintercepted.json")
	// we should get error
	Expect(err).ToNot(BeNil())
}

func TestImportRequestResponsePairs_CanImportASinglePair(t *testing.T) {
	cache := cache.NewInMemoryCache()
	cfg := Configuration{Webserver: false}
	requestMatcher := matching.RequestMatcher{RequestCache: cache, Webserver: &cfg.Webserver}
	hv := Hoverfly{RequestCache: cache, Cfg: &cfg, RequestMatcher: requestMatcher}

	RegisterTestingT(t)

	originalPair := views.RequestResponsePairView{
		Response: views.ResponseDetailsView{
			Status:      200,
			Body:        "hello_world",
			EncodedBody: false,
			Headers:     map[string][]string{"Content-Type": []string{"text/plain"}}},
		Request: views.RequestDetailsView{
			Path:        StringToPointer("/"),
			Method:      StringToPointer("GET"),
			Destination: StringToPointer("/"),
			Scheme:      StringToPointer("scheme"),
			Query:       StringToPointer(""),
			Body:        StringToPointer(""),
			Headers:     map[string][]string{"Hoverfly": []string{"testing"}}}}

	hv.ImportRequestResponsePairViews([]views.RequestResponsePairView{originalPair})
	value, _ := cache.Get([]byte("9b114df98da7f7e2afdc975883dab4f2"))
	decodedPair, _ := models.NewRequestResponsePairFromBytes(value)
	Expect(*decodedPair).To(Equal(models.RequestResponsePair{
		Response: models.ResponseDetails{
			Status:  200,
			Body:    "hello_world",
			Headers: map[string][]string{"Content-Type": []string{"text/plain"}},
		},
		Request: models.RequestDetails{
			Path:        "/",
			Method:      "GET",
			Destination: "/",
			Scheme:      "scheme",
			Query:       "", Body: "",
			Headers: map[string][]string{
				"Content-Type": []string{"text/plain; charset=utf-8"},
				"Hoverfly":     []string{"testing"},
			},
		},
	}))
}

func TestImportImportRequestResponsePairs_CanImportAMultiplePairs(t *testing.T) {
	cache := cache.NewInMemoryCache()
	cfg := Configuration{Webserver: false}
	requestMatcher := matching.RequestMatcher{RequestCache: cache, Webserver: &cfg.Webserver}
	hv := Hoverfly{RequestCache: cache, Cfg: &cfg, RequestMatcher: requestMatcher}

	RegisterTestingT(t)

	originalPair1 := views.RequestResponsePairView{
		Response: views.ResponseDetailsView{
			Status:      200,
			Body:        "hello_world",
			EncodedBody: false,
			Headers:     map[string][]string{"Hoverfly": []string{"testing"}},
		},
		Request: views.RequestDetailsView{
			Path:        StringToPointer("/"),
			Method:      StringToPointer("GET"),
			Destination: StringToPointer("/"),
			Scheme:      StringToPointer("scheme"),
			Query:       StringToPointer(""),
			Body:        StringToPointer(""),
			Headers:     map[string][]string{"Hoverfly": []string{"testing"}}}}

	originalPair2 := originalPair1
	originalPair2.Request.Path = StringToPointer("/new/path")

	originalPair3 := originalPair1
	originalPair3.Request.Path = StringToPointer("/newer/path")

	hv.ImportRequestResponsePairViews([]views.RequestResponsePairView{originalPair1, originalPair2, originalPair3})

	pairBytes, err := cache.Get([]byte("9b114df98da7f7e2afdc975883dab4f2"))
	Expect(err).To(BeNil())
	decodedPair1, err := models.NewRequestResponsePairFromBytes(pairBytes)
	Expect(err).To(BeNil())
	Expect(*decodedPair1).To(Equal(models.NewRequestResponsePairFromRequestResponsePairView(originalPair1)))

	pairBytes, err = cache.Get([]byte("9c03e4af1f30542ff079a712bddad602"))
	Expect(err).To(BeNil())
	decodedPair2, err := models.NewRequestResponsePairFromBytes(pairBytes)
	Expect(err).To(BeNil())
	Expect(*decodedPair2).To(Equal(models.NewRequestResponsePairFromRequestResponsePairView(originalPair2)))

	pairBytes, err = cache.Get([]byte("fd099332afee48101edb7441b098cd4a"))
	Expect(err).To(BeNil())
	decodedPair3, err := models.NewRequestResponsePairFromBytes(pairBytes)
	Expect(err).To(BeNil())
	Expect(*decodedPair3).To(Equal(models.NewRequestResponsePairFromRequestResponsePairView(originalPair3)))
}

func TestImportImportRequestResponsePairs_CanImportARequestTemplateResponsePair(t *testing.T) {
	cache := cache.NewInMemoryCache()
	cfg := Configuration{Webserver: false}
	requestMatcher := matching.RequestMatcher{RequestCache: cache, Webserver: &cfg.Webserver}
	hv := Hoverfly{RequestCache: cache, Cfg: &cfg, RequestMatcher: requestMatcher}

	RegisterTestingT(t)

	requestTemplate := views.RequestDetailsView{
		RequestType: StringToPointer("template"),
		Method:      StringToPointer("GET"),
	}

	responseView := views.ResponseDetailsView{
		Status:      200,
		Body:        "hello_world",
		EncodedBody: false,
		Headers:     map[string][]string{"Hoverfly": []string{"testing"}},
	}

	templatePair := views.RequestResponsePairView{
		Response: responseView,
		Request:  requestTemplate,
	}

	hv.ImportRequestResponsePairViews([]views.RequestResponsePairView{templatePair})

	Expect(len(hv.RequestMatcher.TemplateStore)).To(Equal(1))

	request := models.NewRequestDetailsFromRequestDetailsView(requestTemplate)
	responseFromCache, err := hv.RequestMatcher.TemplateStore.GetResponse(request, false)
	Expect(err).To(BeNil())

	response := models.NewResponseDetailsFromResponseDetailsView(responseView)

	Expect(*responseFromCache).To(Equal(response))
}

func TestImportImportRequestResponsePairs_CanImportARequestResponsePair_AndRequestTemplateResponsePair(t *testing.T) {
	cache := cache.NewInMemoryCache()
	cfg := Configuration{Webserver: false}
	requestMatcher := matching.RequestMatcher{RequestCache: cache, Webserver: &cfg.Webserver}
	hv := Hoverfly{RequestCache: cache, Cfg: &cfg, RequestMatcher: requestMatcher}

	RegisterTestingT(t)

	requestTemplate := views.RequestDetailsView{
		RequestType: StringToPointer("template"),
		Method:      StringToPointer("GET"),
	}

	requestView := views.RequestDetailsView{
		Method:      StringToPointer("GET"),
		Path:        StringToPointer("/"),
		Destination: StringToPointer("test.com"),
		Scheme:      StringToPointer("http"),
	}

	responseView := views.ResponseDetailsView{
		Status:      200,
		Body:        "hello_world",
		EncodedBody: false,
		Headers:     map[string][]string{"Hoverfly": []string{"testing"}},
	}

	templatePair := views.RequestResponsePairView{
		Request:  requestTemplate,
		Response: responseView,
	}

	ordinaryPair := views.RequestResponsePairView{
		Request:  requestView,
		Response: responseView,
	}

	hv.ImportRequestResponsePairViews([]views.RequestResponsePairView{templatePair, ordinaryPair})

	cacheCount, err := hv.RequestCache.RecordsCount()
	Expect(cacheCount).To(Equal(1))
	Expect(err).To(BeNil())

	Expect(len(hv.RequestMatcher.TemplateStore)).To(Equal(1))

	request := models.NewRequestDetailsFromRequestDetailsView(requestTemplate)
	response := models.NewResponseDetailsFromResponseDetailsView(responseView)

	pairBytes, err := hv.RequestCache.Get([]byte("76cf08e38439f083de2658b0971df9bf"))
	Expect(err).To(BeNil())

	savedPair, err := models.NewRequestResponsePairFromBytes(pairBytes)
	Expect(err).To(BeNil())

	Expect(savedPair.Response).To(Equal(response))

	responseFromCache, err := hv.RequestMatcher.TemplateStore.GetResponse(request, false)
	Expect(err).To(BeNil())
	Expect(*responseFromCache).To(Equal(response))

}

// Helper function for base64 encoding
func base64String(s string) string {
	return base64.StdEncoding.EncodeToString([]byte(s))
}

func TestImportImportRequestResponsePairs_CanImportASingleBase64EncodedPair(t *testing.T) {
	cache := cache.NewInMemoryCache()
	cfg := Configuration{Webserver: false}
	requestMatcher := matching.RequestMatcher{RequestCache: cache, Webserver: &cfg.Webserver}
	hv := Hoverfly{RequestCache: cache, Cfg: &cfg, RequestMatcher: requestMatcher}

	RegisterTestingT(t)

	encodedPair := views.RequestResponsePairView{
		Response: views.ResponseDetailsView{
			Status:      200,
			Body:        base64String("hello_world"),
			EncodedBody: true,
			Headers:     map[string][]string{"Content-Encoding": []string{"gzip"}}},
		Request: views.RequestDetailsView{
			Path:        StringToPointer("/"),
			Method:      StringToPointer("GET"),
			Destination: StringToPointer("/"),
			Scheme:      StringToPointer("scheme"),
			Query:       StringToPointer(""),
			Body:        StringToPointer(""),
			Headers:     map[string][]string{"Hoverfly": []string{"testing"}}}}

	hv.ImportRequestResponsePairViews([]views.RequestResponsePairView{encodedPair})

	value, err := cache.Get([]byte("9b114df98da7f7e2afdc975883dab4f2"))
	Expect(err).To(BeNil())

	decodedPair, err := models.NewRequestResponsePairFromBytes(value)
	Expect(err).To(BeNil())

	Expect(decodedPair).ToNot(Equal(models.RequestResponsePair{
		Response: models.ResponseDetails{
			Status:  200,
			Body:    "hello_world",
			Headers: map[string][]string{"Content-Encoding": []string{"gzip"}}},
		Request: models.RequestDetails{
			Path:        "/",
			Method:      "GET",
			Destination: "/",
			Scheme:      "scheme",
			Query:       "", Body: "",
			Headers: map[string][]string{"Hoverfly": []string{"testing"}}}}))
}
<commit_msg>Registering the Ts for testing<commit_after>package hoverfly

import (
	"encoding/base64"
	"github.com/SpectoLabs/hoverfly/core/cache"
	"github.com/SpectoLabs/hoverfly/core/matching"
	"github.com/SpectoLabs/hoverfly/core/models"
	. "github.com/SpectoLabs/hoverfly/core/util"
	"github.com/SpectoLabs/hoverfly/core/views"
	. "github.com/onsi/gomega"
	"io/ioutil"
	"os"
	"testing"
)

func TestIsURLHTTP(t *testing.T) {
	RegisterTestingT(t)

	url := "http://somehost.com"

	b := isURL(url)
	Expect(b).To(BeTrue())
}

func TestIsURLEmpty(t *testing.T) {
	RegisterTestingT(t)

	b := isURL("")
	Expect(b).To(BeFalse())
}

func TestIsURLHTTPS(t *testing.T) {
	RegisterTestingT(t)

	url := "https://somehost.com"

	b := isURL(url)
	Expect(b).To(BeTrue())
}

func TestIsURLWrong(t *testing.T) {
	RegisterTestingT(t)

	url := "somehost.com"

	b := isURL(url)
	Expect(b).To(BeFalse())
}

func TestIsURLWrongTLD(t *testing.T) {
	RegisterTestingT(t)

	url := "http://somehost."

	b := isURL(url)
	Expect(b).To(BeFalse())
}

func TestFileExists(t *testing.T) {
	RegisterTestingT(t)

	fp := "examples/exports/readthedocs.json"

	ex, err := exists(fp)
	Expect(err).To(BeNil())
	Expect(ex).To(BeTrue())
}

func TestFileDoesNotExist(t *testing.T) {
	RegisterTestingT(t)

	fp := "shouldnotbehere.yaml"

	ex, err := exists(fp)
	Expect(err).To(BeNil())
	Expect(ex).To(BeFalse())
}

func TestImportFromDisk(t *testing.T) {
	RegisterTestingT(t)

	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()
	defer dbClient.RequestCache.DeleteData()

	err := dbClient.Import("examples/exports/readthedocs.json")
	Expect(err).To(BeNil())

	recordsCount, err := dbClient.RequestCache.RecordsCount()
	Expect(err).To(BeNil())

	Expect(recordsCount).To(Equal(5))
}

func TestImportFromDiskBlankPath(t *testing.T) {
	RegisterTestingT(t)

	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()
	defer dbClient.RequestCache.DeleteData()

	err := dbClient.ImportFromDisk("")
	Expect(err).ToNot(BeNil())
}

func TestImportFromDiskWrongJson(t *testing.T) {
	RegisterTestingT(t)

	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()
	defer dbClient.RequestCache.DeleteData()

	err := dbClient.ImportFromDisk("examples/exports/README.md")
	Expect(err).ToNot(BeNil())
}

func TestImportFromURL(t *testing.T) {
	RegisterTestingT(t)

	// reading file and preparing json payload
	pairFile, err := os.Open("examples/exports/readthedocs.json")
	Expect(err).To(BeNil())
	pairFileBytes, err := ioutil.ReadAll(pairFile)
	Expect(err).To(BeNil())

	// pretending this is the endpoint with given json
	server, dbClient := testTools(200, string(pairFileBytes))
	defer server.Close()
	defer dbClient.RequestCache.DeleteData()

	// importing payloads
	err = dbClient.Import(server.URL)
	Expect(err).To(BeNil())

	recordsCount, err := dbClient.RequestCache.RecordsCount()
	Expect(err).To(BeNil())
	Expect(recordsCount).To(Equal(5))
}

func TestImportFromURLHTTPFail(t *testing.T) {
	RegisterTestingT(t)

	// this tests simulates unreachable server
	server, dbClient := testTools(200, `this shouldn't matter anyway`)
	// closing it immediately
	server.Close()
	defer dbClient.RequestCache.DeleteData()

	err := dbClient.ImportFromURL("somepath")
	Expect(err).ToNot(BeNil())
}

func TestImportFromURLMalformedJSON(t *testing.T) {
	RegisterTestingT(t)

	// testing behaviour when there is no json on the other end
	server, dbClient := testTools(200, `i am not json :(`)
	defer server.Close()
	defer dbClient.RequestCache.DeleteData()

	// importing payloads
	err := dbClient.Import("http://thiswillbeintercepted.json")
	// we should get error
	Expect(err).ToNot(BeNil())
}

func TestImportRequestResponsePairs_CanImportASinglePair(t *testing.T) {
	RegisterTestingT(t)

	cache := cache.NewInMemoryCache()
	cfg := Configuration{Webserver: false}
	requestMatcher := matching.RequestMatcher{RequestCache: cache, Webserver: &cfg.Webserver}
	hv := Hoverfly{RequestCache: cache, Cfg: &cfg, RequestMatcher: requestMatcher}

	RegisterTestingT(t)

	originalPair := views.RequestResponsePairView{
		Response: views.ResponseDetailsView{
			Status:      200,
			Body:        "hello_world",
			EncodedBody: false,
			Headers:     map[string][]string{"Content-Type": []string{"text/plain"}}},
		Request: views.RequestDetailsView{
			Path:        StringToPointer("/"),
			Method:      StringToPointer("GET"),
			Destination: StringToPointer("/"),
			Scheme:      StringToPointer("scheme"),
			Query:       StringToPointer(""),
			Body:        StringToPointer(""),
			Headers:     map[string][]string{"Hoverfly": []string{"testing"}}}}

	hv.ImportRequestResponsePairViews([]views.RequestResponsePairView{originalPair})
	value, _ := cache.Get([]byte("9b114df98da7f7e2afdc975883dab4f2"))
	decodedPair, _ := models.NewRequestResponsePairFromBytes(value)
	Expect(*decodedPair).To(Equal(models.RequestResponsePair{
		Response: models.ResponseDetails{
			Status:  200,
			Body:    "hello_world",
			Headers: map[string][]string{"Content-Type": []string{"text/plain"}},
		},
		Request: models.RequestDetails{
			Path:        "/",
			Method:      "GET",
			Destination: "/",
			Scheme:      "scheme",
			Query:       "", Body: "",
			Headers: map[string][]string{
				"Content-Type": []string{"text/plain; charset=utf-8"},
				"Hoverfly":     []string{"testing"},
			},
		},
	}))
}

func TestImportImportRequestResponsePairs_CanImportAMultiplePairs(t *testing.T) {
	RegisterTestingT(t)

	cache := cache.NewInMemoryCache()
	cfg := Configuration{Webserver: false}
	requestMatcher := matching.RequestMatcher{RequestCache: cache, Webserver: &cfg.Webserver}
	hv := Hoverfly{RequestCache: cache, Cfg: &cfg, RequestMatcher: requestMatcher}

	RegisterTestingT(t)

	originalPair1 := views.RequestResponsePairView{
		Response: views.ResponseDetailsView{
			Status:      200,
			Body:        "hello_world",
			EncodedBody: false,
			Headers:     map[string][]string{"Hoverfly": []string{"testing"}},
		},
		Request: views.RequestDetailsView{
			Path:        StringToPointer("/"),
			Method:      StringToPointer("GET"),
			Destination: StringToPointer("/"),
			Scheme:      StringToPointer("scheme"),
			Query:       StringToPointer(""),
			Body:        StringToPointer(""),
			Headers:     map[string][]string{"Hoverfly": []string{"testing"}}}}

	originalPair2 := originalPair1
	originalPair2.Request.Path = StringToPointer("/new/path")

	originalPair3 := originalPair1
	originalPair3.Request.Path = StringToPointer("/newer/path")

	hv.ImportRequestResponsePairViews([]views.RequestResponsePairView{originalPair1, originalPair2, originalPair3})

	pairBytes, err := cache.Get([]byte("9b114df98da7f7e2afdc975883dab4f2"))
	Expect(err).To(BeNil())
	decodedPair1, err := models.NewRequestResponsePairFromBytes(pairBytes)
	Expect(err).To(BeNil())
	Expect(*decodedPair1).To(Equal(models.NewRequestResponsePairFromRequestResponsePairView(originalPair1)))

	pairBytes, err = cache.Get([]byte("9c03e4af1f30542ff079a712bddad602"))
	Expect(err).To(BeNil())
	decodedPair2, err := models.NewRequestResponsePairFromBytes(pairBytes)
	Expect(err).To(BeNil())
	Expect(*decodedPair2).To(Equal(models.NewRequestResponsePairFromRequestResponsePairView(originalPair2)))

	pairBytes, err = cache.Get([]byte("fd099332afee48101edb7441b098cd4a"))
	Expect(err).To(BeNil())
	decodedPair3, err := models.NewRequestResponsePairFromBytes(pairBytes)
	Expect(err).To(BeNil())
	Expect(*decodedPair3).To(Equal(models.NewRequestResponsePairFromRequestResponsePairView(originalPair3)))
}

func TestImportImportRequestResponsePairs_CanImportARequestTemplateResponsePair(t *testing.T) {
	RegisterTestingT(t)

	cache := cache.NewInMemoryCache()
	cfg := Configuration{Webserver: false}
	requestMatcher := matching.RequestMatcher{RequestCache: cache, Webserver: &cfg.Webserver}
	hv := Hoverfly{RequestCache: cache, Cfg: &cfg, RequestMatcher: requestMatcher}

	RegisterTestingT(t)

	requestTemplate := views.RequestDetailsView{
		RequestType: StringToPointer("template"),
		Method:      StringToPointer("GET"),
	}

	responseView := views.ResponseDetailsView{
		Status:      200,
		Body:        "hello_world",
		EncodedBody: false,
		Headers:     map[string][]string{"Hoverfly": []string{"testing"}},
	}

	templatePair := views.RequestResponsePairView{
		Response: responseView,
		Request:  requestTemplate,
	}

	hv.ImportRequestResponsePairViews([]views.RequestResponsePairView{templatePair})

	Expect(len(hv.RequestMatcher.TemplateStore)).To(Equal(1))

	request := models.NewRequestDetailsFromRequestDetailsView(requestTemplate)
	responseFromCache, err := hv.RequestMatcher.TemplateStore.GetResponse(request, false)
	Expect(err).To(BeNil())

	response := models.NewResponseDetailsFromResponseDetailsView(responseView)

	Expect(*responseFromCache).To(Equal(response))
}

func TestImportImportRequestResponsePairs_CanImportARequestResponsePair_AndRequestTemplateResponsePair(t *testing.T) {
	RegisterTestingT(t)

	cache := cache.NewInMemoryCache()
	cfg := Configuration{Webserver: false}
	requestMatcher := matching.RequestMatcher{RequestCache: cache, Webserver: &cfg.Webserver}
	hv := Hoverfly{RequestCache: cache, Cfg: &cfg, RequestMatcher: requestMatcher}

	RegisterTestingT(t)

	requestTemplate := views.RequestDetailsView{
		RequestType: StringToPointer("template"),
		Method:      StringToPointer("GET"),
	}

	requestView := views.RequestDetailsView{
		Method:      StringToPointer("GET"),
		Path:        StringToPointer("/"),
		Destination: StringToPointer("test.com"),
		Scheme:      StringToPointer("http"),
	}

	responseView := views.ResponseDetailsView{
		Status:      200,
		Body:        "hello_world",
		EncodedBody: false,
		Headers:     map[string][]string{"Hoverfly": []string{"testing"}},
	}

	templatePair := views.RequestResponsePairView{
		Request:  requestTemplate,
		Response: responseView,
	}

	ordinaryPair := views.RequestResponsePairView{
		Request:  requestView,
		Response: responseView,
	}

	hv.ImportRequestResponsePairViews([]views.RequestResponsePairView{templatePair, ordinaryPair})

	cacheCount, err := hv.RequestCache.RecordsCount()
	Expect(cacheCount).To(Equal(1))
	Expect(err).To(BeNil())

	Expect(len(hv.RequestMatcher.TemplateStore)).To(Equal(1))

	request := models.NewRequestDetailsFromRequestDetailsView(requestTemplate)
	response := models.NewResponseDetailsFromResponseDetailsView(responseView)

	pairBytes, err := hv.RequestCache.Get([]byte("76cf08e38439f083de2658b0971df9bf"))
	Expect(err).To(BeNil())

	savedPair, err := models.NewRequestResponsePairFromBytes(pairBytes)
	Expect(err).To(BeNil())

	Expect(savedPair.Response).To(Equal(response))

	responseFromCache, err := hv.RequestMatcher.TemplateStore.GetResponse(request, false)
	Expect(err).To(BeNil())
	Expect(*responseFromCache).To(Equal(response))

}

// Helper function for base64 encoding
func base64String(s string) string {
	return base64.StdEncoding.EncodeToString([]byte(s))
}

func TestImportImportRequestResponsePairs_CanImportASingleBase64EncodedPair(t *testing.T) {
	RegisterTestingT(t)

	cache := cache.NewInMemoryCache()
	cfg := Configuration{Webserver: false}
	requestMatcher := matching.RequestMatcher{RequestCache: cache, Webserver: &cfg.Webserver}
	hv := Hoverfly{RequestCache: cache, Cfg: &cfg, RequestMatcher: requestMatcher}

	RegisterTestingT(t)

	encodedPair := views.RequestResponsePairView{
		Response: views.ResponseDetailsView{
			Status:      200,
			Body:        base64String("hello_world"),
			EncodedBody: true,
			Headers:     map[string][]string{"Content-Encoding": []string{"gzip"}}},
		Request: views.RequestDetailsView{
			Path:        StringToPointer("/"),
			Method:      StringToPointer("GET"),
			Destination: StringToPointer("/"),
			Scheme:      StringToPointer("scheme"),
			Query:       StringToPointer(""),
			Body:        StringToPointer(""),
			Headers:     map[string][]string{"Hoverfly": []string{"testing"}}}}

	hv.ImportRequestResponsePairViews([]views.RequestResponsePairView{encodedPair})

	value, err := cache.Get([]byte("9b114df98da7f7e2afdc975883dab4f2"))
	Expect(err).To(BeNil())

	decodedPair, err := models.NewRequestResponsePairFromBytes(value)
	Expect(err).To(BeNil())

	Expect(decodedPair).ToNot(Equal(models.RequestResponsePair{
		Response: models.ResponseDetails{
			Status:  200,
			Body:    "hello_world",
			Headers: map[string][]string{"Content-Encoding": []string{"gzip"}}},
		Request: models.RequestDetails{
			Path:        "/",
			Method:      "GET",
			Destination: "/",
			Scheme:      "scheme",
			Query:       "", Body: "",
			Headers: map[string][]string{"Hoverfly": []string{"testing"}}}}))
}
<|endoftext|>


<commit_before>package colorable

import (
	"bytes"
	"io"
)

// NonColorable holds writer but removes escape sequence.
type NonColorable struct {
	out io.Writer
}

// NewNonColorable returns new instance of Writer which removes escape sequence from Writer.
func NewNonColorable(w io.Writer) io.Writer {
	return &NonColorable{out: w}
}

// Write writes data on console
func (w *NonColorable) Write(data []byte) (n int, err error) {
	er := bytes.NewReader(data)
	var bw [1]byte
loop:
	for {
		c1, err := er.ReadByte()
		if err != nil {
			break loop
		}
		if c1 != 0x1b {
			bw[0] = c1
			w.out.Write(bw[:])
			continue
		}
		c2, err := er.ReadByte()
		if err != nil {
			break loop
		}
		if c2 != 0x5b {
			continue
		}

		var buf bytes.Buffer
		for {
			c, err := er.ReadByte()
			if err != nil {
				break loop
			}
			if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
				break
			}
			buf.Write([]byte(string(c)))
		}
	}

	return len(data), nil
}
<commit_msg>Check result of Write<commit_after>package colorable

import (
	"bytes"
	"io"
)

// NonColorable holds writer but removes escape sequence.
type NonColorable struct {
	out io.Writer
}

// NewNonColorable returns new instance of Writer which removes escape sequence from Writer.
func NewNonColorable(w io.Writer) io.Writer {
	return &NonColorable{out: w}
}

// Write writes data on console
func (w *NonColorable) Write(data []byte) (n int, err error) {
	er := bytes.NewReader(data)
	var bw [1]byte
loop:
	for {
		c1, err := er.ReadByte()
		if err != nil {
			break loop
		}
		if c1 != 0x1b {
			bw[0] = c1
			_, err = w.out.Write(bw[:])
			if err != nil {
				break loop
			}
			continue
		}
		c2, err := er.ReadByte()
		if err != nil {
			break loop
		}
		if c2 != 0x5b {
			continue
		}

		var buf bytes.Buffer
		for {
			c, err := er.ReadByte()
			if err != nil {
				break loop
			}
			if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
				break
			}
			buf.Write([]byte(string(c)))
		}
	}

	return len(data), nil
}
<|endoftext|>


<commit_before>// 内部错误封装
// base on protobuff
package services

import (
	"encoding/binary"

	"github.com/gfandada/gserver/network"
	"github.com/golang/protobuf/proto"
)

// 构建一个gataway通用内部错误
// @params err:错误描述
func NewInError(err error) []byte {
	return newError(0, err.Error())
}

// 构建一个gataway通用业务错误
// @params id:错误码
func NewLogicError(id int) []byte {
	return newError(id, "")
}

// 构建一个service通用内部错误(错误码为1000)
// @params err:错误描述
func NewSInError(err error) *network.Data_Frame {
	data := newError(0, err.Error())
	return &network.Data_Frame{
		Type:    network.Data_Message,
		Message: data,
	}
}

// 构建一个service通用业务错误
// @params id:错误码
func NewSLogicError(id int) *network.Data_Frame {
	data := newError(id, "")
	return &network.Data_Frame{
		Type:    network.Data_Message,
		Message: data,
	}
}

func newError(id int, str string) []byte {
	rawId := make([]byte, 2)
	binary.BigEndian.PutUint16(rawId, 2)
	data, err := proto.Marshal(&ErrorAck{
		Errid:  proto.Int32(int32(id)),
		Errstr: proto.String(str),
	})
	if err != nil {
		return nil
	}
	c := make([]byte, 2+len(data))
	copy(c, rawId)
	copy(c[len(rawId):], data)
	return c
}

func newServiceError(id int, str string) []byte {
	rawId := make([]byte, 2)
	binary.BigEndian.PutUint16(rawId, 2)
	data, err := proto.Marshal(&ErrorAck{
		Errid:  proto.Int32(int32(id)),
		Errstr: proto.String(str),
	})
	if err != nil {
		return nil
	}
	c := make([]byte, 2+len(data))
	copy(c, rawId)
	copy(c[len(rawId):], data)
	return c
}
<commit_msg>fix inner error id<commit_after>// 内部错误封装
// base on protobuff
package services

import (
	"encoding/binary"

	"github.com/gfandada/gserver/network"
	"github.com/golang/protobuf/proto"
)

// 构建一个gataway通用内部错误(errid=0)
// @params err:错误描述
func NewInError(err error) []byte {
	return newError(0, err.Error())
}

// 构建一个gataway通用业务错误
// @params id:错误码
func NewLogicError(id int) []byte {
	return newError(id, "")
}

// 构建一个service通用内部错误(errid=1)
// @params err:错误描述
func NewSInError(err error) *network.Data_Frame {
	data := newError(1, err.Error())
	return &network.Data_Frame{
		Type:    network.Data_Message,
		Message: data,
	}
}

// 构建一个service通用业务错误
// @params id:错误码
func NewSLogicError(id int) *network.Data_Frame {
	data := newError(id, "")
	return &network.Data_Frame{
		Type:    network.Data_Message,
		Message: data,
	}
}

func newError(id int, str string) []byte {
	rawId := make([]byte, 2)
	binary.BigEndian.PutUint16(rawId, 2)
	data, err := proto.Marshal(&ErrorAck{
		Errid:  proto.Int32(int32(id)),
		Errstr: proto.String(str),
	})
	if err != nil {
		return nil
	}
	c := make([]byte, 2+len(data))
	copy(c, rawId)
	copy(c[len(rawId):], data)
	return c
}

func newServiceError(id int, str string) []byte {
	rawId := make([]byte, 2)
	binary.BigEndian.PutUint16(rawId, 2)
	data, err := proto.Marshal(&ErrorAck{
		Errid:  proto.Int32(int32(id)),
		Errstr: proto.String(str),
	})
	if err != nil {
		return nil
	}
	c := make([]byte, 2+len(data))
	copy(c, rawId)
	copy(c[len(rawId):], data)
	return c
}
<|endoftext|>