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

// +build go1.7

package http2

import (
	"bytes"
	"fmt"
	"reflect"
	"testing"
)

func fmtDataChunk(chunk []byte) string {
	out := ""
	var last byte
	var count int
	for _, c := range chunk {
		if c != last {
			if count > 0 {
				out += fmt.Sprintf(" x %d ", count)
				count = 0
			}
			out += string([]byte{c})
			last = c
		}
		count++
	}
	if count > 0 {
		out += fmt.Sprintf(" x %d", count)
	}
	return out
}

func fmtDataChunks(chunks [][]byte) string {
	var out string
	for _, chunk := range chunks {
		out += fmt.Sprintf("{%q}", fmtDataChunk(chunk))
	}
	return out
}

func testDataBuffer(t *testing.T, wantBytes []byte, setup func(t *testing.T) *dataBuffer) {
	// Run setup, then read the remaining bytes from the dataBuffer and check
	// that they match wantBytes. We use different read sizes to check corner
	// cases in Read.
	for _, readSize := range []int{1, 2, 1 * 1024, 32 * 1024} {
		t.Run(fmt.Sprintf("ReadSize=%d", readSize), func(t *testing.T) {
			b := setup(t)
			buf := make([]byte, readSize)
			var gotRead bytes.Buffer
			for {
				n, err := b.Read(buf)
				gotRead.Write(buf[:n])
				if err == errReadEmpty {
					break
				}
				if err != nil {
					t.Fatalf("error after %v bytes: %v", gotRead.Len(), err)
				}
			}
			if got, want := gotRead.Bytes(), wantBytes; !bytes.Equal(got, want) {
				t.Errorf("FinalRead=%q, want %q", fmtDataChunk(got), fmtDataChunk(want))
			}
		})
	}
}

func TestDataBufferAllocation(t *testing.T) {
	writes := [][]byte{
		bytes.Repeat([]byte("a"), 1*1024-1),
		[]byte{'a'},
		bytes.Repeat([]byte("b"), 4*1024-1),
		[]byte{'b'},
		bytes.Repeat([]byte("c"), 8*1024-1),
		[]byte{'c'},
		bytes.Repeat([]byte("d"), 16*1024-1),
		[]byte{'d'},
		bytes.Repeat([]byte("e"), 32*1024),
	}
	var wantRead bytes.Buffer
	for _, p := range writes {
		wantRead.Write(p)
	}

	testDataBuffer(t, wantRead.Bytes(), func(t *testing.T) *dataBuffer {
		b := &dataBuffer{}
		for _, p := range writes {
			if n, err := b.Write(p); n != len(p) || err != nil {
				t.Fatalf("Write(%q x %d)=%v,%v want %v,nil", p[:1], len(p), n, err, len(p))
			}
		}
		want := [][]byte{
			bytes.Repeat([]byte("a"), 1*1024),
			bytes.Repeat([]byte("b"), 4*1024),
			bytes.Repeat([]byte("c"), 8*1024),
			bytes.Repeat([]byte("d"), 16*1024),
			bytes.Repeat([]byte("e"), 16*1024),
			bytes.Repeat([]byte("e"), 16*1024),
		}
		if !reflect.DeepEqual(b.chunks, want) {
			t.Errorf("dataBuffer.chunks\ngot:  %s\nwant: %s", fmtDataChunks(b.chunks), fmtDataChunks(want))
		}
		return b
	})
}

func TestDataBufferAllocationWithExpected(t *testing.T) {
	writes := [][]byte{
		bytes.Repeat([]byte("a"), 1*1024), // allocates 16KB
		bytes.Repeat([]byte("b"), 14*1024),
		bytes.Repeat([]byte("c"), 15*1024), // allocates 16KB more
		bytes.Repeat([]byte("d"), 2*1024),
		bytes.Repeat([]byte("e"), 1*1024), // overflows 32KB expectation, allocates just 1KB
	}
	var wantRead bytes.Buffer
	for _, p := range writes {
		wantRead.Write(p)
	}

	testDataBuffer(t, wantRead.Bytes(), func(t *testing.T) *dataBuffer {
		b := &dataBuffer{expected: 32 * 1024}
		for _, p := range writes {
			if n, err := b.Write(p); n != len(p) || err != nil {
				t.Fatalf("Write(%q x %d)=%v,%v want %v,nil", p[:1], len(p), n, err, len(p))
			}
		}
		want := [][]byte{
			append(bytes.Repeat([]byte("a"), 1*1024), append(bytes.Repeat([]byte("b"), 14*1024), bytes.Repeat([]byte("c"), 1*1024)...)...),
			append(bytes.Repeat([]byte("c"), 14*1024), bytes.Repeat([]byte("d"), 2*1024)...),
			bytes.Repeat([]byte("e"), 1*1024),
		}
		if !reflect.DeepEqual(b.chunks, want) {
			t.Errorf("dataBuffer.chunks\ngot:  %s\nwant: %s", fmtDataChunks(b.chunks), fmtDataChunks(want))
		}
		return b
	})
}

func TestDataBufferWriteAfterPartialRead(t *testing.T) {
	testDataBuffer(t, []byte("cdxyz"), func(t *testing.T) *dataBuffer {
		b := &dataBuffer{}
		if n, err := b.Write([]byte("abcd")); n != 4 || err != nil {
			t.Fatalf("Write(\"abcd\")=%v,%v want 4,nil", n, err)
		}
		p := make([]byte, 2)
		if n, err := b.Read(p); n != 2 || err != nil || !bytes.Equal(p, []byte("ab")) {
			t.Fatalf("Read()=%q,%v,%v want \"ab\",2,nil", p, n, err)
		}
		if n, err := b.Write([]byte("xyz")); n != 3 || err != nil {
			t.Fatalf("Write(\"xyz\")=%v,%v want 3,nil", n, err)
		}
		return b
	})
}
<commit_msg>http2: fix style inconsistency in test<commit_after>// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build go1.7

package http2

import (
	"bytes"
	"fmt"
	"reflect"
	"testing"
)

func fmtDataChunk(chunk []byte) string {
	out := ""
	var last byte
	var count int
	for _, c := range chunk {
		if c != last {
			if count > 0 {
				out += fmt.Sprintf(" x %d ", count)
				count = 0
			}
			out += string([]byte{c})
			last = c
		}
		count++
	}
	if count > 0 {
		out += fmt.Sprintf(" x %d", count)
	}
	return out
}

func fmtDataChunks(chunks [][]byte) string {
	var out string
	for _, chunk := range chunks {
		out += fmt.Sprintf("{%q}", fmtDataChunk(chunk))
	}
	return out
}

func testDataBuffer(t *testing.T, wantBytes []byte, setup func(t *testing.T) *dataBuffer) {
	// Run setup, then read the remaining bytes from the dataBuffer and check
	// that they match wantBytes. We use different read sizes to check corner
	// cases in Read.
	for _, readSize := range []int{1, 2, 1 * 1024, 32 * 1024} {
		t.Run(fmt.Sprintf("ReadSize=%d", readSize), func(t *testing.T) {
			b := setup(t)
			buf := make([]byte, readSize)
			var gotRead bytes.Buffer
			for {
				n, err := b.Read(buf)
				gotRead.Write(buf[:n])
				if err == errReadEmpty {
					break
				}
				if err != nil {
					t.Fatalf("error after %v bytes: %v", gotRead.Len(), err)
				}
			}
			if got, want := gotRead.Bytes(), wantBytes; !bytes.Equal(got, want) {
				t.Errorf("FinalRead=%q, want %q", fmtDataChunk(got), fmtDataChunk(want))
			}
		})
	}
}

func TestDataBufferAllocation(t *testing.T) {
	writes := [][]byte{
		bytes.Repeat([]byte("a"), 1*1024-1),
		[]byte("a"),
		bytes.Repeat([]byte("b"), 4*1024-1),
		[]byte("b"),
		bytes.Repeat([]byte("c"), 8*1024-1),
		[]byte("c"),
		bytes.Repeat([]byte("d"), 16*1024-1),
		[]byte("d"),
		bytes.Repeat([]byte("e"), 32*1024),
	}
	var wantRead bytes.Buffer
	for _, p := range writes {
		wantRead.Write(p)
	}

	testDataBuffer(t, wantRead.Bytes(), func(t *testing.T) *dataBuffer {
		b := &dataBuffer{}
		for _, p := range writes {
			if n, err := b.Write(p); n != len(p) || err != nil {
				t.Fatalf("Write(%q x %d)=%v,%v want %v,nil", p[:1], len(p), n, err, len(p))
			}
		}
		want := [][]byte{
			bytes.Repeat([]byte("a"), 1*1024),
			bytes.Repeat([]byte("b"), 4*1024),
			bytes.Repeat([]byte("c"), 8*1024),
			bytes.Repeat([]byte("d"), 16*1024),
			bytes.Repeat([]byte("e"), 16*1024),
			bytes.Repeat([]byte("e"), 16*1024),
		}
		if !reflect.DeepEqual(b.chunks, want) {
			t.Errorf("dataBuffer.chunks\ngot:  %s\nwant: %s", fmtDataChunks(b.chunks), fmtDataChunks(want))
		}
		return b
	})
}

func TestDataBufferAllocationWithExpected(t *testing.T) {
	writes := [][]byte{
		bytes.Repeat([]byte("a"), 1*1024), // allocates 16KB
		bytes.Repeat([]byte("b"), 14*1024),
		bytes.Repeat([]byte("c"), 15*1024), // allocates 16KB more
		bytes.Repeat([]byte("d"), 2*1024),
		bytes.Repeat([]byte("e"), 1*1024), // overflows 32KB expectation, allocates just 1KB
	}
	var wantRead bytes.Buffer
	for _, p := range writes {
		wantRead.Write(p)
	}

	testDataBuffer(t, wantRead.Bytes(), func(t *testing.T) *dataBuffer {
		b := &dataBuffer{expected: 32 * 1024}
		for _, p := range writes {
			if n, err := b.Write(p); n != len(p) || err != nil {
				t.Fatalf("Write(%q x %d)=%v,%v want %v,nil", p[:1], len(p), n, err, len(p))
			}
		}
		want := [][]byte{
			append(bytes.Repeat([]byte("a"), 1*1024), append(bytes.Repeat([]byte("b"), 14*1024), bytes.Repeat([]byte("c"), 1*1024)...)...),
			append(bytes.Repeat([]byte("c"), 14*1024), bytes.Repeat([]byte("d"), 2*1024)...),
			bytes.Repeat([]byte("e"), 1*1024),
		}
		if !reflect.DeepEqual(b.chunks, want) {
			t.Errorf("dataBuffer.chunks\ngot:  %s\nwant: %s", fmtDataChunks(b.chunks), fmtDataChunks(want))
		}
		return b
	})
}

func TestDataBufferWriteAfterPartialRead(t *testing.T) {
	testDataBuffer(t, []byte("cdxyz"), func(t *testing.T) *dataBuffer {
		b := &dataBuffer{}
		if n, err := b.Write([]byte("abcd")); n != 4 || err != nil {
			t.Fatalf("Write(\"abcd\")=%v,%v want 4,nil", n, err)
		}
		p := make([]byte, 2)
		if n, err := b.Read(p); n != 2 || err != nil || !bytes.Equal(p, []byte("ab")) {
			t.Fatalf("Read()=%q,%v,%v want \"ab\",2,nil", p, n, err)
		}
		if n, err := b.Write([]byte("xyz")); n != 3 || err != nil {
			t.Fatalf("Write(\"xyz\")=%v,%v want 3,nil", n, err)
		}
		return b
	})
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Kelsey Hightower. All rights reserved.
// Use of this source code is governed by the MIT License that can be found in
// the LICENSE file.

package envconfig

import (
	"errors"
	"fmt"
	"os"
	"reflect"
	"strconv"
	"strings"
)

// ErrInvalidSpecification indicates that a specification is of the wrong type.
var ErrInvalidSpecification = errors.New("invalid specification must be a struct")

// A ParseError occurs when an environment variable cannot be converted to
// the type required by a struct field during assignment.
type ParseError struct {
	KeyName   string
	FieldName string
	TypeName  string
	Value     string
}

func (e *ParseError) Error() string {
	return fmt.Sprintf("envconfig.Process: assigning %[1]s to %[2]s: converting '%[3]s' to type %[4]s", e.KeyName, e.FieldName, e.Value, e.TypeName)
}

func Process(prefix string, spec interface{}) error {
	s := reflect.ValueOf(spec).Elem()
	if s.Kind() != reflect.Struct {
		return ErrInvalidSpecification
	}
	typeOfSpec := s.Type()
	for i := 0; i < s.NumField(); i++ {
		f := s.Field(i)
		if f.CanSet() {
			var fieldName string
			alt := typeOfSpec.Field(i).Tag.Get("envconfig")
			if alt != "" {
				fieldName = alt
			} else {
				fieldName = typeOfSpec.Field(i).Name
			}
			key := strings.ToUpper(fmt.Sprintf("%s_%s", prefix, fieldName))
			value := os.Getenv(key)
			if value == "" {
				key := strings.ToUpper(fieldName)
				value = os.Getenv(key)
				if value == "" {
					continue
				}
			}
			switch f.Kind() {
			case reflect.String:
				f.SetString(value)
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				intValue, err := strconv.ParseInt(value, 0, f.Type().Bits())
				if err != nil {
					return &ParseError{
						KeyName:   key,
						FieldName: fieldName,
						TypeName:  f.Type().String(),
						Value:     value,
					}
				}
				f.SetInt(intValue)
			case reflect.Bool:
				boolValue, err := strconv.ParseBool(value)
				if err != nil {
					return &ParseError{
						KeyName:   key,
						FieldName: fieldName,
						TypeName:  f.Type().String(),
						Value:     value,
					}
				}
				f.SetBool(boolValue)
			case reflect.Float32:
				floatValue, err := strconv.ParseFloat(value, f.Type().Bits())
				if err != nil {
					return &ParseError{
						KeyName:   key,
						FieldName: fieldName,
						TypeName:  f.Type().String(),
						Value:     value,
					}
				}
				f.SetFloat(floatValue)
			}
		}
	}
	return nil
}
<commit_msg>Don't ignore the prefix if a tag hasn't been set<commit_after>// Copyright (c) 2013 Kelsey Hightower. All rights reserved.
// Use of this source code is governed by the MIT License that can be found in
// the LICENSE file.

package envconfig

import (
	"errors"
	"fmt"
	"os"
	"reflect"
	"strconv"
	"strings"
)

// ErrInvalidSpecification indicates that a specification is of the wrong type.
var ErrInvalidSpecification = errors.New("invalid specification must be a struct")

// A ParseError occurs when an environment variable cannot be converted to
// the type required by a struct field during assignment.
type ParseError struct {
	KeyName   string
	FieldName string
	TypeName  string
	Value     string
}

func (e *ParseError) Error() string {
	return fmt.Sprintf("envconfig.Process: assigning %[1]s to %[2]s: converting '%[3]s' to type %[4]s", e.KeyName, e.FieldName, e.Value, e.TypeName)
}

func Process(prefix string, spec interface{}) error {
	s := reflect.ValueOf(spec).Elem()
	if s.Kind() != reflect.Struct {
		return ErrInvalidSpecification
	}
	typeOfSpec := s.Type()
	for i := 0; i < s.NumField(); i++ {
		f := s.Field(i)
		if f.CanSet() {
			var fieldName string
			var hasTag bool
			alt := typeOfSpec.Field(i).Tag.Get("envconfig")
			if alt != "" {
				fieldName = alt
				hasTag = true
			} else {
				fieldName = typeOfSpec.Field(i).Name
			}
			key := strings.ToUpper(fmt.Sprintf("%s_%s", prefix, fieldName))
			value := os.Getenv(key)
			if value == "" && hasTag {
				key := strings.ToUpper(fieldName)
				value = os.Getenv(key)
			}
			if value == "" {
				continue
			}

			switch f.Kind() {
			case reflect.String:
				f.SetString(value)
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				intValue, err := strconv.ParseInt(value, 0, f.Type().Bits())
				if err != nil {
					return &ParseError{
						KeyName:   key,
						FieldName: fieldName,
						TypeName:  f.Type().String(),
						Value:     value,
					}
				}
				f.SetInt(intValue)
			case reflect.Bool:
				boolValue, err := strconv.ParseBool(value)
				if err != nil {
					return &ParseError{
						KeyName:   key,
						FieldName: fieldName,
						TypeName:  f.Type().String(),
						Value:     value,
					}
				}
				f.SetBool(boolValue)
			case reflect.Float32:
				floatValue, err := strconv.ParseFloat(value, f.Type().Bits())
				if err != nil {
					return &ParseError{
						KeyName:   key,
						FieldName: fieldName,
						TypeName:  f.Type().String(),
						Value:     value,
					}
				}
				f.SetFloat(floatValue)
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package approvals

import (
	"context"
	"errors"
	"time"

	"github.com/rusenask/keel/cache"
	"github.com/rusenask/keel/types"
	"github.com/rusenask/keel/util/codecs"

	log "github.com/Sirupsen/logrus"
)

// Manager is used to manage updates
type Manager interface {
	// request approval for deployment/release/etc..
	Create(r *types.Approval) error
	Update(r *types.Approval) error
	Get(provider types.ProviderType, identifier string) (*types.Approval, error)
	List(provider types.ProviderType) ([]*types.Approval, error)
	Delete(provider types.ProviderType, identifier string) error
}

var (
	ErrApprovalAlreadyExists = errors.New("approval already exists")
)

const (
	ApprovalsPrefix = "approvals"
)

// DefaultManager - default manager implementation
type DefaultManager struct {
	// cache is used to store approvals, key example:
	// approvals/<provider name>/<identifier>
	cache      cache.Cache
	serializer codecs.Serializer
}

// New create new instance of default manager
func New(cache cache.Cache, serializer codecs.Serializer) *DefaultManager {
	return &DefaultManager{
		cache:      cache,
		serializer: serializer,
	}
}

func (m *DefaultManager) Create(r *types.Approval) error {
	_, err := m.Get(r.Provider, r.Identifier)
	if err == nil {
		return ErrApprovalAlreadyExists
	}

	bts, err := m.serializer.Encode(r)
	if err != nil {
		return err
	}

	ctx := cache.SetContextExpiration(context.Background(), r.Deadline)

	return m.cache.Put(ctx, getKey(r.Provider, r.Identifier), bts)
}

func (m *DefaultManager) Update(r *types.Approval) error {
	existing, err := m.Get(r.Provider, r.Identifier)
	if err != nil {
		return err
	}

	r.CreatedAt = existing.CreatedAt
	r.UpdatedAt = time.Now()

	bts, err := m.serializer.Encode(r)
	if err != nil {
		return err
	}

	ctx := cache.SetContextExpiration(context.Background(), r.Deadline)

	return m.cache.Put(ctx, getKey(r.Provider, r.Identifier), bts)
}

func (m *DefaultManager) Get(provider types.ProviderType, identifier string) (*types.Approval, error) {
	bts, err := m.cache.Get(context.Background(), getKey(provider, identifier))
	if err != nil {
		return nil, err
	}

	var approval types.Approval
	err = m.serializer.Decode(bts, &approval)
	return &approval, err
}

func (m *DefaultManager) List(provider types.ProviderType) ([]*types.Approval, error) {
	prefix := ""
	if provider != types.ProviderTypeUnknown {
		prefix = provider.String()
	}
	bts, err := m.cache.List(prefix)
	if err != nil {
		return nil, err
	}

	var approvals []*types.Approval
	for _, v := range bts {
		var approval types.Approval
		err = m.serializer.Decode(v, &approval)
		if err != nil {
			log.WithFields(log.Fields{
				"error": err,
			}).Error("approvals.manager: failed to decode payload")
			continue
		}
		approvals = append(approvals, &approval)
	}
	return approvals, nil

}
func (m *DefaultManager) Delete(provider types.ProviderType, identifier string) error {
	return m.cache.Delete(context.Background(), getKey(provider, identifier))
}

func getKey(provider types.ProviderType, identifier string) string {
	return ApprovalsPrefix + "/" + provider.String() + "/" + identifier
}
<commit_msg>specialised reject/approve methods<commit_after>package approvals

import (
	"context"
	"errors"
	"sync"
	"time"

	"github.com/rusenask/keel/cache"
	"github.com/rusenask/keel/provider"
	"github.com/rusenask/keel/types"
	"github.com/rusenask/keel/util/codecs"

	log "github.com/Sirupsen/logrus"
)

// Manager is used to manage updates
type Manager interface {
	// request approval for deployment/release/etc..
	Create(r *types.Approval) error
	// Update whole approval object
	Update(r *types.Approval) error

	// Increases Approval votes by 1
	Approve(provider types.ProviderType, identifier string) (*types.Approval, error)
	// Rejects Approval
	Reject(provider types.ProviderType, identifier string) (*types.Approval, error)

	Get(provider types.ProviderType, identifier string) (*types.Approval, error)
	List(provider types.ProviderType) ([]*types.Approval, error)
	Delete(provider types.ProviderType, identifier string) error
}

// Approvals related errors
var (
	ErrApprovalAlreadyExists = errors.New("approval already exists")
)

// Approvals cache prefix
const (
	ApprovalsPrefix = "approvals"
)

// DefaultManager - default manager implementation
type DefaultManager struct {
	// cache is used to store approvals, key example:
	// approvals/<provider name>/<identifier>
	cache      cache.Cache
	serializer codecs.Serializer

	// providers are used to re-submit event
	// when all approvals are collected
	providers provider.Providers

	mu *sync.Mutex
}

// New create new instance of default manager
func New(cache cache.Cache, serializer codecs.Serializer, providers provider.Providers) *DefaultManager {
	return &DefaultManager{
		cache:      cache,
		serializer: serializer,
		providers:  providers,
		mu:         &sync.Mutex{},
	}
}

func (m *DefaultManager) Create(r *types.Approval) error {
	_, err := m.Get(r.Provider, r.Identifier)
	if err == nil {
		return ErrApprovalAlreadyExists
	}

	bts, err := m.serializer.Encode(r)
	if err != nil {
		return err
	}

	ctx := cache.SetContextExpiration(context.Background(), r.Deadline)

	return m.cache.Put(ctx, getKey(r.Provider, r.Identifier), bts)
}

func (m *DefaultManager) Update(r *types.Approval) error {
	existing, err := m.Get(r.Provider, r.Identifier)
	if err != nil {
		return err
	}

	r.CreatedAt = existing.CreatedAt
	r.UpdatedAt = time.Now()

	bts, err := m.serializer.Encode(r)
	if err != nil {
		return err
	}

	if r.Approved() {
		err = m.providers.Submit(*r.Event)
		if err != nil {
			log.WithFields(log.Fields{
				"error":    err,
				"approval": r.Identifier,
				"provider": r.Provider,
			}).Error("approvals.manager: failed to re-submit event after approvals were collected")
		}
	}

	ctx := cache.SetContextExpiration(context.Background(), r.Deadline)
	return m.cache.Put(ctx, getKey(r.Provider, r.Identifier), bts)
}

// Approve - increase VotesReceived by 1 and returns updated version
func (m *DefaultManager) Approve(provider types.ProviderType, identifier string) (*types.Approval, error) {
	m.mu.Lock()
	defer m.mu.Unlock()

	existing, err := m.Get(provider, identifier)
	if err != nil {
		return nil, err
	}

	existing.VotesReceived++

	err = m.Update(existing)
	if err != nil {
		return nil, err
	}

	return existing, nil
}

// Reject - rejects approval (marks rejected=true), approval will not be valid even if it
// collects required votes
func (m *DefaultManager) Reject(provider types.ProviderType, identifier string) (*types.Approval, error) {
	m.mu.Lock()
	defer m.mu.Unlock()

	existing, err := m.Get(provider, identifier)
	if err != nil {
		return nil, err
	}

	existing.Rejected = true

	err = m.Update(existing)
	if err != nil {
		return nil, err
	}

	return existing, nil
}

func (m *DefaultManager) Get(provider types.ProviderType, identifier string) (*types.Approval, error) {
	bts, err := m.cache.Get(context.Background(), getKey(provider, identifier))
	if err != nil {
		return nil, err
	}

	var approval types.Approval
	err = m.serializer.Decode(bts, &approval)
	return &approval, err
}

func (m *DefaultManager) List(provider types.ProviderType) ([]*types.Approval, error) {
	prefix := ""
	if provider != types.ProviderTypeUnknown {
		prefix = provider.String()
	}
	bts, err := m.cache.List(prefix)
	if err != nil {
		return nil, err
	}

	var approvals []*types.Approval
	for _, v := range bts {
		var approval types.Approval
		err = m.serializer.Decode(v, &approval)
		if err != nil {
			log.WithFields(log.Fields{
				"error": err,
			}).Error("approvals.manager: failed to decode payload")
			continue
		}
		approvals = append(approvals, &approval)
	}
	return approvals, nil

}
func (m *DefaultManager) Delete(provider types.ProviderType, identifier string) error {
	return m.cache.Delete(context.Background(), getKey(provider, identifier))
}

func getKey(provider types.ProviderType, identifier string) string {
	return ApprovalsPrefix + "/" + provider.String() + "/" + identifier
}
<|endoftext|>


<commit_before>package project

import (
	"fmt"
	"strings"
)

// Default is the string used for a default project.
const Default = "default"

// separator is used to delimit the project name from the suffix.
const separator = "_"

// Instance adds the "<project>_" prefix to instance name when the given project name is not "default".
func Instance(projectName string, instanceName string) string {
	if projectName != Default {
		return fmt.Sprintf("%s%s%s", projectName, separator, instanceName)
	}

	return instanceName
}

// InstanceParts takes a project prefixed Instance name string and returns the project and instance name.
// If a non-project prefixed Instance name is supplied, then the project is returned as "default" and the instance
// name is returned unmodified in the 2nd return value. This is suitable for passing back into Prefix().
// Note: This should only be used with Instance names (because they cannot contain the project separator) and this
// function relies on this rule as project names can contain the project separator.
func InstanceParts(projectInstanceName string) (string, string) {
	i := strings.LastIndex(projectInstanceName, separator)
	if i < 0 {
		// This string is not project prefixed or is part of default project.
		return Default, projectInstanceName
	}

	// As project names can container separator, we effectively split once from the right hand side as
	// Instance names are not allowed to container the separator value.
	return projectInstanceName[0:i], projectInstanceName[i+1:]
}

// StorageVolume adds the "<project>_prefix" to the storage volume name. Even if the project name is "default".
func StorageVolume(projectName string, storageVolumeName string) string {
	return fmt.Sprintf("%s%s%s", projectName, separator, storageVolumeName)
}

// StorageVolumeParts takes a project prefixed storage volume name and returns the project and storage volume
// name as separate variables.
func StorageVolumeParts(projectStorageVolumeName string) (string, string) {
	parts := strings.SplitN(projectStorageVolumeName, "_", 2)
	return parts[0], parts[1]
}
<commit_msg>lxd/project/project: Adds StorageVolumeProject function<commit_after>package project

import (
	"fmt"
	"strings"

	"github.com/pkg/errors"

	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
)

// Default is the string used for a default project.
const Default = "default"

// separator is used to delimit the project name from the suffix.
const separator = "_"

// Instance adds the "<project>_" prefix to instance name when the given project name is not "default".
func Instance(projectName string, instanceName string) string {
	if projectName != Default {
		return fmt.Sprintf("%s%s%s", projectName, separator, instanceName)
	}

	return instanceName
}

// InstanceParts takes a project prefixed Instance name string and returns the project and instance name.
// If a non-project prefixed Instance name is supplied, then the project is returned as "default" and the instance
// name is returned unmodified in the 2nd return value. This is suitable for passing back into Prefix().
// Note: This should only be used with Instance names (because they cannot contain the project separator) and this
// function relies on this rule as project names can contain the project separator.
func InstanceParts(projectInstanceName string) (string, string) {
	i := strings.LastIndex(projectInstanceName, separator)
	if i < 0 {
		// This string is not project prefixed or is part of default project.
		return Default, projectInstanceName
	}

	// As project names can container separator, we effectively split once from the right hand side as
	// Instance names are not allowed to container the separator value.
	return projectInstanceName[0:i], projectInstanceName[i+1:]
}

// StorageVolume adds the "<project>_prefix" to the storage volume name. Even if the project name is "default".
func StorageVolume(projectName string, storageVolumeName string) string {
	return fmt.Sprintf("%s%s%s", projectName, separator, storageVolumeName)
}

// StorageVolumeParts takes a project prefixed storage volume name and returns the project and storage volume
// name as separate variables.
func StorageVolumeParts(projectStorageVolumeName string) (string, string) {
	parts := strings.SplitN(projectStorageVolumeName, "_", 2)
	return parts[0], parts[1]
}

// StorageVolumeProject returns the project name to use to for the volume based on the requested project.
// For custom volume type, if the project specified has the "features.storage.volumes" flag enabled then the
// project name is returned, otherwise the default project name is returned. For all other volume types the
// supplied project name is returned.
func StorageVolumeProject(c *db.Cluster, projectName string, volumeType int) (string, error) {
	// Non-custom volumes always use the project specified.
	if volumeType != db.StoragePoolVolumeTypeCustom {
		return projectName, nil
	}

	var project *api.Project
	var err error

	err = c.Transaction(func(tx *db.ClusterTx) error {
		project, err = tx.ProjectGet(projectName)
		if err != nil {
			return err
		}

		return nil
	})

	if err != nil {
		return "", errors.Wrapf(err, "Failed to load project %q", projectName)
	}

	// Custom volumes only use the project specified if the project has the features.storage.volumes feature
	// enabled, otherwise the legacy behaviour of using the default project for custom volumes is used.
	if shared.IsTrue(project.Config["features.storage.volumes"]) {
		return projectName, nil
	}

	return Default, nil
}
<|endoftext|>


<commit_before>package storage

import (
	"context"
	"os"

	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/instance/instancetype"
	"github.com/lxc/lxd/lxd/project"
	"github.com/lxc/lxd/lxd/state"
	"github.com/lxc/lxd/shared"
)

// InstancePath returns the directory of an instance or snapshot.
func InstancePath(instanceType instancetype.Type, projectName, instanceName string, isSnapshot bool) string {
	fullName := project.Instance(projectName, instanceName)
	if instanceType == instancetype.VM {
		if isSnapshot {
			return shared.VarPath("virtual-machines-snapshots", fullName)
		}

		return shared.VarPath("virtual-machines", fullName)
	}

	if isSnapshot {
		return shared.VarPath("snapshots", fullName)
	}

	return shared.VarPath("containers", fullName)
}

// InstanceImportingFilePath returns the file path used to indicate an instance import is in progress.
// This marker file is created when using `lxd import` to import an instance that exists on the storage device
// but does not exist in the LXD database. The presence of this file causes the instance not to be removed from
// the storage device if the import should fail for some reason.
func InstanceImportingFilePath(instanceType instancetype.Type, poolName, projectName, instanceName string) string {
	fullName := project.Instance(projectName, instanceName)

	typeDir := "containers"
	if instanceType == instancetype.VM {
		typeDir = "virtual-machines"
	}

	return shared.VarPath("storage-pools", poolName, typeDir, fullName, ".importing")
}

// GetStoragePoolMountPoint returns the mountpoint of the given pool.
// {LXD_DIR}/storage-pools/<pool>
// Deprecated, use GetPoolMountPath in storage/drivers package.
func GetStoragePoolMountPoint(poolName string) string {
	return shared.VarPath("storage-pools", poolName)
}

// GetSnapshotMountPoint returns the mountpoint of the given container snapshot.
// ${LXD_DIR}/storage-pools/<pool>/containers-snapshots/<snapshot_name>.
func GetSnapshotMountPoint(projectName, poolName string, snapshotName string) string {
	return shared.VarPath("storage-pools", poolName, "containers-snapshots", project.Instance(projectName, snapshotName))
}

// GetImageMountPoint returns the mountpoint of the given image.
// ${LXD_DIR}/storage-pools/<pool>/images/<fingerprint>.
func GetImageMountPoint(poolName string, fingerprint string) string {
	return shared.VarPath("storage-pools", poolName, "images", fingerprint)
}

// GetStoragePoolVolumeSnapshotMountPoint returns the mountpoint of the given pool volume snapshot.
// ${LXD_DIR}/storage-pools/<pool>/custom-snapshots/<custom volume name>/<snapshot name>.
func GetStoragePoolVolumeSnapshotMountPoint(poolName string, snapshotName string) string {
	return shared.VarPath("storage-pools", poolName, "custom-snapshots", snapshotName)
}

// CreateContainerMountpoint creates the provided container mountpoint and symlink.
func CreateContainerMountpoint(mountPoint string, mountPointSymlink string, privileged bool) error {
	mntPointSymlinkExist := shared.PathExists(mountPointSymlink)
	mntPointSymlinkTargetExist := shared.PathExists(mountPoint)

	var err error
	if !mntPointSymlinkTargetExist {
		err = os.MkdirAll(mountPoint, 0711)
		if err != nil {
			return err
		}
	}

	err = os.Chmod(mountPoint, 0100)
	if err != nil {
		return err
	}

	if !mntPointSymlinkExist {
		err := os.Symlink(mountPoint, mountPointSymlink)
		if err != nil {
			return err
		}
	}

	return nil
}

// CreateSnapshotMountpoint creates the provided container snapshot mountpoint
// and symlink.
func CreateSnapshotMountpoint(snapshotMountpoint string, snapshotsSymlinkTarget string, snapshotsSymlink string) error {
	snapshotMntPointExists := shared.PathExists(snapshotMountpoint)
	mntPointSymlinkExist := shared.PathExists(snapshotsSymlink)

	if !snapshotMntPointExists {
		err := os.MkdirAll(snapshotMountpoint, 0711)
		if err != nil {
			return err
		}
	}

	if !mntPointSymlinkExist {
		err := os.Symlink(snapshotsSymlinkTarget, snapshotsSymlink)
		if err != nil {
			return err
		}
	}

	return nil
}

// UsedBy returns list of API resources using storage pool. Accepts firstOnly argument to indicate that only the
// first resource using network should be returned. This can help to quickly check if the storage pool is in use.
func UsedBy(ctx context.Context, s *state.State, poolName string, firstOnly bool, allNodes bool) ([]string, error) {
	var err error
	var usedBy []string

	err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error {
		usedBy, err = tx.GetStoragePoolUsedBy(poolName, allNodes)

		return err
	})
	if err != nil {
		return nil, err
	}

	return usedBy, nil
}
<commit_msg>lxd/storage/storage: Reworks UsedBy to use tx.GetStoragePoolVolumes<commit_after>package storage

import (
	"context"
	"fmt"
	"os"
	"sort"

	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/db/cluster"
	"github.com/lxc/lxd/lxd/instance/instancetype"
	"github.com/lxc/lxd/lxd/project"
	"github.com/lxc/lxd/lxd/state"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/version"
)

// InstancePath returns the directory of an instance or snapshot.
func InstancePath(instanceType instancetype.Type, projectName, instanceName string, isSnapshot bool) string {
	fullName := project.Instance(projectName, instanceName)
	if instanceType == instancetype.VM {
		if isSnapshot {
			return shared.VarPath("virtual-machines-snapshots", fullName)
		}

		return shared.VarPath("virtual-machines", fullName)
	}

	if isSnapshot {
		return shared.VarPath("snapshots", fullName)
	}

	return shared.VarPath("containers", fullName)
}

// InstanceImportingFilePath returns the file path used to indicate an instance import is in progress.
// This marker file is created when using `lxd import` to import an instance that exists on the storage device
// but does not exist in the LXD database. The presence of this file causes the instance not to be removed from
// the storage device if the import should fail for some reason.
func InstanceImportingFilePath(instanceType instancetype.Type, poolName, projectName, instanceName string) string {
	fullName := project.Instance(projectName, instanceName)

	typeDir := "containers"
	if instanceType == instancetype.VM {
		typeDir = "virtual-machines"
	}

	return shared.VarPath("storage-pools", poolName, typeDir, fullName, ".importing")
}

// GetStoragePoolMountPoint returns the mountpoint of the given pool.
// {LXD_DIR}/storage-pools/<pool>
// Deprecated, use GetPoolMountPath in storage/drivers package.
func GetStoragePoolMountPoint(poolName string) string {
	return shared.VarPath("storage-pools", poolName)
}

// GetSnapshotMountPoint returns the mountpoint of the given container snapshot.
// ${LXD_DIR}/storage-pools/<pool>/containers-snapshots/<snapshot_name>.
func GetSnapshotMountPoint(projectName, poolName string, snapshotName string) string {
	return shared.VarPath("storage-pools", poolName, "containers-snapshots", project.Instance(projectName, snapshotName))
}

// GetImageMountPoint returns the mountpoint of the given image.
// ${LXD_DIR}/storage-pools/<pool>/images/<fingerprint>.
func GetImageMountPoint(poolName string, fingerprint string) string {
	return shared.VarPath("storage-pools", poolName, "images", fingerprint)
}

// GetStoragePoolVolumeSnapshotMountPoint returns the mountpoint of the given pool volume snapshot.
// ${LXD_DIR}/storage-pools/<pool>/custom-snapshots/<custom volume name>/<snapshot name>.
func GetStoragePoolVolumeSnapshotMountPoint(poolName string, snapshotName string) string {
	return shared.VarPath("storage-pools", poolName, "custom-snapshots", snapshotName)
}

// CreateContainerMountpoint creates the provided container mountpoint and symlink.
func CreateContainerMountpoint(mountPoint string, mountPointSymlink string, privileged bool) error {
	mntPointSymlinkExist := shared.PathExists(mountPointSymlink)
	mntPointSymlinkTargetExist := shared.PathExists(mountPoint)

	var err error
	if !mntPointSymlinkTargetExist {
		err = os.MkdirAll(mountPoint, 0711)
		if err != nil {
			return err
		}
	}

	err = os.Chmod(mountPoint, 0100)
	if err != nil {
		return err
	}

	if !mntPointSymlinkExist {
		err := os.Symlink(mountPoint, mountPointSymlink)
		if err != nil {
			return err
		}
	}

	return nil
}

// CreateSnapshotMountpoint creates the provided container snapshot mountpoint
// and symlink.
func CreateSnapshotMountpoint(snapshotMountpoint string, snapshotsSymlinkTarget string, snapshotsSymlink string) error {
	snapshotMntPointExists := shared.PathExists(snapshotMountpoint)
	mntPointSymlinkExist := shared.PathExists(snapshotsSymlink)

	if !snapshotMntPointExists {
		err := os.MkdirAll(snapshotMountpoint, 0711)
		if err != nil {
			return err
		}
	}

	if !mntPointSymlinkExist {
		err := os.Symlink(snapshotsSymlinkTarget, snapshotsSymlink)
		if err != nil {
			return err
		}
	}

	return nil
}

// UsedBy returns list of API resources using storage pool. Accepts firstOnly argument to indicate that only the
// first resource using network should be returned. This can help to quickly check if the storage pool is in use.
// If memberSpecific is true, then the search is restricted to volumes that belong to this member or belong to
// all members. The ignoreVolumeType argument can be used to exclude certain volume type(s) from the list.
func UsedBy(ctx context.Context, s *state.State, pool Pool, firstOnly bool, memberSpecific bool, ignoreVolumeType ...string) ([]string, error) {
	var err error
	var usedBy []string

	err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error {
		// Get all the volumes using the storage pool.
		projectsVolumes, err := tx.GetStoragePoolVolumes(pool.ID(), nil, memberSpecific)
		if err != nil {
			return fmt.Errorf("Failed loading volumes: %w", err)
		}

		for projectName, projectVolumes := range projectsVolumes {
			for _, vol := range projectVolumes {
				var u *api.URL

				if shared.StringInSlice(vol.Type, ignoreVolumeType) {
					continue
				}

				// Generate URL for volume based on types that map to other entities.
				if vol.Type == db.StoragePoolVolumeTypeNameContainer || vol.Type == db.StoragePoolVolumeTypeNameVM {
					volName, snapName, isSnap := api.GetParentAndSnapshotName(vol.Name)
					if isSnap {
						u = api.NewURL().Path(version.APIVersion, "instances", volName, "snapshots", snapName).Project(projectName)
					} else {
						u = api.NewURL().Path(version.APIVersion, "instances", volName).Project(projectName)
					}

					usedBy = append(usedBy, u.String())
				} else if vol.Type == db.StoragePoolVolumeTypeNameImage {
					imgProjectNames, err := tx.GetProjectsUsingImage(vol.Name)
					if err != nil {
						return fmt.Errorf("Failed loading projects using image %q: %w", vol.Name, err)
					}

					if len(imgProjectNames) > 0 {
						for _, imgProjectName := range imgProjectNames {
							u = api.NewURL().Path(version.APIVersion, "images", vol.Name).Project(imgProjectName).Target(vol.Location)
							usedBy = append(usedBy, u.String())
						}
					} else {
						// Handle orphaned image volumes that are not associated to an image.
						u = vol.URL(version.APIVersion, pool.Name(), projectName)
						usedBy = append(usedBy, u.String())
					}
				} else {
					u = vol.URL(version.APIVersion, pool.Name(), projectName)
					usedBy = append(usedBy, u.String())
				}

				if firstOnly {
					return nil
				}
			}
		}

		// Get all the profiles using the storage pool.
		profiles, err := cluster.GetProfiles(ctx, tx.Tx(), cluster.ProfileFilter{})
		if err != nil {
			return fmt.Errorf("Failed loading profiles: %w", err)
		}

		for _, profile := range profiles {
			profileDevices, err := cluster.GetProfileDevices(ctx, tx.Tx(), profile.ID)
			if err != nil {
				return fmt.Errorf("Failed loading profile devices: %w", err)
			}

			for _, device := range profileDevices {
				if device.Type != cluster.TypeDisk {
					continue
				}

				if device.Config["pool"] != pool.Name() {
					continue
				}

				u := api.NewURL().Path(version.APIVersion, "profiles", profile.Name).Project(profile.Project)
				usedBy = append(usedBy, u.String())

				if firstOnly {
					return nil
				}
			}
		}

		return err
	})
	if err != nil {
		return nil, err
	}

	sort.Strings(usedBy)

	return usedBy, nil
}
<|endoftext|>


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

package check

import (
	"fmt"
	"runtime"
	"time"
)

var memStats runtime.MemStats

// testingB is a type passed to Benchmark functions to manage benchmark
// timing and to specify the number of iterations to run.
type timer struct {
	start     time.Time // Time test or benchmark started
	duration  time.Duration
	N         int
	bytes     int64
	timerOn   bool
	benchTime time.Duration
	// The initial states of memStats.Mallocs and memStats.TotalAlloc.
	startAllocs uint64
	startBytes  uint64
	// The net total of this test after being run.
	netAllocs uint64
	netBytes  uint64
}

// StartTimer starts timing a test. This function is called automatically
// before a benchmark starts, but it can also used to resume timing after
// a call to StopTimer.
func (c *C) StartTimer() {
	if !c.timerOn {
		c.start = time.Now()
		c.timerOn = true

		runtime.ReadMemStats(&memStats)
		c.startAllocs = memStats.Mallocs
		c.startBytes = memStats.TotalAlloc
	}
}

// StopTimer stops timing a test. This can be used to pause the timer
// while performing complex initialization that you don't
// want to measure.
func (c *C) StopTimer() {
	if c.timerOn {
		c.duration += time.Now().Sub(c.start)
		c.timerOn = false
		runtime.ReadMemStats(&memStats)
		c.netAllocs += memStats.Mallocs - c.startAllocs
		c.netBytes += memStats.TotalAlloc - c.startBytes
	}
}

// ResetTimer sets the elapsed benchmark time to zero.
// It does not affect whether the timer is running.
func (c *C) ResetTimer() {
	if c.timerOn {
		c.start = time.Now()
		runtime.ReadMemStats(&memStats)
		c.startAllocs = memStats.Mallocs
		c.startBytes = memStats.TotalAlloc
	}
	c.duration = 0
	c.netAllocs = 0
	c.netBytes = 0
}

// SetBytes informs the number of bytes that the benchmark processes
// on each iteration. If this is called in a benchmark it will also
// report MB/s.
func (c *C) SetBytes(n int64) {
	c.bytes = n
}

func (c *C) nsPerOp() int64 {
	if c.N <= 0 {
		return 0
	}
	return c.duration.Nanoseconds() / int64(c.N)
}

func (c *C) mbPerSec() float64 {
	if c.bytes <= 0 || c.duration <= 0 || c.N <= 0 {
		return 0
	}
	return (float64(c.bytes) * float64(c.N) / 1e6) / c.duration.Seconds()
}

func (c *C) timerString() string {
	if c.N <= 0 {
		return fmt.Sprintf("%3.3fs", float64(c.duration.Nanoseconds())/1e9)
	}
	mbs := c.mbPerSec()
	mb := ""
	if mbs != 0 {
		mb = fmt.Sprintf("\t%7.2f MB/s", mbs)
	}
	nsop := c.nsPerOp()
	ns := fmt.Sprintf("%10d ns/op", nsop)
	if c.N > 0 && nsop < 100 {
		// The format specifiers here make sure that
		// the ones digits line up for all three possible formats.
		if nsop < 10 {
			ns = fmt.Sprintf("%13.2f ns/op", float64(c.duration.Nanoseconds())/float64(c.N))
		} else {
			ns = fmt.Sprintf("%12.1f ns/op", float64(c.duration.Nanoseconds())/float64(c.N))
		}
	}
	memStats := ""
	if c.benchMem {
		allocedBytes := fmt.Sprintf("%8d B/op", int64(c.netBytes)/int64(c.N))
		allocs := fmt.Sprintf("%8d allocs/op", int64(c.netAllocs)/int64(c.N))
		memStats = fmt.Sprintf("\t%s\t%s", allocedBytes, allocs)
	}
	return fmt.Sprintf("%8d\t%s%s%s", c.N, ns, mb, memStats)
}

func min(x, y int) int {
	if x > y {
		return y
	}
	return x
}

func max(x, y int) int {
	if x < y {
		return y
	}
	return x
}

// roundDown10 rounds a number down to the nearest power of 10.
func roundDown10(n int) int {
	var tens = 0
	// tens = floor(log_10(n))
	for n > 10 {
		n = n / 10
		tens++
	}
	// result = 10^tens
	result := 1
	for i := 0; i < tens; i++ {
		result *= 10
	}
	return result
}

// roundUp rounds x up to a number of the form [1eX, 2eX, 5eX].
func roundUp(n int) int {
	base := roundDown10(n)
	if n < (2 * base) {
		return 2 * base
	}
	if n < (5 * base) {
		return 5 * base
	}
	return 10 * base
}
<commit_msg>Include the whole Go license on benchmark.go.<commit_after>// Copyright (c) 2012 The Go Authors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//    * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//    * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package check

import (
	"fmt"
	"runtime"
	"time"
)

var memStats runtime.MemStats

// testingB is a type passed to Benchmark functions to manage benchmark
// timing and to specify the number of iterations to run.
type timer struct {
	start     time.Time // Time test or benchmark started
	duration  time.Duration
	N         int
	bytes     int64
	timerOn   bool
	benchTime time.Duration
	// The initial states of memStats.Mallocs and memStats.TotalAlloc.
	startAllocs uint64
	startBytes  uint64
	// The net total of this test after being run.
	netAllocs uint64
	netBytes  uint64
}

// StartTimer starts timing a test. This function is called automatically
// before a benchmark starts, but it can also used to resume timing after
// a call to StopTimer.
func (c *C) StartTimer() {
	if !c.timerOn {
		c.start = time.Now()
		c.timerOn = true

		runtime.ReadMemStats(&memStats)
		c.startAllocs = memStats.Mallocs
		c.startBytes = memStats.TotalAlloc
	}
}

// StopTimer stops timing a test. This can be used to pause the timer
// while performing complex initialization that you don't
// want to measure.
func (c *C) StopTimer() {
	if c.timerOn {
		c.duration += time.Now().Sub(c.start)
		c.timerOn = false
		runtime.ReadMemStats(&memStats)
		c.netAllocs += memStats.Mallocs - c.startAllocs
		c.netBytes += memStats.TotalAlloc - c.startBytes
	}
}

// ResetTimer sets the elapsed benchmark time to zero.
// It does not affect whether the timer is running.
func (c *C) ResetTimer() {
	if c.timerOn {
		c.start = time.Now()
		runtime.ReadMemStats(&memStats)
		c.startAllocs = memStats.Mallocs
		c.startBytes = memStats.TotalAlloc
	}
	c.duration = 0
	c.netAllocs = 0
	c.netBytes = 0
}

// SetBytes informs the number of bytes that the benchmark processes
// on each iteration. If this is called in a benchmark it will also
// report MB/s.
func (c *C) SetBytes(n int64) {
	c.bytes = n
}

func (c *C) nsPerOp() int64 {
	if c.N <= 0 {
		return 0
	}
	return c.duration.Nanoseconds() / int64(c.N)
}

func (c *C) mbPerSec() float64 {
	if c.bytes <= 0 || c.duration <= 0 || c.N <= 0 {
		return 0
	}
	return (float64(c.bytes) * float64(c.N) / 1e6) / c.duration.Seconds()
}

func (c *C) timerString() string {
	if c.N <= 0 {
		return fmt.Sprintf("%3.3fs", float64(c.duration.Nanoseconds())/1e9)
	}
	mbs := c.mbPerSec()
	mb := ""
	if mbs != 0 {
		mb = fmt.Sprintf("\t%7.2f MB/s", mbs)
	}
	nsop := c.nsPerOp()
	ns := fmt.Sprintf("%10d ns/op", nsop)
	if c.N > 0 && nsop < 100 {
		// The format specifiers here make sure that
		// the ones digits line up for all three possible formats.
		if nsop < 10 {
			ns = fmt.Sprintf("%13.2f ns/op", float64(c.duration.Nanoseconds())/float64(c.N))
		} else {
			ns = fmt.Sprintf("%12.1f ns/op", float64(c.duration.Nanoseconds())/float64(c.N))
		}
	}
	memStats := ""
	if c.benchMem {
		allocedBytes := fmt.Sprintf("%8d B/op", int64(c.netBytes)/int64(c.N))
		allocs := fmt.Sprintf("%8d allocs/op", int64(c.netAllocs)/int64(c.N))
		memStats = fmt.Sprintf("\t%s\t%s", allocedBytes, allocs)
	}
	return fmt.Sprintf("%8d\t%s%s%s", c.N, ns, mb, memStats)
}

func min(x, y int) int {
	if x > y {
		return y
	}
	return x
}

func max(x, y int) int {
	if x < y {
		return y
	}
	return x
}

// roundDown10 rounds a number down to the nearest power of 10.
func roundDown10(n int) int {
	var tens = 0
	// tens = floor(log_10(n))
	for n > 10 {
		n = n / 10
		tens++
	}
	// result = 10^tens
	result := 1
	for i := 0; i < tens; i++ {
		result *= 10
	}
	return result
}

// roundUp rounds x up to a number of the form [1eX, 2eX, 5eX].
func roundUp(n int) int {
	base := roundDown10(n)
	if n < (2 * base) {
		return 2 * base
	}
	if n < (5 * base) {
		return 5 * base
	}
	return 10 * base
}
<|endoftext|>


<commit_before>// !py3.4
// !py3.5
// !py3.6

package mainthread

/*
#cgo pkg-config: python-2.7
*/
import "C"
<commit_msg>fix tag comment for build constraints<commit_after>// +build !py3.4
// +build !py3.5
// +build !py3.6

package mainthread

/*
#cgo pkg-config: python-2.7
*/
import "C"
<|endoftext|>


<commit_before>// Package eval handles evaluation of nodes and consists the runtime of the
// shell.
package eval

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"unicode/utf8"

	"github.com/elves/elvish/parse"
	"github.com/elves/elvish/store"
	"github.com/elves/elvish/stub"
	"github.com/elves/elvish/sys"
	"github.com/elves/elvish/util"
)

var Logger = util.GetLogger("[eval] ")

// FnPrefix is the prefix for the variable names of functions. Defining a
// function "foo" is equivalent to setting a variable named FnPrefix + "foo".
const FnPrefix = "&"

// Namespace is a map from name to variables.
type Namespace map[string]Variable

// Evaler is used to evaluate elvish sources. It maintains runtime context
// shared among all evalCtx instances.
type Evaler struct {
	Global  Namespace
	Modules map[string]Namespace
	Store   *store.Store
	Editor  Editor
	Stub    *stub.Stub
	intCh   chan struct{}
}

// EvalCtx maintains an Evaler along with its runtime context. After creation
// an EvalCtx is not modified, and new instances are created when needed.
type EvalCtx struct {
	*Evaler
	name, text, context string

	local, up   Namespace
	ports       []*Port
	positionals []Value
	verdict     bool

	begin, end int
	traceback  *util.Traceback
}

func (ec *EvalCtx) falsify() {
	ec.verdict = false
}

func (ec *EvalCtx) evaling(begin, end int) {
	ec.begin, ec.end = begin, end
}

// NewEvaler creates a new Evaler.
func NewEvaler(st *store.Store) *Evaler {
	return &Evaler{Namespace{}, map[string]Namespace{}, st, nil, nil, nil}
}

func (e *Evaler) searchPaths() []string {
	return builtinNamespace["paths"].(*EnvPathList).get()
}

const (
	outChanSize    = 32
	outChanLeader  = "▶ "
	falseIndicator = "✗"
	initIndent     = NoPretty
)

// NewTopEvalCtx creates a top-level evalCtx.
func NewTopEvalCtx(ev *Evaler, name, text string, ports []*Port) *EvalCtx {
	return &EvalCtx{
		ev,
		name, text, "top",
		ev.Global, Namespace{},
		ports, nil, true,
		0, len(text), nil,
	}
}

// fork returns a modified copy of ec. The ports are forked, and the context is
// changed to the given value. Other fields are copied shallowly.
func (ec *EvalCtx) fork(newContext string) *EvalCtx {
	newPorts := make([]*Port, len(ec.ports))
	for i, p := range ec.ports {
		newPorts[i] = p.Fork()
	}
	return &EvalCtx{
		ec.Evaler,
		ec.name, ec.text, newContext,
		ec.local, ec.up,
		newPorts, ec.positionals, true,
		ec.begin, ec.end, ec.traceback,
	}
}

// port returns ec.ports[i] or nil if i is out of range. This makes it possible
// to treat ec.ports as if it has an infinite tail of nil's.
func (ec *EvalCtx) port(i int) *Port {
	if i >= len(ec.ports) {
		return nil
	}
	return ec.ports[i]
}

// growPorts makes the size of ec.ports at least n, adding nil's if necessary.
func (ec *EvalCtx) growPorts(n int) {
	if len(ec.ports) >= n {
		return
	}
	ports := ec.ports
	ec.ports = make([]*Port, n)
	copy(ec.ports, ports)
}

func makeScope(s Namespace) scope {
	sc := scope{}
	for name := range s {
		sc[name] = true
	}
	return sc
}

// Eval evaluates a chunk node n. The supplied name and text are used in
// diagnostic messages.
func (ev *Evaler) Eval(name, text string, n *parse.Chunk, ports []*Port) (bool, error) {
	op, err := ev.Compile(n, name, text)
	if err != nil {
		return false, err
	}
	ec := NewTopEvalCtx(ev, name, text, ports)
	err = ec.PEval(op)
	return ec.verdict, err
}

func (ec *EvalCtx) Interrupts() <-chan struct{} {
	return ec.intCh
}

func (ev *Evaler) EvalInteractive(text string, n *parse.Chunk) error {
	inCh := make(chan Value)
	close(inCh)

	outCh := make(chan Value, outChanSize)
	outDone := make(chan struct{})
	go func() {
		for v := range outCh {
			fmt.Printf("%s%s\n", outChanLeader, v.Repr(initIndent))
		}
		close(outDone)
	}()

	ports := []*Port{
		{File: os.Stdin, Chan: inCh},
		{File: os.Stdout, Chan: outCh},
		{File: os.Stderr},
	}

	signal.Ignore(syscall.SIGTTIN)
	signal.Ignore(syscall.SIGTTOU)
	stopSigGoroutine := make(chan struct{})
	sigGoRoutineDone := make(chan struct{})
	// XXX Should use fd of /dev/terminal instead of 0.
	if ev.Stub != nil && ev.Stub.Alive() && sys.IsATTY(0) {
		ev.Stub.SetTitle(summarize(text))
		dir, err := os.Getwd()
		if err != nil {
			dir = "/"
		}
		ev.Stub.Chdir(dir)
		err = sys.Tcsetpgrp(0, ev.Stub.Process().Pid)
		if err != nil {
			fmt.Println("failed to put stub in foreground:", err)
		}

		ev.intCh = make(chan struct{})
		go func() {
			closedIntCh := false
		loop:
			for {
				select {
				case sig := <-ev.Stub.Signals():
					switch sig {
					case syscall.SIGINT, syscall.SIGQUIT:
						if !closedIntCh {
							close(ev.intCh)
							closedIntCh = true
						}
					}
				case <-stopSigGoroutine:
					break loop
				}
			}
			ev.intCh = nil
			close(sigGoRoutineDone)
		}()
	}

	ret, err := ev.Eval("[interactive]", text, n, ports)
	close(outCh)
	<-outDone
	close(stopSigGoroutine)
	<-sigGoRoutineDone

	if !ret {
		fmt.Println(falseIndicator)
	}

	// XXX Should use fd of /dev/tty instead of 0.
	if sys.IsATTY(0) {
		err := sys.Tcsetpgrp(0, syscall.Getpgrp())
		if err != nil {
			fmt.Println("failed to put myself in foreground:", err)
		}
	}

	return err
}

func summarize(text string) string {
	// TODO Make a proper summary.
	if len(text) < 32 {
		return text
	}
	var b bytes.Buffer
	for i, r := range text {
		if i+len(string(r)) >= 32 {
			break
		}
		b.WriteRune(r)
	}
	return b.String()
}

// Compile compiles elvish code in the global scope.
func (ev *Evaler) Compile(n *parse.Chunk, name, text string) (Op, error) {
	return compile(makeScope(ev.Global), n, name, text)
}

// PEval evaluates an op in a protected environment so that calls to errorf are
// wrapped in an Error.
func (ec *EvalCtx) PEval(op Op) (err error) {
	defer catch(&err, ec)
	op.Exec(ec)
	return nil
}

func (ec *EvalCtx) PCall(f Fn, args []Value, opts map[string]Value) (err error) {
	defer catch(&err, ec)
	f.Call(ec, args, opts)
	return nil
}

func (ec *EvalCtx) PCaptureOutput(f Fn, args []Value, opts map[string]Value) (vs []Value, err error) {
	defer catch(&err, ec)
	// XXX There is no source.
	return captureOutput(ec, Op{
		func(newec *EvalCtx) { f.Call(newec, args, opts) }, -1, -1}), nil
}

func catch(perr *error, ec *EvalCtx) {
	// NOTE: We have to duplicate instead of calling util.Catch here, since
	// recover can only catch a panic when called directly from a deferred
	// function.
	r := recover()
	if r == nil {
		return
	}
	if exc, ok := r.(util.Exception); ok {
		err := exc.Error
		if _, ok := err.(*util.TracebackError); !ok {
			if _, ok := err.(flow); !ok {
				err = ec.makeTracebackError(err)
			}
		}
		*perr = err
	} else if r != nil {
		panic(r)
	}
}

func (ec *EvalCtx) makeTracebackError(e error) *util.TracebackError {
	return &util.TracebackError{Cause: e, Traceback: ec.addTraceback()}
}

func (ec *EvalCtx) addTraceback() *util.Traceback {
	return &util.Traceback{
		Name: ec.name, Source: ec.text,
		Begin: ec.begin, End: ec.end, Next: ec.traceback,
	}
}

// errorpf stops the ec.eval immediately by panicking with a diagnostic message.
// The panic is supposed to be caught by ec.eval.
func (ec *EvalCtx) errorpf(begin, end int, format string, args ...interface{}) {
	throw(&util.PosError{begin, end, fmt.Errorf(format, args...)})
}

// SourceText evaluates a chunk of elvish source.
func (ev *Evaler) SourceText(src string) error {
	n, err := parse.Parse(src)
	if err != nil {
		return err
	}
	return ev.EvalInteractive(src, n)
}

func readFileUTF8(fname string) (string, error) {
	bytes, err := ioutil.ReadFile(fname)
	if err != nil {
		return "", err
	}
	if !utf8.Valid(bytes) {
		return "", fmt.Errorf("%s: source is not valid UTF-8", fname)
	}
	return string(bytes), nil
}

// Source evaluates the content of a file.
func (ev *Evaler) Source(fname string) error {
	src, err := readFileUTF8(fname)
	if err != nil {
		return err
	}
	return ev.SourceText(src)
}

// Builtin returns the builtin namespace.
func Builtin() Namespace {
	return builtinNamespace
}

// ErrStoreUnconnected is thrown by ResolveVar when a shared: variable needs to
// be resolved but the store is not connected.
var ErrStoreUnconnected = errors.New("store unconnected")

// ResolveVar resolves a variable. When the variable cannot be found, nil is
// returned.
func (ec *EvalCtx) ResolveVar(ns, name string) Variable {
	switch ns {
	case "local":
		return ec.getLocal(name)
	case "up":
		return ec.up[name]
	case "builtin":
		return builtinNamespace[name]
	case "":
		if v := ec.getLocal(name); v != nil {
			return v
		}
		if v, ok := ec.up[name]; ok {
			return v
		}
		return builtinNamespace[name]
	case "e", "E":
		if strings.HasPrefix(name, FnPrefix) {
			return NewRoVariable(ExternalCmd{name[len(FnPrefix):]})
		}
		return envVariable{name}
	case "shared":
		if ec.Store == nil {
			throw(ErrStoreUnconnected)
		}
		return sharedVariable{ec.Store, name}
	default:
		if ns, ok := ec.Modules[ns]; ok {
			return ns[name]
		} else {
			return nil
		}
	}
}

// getLocal finds the named local variable.
func (ec *EvalCtx) getLocal(name string) Variable {
	i, err := strconv.Atoi(name)
	if err == nil {
		// Logger.Println("positional variable", i)
		// Logger.Printf("EvalCtx=%p, args=%v", ec, ec.positionals)
		if i < 0 {
			i += len(ec.positionals)
		}
		if i < 0 || i >= len(ec.positionals) {
			// Logger.Print("out of range")
			return nil
		}
		// Logger.Print("found")
		return NewRoVariable(ec.positionals[i])
	}
	return ec.local[name]
}

var ErrMoreThanOneRest = errors.New("more than one @ lvalue")

// IterateInput calls the passed function for each input element.
func (ec *EvalCtx) IterateInputs(f func(Value)) {
	var w sync.WaitGroup
	inputs := make(chan Value)

	w.Add(2)
	go func() {
		filein := bufio.NewReader(ec.ports[0].File)
		for {
			line, err := filein.ReadString('\n')
			if line != "" {
				inputs <- String(strings.TrimSuffix(line, "\n"))
			}
			if err != nil {
				if err != io.EOF {
					Logger.Println("error on pipe:", err)
				}
				break
			}
		}
		w.Done()
	}()
	go func() {
		for v := range ec.ports[0].Chan {
			inputs <- v
		}
		w.Done()
	}()
	go func() {
		w.Wait()
		close(inputs)
	}()

	for v := range inputs {
		f(v)
	}
}

// OutputChan returns a channel onto which output can be written.
func (ec *EvalCtx) OutputChan() chan<- Value {
	return ec.ports[1].Chan
}
<commit_msg>Fix a comment.<commit_after>// Package eval handles evaluation of nodes and consists the runtime of the
// shell.
package eval

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"unicode/utf8"

	"github.com/elves/elvish/parse"
	"github.com/elves/elvish/store"
	"github.com/elves/elvish/stub"
	"github.com/elves/elvish/sys"
	"github.com/elves/elvish/util"
)

var Logger = util.GetLogger("[eval] ")

// FnPrefix is the prefix for the variable names of functions. Defining a
// function "foo" is equivalent to setting a variable named FnPrefix + "foo".
const FnPrefix = "&"

// Namespace is a map from name to variables.
type Namespace map[string]Variable

// Evaler is used to evaluate elvish sources. It maintains runtime context
// shared among all evalCtx instances.
type Evaler struct {
	Global  Namespace
	Modules map[string]Namespace
	Store   *store.Store
	Editor  Editor
	Stub    *stub.Stub
	intCh   chan struct{}
}

// EvalCtx maintains an Evaler along with its runtime context. After creation
// an EvalCtx is not modified, and new instances are created when needed.
type EvalCtx struct {
	*Evaler
	name, text, context string

	local, up   Namespace
	ports       []*Port
	positionals []Value
	verdict     bool

	begin, end int
	traceback  *util.Traceback
}

func (ec *EvalCtx) falsify() {
	ec.verdict = false
}

func (ec *EvalCtx) evaling(begin, end int) {
	ec.begin, ec.end = begin, end
}

// NewEvaler creates a new Evaler.
func NewEvaler(st *store.Store) *Evaler {
	return &Evaler{Namespace{}, map[string]Namespace{}, st, nil, nil, nil}
}

func (e *Evaler) searchPaths() []string {
	return builtinNamespace["paths"].(*EnvPathList).get()
}

const (
	outChanSize    = 32
	outChanLeader  = "▶ "
	falseIndicator = "✗"
	initIndent     = NoPretty
)

// NewTopEvalCtx creates a top-level evalCtx.
func NewTopEvalCtx(ev *Evaler, name, text string, ports []*Port) *EvalCtx {
	return &EvalCtx{
		ev,
		name, text, "top",
		ev.Global, Namespace{},
		ports, nil, true,
		0, len(text), nil,
	}
}

// fork returns a modified copy of ec. The ports are forked, and the context is
// changed to the given value. Other fields are copied shallowly.
func (ec *EvalCtx) fork(newContext string) *EvalCtx {
	newPorts := make([]*Port, len(ec.ports))
	for i, p := range ec.ports {
		newPorts[i] = p.Fork()
	}
	return &EvalCtx{
		ec.Evaler,
		ec.name, ec.text, newContext,
		ec.local, ec.up,
		newPorts, ec.positionals, true,
		ec.begin, ec.end, ec.traceback,
	}
}

// port returns ec.ports[i] or nil if i is out of range. This makes it possible
// to treat ec.ports as if it has an infinite tail of nil's.
func (ec *EvalCtx) port(i int) *Port {
	if i >= len(ec.ports) {
		return nil
	}
	return ec.ports[i]
}

// growPorts makes the size of ec.ports at least n, adding nil's if necessary.
func (ec *EvalCtx) growPorts(n int) {
	if len(ec.ports) >= n {
		return
	}
	ports := ec.ports
	ec.ports = make([]*Port, n)
	copy(ec.ports, ports)
}

func makeScope(s Namespace) scope {
	sc := scope{}
	for name := range s {
		sc[name] = true
	}
	return sc
}

// Eval evaluates a chunk node n. The supplied name and text are used in
// diagnostic messages.
func (ev *Evaler) Eval(name, text string, n *parse.Chunk, ports []*Port) (bool, error) {
	op, err := ev.Compile(n, name, text)
	if err != nil {
		return false, err
	}
	ec := NewTopEvalCtx(ev, name, text, ports)
	err = ec.PEval(op)
	return ec.verdict, err
}

func (ec *EvalCtx) Interrupts() <-chan struct{} {
	return ec.intCh
}

func (ev *Evaler) EvalInteractive(text string, n *parse.Chunk) error {
	inCh := make(chan Value)
	close(inCh)

	outCh := make(chan Value, outChanSize)
	outDone := make(chan struct{})
	go func() {
		for v := range outCh {
			fmt.Printf("%s%s\n", outChanLeader, v.Repr(initIndent))
		}
		close(outDone)
	}()

	ports := []*Port{
		{File: os.Stdin, Chan: inCh},
		{File: os.Stdout, Chan: outCh},
		{File: os.Stderr},
	}

	signal.Ignore(syscall.SIGTTIN)
	signal.Ignore(syscall.SIGTTOU)
	stopSigGoroutine := make(chan struct{})
	sigGoRoutineDone := make(chan struct{})
	// XXX Should use fd of /dev/terminal instead of 0.
	if ev.Stub != nil && ev.Stub.Alive() && sys.IsATTY(0) {
		ev.Stub.SetTitle(summarize(text))
		dir, err := os.Getwd()
		if err != nil {
			dir = "/"
		}
		ev.Stub.Chdir(dir)
		err = sys.Tcsetpgrp(0, ev.Stub.Process().Pid)
		if err != nil {
			fmt.Println("failed to put stub in foreground:", err)
		}

		ev.intCh = make(chan struct{})
		go func() {
			closedIntCh := false
		loop:
			for {
				select {
				case sig := <-ev.Stub.Signals():
					switch sig {
					case syscall.SIGINT, syscall.SIGQUIT:
						if !closedIntCh {
							close(ev.intCh)
							closedIntCh = true
						}
					}
				case <-stopSigGoroutine:
					break loop
				}
			}
			ev.intCh = nil
			close(sigGoRoutineDone)
		}()
	}

	ret, err := ev.Eval("[interactive]", text, n, ports)
	close(outCh)
	<-outDone
	close(stopSigGoroutine)
	<-sigGoRoutineDone

	if !ret {
		fmt.Println(falseIndicator)
	}

	// XXX Should use fd of /dev/tty instead of 0.
	if sys.IsATTY(0) {
		err := sys.Tcsetpgrp(0, syscall.Getpgrp())
		if err != nil {
			fmt.Println("failed to put myself in foreground:", err)
		}
	}

	return err
}

func summarize(text string) string {
	// TODO Make a proper summary.
	if len(text) < 32 {
		return text
	}
	var b bytes.Buffer
	for i, r := range text {
		if i+len(string(r)) >= 32 {
			break
		}
		b.WriteRune(r)
	}
	return b.String()
}

// Compile compiles elvish code in the global scope.
func (ev *Evaler) Compile(n *parse.Chunk, name, text string) (Op, error) {
	return compile(makeScope(ev.Global), n, name, text)
}

// PEval evaluates an op in a protected environment so that calls to errorf are
// wrapped in an Error.
func (ec *EvalCtx) PEval(op Op) (err error) {
	defer catch(&err, ec)
	op.Exec(ec)
	return nil
}

func (ec *EvalCtx) PCall(f Fn, args []Value, opts map[string]Value) (err error) {
	defer catch(&err, ec)
	f.Call(ec, args, opts)
	return nil
}

func (ec *EvalCtx) PCaptureOutput(f Fn, args []Value, opts map[string]Value) (vs []Value, err error) {
	defer catch(&err, ec)
	// XXX There is no source.
	return captureOutput(ec, Op{
		func(newec *EvalCtx) { f.Call(newec, args, opts) }, -1, -1}), nil
}

func catch(perr *error, ec *EvalCtx) {
	// NOTE: We have to duplicate instead of calling util.Catch here, since
	// recover can only catch a panic when called directly from a deferred
	// function.
	r := recover()
	if r == nil {
		return
	}
	if exc, ok := r.(util.Exception); ok {
		err := exc.Error
		if _, ok := err.(*util.TracebackError); !ok {
			if _, ok := err.(flow); !ok {
				err = ec.makeTracebackError(err)
			}
		}
		*perr = err
	} else if r != nil {
		panic(r)
	}
}

func (ec *EvalCtx) makeTracebackError(e error) *util.TracebackError {
	return &util.TracebackError{Cause: e, Traceback: ec.addTraceback()}
}

func (ec *EvalCtx) addTraceback() *util.Traceback {
	return &util.Traceback{
		Name: ec.name, Source: ec.text,
		Begin: ec.begin, End: ec.end, Next: ec.traceback,
	}
}

// errorpf stops the ec.eval immediately by panicking with a diagnostic message.
// The panic is supposed to be caught by ec.eval.
func (ec *EvalCtx) errorpf(begin, end int, format string, args ...interface{}) {
	throw(&util.PosError{begin, end, fmt.Errorf(format, args...)})
}

// SourceText evaluates a chunk of elvish source.
func (ev *Evaler) SourceText(src string) error {
	n, err := parse.Parse(src)
	if err != nil {
		return err
	}
	return ev.EvalInteractive(src, n)
}

func readFileUTF8(fname string) (string, error) {
	bytes, err := ioutil.ReadFile(fname)
	if err != nil {
		return "", err
	}
	if !utf8.Valid(bytes) {
		return "", fmt.Errorf("%s: source is not valid UTF-8", fname)
	}
	return string(bytes), nil
}

// Source evaluates the content of a file.
func (ev *Evaler) Source(fname string) error {
	src, err := readFileUTF8(fname)
	if err != nil {
		return err
	}
	return ev.SourceText(src)
}

// Builtin returns the builtin namespace.
func Builtin() Namespace {
	return builtinNamespace
}

// ErrStoreUnconnected is thrown by ResolveVar when a shared: variable needs to
// be resolved but the store is not connected.
var ErrStoreUnconnected = errors.New("store unconnected")

// ResolveVar resolves a variable. When the variable cannot be found, nil is
// returned.
func (ec *EvalCtx) ResolveVar(ns, name string) Variable {
	switch ns {
	case "local":
		return ec.getLocal(name)
	case "up":
		return ec.up[name]
	case "builtin":
		return builtinNamespace[name]
	case "":
		if v := ec.getLocal(name); v != nil {
			return v
		}
		if v, ok := ec.up[name]; ok {
			return v
		}
		return builtinNamespace[name]
	case "e", "E":
		if strings.HasPrefix(name, FnPrefix) {
			return NewRoVariable(ExternalCmd{name[len(FnPrefix):]})
		}
		return envVariable{name}
	case "shared":
		if ec.Store == nil {
			throw(ErrStoreUnconnected)
		}
		return sharedVariable{ec.Store, name}
	default:
		if ns, ok := ec.Modules[ns]; ok {
			return ns[name]
		} else {
			return nil
		}
	}
}

// getLocal finds the named local variable.
func (ec *EvalCtx) getLocal(name string) Variable {
	i, err := strconv.Atoi(name)
	if err == nil {
		// Logger.Println("positional variable", i)
		// Logger.Printf("EvalCtx=%p, args=%v", ec, ec.positionals)
		if i < 0 {
			i += len(ec.positionals)
		}
		if i < 0 || i >= len(ec.positionals) {
			// Logger.Print("out of range")
			return nil
		}
		// Logger.Print("found")
		return NewRoVariable(ec.positionals[i])
	}
	return ec.local[name]
}

var ErrMoreThanOneRest = errors.New("more than one @ lvalue")

// IterateInputs calls the passed function for each input element.
func (ec *EvalCtx) IterateInputs(f func(Value)) {
	var w sync.WaitGroup
	inputs := make(chan Value)

	w.Add(2)
	go func() {
		filein := bufio.NewReader(ec.ports[0].File)
		for {
			line, err := filein.ReadString('\n')
			if line != "" {
				inputs <- String(strings.TrimSuffix(line, "\n"))
			}
			if err != nil {
				if err != io.EOF {
					Logger.Println("error on pipe:", err)
				}
				break
			}
		}
		w.Done()
	}()
	go func() {
		for v := range ec.ports[0].Chan {
			inputs <- v
		}
		w.Done()
	}()
	go func() {
		w.Wait()
		close(inputs)
	}()

	for v := range inputs {
		f(v)
	}
}

// OutputChan returns a channel onto which output can be written.
func (ec *EvalCtx) OutputChan() chan<- Value {
	return ec.ports[1].Chan
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net"
	"os"
	"os/signal"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/getcfs/megacfs/oort/api/server"
	"github.com/gholt/ring"
	"golang.org/x/net/context"
)

const (
	ADDR_FORMIC = iota
	ADDR_GROUP_GRPC
	ADDR_GROUP_REPL
	ADDR_VALUE_GRPC
	ADDR_VALUE_REPL
)

func main() {
	// TODO: Completely missing all formic stuff

	fp, err := os.Open("/etc/cfsd/cfs.ring")
	if err != nil {
		panic(err)
	}
	oneRing, err := ring.LoadRing(fp)
	if err != nil {
		panic(err)
	}
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		panic(err)
	}
FIND_LOCAL_NODE:
	for _, addrObj := range addrs {
		if ipNet, ok := addrObj.(*net.IPNet); ok {
			for _, node := range oneRing.Nodes() {
				for _, nodeAddr := range node.Addresses() {
					i := strings.LastIndex(nodeAddr, ":")
					if i < 0 {
						continue
					}
					nodeIP := net.ParseIP(nodeAddr[:i])
					if ipNet.Contains(nodeIP) {
						oneRing.SetLocalNode(node.ID())
						break FIND_LOCAL_NODE
					}
				}
			}
		}
	}

	waitGroup := &sync.WaitGroup{}
	shutdownChan := make(chan struct{})

	groupStore, groupStoreRestartChan, err := server.NewGroupStore(&server.GroupStoreConfig{
		GRPCAddressIndex: ADDR_GROUP_GRPC,
		ReplAddressIndex: ADDR_GROUP_REPL,
		CertFile:         "/etc/cfsd/cert.pem",
		KeyFile:          "/etc/cfsd/cert-key.pem",
		CAFile:           "/etc/cfsd/ca.pem",
		Scale:            0.4,
		Path:             "/mnt/cfsd",
		Ring:             oneRing,
	})
	waitGroup.Add(1)
	go func() {
		for {
			select {
			case <-groupStoreRestartChan:
				ctx, _ := context.WithTimeout(context.Background(), time.Minute)
				groupStore.Shutdown(ctx)
				ctx, _ = context.WithTimeout(context.Background(), time.Minute)
				groupStore.Startup(ctx)
			case <-shutdownChan:
				ctx, _ := context.WithTimeout(context.Background(), time.Minute)
				groupStore.Shutdown(ctx)
				waitGroup.Done()
				return
			}
		}
	}()
	ctx, _ := context.WithTimeout(context.Background(), time.Minute)
	if err = groupStore.Startup(ctx); err != nil {
		ctx, _ = context.WithTimeout(context.Background(), time.Minute)
		groupStore.Shutdown(ctx)
		panic(err)
	}

	valueStore, valueStoreRestartChan, err := server.NewValueStore(&server.ValueStoreConfig{
		GRPCAddressIndex: ADDR_VALUE_GRPC,
		ReplAddressIndex: ADDR_VALUE_REPL,
		CertFile:         "/etc/cfsd/cert.pem",
		KeyFile:          "/etc/cfsd/cert-key.pem",
		CAFile:           "/etc/cfsd/ca.pem",
		Scale:            0.4,
		Path:             "/mnt/cfsd",
		Ring:             oneRing,
	})
	waitGroup.Add(1)
	go func() {
		for {
			select {
			case <-valueStoreRestartChan:
				ctx, _ := context.WithTimeout(context.Background(), time.Minute)
				valueStore.Shutdown(ctx)
				ctx, _ = context.WithTimeout(context.Background(), time.Minute)
				valueStore.Startup(ctx)
			case <-shutdownChan:
				ctx, _ := context.WithTimeout(context.Background(), time.Minute)
				valueStore.Shutdown(ctx)
				waitGroup.Done()
				return
			}
		}
	}()
	ctx, _ = context.WithTimeout(context.Background(), time.Minute)
	if err = valueStore.Startup(ctx); err != nil {
		ctx, _ = context.WithTimeout(context.Background(), time.Minute)
		valueStore.Shutdown(ctx)
		panic(err)
	}

	ch := make(chan os.Signal)
	signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
	waitGroup.Add(1)
	go func() {
		for {
			select {
			case <-ch:
				fmt.Println("Shutting down due to signal")
				close(shutdownChan)
				waitGroup.Done()
				return
			case <-shutdownChan:
				waitGroup.Done()
				return
			}
		}
	}()

	fmt.Println("Done launching components")
	waitGroup.Wait()
}
<commit_msg>Fixed bug in IP matching<commit_after>package main

import (
	"fmt"
	"net"
	"os"
	"os/signal"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/getcfs/megacfs/oort/api/server"
	"github.com/gholt/ring"
	"golang.org/x/net/context"
)

const (
	ADDR_FORMIC = iota
	ADDR_GROUP_GRPC
	ADDR_GROUP_REPL
	ADDR_VALUE_GRPC
	ADDR_VALUE_REPL
)

func main() {
	// TODO: Completely missing all formic stuff

	fp, err := os.Open("/etc/cfsd/cfs.ring")
	if err != nil {
		panic(err)
	}
	oneRing, err := ring.LoadRing(fp)
	if err != nil {
		panic(err)
	}
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		panic(err)
	}
FIND_LOCAL_NODE:
	for _, addrObj := range addrs {
		if ipNet, ok := addrObj.(*net.IPNet); ok {
			for _, node := range oneRing.Nodes() {
				for _, nodeAddr := range node.Addresses() {
					i := strings.LastIndex(nodeAddr, ":")
					if i < 0 {
						continue
					}
					nodeIP := net.ParseIP(nodeAddr[:i])
					if ipNet.IP.Equal(nodeIP) {
						oneRing.SetLocalNode(node.ID())
						break FIND_LOCAL_NODE
					}
				}
			}
		}
	}

	waitGroup := &sync.WaitGroup{}
	shutdownChan := make(chan struct{})

	groupStore, groupStoreRestartChan, err := server.NewGroupStore(&server.GroupStoreConfig{
		GRPCAddressIndex: ADDR_GROUP_GRPC,
		ReplAddressIndex: ADDR_GROUP_REPL,
		CertFile:         "/etc/cfsd/cert.pem",
		KeyFile:          "/etc/cfsd/cert-key.pem",
		CAFile:           "/etc/cfsd/ca.pem",
		Scale:            0.4,
		Path:             "/mnt/cfsd",
		Ring:             oneRing,
	})
	waitGroup.Add(1)
	go func() {
		for {
			select {
			case <-groupStoreRestartChan:
				ctx, _ := context.WithTimeout(context.Background(), time.Minute)
				groupStore.Shutdown(ctx)
				ctx, _ = context.WithTimeout(context.Background(), time.Minute)
				groupStore.Startup(ctx)
			case <-shutdownChan:
				ctx, _ := context.WithTimeout(context.Background(), time.Minute)
				groupStore.Shutdown(ctx)
				waitGroup.Done()
				return
			}
		}
	}()
	ctx, _ := context.WithTimeout(context.Background(), time.Minute)
	if err = groupStore.Startup(ctx); err != nil {
		ctx, _ = context.WithTimeout(context.Background(), time.Minute)
		groupStore.Shutdown(ctx)
		panic(err)
	}

	valueStore, valueStoreRestartChan, err := server.NewValueStore(&server.ValueStoreConfig{
		GRPCAddressIndex: ADDR_VALUE_GRPC,
		ReplAddressIndex: ADDR_VALUE_REPL,
		CertFile:         "/etc/cfsd/cert.pem",
		KeyFile:          "/etc/cfsd/cert-key.pem",
		CAFile:           "/etc/cfsd/ca.pem",
		Scale:            0.4,
		Path:             "/mnt/cfsd",
		Ring:             oneRing,
	})
	waitGroup.Add(1)
	go func() {
		for {
			select {
			case <-valueStoreRestartChan:
				ctx, _ := context.WithTimeout(context.Background(), time.Minute)
				valueStore.Shutdown(ctx)
				ctx, _ = context.WithTimeout(context.Background(), time.Minute)
				valueStore.Startup(ctx)
			case <-shutdownChan:
				ctx, _ := context.WithTimeout(context.Background(), time.Minute)
				valueStore.Shutdown(ctx)
				waitGroup.Done()
				return
			}
		}
	}()
	ctx, _ = context.WithTimeout(context.Background(), time.Minute)
	if err = valueStore.Startup(ctx); err != nil {
		ctx, _ = context.WithTimeout(context.Background(), time.Minute)
		valueStore.Shutdown(ctx)
		panic(err)
	}

	ch := make(chan os.Signal)
	signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
	waitGroup.Add(1)
	go func() {
		for {
			select {
			case <-ch:
				fmt.Println("Shutting down due to signal")
				close(shutdownChan)
				waitGroup.Done()
				return
			case <-shutdownChan:
				waitGroup.Done()
				return
			}
		}
	}()

	fmt.Println("Done launching components")
	waitGroup.Wait()
}
<|endoftext|>


<commit_before>package fweight

import (
	"compress/flate"
	"compress/gzip"
	"io"
	"net/http"
	"strings"
)

type Extension interface {
	TransformRequest(rw http.ResponseWriter,
		rq *http.Request) (http.ResponseWriter, *http.Request)
}

type RequestCompleteHooker interface {
	RequestCompleted(rw http.ResponseWriter, rq *http.Request)
}

type IgnorePort struct {
}

func (i IgnorePort) TransformRequest(rw http.ResponseWriter, rq *http.Request) (http.ResponseWriter, *http.Request) {
	if spl := strings.SplitN(rq.Host, ":", 2); len(spl) > 1 {
		rq.Host = spl[0]
	}
	return rw, rq
}

type Compression struct {
	compressor
}

func (c Compression) RequestCompleted(rw http.ResponseWriter, rq *http.Request) {
	rw.(compressionWrap).Close()
}

type compressor interface {
	io.Writer
	Close() error
	Flush() error
}

type compressionWrap struct {
	rw         http.ResponseWriter
	compressor compressor
}

func (c compressionWrap) Close() {
	c.compressor.Flush()
	c.compressor.Close()
}

func (c compressionWrap) Write(b []byte) (n int, err error) {

	var bt = b
	var cnt int = 0
	for ; cnt < len(b); bt = bt[cnt:] {
		var thisW int
		thisW, err = c.compressor.Write(bt)
		cnt += thisW
		if err != nil {
			return cnt, err
		}
	}

	return cnt, err
}

func (c compressionWrap) Header() http.Header {
	return c.rw.Header()
}

func (c compressionWrap) WriteHeader(an int) {
	c.rw.WriteHeader(an)
}

func (c Compression) TransformRequest(rw http.ResponseWriter, rq *http.Request) (http.ResponseWriter, *http.Request) {
	if ae := rq.Header.Get("Accept-Encoding"); ae == "" {
		return rw, rq
	} else {
		var compressor compressor
		for _, encoding := range strings.Split(strings.ToLower(ae), ",") {
			switch encoding {
			case "gzip":
				compressor = gzip.NewWriter(rw)
				rw.Header().Set("Content-Encoding", "gzip")
			case "deflate":
				var err error
				compressor, err = flate.NewWriter(rw, -1)
				if err != nil {
					compressor = nil
				} else {
					rw.Header().Set("Content-Encoding", "deflate")
				}
			}
			if compressor != nil {
				c.compressor = compressor
				return compressionWrap{rw, compressor}, rq
			}
		}
	}

	return rw, rq
}
<commit_msg>Fixed bug in compression that would cause a nil pointer dereference<commit_after>package fweight

import (
	"compress/flate"
	"compress/gzip"
	"io"
	"net/http"
	"strings"
)

type Extension interface {
	TransformRequest(rw http.ResponseWriter,
		rq *http.Request) (http.ResponseWriter, *http.Request)
}

type RequestCompleteHooker interface {
	RequestCompleted(rw http.ResponseWriter, rq *http.Request)
}

type IgnorePort struct {
}

func (i IgnorePort) TransformRequest(rw http.ResponseWriter, rq *http.Request) (http.ResponseWriter, *http.Request) {
	if spl := strings.SplitN(rq.Host, ":", 2); len(spl) > 1 {
		rq.Host = spl[0]
	}
	return rw, rq
}

type Compression struct {
	compressor
}

func (c Compression) RequestCompleted(rw http.ResponseWriter, rq *http.Request) {
	if l, ok := rw.(compressionWrap); ok{
		l.Close()
	}
}

type compressor interface {
	io.Writer
	Close() error
	Flush() error
}

type compressionWrap struct {
	rw         http.ResponseWriter
	compressor compressor
}

func (c compressionWrap) Close() {
	if c.compressor != nil {
		c.compressor.Flush()
		c.compressor.Close()
	}
}

func (c compressionWrap) Write(b []byte) (n int, err error) {

	var bt = b
	var cnt int = 0
	for ; cnt < len(b); bt = bt[cnt:] {
		var thisW int
		thisW, err = c.compressor.Write(bt)
		cnt += thisW
		if err != nil {
			return cnt, err
		}
	}

	return cnt, err
}

func (c compressionWrap) Header() http.Header {
	return c.rw.Header()
}

func (c compressionWrap) WriteHeader(an int) {
	c.rw.WriteHeader(an)
}

func (c Compression) TransformRequest(rw http.ResponseWriter, rq *http.Request) (http.ResponseWriter, *http.Request) {
	if ae := rq.Header.Get("Accept-Encoding"); ae == "" {
		return rw, rq
	} else {
		var compressor compressor
		for _, encoding := range strings.Split(strings.ToLower(ae), ",") {
			switch encoding {
			case "gzip":
				compressor = gzip.NewWriter(rw)
				rw.Header().Set("Content-Encoding", "gzip")
			case "deflate":
				var err error
				compressor, err = flate.NewWriter(rw, -1)
				if err != nil {
					compressor = nil
				} else {
					rw.Header().Set("Content-Encoding", "deflate")
				}
			}
			if compressor != nil {
				c.compressor = compressor
				return compressionWrap{rw, compressor}, rq
			}
		}
	}

	return rw, rq
}
<|endoftext|>


<commit_before>package file

import (
	"bufio"
	"github.com/luopengift/golibs/logger"
	"io"
	"os"
	"strings"
	"time"
)

type Tail struct {
	*File
	cname    string //config name
	line     chan *string
	reader   *bufio.Reader
	interval int64
}

func NewTail(cname string) *Tail {
	name := HandlerRule(cname)
	file := NewFile(name, os.O_RDONLY)
	return &Tail{
		file,
		cname,
		make(chan *string),
		bufio.NewReader(file.fd),
		1000, //ms
	}
}

func (self *Tail) ReOpen() {
	time.Sleep(time.Duration(self.interval) * time.Millisecond)
	if err := self.Close(); err != nil {
		logger.Error("<file %v close fail:%v>", self.name, err)
	}
	self.name = HandlerRule(self.cname)
	err := self.Open()
	if err != nil {
		return
	}
	self.reader = bufio.NewReader(self.fd)
}

func (self *Tail) Stop() {
	self.Close()
	close(self.line)
}

func (self *Tail) ReadLine() {
	go func() {
		for {
			line, err := self.reader.ReadString('\n')
			switch {
			case err == io.EOF:
				if self.name == self.cname {
					if inode, err := Inode(self.name); err != nil { //检测是否需要重新打开新的文件
						continue
					} else {
						if inode != self.inode {
							self.ReOpen()
						}
					}
				} else {
					if self.name == HandlerRule(self.cname) { //检测是否需要按时间轮转新文件
						continue
					} else {
						self.ReOpen()
					}
				}

			case err != nil && err != io.EOF:
				logger.Error("<Read file error:%v,%v>", line, err)
				self.ReOpen()
				continue
			default:
				msg := strings.TrimRight(line, "\n")
				self.line <- &msg
			}
		}
	}()
}

func (self *Tail) NextLine() chan *string {
	return self.line
}

func (self *Tail) Offset() int64 {
	offset, _ := self.fd.Seek(0, os.SEEK_CUR)
	return offset
}
<commit_msg>fix cpu 100% when the stat is end of file<commit_after>package file

import (
	"bufio"
	"github.com/luopengift/golibs/logger"
	"io"
	"os"
	"strings"
	"time"
)

type Tail struct {
	*File
	cname    string //config name
	line     chan *string
	reader   *bufio.Reader
	interval int64
}

func NewTail(cname string) *Tail {
	name := HandlerRule(cname)
	file := NewFile(name, os.O_RDONLY)
	return &Tail{
		file,
		cname,
		make(chan *string),
		bufio.NewReader(file.fd),
		1000, //ms
	}
}

func (self *Tail) ReOpen() {
	time.Sleep(time.Duration(self.interval) * time.Millisecond)
	if err := self.Close(); err != nil {
		logger.Error("<file %v close fail:%v>", self.name, err)
	}
	self.name = HandlerRule(self.cname)
	err := self.Open()
	if err != nil {
		return
	}
	self.reader = bufio.NewReader(self.fd)
}

func (self *Tail) Stop() {
	self.Close()
	close(self.line)
}

func (self *Tail) ReadLine() {
	go func() {
		for {
			line, err := self.reader.ReadString('\n')
			switch {
			case err == io.EOF:
	            time.Sleep(time.Duration(self.interval) * time.Millisecond)
				if self.name == self.cname {
					if inode, err := Inode(self.name); err != nil { //检测是否需要重新打开新的文件
						continue
					} else {
						if inode != self.inode {
							self.ReOpen()
						}
					}
				} else {
					if self.name == HandlerRule(self.cname) { //检测是否需要按时间轮转新文件
						continue
					} else {
						self.ReOpen()
					}
				}

			case err != nil && err != io.EOF:
				logger.Error("<Read file error:%v,%v>", line, err)
				self.ReOpen()
				continue
			default:
				msg := strings.TrimRight(line, "\n")
				self.line <- &msg
			}
		}
	}()
}

func (self *Tail) NextLine() chan *string {
	return self.line
}

func (self *Tail) Offset() int64 {
	offset, _ := self.fd.Seek(0, os.SEEK_CUR)
	return offset
}
<|endoftext|>


<commit_before>// File operations. Retrieve players from csv

package main

import (
	"encoding/csv"
	"os"
	"strconv"

	"github.com/topher200/baseutil"
)

func ParsePlayers(inputFilename string) []Player {
	// Open our input Players file
	file, err := os.Open(inputFilename)
	baseutil.Check(err)
	defer file.Close()

	// Read in our csv. Throw away the header. Because we're getting our input
	// directly from the league signup form, we expect the input to be shaped like
	// this:
	// Field 3: First name
	// Field 4: Last name
	// Field 8: "Male" or "Female"
	// Field 38: Rating
	playersCsv := csv.NewReader(file)
	_, err = playersCsv.Read()
	baseutil.Check(err)

	// Read in all players
	playersCsvLines, err := playersCsv.ReadAll()
	baseutil.Check(err)
	players := make([]Player, len(playersCsvLines))
	for i, player := range playersCsvLines {
		firstName := player[3]
		lastName := player[4]
		gender, err := StringToGender(player[8])
		baseutil.Check(err)
		rating, err := strconv.ParseFloat(player[38], 32)
		baseutil.Check(err)
		players[i] = Player{
			Name{firstName, lastName}, float32(rating), gender, uint8(0), Name{}}
	}
	return players
}

// ParseBaggages has the side effect of setting the .baggage for all Players
func ParseBaggages(inputFilename string, players []Player) {
	// Read in our csv. Throw away the header. We expect this format:
	// Field 0: Player 1 First Name
	// Field 1: Player 1 Last Name
	// Field 2: Player 2 First Name
	// Field 3: Player 2 Last Name
	file, err := os.Open(inputFilename)
	baseutil.Check(err)
	defer file.Close()
	baggagesCsv := csv.NewReader(file)
	_, err = baggagesCsv.Read()
	baseutil.Check(err)

	baggagesCsvLines, err := baggagesCsv.ReadAll()
	baseutil.Check(err)
	for _, baggage := range baggagesCsvLines {
		playerPointer, err := FindPlayer(players, Name{baggage[0], baggage[1]})
		baseutil.Check(err)
		if playerPointer.HasBaggage() {
			newLog.Panicf("Player %v already has baggage %v",
				*playerPointer, playerPointer.baggage)
		}
		playerPointer.baggage = Name{baggage[2], baggage[3]}
		newLog.Info("Found baggage of %v for %v",
			playerPointer.baggage, playerPointer.String())
	}
}
<commit_msg>use header to find csv values<commit_after>// File operations. Retrieve players from csv

package main

import (
	"encoding/csv"
	"os"
	"strconv"

	"github.com/topher200/baseutil"
)

func ParsePlayers(inputFilename string) []Player {
	// Open our input Players file
	file, err := os.Open(inputFilename)
	baseutil.Check(err)
	defer file.Close()

	// Read in our csv. Throw away the header. Because we're getting our input
	// directly from the league signup form, we expect the input to be shaped like
	// this:
	// Field 3: First name
	// Field 4: Last name
	// Field 8: "Male" or "Female"
	// Field 38: Rating
	playersCsv := csv.NewReader(file)
	columnNames, err := playersCsv.Read()
	baseutil.Check(err)

	// Read in all players
	playersCsvLines, err := playersCsv.ReadAll()
	baseutil.Check(err)
	players := make([]Player, len(playersCsvLines))
	rows := make([]map[string]string, len(playersCsvLines))
	for rowNum, row := range playersCsvLines {
		rows[rowNum] = make(map[string]string)
		for columnNum, value := range row {
			if value == "" {
				continue
			}
			rows[rowNum][columnNames[columnNum]] = value
		}
	}

	for i, row := range rows {
		firstName := row["firstname"]
		lastName := row["lastname"]
		gender, err := StringToGender(row["gender"])
		baseutil.Check(err)
		rating, err := strconv.ParseFloat(row["rating"], 32)
		baseutil.Check(err)
		players[i] = Player{
			Name{firstName, lastName}, float32(rating), gender, uint8(0), Name{}}
	}
	return players
}

// ParseBaggages has the side effect of setting the .baggage for all Players
func ParseBaggages(inputFilename string, players []Player) {
	// Read in our csv. Throw away the header. We expect this format:
	// Field 0: Player 1 First Name
	// Field 1: Player 1 Last Name
	// Field 2: Player 2 First Name
	// Field 3: Player 2 Last Name
	file, err := os.Open(inputFilename)
	baseutil.Check(err)
	defer file.Close()
	baggagesCsv := csv.NewReader(file)
	_, err = baggagesCsv.Read()
	baseutil.Check(err)

	baggagesCsvLines, err := baggagesCsv.ReadAll()
	baseutil.Check(err)
	for _, baggage := range baggagesCsvLines {
		playerPointer, err := FindPlayer(players, Name{baggage[0], baggage[1]})
		baseutil.Check(err)
		if playerPointer.HasBaggage() {
			newLog.Panicf("Player %v already has baggage %v",
				*playerPointer, playerPointer.baggage)
		}
		playerPointer.baggage = Name{baggage[2], baggage[3]}
		newLog.Info("Found baggage of %v for %v",
			playerPointer.baggage, playerPointer.String())
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
)

const VERSION = "0.0.27"

func main() {
	// XXX (reed): normalize
	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.7", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	g, err := lb.NewAllGrouper(conf)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	h := lb.NewProxy(k, g, r, conf)
	h = g.Wrap(h) // add/del/list endpoints
	h = r.Wrap(h) // stats / dash endpoint

	err = serve(conf.Listen, h)
	if err != nil {
		logrus.WithError(err).Fatal("server error")
	}
}

func serve(addr string, handler http.Handler) error {
	server := &http.Server{Addr: addr, Handler: handler}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)
	go func() {
		for sig := range ch {
			logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")
			server.Shutdown(context.Background()) // safe shutdown
			return
		}
	}()
	return server.ListenAndServe()
}
<commit_msg>fnlb: 0.0.28 release [skip ci]<commit_after>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
)

const VERSION = "0.0.28"

func main() {
	// XXX (reed): normalize
	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.7", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	g, err := lb.NewAllGrouper(conf)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	h := lb.NewProxy(k, g, r, conf)
	h = g.Wrap(h) // add/del/list endpoints
	h = r.Wrap(h) // stats / dash endpoint

	err = serve(conf.Listen, h)
	if err != nil {
		logrus.WithError(err).Fatal("server error")
	}
}

func serve(addr string, handler http.Handler) error {
	server := &http.Server{Addr: addr, Handler: handler}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)
	go func() {
		for sig := range ch {
			logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")
			server.Shutdown(context.Background()) // safe shutdown
			return
		}
	}()
	return server.ListenAndServe()
}
<|endoftext|>