<commit_before>package kv

import (
	"bytes"
	"encoding/hex"
	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/pkg/errors"

	wire "github.com/tendermint/go-wire"
	cmn "github.com/tendermint/tmlibs/common"
	dbm "github.com/tendermint/tmlibs/db"
	"github.com/tendermint/tmlibs/pubsub/query"

	"github.com/tendermint/tendermint/state/txindex"
	"github.com/tendermint/tendermint/types"
)

const (
	tagKeySeparator = "/"
)

var _ txindex.TxIndexer = (*TxIndex)(nil)

// TxIndex is the simplest possible indexer, backed by key-value storage (levelDB).
type TxIndex struct {
	store        dbm.DB
	tagsToIndex  []string
	indexAllTags bool
}

// NewTxIndex creates new KV indexer.
func NewTxIndex(store dbm.DB, options ...func(*TxIndex)) *TxIndex {
	txi := &TxIndex{store: store, tagsToIndex: make([]string, 0), indexAllTags: false}
	for _, o := range options {
		o(txi)
	}
	return txi
}

// IndexTags is an option for setting which tags to index.
func IndexTags(tags []string) func(*TxIndex) {
	return func(txi *TxIndex) {
		txi.tagsToIndex = tags
	}
}

// IndexAllTags is an option for indexing all tags.
func IndexAllTags() func(*TxIndex) {
	return func(txi *TxIndex) {
		txi.indexAllTags = true
	}
}

// Get gets transaction from the TxIndex storage and returns it or nil if the
// transaction is not found.
func (txi *TxIndex) Get(hash []byte) (*types.TxResult, error) {
	if len(hash) == 0 {
		return nil, txindex.ErrorEmptyHash
	}

	rawBytes := txi.store.Get(hash)
	if rawBytes == nil {
		return nil, nil
	}

	txResult := new(types.TxResult)
	err := wire.UnmarshalBinary(rawBytes, &txResult)
	if err != nil {
		return nil, fmt.Errorf("Error reading TxResult: %v", err)
	}

	return txResult, nil
}

// AddBatch indexes a batch of transactions using the given list of tags.
func (txi *TxIndex) AddBatch(b *txindex.Batch) error {
	storeBatch := txi.store.NewBatch()

	for _, result := range b.Ops {
		hash := result.Tx.Hash()

		// index tx by tags
		for _, tag := range result.Result.Tags {
			if txi.indexAllTags || cmn.StringInSlice(string(tag.Key), txi.tagsToIndex) {
				storeBatch.Set(keyForTag(tag, result), hash)
			}
		}

		// index tx by hash
		rawBytes, err := wire.MarshalBinary(result)
		if err != nil {
			return err
		}
		storeBatch.Set(hash, rawBytes)
	}

	storeBatch.Write()
	return nil
}

// Index indexes a single transaction using the given list of tags.
func (txi *TxIndex) Index(result *types.TxResult) error {
	b := txi.store.NewBatch()

	hash := result.Tx.Hash()

	// index tx by tags
	for _, tag := range result.Result.Tags {
		if txi.indexAllTags || cmn.StringInSlice(string(tag.Key), txi.tagsToIndex) {
			b.Set(keyForTag(tag, result), hash)
		}
	}

	// index tx by hash
	rawBytes, err := wire.MarshalBinary(result)
	if err != nil {
		return err
	}
	b.Set(hash, rawBytes)

	b.Write()
	return nil
}

// Search performs a search using the given query. It breaks the query into
// conditions (like "tx.height > 5"). For each condition, it queries the DB
// index. One special use cases here: (1) if "tx.hash" is found, it returns tx
// result for it (2) for range queries it is better for the client to provide
// both lower and upper bounds, so we are not performing a full scan. Results
// from querying indexes are then intersected and returned to the caller.
func (txi *TxIndex) Search(q *query.Query) ([]*types.TxResult, error) {
	var hashes [][]byte
	var hashesInitialized bool

	// get a list of conditions (like "tx.height > 5")
	conditions := q.Conditions()

	// if there is a hash condition, return the result immediately
	hash, err, ok := lookForHash(conditions)
	if err != nil {
		return nil, errors.Wrap(err, "error during searching for a hash in the query")
	} else if ok {
		res, err := txi.Get(hash)
		if res == nil {
			return []*types.TxResult{}, nil
		} else {
			return []*types.TxResult{res}, errors.Wrap(err, "error while retrieving the result")
		}
	}

	// conditions to skip because they're handled before "everything else"
	skipIndexes := make([]int, 0)

	// if there is a height condition ("tx.height=3"), extract it for faster lookups
	height, heightIndex := lookForHeight(conditions)
	if heightIndex >= 0 {
		skipIndexes = append(skipIndexes, heightIndex)
	}

	// extract ranges
	// if both upper and lower bounds exist, it's better to get them in order not
	// no iterate over kvs that are not within range.
	ranges, rangeIndexes := lookForRanges(conditions)
	if len(ranges) > 0 {
		skipIndexes = append(skipIndexes, rangeIndexes...)

		for _, r := range ranges {
			if !hashesInitialized {
				hashes = txi.matchRange(r, startKeyForRange(r, height))
				hashesInitialized = true
			} else {
				hashes = intersect(hashes, txi.matchRange(r, startKeyForRange(r, height)))
			}
		}
	}

	// for all other conditions
	for i, c := range conditions {
		if cmn.IntInSlice(i, skipIndexes) {
			continue
		}

		if !hashesInitialized {
			hashes = txi.match(c, startKey(c, height))
			hashesInitialized = true
		} else {
			hashes = intersect(hashes, txi.match(c, startKey(c, height)))
		}
	}

	results := make([]*types.TxResult, len(hashes))
	i := 0
	for _, h := range hashes {
		results[i], err = txi.Get(h)
		if err != nil {
			return nil, errors.Wrapf(err, "failed to get Tx{%X}", h)
		}
		i++
	}

	return results, nil
}

func lookForHash(conditions []query.Condition) (hash []byte, err error, ok bool) {
	for _, c := range conditions {
		if c.Tag == types.TxHashKey {
			decoded, err := hex.DecodeString(c.Operand.(string))
			return decoded, err, true
		}
	}
	return
}

func lookForHeight(conditions []query.Condition) (height int64, index int) {
	for i, c := range conditions {
		if c.Tag == types.TxHeightKey {
			return c.Operand.(int64), i
		}
	}
	return 0, -1
}

// special map to hold range conditions
// Example: account.number => queryRange{lowerBound: 1, upperBound: 5}
type queryRanges map[string]queryRange

type queryRange struct {
	key               string
	lowerBound        interface{} // int || time.Time
	includeLowerBound bool
	upperBound        interface{} // int || time.Time
	includeUpperBound bool
}

func lookForRanges(conditions []query.Condition) (ranges queryRanges, indexes []int) {
	ranges = make(queryRanges)
	for i, c := range conditions {
		if isRangeOperation(c.Op) {
			r, ok := ranges[c.Tag]
			if !ok {
				r = queryRange{key: c.Tag}
			}
			switch c.Op {
			case query.OpGreater:
				r.lowerBound = c.Operand
			case query.OpGreaterEqual:
				r.includeLowerBound = true
				r.lowerBound = c.Operand
			case query.OpLess:
				r.upperBound = c.Operand
			case query.OpLessEqual:
				r.includeUpperBound = true
				r.upperBound = c.Operand
			}
			ranges[c.Tag] = r
			indexes = append(indexes, i)
		}
	}
	return ranges, indexes
}

func isRangeOperation(op query.Operator) bool {
	switch op {
	case query.OpGreater, query.OpGreaterEqual, query.OpLess, query.OpLessEqual:
		return true
	default:
		return false
	}
}

func (txi *TxIndex) match(c query.Condition, startKey []byte) (hashes [][]byte) {
	if c.Op == query.OpEqual {
		it := dbm.IteratePrefix(txi.store, startKey)
		defer it.Close()
		for ; it.Valid(); it.Next() {
			hashes = append(hashes, it.Value())
		}
	} else if c.Op == query.OpContains {
		// XXX: doing full scan because startKey does not apply here
		// For example, if startKey = "account.owner=an" and search query = "accoutn.owner CONSISTS an"
		// we can't iterate with prefix "account.owner=an" because we might miss keys like "account.owner=Ulan"
		it := txi.store.Iterator(nil, nil)
		defer it.Close()
		for ; it.Valid(); it.Next() {
			if !isTagKey(it.Key()) {
				continue
			}
			if strings.Contains(extractValueFromKey(it.Key()), c.Operand.(string)) {
				hashes = append(hashes, it.Value())
			}
		}
	} else {
		panic("other operators should be handled already")
	}
	return
}

func (txi *TxIndex) matchRange(r queryRange, startKey []byte) (hashes [][]byte) {
	it := dbm.IteratePrefix(txi.store, startKey)
	defer it.Close()
LOOP:
	for ; it.Valid(); it.Next() {
		if !isTagKey(it.Key()) {
			continue
		}
		if r.upperBound != nil {
			// no other way to stop iterator other than checking for upperBound
			switch (r.upperBound).(type) {
			case int64:
				v, err := strconv.ParseInt(extractValueFromKey(it.Key()), 10, 64)
				if err == nil && v == r.upperBound {
					if r.includeUpperBound {
						hashes = append(hashes, it.Value())
					}
					break LOOP
				}
				// XXX: passing time in a ABCI Tags is not yet implemented
				// case time.Time:
				// 	v := strconv.ParseInt(extractValueFromKey(it.Key()), 10, 64)
				// 	if v == r.upperBound {
				// 		break
				// 	}
			}
		}
		hashes = append(hashes, it.Value())
	}
	return
}

///////////////////////////////////////////////////////////////////////////////
// Keys

func startKey(c query.Condition, height int64) []byte {
	var key string
	if height > 0 {
		key = fmt.Sprintf("%s/%v/%d", c.Tag, c.Operand, height)
	} else {
		key = fmt.Sprintf("%s/%v", c.Tag, c.Operand)
	}
	return []byte(key)
}

func startKeyForRange(r queryRange, height int64) []byte {
	if r.lowerBound == nil {
		return []byte(r.key)
	}

	var lowerBound interface{}
	if r.includeLowerBound {
		lowerBound = r.lowerBound
	} else {
		switch t := r.lowerBound.(type) {
		case int64:
			lowerBound = t + 1
		case time.Time:
			lowerBound = t.Unix() + 1
		default:
			panic("not implemented")
		}
	}
	var key string
	if height > 0 {
		key = fmt.Sprintf("%s/%v/%d", r.key, lowerBound, height)
	} else {
		key = fmt.Sprintf("%s/%v", r.key, lowerBound)
	}
	return []byte(key)
}

func isTagKey(key []byte) bool {
	return strings.Count(string(key), tagKeySeparator) == 3
}

func extractValueFromKey(key []byte) string {
	parts := strings.SplitN(string(key), tagKeySeparator, 3)
	return parts[1]
}

func keyForTag(tag cmn.KVPair, result *types.TxResult) []byte {
	return []byte(fmt.Sprintf("%s/%s/%d/%d", tag.Key, tag.Value, result.Height, result.Index))
}

///////////////////////////////////////////////////////////////////////////////
// Utils

func intersect(as, bs [][]byte) [][]byte {
	i := make([][]byte, 0, cmn.MinInt(len(as), len(bs)))
	for _, a := range as {
		for _, b := range bs {
			if bytes.Equal(a, b) {
				i = append(i, a)
			}
		}
	}
	return i
}
<commit_msg>sort /tx_search results by height by default<commit_after>package kv

import (
	"bytes"
	"encoding/hex"
	"fmt"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/pkg/errors"

	wire "github.com/tendermint/go-wire"
	cmn "github.com/tendermint/tmlibs/common"
	dbm "github.com/tendermint/tmlibs/db"
	"github.com/tendermint/tmlibs/pubsub/query"

	"github.com/tendermint/tendermint/state/txindex"
	"github.com/tendermint/tendermint/types"
)

const (
	tagKeySeparator = "/"
)

var _ txindex.TxIndexer = (*TxIndex)(nil)

// TxIndex is the simplest possible indexer, backed by key-value storage (levelDB).
type TxIndex struct {
	store        dbm.DB
	tagsToIndex  []string
	indexAllTags bool
}

// NewTxIndex creates new KV indexer.
func NewTxIndex(store dbm.DB, options ...func(*TxIndex)) *TxIndex {
	txi := &TxIndex{store: store, tagsToIndex: make([]string, 0), indexAllTags: false}
	for _, o := range options {
		o(txi)
	}
	return txi
}

// IndexTags is an option for setting which tags to index.
func IndexTags(tags []string) func(*TxIndex) {
	return func(txi *TxIndex) {
		txi.tagsToIndex = tags
	}
}

// IndexAllTags is an option for indexing all tags.
func IndexAllTags() func(*TxIndex) {
	return func(txi *TxIndex) {
		txi.indexAllTags = true
	}
}

// Get gets transaction from the TxIndex storage and returns it or nil if the
// transaction is not found.
func (txi *TxIndex) Get(hash []byte) (*types.TxResult, error) {
	if len(hash) == 0 {
		return nil, txindex.ErrorEmptyHash
	}

	rawBytes := txi.store.Get(hash)
	if rawBytes == nil {
		return nil, nil
	}

	txResult := new(types.TxResult)
	err := wire.UnmarshalBinary(rawBytes, &txResult)
	if err != nil {
		return nil, fmt.Errorf("Error reading TxResult: %v", err)
	}

	return txResult, nil
}

// AddBatch indexes a batch of transactions using the given list of tags.
func (txi *TxIndex) AddBatch(b *txindex.Batch) error {
	storeBatch := txi.store.NewBatch()

	for _, result := range b.Ops {
		hash := result.Tx.Hash()

		// index tx by tags
		for _, tag := range result.Result.Tags {
			if txi.indexAllTags || cmn.StringInSlice(string(tag.Key), txi.tagsToIndex) {
				storeBatch.Set(keyForTag(tag, result), hash)
			}
		}

		// index tx by hash
		rawBytes, err := wire.MarshalBinary(result)
		if err != nil {
			return err
		}
		storeBatch.Set(hash, rawBytes)
	}

	storeBatch.Write()
	return nil
}

// Index indexes a single transaction using the given list of tags.
func (txi *TxIndex) Index(result *types.TxResult) error {
	b := txi.store.NewBatch()

	hash := result.Tx.Hash()

	// index tx by tags
	for _, tag := range result.Result.Tags {
		if txi.indexAllTags || cmn.StringInSlice(string(tag.Key), txi.tagsToIndex) {
			b.Set(keyForTag(tag, result), hash)
		}
	}

	// index tx by hash
	rawBytes, err := wire.MarshalBinary(result)
	if err != nil {
		return err
	}
	b.Set(hash, rawBytes)

	b.Write()
	return nil
}

// Search performs a search using the given query. It breaks the query into
// conditions (like "tx.height > 5"). For each condition, it queries the DB
// index. One special use cases here: (1) if "tx.hash" is found, it returns tx
// result for it (2) for range queries it is better for the client to provide
// both lower and upper bounds, so we are not performing a full scan. Results
// from querying indexes are then intersected and returned to the caller.
func (txi *TxIndex) Search(q *query.Query) ([]*types.TxResult, error) {
	var hashes [][]byte
	var hashesInitialized bool

	// get a list of conditions (like "tx.height > 5")
	conditions := q.Conditions()

	// if there is a hash condition, return the result immediately
	hash, err, ok := lookForHash(conditions)
	if err != nil {
		return nil, errors.Wrap(err, "error during searching for a hash in the query")
	} else if ok {
		res, err := txi.Get(hash)
		if res == nil {
			return []*types.TxResult{}, nil
		} else {
			return []*types.TxResult{res}, errors.Wrap(err, "error while retrieving the result")
		}
	}

	// conditions to skip because they're handled before "everything else"
	skipIndexes := make([]int, 0)

	// if there is a height condition ("tx.height=3"), extract it for faster lookups
	height, heightIndex := lookForHeight(conditions)
	if heightIndex >= 0 {
		skipIndexes = append(skipIndexes, heightIndex)
	}

	// extract ranges
	// if both upper and lower bounds exist, it's better to get them in order not
	// no iterate over kvs that are not within range.
	ranges, rangeIndexes := lookForRanges(conditions)
	if len(ranges) > 0 {
		skipIndexes = append(skipIndexes, rangeIndexes...)

		for _, r := range ranges {
			if !hashesInitialized {
				hashes = txi.matchRange(r, startKeyForRange(r, height))
				hashesInitialized = true
			} else {
				hashes = intersect(hashes, txi.matchRange(r, startKeyForRange(r, height)))
			}
		}
	}

	// for all other conditions
	for i, c := range conditions {
		if cmn.IntInSlice(i, skipIndexes) {
			continue
		}

		if !hashesInitialized {
			hashes = txi.match(c, startKey(c, height))
			hashesInitialized = true
		} else {
			hashes = intersect(hashes, txi.match(c, startKey(c, height)))
		}
	}

	results := make([]*types.TxResult, len(hashes))
	i := 0
	for _, h := range hashes {
		results[i], err = txi.Get(h)
		if err != nil {
			return nil, errors.Wrapf(err, "failed to get Tx{%X}", h)
		}
		i++
	}

	// sort by height by default
	sort.Slice(results, func(i, j int) bool {
		return results[i].Height < results[j].Height
	})

	return results, nil
}

func lookForHash(conditions []query.Condition) (hash []byte, err error, ok bool) {
	for _, c := range conditions {
		if c.Tag == types.TxHashKey {
			decoded, err := hex.DecodeString(c.Operand.(string))
			return decoded, err, true
		}
	}
	return
}

func lookForHeight(conditions []query.Condition) (height int64, index int) {
	for i, c := range conditions {
		if c.Tag == types.TxHeightKey {
			return c.Operand.(int64), i
		}
	}
	return 0, -1
}

// special map to hold range conditions
// Example: account.number => queryRange{lowerBound: 1, upperBound: 5}
type queryRanges map[string]queryRange

type queryRange struct {
	key               string
	lowerBound        interface{} // int || time.Time
	includeLowerBound bool
	upperBound        interface{} // int || time.Time
	includeUpperBound bool
}

func lookForRanges(conditions []query.Condition) (ranges queryRanges, indexes []int) {
	ranges = make(queryRanges)
	for i, c := range conditions {
		if isRangeOperation(c.Op) {
			r, ok := ranges[c.Tag]
			if !ok {
				r = queryRange{key: c.Tag}
			}
			switch c.Op {
			case query.OpGreater:
				r.lowerBound = c.Operand
			case query.OpGreaterEqual:
				r.includeLowerBound = true
				r.lowerBound = c.Operand
			case query.OpLess:
				r.upperBound = c.Operand
			case query.OpLessEqual:
				r.includeUpperBound = true
				r.upperBound = c.Operand
			}
			ranges[c.Tag] = r
			indexes = append(indexes, i)
		}
	}
	return ranges, indexes
}

func isRangeOperation(op query.Operator) bool {
	switch op {
	case query.OpGreater, query.OpGreaterEqual, query.OpLess, query.OpLessEqual:
		return true
	default:
		return false
	}
}

func (txi *TxIndex) match(c query.Condition, startKey []byte) (hashes [][]byte) {
	if c.Op == query.OpEqual {
		it := dbm.IteratePrefix(txi.store, startKey)
		defer it.Close()
		for ; it.Valid(); it.Next() {
			hashes = append(hashes, it.Value())
		}
	} else if c.Op == query.OpContains {
		// XXX: doing full scan because startKey does not apply here
		// For example, if startKey = "account.owner=an" and search query = "accoutn.owner CONSISTS an"
		// we can't iterate with prefix "account.owner=an" because we might miss keys like "account.owner=Ulan"
		it := txi.store.Iterator(nil, nil)
		defer it.Close()
		for ; it.Valid(); it.Next() {
			if !isTagKey(it.Key()) {
				continue
			}
			if strings.Contains(extractValueFromKey(it.Key()), c.Operand.(string)) {
				hashes = append(hashes, it.Value())
			}
		}
	} else {
		panic("other operators should be handled already")
	}
	return
}

func (txi *TxIndex) matchRange(r queryRange, startKey []byte) (hashes [][]byte) {
	it := dbm.IteratePrefix(txi.store, startKey)
	defer it.Close()
LOOP:
	for ; it.Valid(); it.Next() {
		if !isTagKey(it.Key()) {
			continue
		}
		if r.upperBound != nil {
			// no other way to stop iterator other than checking for upperBound
			switch (r.upperBound).(type) {
			case int64:
				v, err := strconv.ParseInt(extractValueFromKey(it.Key()), 10, 64)
				if err == nil && v == r.upperBound {
					if r.includeUpperBound {
						hashes = append(hashes, it.Value())
					}
					break LOOP
				}
				// XXX: passing time in a ABCI Tags is not yet implemented
				// case time.Time:
				// 	v := strconv.ParseInt(extractValueFromKey(it.Key()), 10, 64)
				// 	if v == r.upperBound {
				// 		break
				// 	}
			}
		}
		hashes = append(hashes, it.Value())
	}
	return
}

///////////////////////////////////////////////////////////////////////////////
// Keys

func startKey(c query.Condition, height int64) []byte {
	var key string
	if height > 0 {
		key = fmt.Sprintf("%s/%v/%d", c.Tag, c.Operand, height)
	} else {
		key = fmt.Sprintf("%s/%v", c.Tag, c.Operand)
	}
	return []byte(key)
}

func startKeyForRange(r queryRange, height int64) []byte {
	if r.lowerBound == nil {
		return []byte(r.key)
	}

	var lowerBound interface{}
	if r.includeLowerBound {
		lowerBound = r.lowerBound
	} else {
		switch t := r.lowerBound.(type) {
		case int64:
			lowerBound = t + 1
		case time.Time:
			lowerBound = t.Unix() + 1
		default:
			panic("not implemented")
		}
	}
	var key string
	if height > 0 {
		key = fmt.Sprintf("%s/%v/%d", r.key, lowerBound, height)
	} else {
		key = fmt.Sprintf("%s/%v", r.key, lowerBound)
	}
	return []byte(key)
}

func isTagKey(key []byte) bool {
	return strings.Count(string(key), tagKeySeparator) == 3
}

func extractValueFromKey(key []byte) string {
	parts := strings.SplitN(string(key), tagKeySeparator, 3)
	return parts[1]
}

func keyForTag(tag cmn.KVPair, result *types.TxResult) []byte {
	return []byte(fmt.Sprintf("%s/%s/%d/%d", tag.Key, tag.Value, result.Height, result.Index))
}

///////////////////////////////////////////////////////////////////////////////
// Utils

func intersect(as, bs [][]byte) [][]byte {
	i := make([][]byte, 0, cmn.MinInt(len(as), len(bs)))
	for _, a := range as {
		for _, b := range bs {
			if bytes.Equal(a, b) {
				i = append(i, a)
			}
		}
	}
	return i
}
<|endoftext|>


<commit_before>package runnice

import (
	"os/exec"
)

type Cmd exec.Cmd

func Command(name string, arg ...string) *Cmd {
	return (*Cmd)(exec.Command(name, arg...))
}

func unwrap(c *Cmd) *exec.Cmd {
	return (*exec.Cmd)(c)
}
<commit_msg>Add doc string<commit_after>// Runs processes with less priority.
package runnice

import (
	"os/exec"
)

type Cmd exec.Cmd

func Command(name string, arg ...string) *Cmd {
	return (*Cmd)(exec.Command(name, arg...))
}

func unwrap(c *Cmd) *exec.Cmd {
	return (*exec.Cmd)(c)
}
<|endoftext|>


<commit_before>package docker

import (
	"container/list"
	"fmt"
	"github.com/dotcloud/docker/auth"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"sort"
	"strings"
	"time"
)

type Capabilities struct {
	MemoryLimit bool
	SwapLimit   bool
}

type Runtime struct {
	root           string
	repository     string
	containers     *list.List
	networkManager *NetworkManager
	graph          *Graph
	repositories   *TagStore
	authConfig     *auth.AuthConfig
	idIndex        *TruncIndex
	capabilities   *Capabilities
	kernelVersion  *KernelVersionInfo
}

var sysInitPath string

func init() {
	sysInitPath = SelfPath()
}

func (runtime *Runtime) List() []*Container {
	containers := new(History)
	for e := runtime.containers.Front(); e != nil; e = e.Next() {
		containers.Add(e.Value.(*Container))
	}
	return *containers
}

func (runtime *Runtime) getContainerElement(id string) *list.Element {
	for e := runtime.containers.Front(); e != nil; e = e.Next() {
		container := e.Value.(*Container)
		if container.Id == id {
			return e
		}
	}
	return nil
}

func (runtime *Runtime) Get(name string) *Container {
	id, err := runtime.idIndex.Get(name)
	if err != nil {
		return nil
	}
	e := runtime.getContainerElement(id)
	if e == nil {
		return nil
	}
	return e.Value.(*Container)
}

func (runtime *Runtime) Exists(id string) bool {
	return runtime.Get(id) != nil
}

func (runtime *Runtime) containerRoot(id string) string {
	return path.Join(runtime.repository, id)
}

func (runtime *Runtime) mergeConfig(userConf, imageConf *Config) {
	if userConf.Hostname != "" {
		userConf.Hostname = imageConf.Hostname
	}
	if userConf.User != "" {
		userConf.User = imageConf.User
	}
	if userConf.Memory == 0 {
		userConf.Memory = imageConf.Memory
	}
	if userConf.MemorySwap == 0 {
		userConf.MemorySwap = imageConf.MemorySwap
	}
	if userConf.PortSpecs == nil || len(userConf.PortSpecs) == 0 {
		userConf.PortSpecs = imageConf.PortSpecs
	}
	if !userConf.Tty {
		userConf.Tty = userConf.Tty
	}
	if !userConf.OpenStdin {
		userConf.OpenStdin = imageConf.OpenStdin
	}
	if !userConf.StdinOnce {
		userConf.StdinOnce = imageConf.StdinOnce
	}
	if userConf.Env == nil || len(userConf.Env) == 0 {
		userConf.Env = imageConf.Env
	}
	if userConf.Cmd == nil || len(userConf.Cmd) == 0 {
		userConf.Cmd = imageConf.Cmd
	}
	if userConf.Dns == nil || len(userConf.Dns) == 0 {
		userConf.Dns = imageConf.Dns
	}
}

func (runtime *Runtime) Create(config *Config) (*Container, error) {

	// Lookup image
	img, err := runtime.repositories.LookupImage(config.Image)
	if err != nil {
		return nil, err
	}

	//runtime.mergeConfig(config, img.Config)
	if img.Config != nil {
		config = img.Config
	}

	if config.Cmd == nil {
		return nil, fmt.Errorf("No command specified")
	}

	// Generate id
	id := GenerateId()
	// Generate default hostname
	// FIXME: the lxc template no longer needs to set a default hostname
	if config.Hostname == "" {
		config.Hostname = id[:12]
	}

	container := &Container{
		// FIXME: we should generate the ID here instead of receiving it as an argument
		Id:              id,
		Created:         time.Now(),
		Path:            config.Cmd[0],
		Args:            config.Cmd[1:], //FIXME: de-duplicate from config
		Config:          config,
		Image:           img.Id, // Always use the resolved image id
		NetworkSettings: &NetworkSettings{},
		// FIXME: do we need to store this in the container?
		SysInitPath: sysInitPath,
	}

	container.root = runtime.containerRoot(container.Id)
	// Step 1: create the container directory.
	// This doubles as a barrier to avoid race conditions.
	if err := os.Mkdir(container.root, 0700); err != nil {
		return nil, err
	}

	// If custom dns exists, then create a resolv.conf for the container
	if len(config.Dns) > 0 {
		container.ResolvConfPath = path.Join(container.root, "resolv.conf")
		f, err := os.Create(container.ResolvConfPath)
		if err != nil {
			return nil, err
		}
		defer f.Close()
		for _, dns := range config.Dns {
			if _, err := f.Write([]byte("nameserver " + dns + "\n")); err != nil {
				return nil, err
			}
		}
	} else {
		container.ResolvConfPath = "/etc/resolv.conf"
	}

	// Step 2: save the container json
	if err := container.ToDisk(); err != nil {
		return nil, err
	}
	// Step 3: register the container
	if err := runtime.Register(container); err != nil {
		return nil, err
	}
	return container, nil
}

func (runtime *Runtime) Load(id string) (*Container, error) {
	container := &Container{root: runtime.containerRoot(id)}
	if err := container.FromDisk(); err != nil {
		return nil, err
	}
	if container.Id != id {
		return container, fmt.Errorf("Container %s is stored at %s", container.Id, id)
	}
	if container.State.Running {
		container.State.Ghost = true
	}
	if err := runtime.Register(container); err != nil {
		return nil, err
	}
	return container, nil
}

// Register makes a container object usable by the runtime as <container.Id>
func (runtime *Runtime) Register(container *Container) error {
	if container.runtime != nil || runtime.Exists(container.Id) {
		return fmt.Errorf("Container is already loaded")
	}
	if err := validateId(container.Id); err != nil {
		return err
	}

	// init the wait lock
	container.waitLock = make(chan struct{})

	// FIXME: if the container is supposed to be running but is not, auto restart it?
	//        if so, then we need to restart monitor and init a new lock
	// If the container is supposed to be running, make sure of it
	if container.State.Running {
		if output, err := exec.Command("lxc-info", "-n", container.Id).CombinedOutput(); err != nil {
			return err
		} else {
			if !strings.Contains(string(output), "RUNNING") {
				Debugf("Container %s was supposed to be running be is not.", container.Id)
				container.State.setStopped(-127)
				if err := container.ToDisk(); err != nil {
					return err
				}
			}
		}
	}

	// Even if not running, we init the lock (prevents races in start/stop/kill)
	container.State.initLock()

	container.runtime = runtime

	// Attach to stdout and stderr
	container.stderr = newWriteBroadcaster()
	container.stdout = newWriteBroadcaster()
	// Attach to stdin
	if container.Config.OpenStdin {
		container.stdin, container.stdinPipe = io.Pipe()
	} else {
		container.stdinPipe = NopWriteCloser(ioutil.Discard) // Silently drop stdin
	}
	// done
	runtime.containers.PushBack(container)
	runtime.idIndex.Add(container.Id)

	// If the container is not running or just has been flagged not running
	// then close the wait lock chan (will be reset upon start)
	if !container.State.Running {
		close(container.waitLock)
	} else {
		container.allocateNetwork()
		go container.monitor()
	}
	return nil
}

func (runtime *Runtime) LogToDisk(src *writeBroadcaster, dst string) error {
	log, err := os.OpenFile(dst, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600)
	if err != nil {
		return err
	}
	src.AddWriter(log)
	return nil
}

func (runtime *Runtime) Destroy(container *Container) error {
	element := runtime.getContainerElement(container.Id)
	if element == nil {
		return fmt.Errorf("Container %v not found - maybe it was already destroyed?", container.Id)
	}

	if err := container.Stop(10); err != nil {
		return err
	}
	if mounted, err := container.Mounted(); err != nil {
		return err
	} else if mounted {
		if err := container.Unmount(); err != nil {
			return fmt.Errorf("Unable to unmount container %v: %v", container.Id, err)
		}
	}
	// Deregister the container before removing its directory, to avoid race conditions
	runtime.idIndex.Delete(container.Id)
	runtime.containers.Remove(element)
	if err := os.RemoveAll(container.root); err != nil {
		return fmt.Errorf("Unable to remove filesystem for %v: %v", container.Id, err)
	}
	return nil
}

// Commit creates a new filesystem image from the current state of a container.
// The image can optionally be tagged into a repository
func (runtime *Runtime) Commit(id, repository, tag, comment, author string, config *Config) (*Image, error) {
	container := runtime.Get(id)
	if container == nil {
		return nil, fmt.Errorf("No such container: %s", id)
	}
	// FIXME: freeze the container before copying it to avoid data corruption?
	// FIXME: this shouldn't be in commands.
	rwTar, err := container.ExportRw()
	if err != nil {
		return nil, err
	}
	// Create a new image from the container's base layers + a new layer from container changes
	img, err := runtime.graph.Create(rwTar, container, comment, author, config)
	if err != nil {
		return nil, err
	}
	// Register the image if needed
	if repository != "" {
		if err := runtime.repositories.Set(repository, tag, img.Id, true); err != nil {
			return img, err
		}
	}
	return img, nil
}

func (runtime *Runtime) restore() error {
	dir, err := ioutil.ReadDir(runtime.repository)
	if err != nil {
		return err
	}
	for _, v := range dir {
		id := v.Name()
		container, err := runtime.Load(id)
		if err != nil {
			Debugf("Failed to load container %v: %v", id, err)
			continue
		}
		Debugf("Loaded container %v", container.Id)
	}
	return nil
}

// FIXME: harmonize with NewGraph()
func NewRuntime() (*Runtime, error) {
	runtime, err := NewRuntimeFromDirectory("/var/lib/docker")
	if err != nil {
		return nil, err
	}

	if k, err := GetKernelVersion(); err != nil {
		log.Printf("WARNING: %s\n", err)
	} else {
		runtime.kernelVersion = k
		if CompareKernelVersion(k, &KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0}) < 0 {
			log.Printf("WARNING: You are running linux kernel version %s, which might be unstable running docker. Please upgrade your kernel to 3.8.0.", k.String())
		}
	}

	if cgroupMemoryMountpoint, err := FindCgroupMountpoint("memory"); err != nil {
		log.Printf("WARNING: %s\n", err)
	} else {
		_, err1 := ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.limit_in_bytes"))
		_, err2 := ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.soft_limit_in_bytes"))
		runtime.capabilities.MemoryLimit = err1 == nil && err2 == nil
		if !runtime.capabilities.MemoryLimit {
			log.Printf("WARNING: Your kernel does not support cgroup memory limit.")
		}

		_, err = ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.memsw.limit_in_bytes"))
		runtime.capabilities.SwapLimit = err == nil
		if !runtime.capabilities.SwapLimit {
			log.Printf("WARNING: Your kernel does not support cgroup swap limit.")
		}
	}
	return runtime, nil
}

func NewRuntimeFromDirectory(root string) (*Runtime, error) {
	runtimeRepo := path.Join(root, "containers")

	if err := os.MkdirAll(runtimeRepo, 0700); err != nil && !os.IsExist(err) {
		return nil, err
	}

	g, err := NewGraph(path.Join(root, "graph"))
	if err != nil {
		return nil, err
	}
	repositories, err := NewTagStore(path.Join(root, "repositories"), g)
	if err != nil {
		return nil, fmt.Errorf("Couldn't create Tag store: %s", err)
	}
	if NetworkBridgeIface == "" {
		NetworkBridgeIface = DefaultNetworkBridge
	}
	netManager, err := newNetworkManager(NetworkBridgeIface)
	if err != nil {
		return nil, err
	}
	authConfig, err := auth.LoadConfig(root)
	if err != nil && authConfig == nil {
		// If the auth file does not exist, keep going
		return nil, err
	}
	runtime := &Runtime{
		root:           root,
		repository:     runtimeRepo,
		containers:     list.New(),
		networkManager: netManager,
		graph:          g,
		repositories:   repositories,
		authConfig:     authConfig,
		idIndex:        NewTruncIndex(),
		capabilities:   &Capabilities{},
	}

	if err := runtime.restore(); err != nil {
		return nil, err
	}
	return runtime, nil
}

type History []*Container

func (history *History) Len() int {
	return len(*history)
}

func (history *History) Less(i, j int) bool {
	containers := *history
	return containers[j].When().Before(containers[i].When())
}

func (history *History) Swap(i, j int) {
	containers := *history
	tmp := containers[i]
	containers[i] = containers[j]
	containers[j] = tmp
}

func (history *History) Add(container *Container) {
	*history = append(*history, container)
	sort.Sort(history)
}
<commit_msg>Actually use the mergeConfig function<commit_after>package docker

import (
	"container/list"
	"fmt"
	"github.com/dotcloud/docker/auth"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"sort"
	"strings"
	"time"
)

type Capabilities struct {
	MemoryLimit bool
	SwapLimit   bool
}

type Runtime struct {
	root           string
	repository     string
	containers     *list.List
	networkManager *NetworkManager
	graph          *Graph
	repositories   *TagStore
	authConfig     *auth.AuthConfig
	idIndex        *TruncIndex
	capabilities   *Capabilities
	kernelVersion  *KernelVersionInfo
}

var sysInitPath string

func init() {
	sysInitPath = SelfPath()
}

func (runtime *Runtime) List() []*Container {
	containers := new(History)
	for e := runtime.containers.Front(); e != nil; e = e.Next() {
		containers.Add(e.Value.(*Container))
	}
	return *containers
}

func (runtime *Runtime) getContainerElement(id string) *list.Element {
	for e := runtime.containers.Front(); e != nil; e = e.Next() {
		container := e.Value.(*Container)
		if container.Id == id {
			return e
		}
	}
	return nil
}

func (runtime *Runtime) Get(name string) *Container {
	id, err := runtime.idIndex.Get(name)
	if err != nil {
		return nil
	}
	e := runtime.getContainerElement(id)
	if e == nil {
		return nil
	}
	return e.Value.(*Container)
}

func (runtime *Runtime) Exists(id string) bool {
	return runtime.Get(id) != nil
}

func (runtime *Runtime) containerRoot(id string) string {
	return path.Join(runtime.repository, id)
}

func (runtime *Runtime) mergeConfig(userConf, imageConf *Config) {
	if userConf.Hostname != "" {
		userConf.Hostname = imageConf.Hostname
	}
	if userConf.User != "" {
		userConf.User = imageConf.User
	}
	if userConf.Memory == 0 {
		userConf.Memory = imageConf.Memory
	}
	if userConf.MemorySwap == 0 {
		userConf.MemorySwap = imageConf.MemorySwap
	}
	if userConf.PortSpecs == nil || len(userConf.PortSpecs) == 0 {
		userConf.PortSpecs = imageConf.PortSpecs
	}
	if !userConf.Tty {
		userConf.Tty = userConf.Tty
	}
	if !userConf.OpenStdin {
		userConf.OpenStdin = imageConf.OpenStdin
	}
	if !userConf.StdinOnce {
		userConf.StdinOnce = imageConf.StdinOnce
	}
	if userConf.Env == nil || len(userConf.Env) == 0 {
		userConf.Env = imageConf.Env
	}
	if userConf.Cmd == nil || len(userConf.Cmd) == 0 {
		userConf.Cmd = imageConf.Cmd
	}
	if userConf.Dns == nil || len(userConf.Dns) == 0 {
		userConf.Dns = imageConf.Dns
	}
}

func (runtime *Runtime) Create(config *Config) (*Container, error) {

	// Lookup image
	img, err := runtime.repositories.LookupImage(config.Image)
	if err != nil {
		return nil, err
	}

	if img.Config != nil {
		runtime.mergeConfig(config, img.Config)
	}

	if config.Cmd == nil {
		return nil, fmt.Errorf("No command specified")
	}

	// Generate id
	id := GenerateId()
	// Generate default hostname
	// FIXME: the lxc template no longer needs to set a default hostname
	if config.Hostname == "" {
		config.Hostname = id[:12]
	}

	container := &Container{
		// FIXME: we should generate the ID here instead of receiving it as an argument
		Id:              id,
		Created:         time.Now(),
		Path:            config.Cmd[0],
		Args:            config.Cmd[1:], //FIXME: de-duplicate from config
		Config:          config,
		Image:           img.Id, // Always use the resolved image id
		NetworkSettings: &NetworkSettings{},
		// FIXME: do we need to store this in the container?
		SysInitPath: sysInitPath,
	}

	container.root = runtime.containerRoot(container.Id)
	// Step 1: create the container directory.
	// This doubles as a barrier to avoid race conditions.
	if err := os.Mkdir(container.root, 0700); err != nil {
		return nil, err
	}

	// If custom dns exists, then create a resolv.conf for the container
	if len(config.Dns) > 0 {
		container.ResolvConfPath = path.Join(container.root, "resolv.conf")
		f, err := os.Create(container.ResolvConfPath)
		if err != nil {
			return nil, err
		}
		defer f.Close()
		for _, dns := range config.Dns {
			if _, err := f.Write([]byte("nameserver " + dns + "\n")); err != nil {
				return nil, err
			}
		}
	} else {
		container.ResolvConfPath = "/etc/resolv.conf"
	}

	// Step 2: save the container json
	if err := container.ToDisk(); err != nil {
		return nil, err
	}
	// Step 3: register the container
	if err := runtime.Register(container); err != nil {
		return nil, err
	}
	return container, nil
}

func (runtime *Runtime) Load(id string) (*Container, error) {
	container := &Container{root: runtime.containerRoot(id)}
	if err := container.FromDisk(); err != nil {
		return nil, err
	}
	if container.Id != id {
		return container, fmt.Errorf("Container %s is stored at %s", container.Id, id)
	}
	if container.State.Running {
		container.State.Ghost = true
	}
	if err := runtime.Register(container); err != nil {
		return nil, err
	}
	return container, nil
}

// Register makes a container object usable by the runtime as <container.Id>
func (runtime *Runtime) Register(container *Container) error {
	if container.runtime != nil || runtime.Exists(container.Id) {
		return fmt.Errorf("Container is already loaded")
	}
	if err := validateId(container.Id); err != nil {
		return err
	}

	// init the wait lock
	container.waitLock = make(chan struct{})

	// FIXME: if the container is supposed to be running but is not, auto restart it?
	//        if so, then we need to restart monitor and init a new lock
	// If the container is supposed to be running, make sure of it
	if container.State.Running {
		if output, err := exec.Command("lxc-info", "-n", container.Id).CombinedOutput(); err != nil {
			return err
		} else {
			if !strings.Contains(string(output), "RUNNING") {
				Debugf("Container %s was supposed to be running be is not.", container.Id)
				container.State.setStopped(-127)
				if err := container.ToDisk(); err != nil {
					return err
				}
			}
		}
	}

	// Even if not running, we init the lock (prevents races in start/stop/kill)
	container.State.initLock()

	container.runtime = runtime

	// Attach to stdout and stderr
	container.stderr = newWriteBroadcaster()
	container.stdout = newWriteBroadcaster()
	// Attach to stdin
	if container.Config.OpenStdin {
		container.stdin, container.stdinPipe = io.Pipe()
	} else {
		container.stdinPipe = NopWriteCloser(ioutil.Discard) // Silently drop stdin
	}
	// done
	runtime.containers.PushBack(container)
	runtime.idIndex.Add(container.Id)

	// If the container is not running or just has been flagged not running
	// then close the wait lock chan (will be reset upon start)
	if !container.State.Running {
		close(container.waitLock)
	} else {
		container.allocateNetwork()
		go container.monitor()
	}
	return nil
}

func (runtime *Runtime) LogToDisk(src *writeBroadcaster, dst string) error {
	log, err := os.OpenFile(dst, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600)
	if err != nil {
		return err
	}
	src.AddWriter(log)
	return nil
}

func (runtime *Runtime) Destroy(container *Container) error {
	element := runtime.getContainerElement(container.Id)
	if element == nil {
		return fmt.Errorf("Container %v not found - maybe it was already destroyed?", container.Id)
	}

	if err := container.Stop(10); err != nil {
		return err
	}
	if mounted, err := container.Mounted(); err != nil {
		return err
	} else if mounted {
		if err := container.Unmount(); err != nil {
			return fmt.Errorf("Unable to unmount container %v: %v", container.Id, err)
		}
	}
	// Deregister the container before removing its directory, to avoid race conditions
	runtime.idIndex.Delete(container.Id)
	runtime.containers.Remove(element)
	if err := os.RemoveAll(container.root); err != nil {
		return fmt.Errorf("Unable to remove filesystem for %v: %v", container.Id, err)
	}
	return nil
}

// Commit creates a new filesystem image from the current state of a container.
// The image can optionally be tagged into a repository
func (runtime *Runtime) Commit(id, repository, tag, comment, author string, config *Config) (*Image, error) {
	container := runtime.Get(id)
	if container == nil {
		return nil, fmt.Errorf("No such container: %s", id)
	}
	// FIXME: freeze the container before copying it to avoid data corruption?
	// FIXME: this shouldn't be in commands.
	rwTar, err := container.ExportRw()
	if err != nil {
		return nil, err
	}
	// Create a new image from the container's base layers + a new layer from container changes
	img, err := runtime.graph.Create(rwTar, container, comment, author, config)
	if err != nil {
		return nil, err
	}
	// Register the image if needed
	if repository != "" {
		if err := runtime.repositories.Set(repository, tag, img.Id, true); err != nil {
			return img, err
		}
	}
	return img, nil
}

func (runtime *Runtime) restore() error {
	dir, err := ioutil.ReadDir(runtime.repository)
	if err != nil {
		return err
	}
	for _, v := range dir {
		id := v.Name()
		container, err := runtime.Load(id)
		if err != nil {
			Debugf("Failed to load container %v: %v", id, err)
			continue
		}
		Debugf("Loaded container %v", container.Id)
	}
	return nil
}

// FIXME: harmonize with NewGraph()
func NewRuntime() (*Runtime, error) {
	runtime, err := NewRuntimeFromDirectory("/var/lib/docker")
	if err != nil {
		return nil, err
	}

	if k, err := GetKernelVersion(); err != nil {
		log.Printf("WARNING: %s\n", err)
	} else {
		runtime.kernelVersion = k
		if CompareKernelVersion(k, &KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0}) < 0 {
			log.Printf("WARNING: You are running linux kernel version %s, which might be unstable running docker. Please upgrade your kernel to 3.8.0.", k.String())
		}
	}

	if cgroupMemoryMountpoint, err := FindCgroupMountpoint("memory"); err != nil {
		log.Printf("WARNING: %s\n", err)
	} else {
		_, err1 := ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.limit_in_bytes"))
		_, err2 := ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.soft_limit_in_bytes"))
		runtime.capabilities.MemoryLimit = err1 == nil && err2 == nil
		if !runtime.capabilities.MemoryLimit {
			log.Printf("WARNING: Your kernel does not support cgroup memory limit.")
		}

		_, err = ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.memsw.limit_in_bytes"))
		runtime.capabilities.SwapLimit = err == nil
		if !runtime.capabilities.SwapLimit {
			log.Printf("WARNING: Your kernel does not support cgroup swap limit.")
		}
	}
	return runtime, nil
}

func NewRuntimeFromDirectory(root string) (*Runtime, error) {
	runtimeRepo := path.Join(root, "containers")

	if err := os.MkdirAll(runtimeRepo, 0700); err != nil && !os.IsExist(err) {
		return nil, err
	}

	g, err := NewGraph(path.Join(root, "graph"))
	if err != nil {
		return nil, err
	}
	repositories, err := NewTagStore(path.Join(root, "repositories"), g)
	if err != nil {
		return nil, fmt.Errorf("Couldn't create Tag store: %s", err)
	}
	if NetworkBridgeIface == "" {
		NetworkBridgeIface = DefaultNetworkBridge
	}
	netManager, err := newNetworkManager(NetworkBridgeIface)
	if err != nil {
		return nil, err
	}
	authConfig, err := auth.LoadConfig(root)
	if err != nil && authConfig == nil {
		// If the auth file does not exist, keep going
		return nil, err
	}
	runtime := &Runtime{
		root:           root,
		repository:     runtimeRepo,
		containers:     list.New(),
		networkManager: netManager,
		graph:          g,
		repositories:   repositories,
		authConfig:     authConfig,
		idIndex:        NewTruncIndex(),
		capabilities:   &Capabilities{},
	}

	if err := runtime.restore(); err != nil {
		return nil, err
	}
	return runtime, nil
}

type History []*Container

func (history *History) Len() int {
	return len(*history)
}

func (history *History) Less(i, j int) bool {
	containers := *history
	return containers[j].When().Before(containers[i].When())
}

func (history *History) Swap(i, j int) {
	containers := *history
	tmp := containers[i]
	containers[i] = containers[j]
	containers[j] = tmp
}

func (history *History) Add(container *Container) {
	*history = append(*history, container)
	sort.Sort(history)
}
<|endoftext|>


<commit_before>package irc

import (
	"fmt"
	"strings"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

type MockConn struct {
	ch  *Channels
	msg *Message
	ev  *Events

	local, user *User
}

func NewMockConn() *MockConn {
	return &MockConn{
		ch:    &Channels{m: make(map[string]*Channel)},
		local: NewUser("anolis!bot@i.am.a.bot"),
		user:  NewUser("foo!bar@irc.localhost"),
		ev:    NewEvents(),
	}
}

// No-op
func (m *MockConn) Close() {}

// No-op
func (m *MockConn) WaitForClose() <-chan struct{} { return nil }

func (m *MockConn) CurrentNick() string { return m.local.Nickname }

func (m *MockConn) Join(room string)    { m.ev.Dispatch(m.msg, m) }
func (m *MockConn) Part(room string)    { m.ev.Dispatch(m.msg, m) }
func (m *MockConn) Kick(r, u, a string) { m.ev.Dispatch(m.msg, m) }
func (m *MockConn) Nick(nick string)    { m.ev.Dispatch(m.msg, m) }
func (m *MockConn) Quit(msg string)     { m.ev.Dispatch(m.msg, m) }

func (m *MockConn) Raw(f string, args ...interface{})        { m.ev.Dispatch(m.msg, m) }
func (m *MockConn) Privmsg(t, f string, args ...interface{}) { m.ev.Dispatch(m.msg, m) }
func (m *MockConn) Notice(t, f string, args ...interface{})  { m.ev.Dispatch(m.msg, m) }

func (m *MockConn) Channels() *Channels { return m.ch }
func (m *MockConn) Connection() Conn    { return m }
func (m *MockConn) Commands() Commands  { return m }

func (m *MockConn) Do(fn func(), u *User, ev string, args ...string) {
	m.msg = ParseMessage(fmt.Sprintf(
		":%s!%s@%s %s %s",
		u.Nickname, u.Username, u.Hostname,
		ev, strings.Join(args, " "),
	))
	m.msg.Source = u
	fn()
}

func TestConnection(t *testing.T) {
	mock := NewMockConn()
	Convey("connection should", t, func() {
		mock.Do(func() { mock.Join("#hello") }, mock.local, "JOIN", "#hello")
		Convey("add a channel when we join", func() {
			ch, ok := mock.Channels().Get("#hello")
			So(ok, ShouldBeTrue)
			So(ch.Users().Has(mock.local), ShouldBeTrue)
		})
		Convey("remove a channel", func() {
			Convey("when we part", func() {
				mock.Do(func() { mock.Part("#hello") }, mock.local, "PART", "#hello", ":byt")
				_, ok := mock.Channels().Get("#hello")
				So(ok, ShouldBeFalse)
			})
			Convey("when we get kicked", func() {
				mock.Do(func() { mock.Kick("#hello", mock.local.Nickname, "bye") },
					mock.user, "KICK", "#hello", mock.local.Nickname, ":bye")
				_, ok := mock.Channels().Get("#hello")
				So(ok, ShouldBeFalse)
			})
		})
	})
}
<commit_msg>added more tests for part/kick/join events<commit_after>package irc

import (
	"fmt"
	"strings"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

type MockConn struct {
	ch  *Channels
	msg *Message
	ev  *Events

	local, user *User
}

func NewMockConn() *MockConn {
	return &MockConn{
		ch:    &Channels{m: make(map[string]*Channel)},
		local: NewUser("anolis!bot@i.am.a.bot"),
		user:  NewUser("foo!bar@irc.localhost"),
		ev:    NewEvents(),
	}
}

// No-op
func (m *MockConn) Close() {}

// No-op
func (m *MockConn) WaitForClose() <-chan struct{} { return nil }

func (m *MockConn) CurrentNick() string { return m.local.Nickname }

func (m *MockConn) Join(room string)    { m.ev.Dispatch(m.msg, m) }
func (m *MockConn) Part(room string)    { m.ev.Dispatch(m.msg, m) }
func (m *MockConn) Kick(r, u, a string) { m.ev.Dispatch(m.msg, m) }
func (m *MockConn) Nick(nick string)    { m.ev.Dispatch(m.msg, m) }
func (m *MockConn) Quit(msg string)     { m.ev.Dispatch(m.msg, m) }

func (m *MockConn) Raw(f string, args ...interface{})        { m.ev.Dispatch(m.msg, m) }
func (m *MockConn) Privmsg(t, f string, args ...interface{}) { m.ev.Dispatch(m.msg, m) }
func (m *MockConn) Notice(t, f string, args ...interface{})  { m.ev.Dispatch(m.msg, m) }

func (m *MockConn) Channels() *Channels { return m.ch }
func (m *MockConn) Connection() Conn    { return m }
func (m *MockConn) Commands() Commands  { return m }

func (m *MockConn) Do(fn func(), u *User, ev string, args ...string) {
	m.msg = ParseMessage(fmt.Sprintf(
		":%s!%s@%s %s %s",
		u.Nickname, u.Username, u.Hostname,
		ev, strings.Join(args, " "),
	))
	m.msg.Source = u
	fn()
}

func TestConnection_LocalUser(t *testing.T) {
	mock := NewMockConn()
	Convey("connection should", t, func() {
		mock.Do(func() { mock.Join("#hello") }, mock.local, "JOIN", "#hello")
		Convey("add a channel when we join", func() {
			ch, ok := mock.Channels().Get("#hello")
			So(ok, ShouldBeTrue)
			So(ch.Users().Has(mock.local), ShouldBeTrue)
		})
		Convey("remove a channel", func() {
			Convey("when we part", func() {
				mock.Do(func() { mock.Part("#hello") }, mock.local, "PART", "#hello", ":byt")
				_, ok := mock.Channels().Get("#hello")
				So(ok, ShouldBeFalse)
			})
			Convey("when we get kicked", func() {
				mock.Do(func() { mock.Kick("#hello", mock.local.Nickname, "bye") },
					mock.user, "KICK", "#hello", mock.local.Nickname, ":bye")
				_, ok := mock.Channels().Get("#hello")
				So(ok, ShouldBeFalse)
			})
		})
	})
}

func TestConnection_User(t *testing.T) {
	mock := NewMockConn()
	Convey("connection should update channel", t, func() {
		mock.Do(func() { mock.Join("#hello") }, mock.local, "JOIN", "#hello")
		mock.Do(func() { mock.Join("#hello") }, mock.user, "JOIN", ":#hello")

		Convey("when a user joins", func() {
			ch, ok := mock.Channels().Get("#hello")
			So(ok, ShouldBeTrue)
			So(ch.Users().Has(mock.user), ShouldBeTrue)
		})

		Convey("when a user parts", func() {
			ch, _ := mock.Channels().Get("#hello")
			mock.Do(func() { mock.Part("#hello") }, mock.user, "PART", "#hello", ":bye")
			So(ch.Users().Has(mock.user), ShouldBeFalse)
		})

		Convey("when a user gets kicked", func() {
			ch, _ := mock.Channels().Get("#hello")
			mock.Do(func() { mock.Kick("#hello", mock.user.Nickname, "bye") },
				mock.local, "KICK", "#hello", mock.user.Nickname, ":bye")
			So(ch.Users().Has(mock.user), ShouldBeFalse)
		})
	})
}
<|endoftext|>


<commit_before>// +build linux

package action

import "os"

func getEditor() string {
	if ed := os.Getenv("EDITOR"); ed != "" {
		return ed
	}
	return "editor"
}
<commit_msg>Default to vi in Linux (#479)<commit_after>// +build linux

package action

import (
	"os"
	"os/exec"
)

func getEditor() string {
	if ed := os.Getenv("EDITOR"); ed != "" {
		return ed
	}
	if p, err := exec.LookPath("editor"); err == nil {
		return p
	}
	// if neither EDITOR is set nor "editor" available we'll just assume that vi
	// is installed. If this fails the user will have to set $EDITOR
	return "vi"
}
<|endoftext|>


<commit_before>package hands

import (
	"testing"
	"time"
)

func TestGetHostPort(t *testing.T) {
	t.Parallel()
	mine := New()
	thisIP := "127.5.6.250:2016"

	mine.Set("trump", thisIP)

	gotIP := mine.Get("trump")

	if gotIP != thisIP {
		t.Fatalf("Mismatched HostPort, expected %q, got %q\n", thisIP, gotIP)
	}
}

func TestGetTimestamp(t *testing.T) {
	t.Parallel()
	mine := New()

	mine.Set("trump", "127.5.6.250:2016")

	timestamp := mine.GetTimestamp("trump")
	if time.Since(timestamp).Seconds() > 1 {
		t.Fatalf("Incorrect timestamp")
	}
}

func TestGetExpired(t *testing.T) {
	t.Parallel()

        mine := &DB{
            db: make(map[string]dbEntry),
            duration: time.Duration(time.Second),
        }

        mine.Set("trump", "127.5.6.250:2016")
        time.Sleep(1 * time.Second)

        gotHost := mine.Get("trump")

        if gotHost != "" {
            t.Fatalf("data persists after expiration")
        }
}

func TestGetAll(t *testing.T) {
	t.Parallel()
	mine := New()

	mine.Set("trump", "127.5.6.250:2016")
	mine.Set("drumpf", "127.0.0.1:2020")

	all := mine.GetAll()

	if !(all[0] == "trump" && all[1] == "drumpf") {
		t.Fatalf("failed to retreive all entries")
	}
}

func TestGetAllExpired(t *testing.T) {
	t.Parallel()

        mine := &DB{
            db: make(map[string]dbEntry),
            duration: time.Duration(time.Second),
        }

        mine.Set("trump", "127.5.6.250:2016")
        time.Sleep(1 * time.Second)
        mine.Set("drumpf", "127.0.0.1:2020")

        gotHosts := mine.GetAll()

        if len(gotHosts) != 1 || gotHosts[0] != "drumpf" {
            t.Fatalf("data persists after expiration")
        }
}
func TestNotExist(t *testing.T) {
	t.Parallel()
	mine := New()

	gotHostPort := mine.Get("trump")
	if gotHostPort != "" {
		t.Fatalf("Got non-zero result for non-existant value: %q\n", gotHostPort)
	}
}

func TestOverwrite(t *testing.T) {
	t.Parallel()

	mine := New()
	thisIP := "127.5.6.250:2016"
	newIP := "127.0.0.1:2020"
	mine.Set("trump", thisIP)
	mine.Set("trump", newIP)

	gotHostPort := mine.Get("trump")

	if gotHostPort != newIP {

		t.Fatalf("Got wrong values for overwritten entry: %q\n", gotHostPort)
	}
}
<commit_msg>Make hands even greater again again<commit_after>package hands

import (
	"testing"
	"time"
)

func TestGetHostPort(t *testing.T) {
	t.Parallel()
	mine := New()
	thisIP := "127.5.6.250:2016"

	mine.Set("trump", thisIP)

	gotIP := mine.Get("trump")

	if gotIP != thisIP {
		t.Fatalf("Mismatched HostPort, expected %q, got %q\n", thisIP, gotIP)
	}
}

func TestGetTimestamp(t *testing.T) {
	t.Parallel()
	mine := New()

	mine.Set("trump", "127.5.6.250:2016")

	timestamp := mine.GetTimestamp("trump")
	if time.Since(timestamp).Seconds() > 1 {
		t.Fatalf("Incorrect timestamp")
	}
}

func TestGetExpired(t *testing.T) {
	t.Parallel()

        mine := &DB{
            db: make(map[string]dbEntry),
            duration: time.Duration(500 * time.Millisecond),
        }

        mine.Set("trump", "127.5.6.250:2016")
        time.Sleep(501 * time.Millisecond)

        gotHost := mine.Get("trump")

        if gotHost != "" {
            t.Fatalf("data persists after expiration")
        }
}

func TestGetAll(t *testing.T) {
	t.Parallel()
	mine := New()

	mine.Set("trump", "127.5.6.250:2016")
	mine.Set("drumpf", "127.0.0.1:2020")

	all := mine.GetAll()

	if !(all[0] == "trump" && all[1] == "drumpf") {
		t.Fatalf("failed to retreive all entries")
	}
}

func TestGetAllExpired(t *testing.T) {
	t.Parallel()

        mine := &DB{
            db: make(map[string]dbEntry),
            duration: time.Duration(500 * time.Millisecond),
        }

        mine.Set("trump", "127.5.6.250:2016")
        time.Sleep(501 * time.Millisecond)
        mine.Set("drumpf", "127.0.0.1:2020")

        gotHosts := mine.GetAll()

        if len(gotHosts) != 1 || gotHosts[0] != "drumpf" {
            t.Fatalf("data persists after expiration")
        }
}
func TestNotExist(t *testing.T) {
	t.Parallel()
	mine := New()

	gotHostPort := mine.Get("trump")
	if gotHostPort != "" {
		t.Fatalf("Got non-zero result for non-existant value: %q\n", gotHostPort)
	}
}

func TestOverwrite(t *testing.T) {
	t.Parallel()

	mine := New()
	thisIP := "127.5.6.250:2016"
	newIP := "127.0.0.1:2020"
	mine.Set("trump", thisIP)
	mine.Set("trump", newIP)

	gotHostPort := mine.Get("trump")

	if gotHostPort != newIP {

		t.Fatalf("Got wrong values for overwritten entry: %q\n", gotHostPort)
	}
}
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2014 DutchCoders [https://github.com/dutchcoders/]

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

package main

import (
	// _ "transfer.sh/app/handlers"
	// _ "transfer.sh/app/utils"
	"flag"
	"fmt"
	"github.com/PuerkitoBio/ghost/handlers"
	"github.com/gorilla/mux"
	"log"
	"math/rand"
	"mime"
	"net/http"
	"net/url"
	"os"
	"time"
)

const SERVER_INFO = "transfer.sh"

// parse request with maximum memory of _24Kilobits
const _24K = (1 << 20) * 24

var config struct {
	AWS_ACCESS_KEY     string
	AWS_SECRET_KEY     string
	BUCKET             string
	VIRUSTOTAL_KEY     string
	CLAMAV_DAEMON_HOST string "/tmp/clamd.socket"
	Temp               string
}

var storage Storage

func init() {
	config.AWS_ACCESS_KEY = os.Getenv("AWS_ACCESS_KEY_ID")
	config.AWS_SECRET_KEY = os.Getenv("AWS_SECRET_KEY")
	config.BUCKET = os.Getenv("BUCKET")

	config.VIRUSTOTAL_KEY = os.Getenv("VIRUSTOTAL_KEY")

	if os.Getenv("CLAMAV_DAEMON_HOST") != "" {
		config.CLAMAV_DAEMON_HOST = os.Getenv("CLAMAV_DAEMON_HOST")
	}

	config.Temp = os.TempDir()
}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())

	r := mux.NewRouter()

	r.PathPrefix("/scripts/").Methods("GET").Handler(http.FileServer(http.Dir("./static/")))
	r.PathPrefix("/styles/").Methods("GET").Handler(http.FileServer(http.Dir("./static/")))
	r.PathPrefix("/images/").Methods("GET").Handler(http.FileServer(http.Dir("./static/")))
	r.PathPrefix("/fonts/").Methods("GET").Handler(http.FileServer(http.Dir("./static/")))
	r.PathPrefix("/ico/").Methods("GET").Handler(http.FileServer(http.Dir("./static/")))
	r.PathPrefix("/favicon.ico").Methods("GET").Handler(http.FileServer(http.Dir("./static/")))
	r.PathPrefix("/robots.txt").Methods("GET").Handler(http.FileServer(http.Dir("./static/")))

	r.HandleFunc("/({files:.*}).zip", zipHandler).Methods("GET")
	r.HandleFunc("/({files:.*}).tar", tarHandler).Methods("GET")
	r.HandleFunc("/({files:.*}).tar.gz", tarGzHandler).Methods("GET")
	r.HandleFunc("/download/{token}/{filename}", getHandler).Methods("GET")

	r.HandleFunc("/{token}/{filename}", previewHandler).MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) (match bool) {
		match = false

		// The file will show a preview page when opening the link in browser directly or
		// from external link. If the referer url path and current path are the same it will be
		// downloaded.
		if !acceptsHtml(r.Header) {
			return false
		}

		match = (r.Referer() == "")

		u, err := url.Parse(r.Referer())
		if err != nil {
			log.Fatal(err)
			return
		}

		match = match || (u.Path != r.URL.Path)
		return
	}).Methods("GET")

	r.HandleFunc("/{token}/{filename}", getHandler).Methods("GET")
	r.HandleFunc("/get/{token}/{filename}", getHandler).Methods("GET")
	r.HandleFunc("/{filename}/virustotal", virusTotalHandler).Methods("PUT")
	r.HandleFunc("/{filename}/scan", scanHandler).Methods("PUT")
	r.HandleFunc("/put/{filename}", putHandler).Methods("PUT")
	r.HandleFunc("/upload/{filename}", putHandler).Methods("PUT")
	r.HandleFunc("/{filename}", putHandler).Methods("PUT")
	r.HandleFunc("/health.html", healthHandler).Methods("GET")
	r.HandleFunc("/", postHandler).Methods("POST")
	// r.HandleFunc("/{page}", viewHandler).Methods("GET")
	r.HandleFunc("/", viewHandler).Methods("GET")

	r.NotFoundHandler = http.HandlerFunc(notFoundHandler)

	port := flag.String("port", "8080", "port number, default: 8080")
	temp := flag.String("temp", config.Temp, "")
	basedir := flag.String("basedir", "", "")
	logpath := flag.String("log", "", "")
	provider := flag.String("provider", "s3", "")

	flag.Parse()

	if *logpath != "" {
		f, err := os.OpenFile(*logpath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
		if err != nil {
			log.Fatalf("error opening file: %v", err)
		}

		defer f.Close()

		log.SetOutput(f)
	}

	config.Temp = *temp

	var err error

	switch *provider {
	case "s3":
		storage, err = NewS3Storage()
	case "local":
		if *basedir == "" {
			log.Panic("basedir not set")
		}

		storage, err = NewLocalStorage(*basedir)
	}

	if err != nil {
		log.Panic("Error while creating storage.", err)
	}

	mime.AddExtensionType(".md", "text/x-markdown")

	log.Printf("Transfer.sh server started. :\nlistening on port: %v\nusing temp folder: %s\nusing storage provider: %s", *port, config.Temp, *provider)
	log.Printf("---------------------------")

	s := &http.Server{
		Addr:    fmt.Sprintf(":%s", *port),
		Handler: handlers.PanicHandler(LoveHandler(RedirectHandler(handlers.LogHandler(r, handlers.NewLogOptions(log.Printf, "_default_")))), nil),
	}

	log.Panic(s.ListenAndServe())
	log.Printf("Server stopped.")
}
<commit_msg>Add mkv playback support as webm<commit_after>/*
The MIT License (MIT)

Copyright (c) 2014 DutchCoders [https://github.com/dutchcoders/]

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

package main

import (
	// _ "transfer.sh/app/handlers"
	// _ "transfer.sh/app/utils"
	"flag"
	"fmt"
	"github.com/PuerkitoBio/ghost/handlers"
	"github.com/gorilla/mux"
	"log"
	"math/rand"
	"mime"
	"net/http"
	"net/url"
	"os"
	"time"
)

const SERVER_INFO = "transfer.sh"

// parse request with maximum memory of _24Kilobits
const _24K = (1 << 20) * 24

var config struct {
	AWS_ACCESS_KEY     string
	AWS_SECRET_KEY     string
	BUCKET             string
	VIRUSTOTAL_KEY     string
	CLAMAV_DAEMON_HOST string "/tmp/clamd.socket"
	Temp               string
}

var storage Storage

func init() {
	config.AWS_ACCESS_KEY = os.Getenv("AWS_ACCESS_KEY_ID")
	config.AWS_SECRET_KEY = os.Getenv("AWS_SECRET_KEY")
	config.BUCKET = os.Getenv("BUCKET")

	config.VIRUSTOTAL_KEY = os.Getenv("VIRUSTOTAL_KEY")

	if os.Getenv("CLAMAV_DAEMON_HOST") != "" {
		config.CLAMAV_DAEMON_HOST = os.Getenv("CLAMAV_DAEMON_HOST")
	}

	config.Temp = os.TempDir()
}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())

	r := mux.NewRouter()

	r.PathPrefix("/scripts/").Methods("GET").Handler(http.FileServer(http.Dir("./static/")))
	r.PathPrefix("/styles/").Methods("GET").Handler(http.FileServer(http.Dir("./static/")))
	r.PathPrefix("/images/").Methods("GET").Handler(http.FileServer(http.Dir("./static/")))
	r.PathPrefix("/fonts/").Methods("GET").Handler(http.FileServer(http.Dir("./static/")))
	r.PathPrefix("/ico/").Methods("GET").Handler(http.FileServer(http.Dir("./static/")))
	r.PathPrefix("/favicon.ico").Methods("GET").Handler(http.FileServer(http.Dir("./static/")))
	r.PathPrefix("/robots.txt").Methods("GET").Handler(http.FileServer(http.Dir("./static/")))

	r.HandleFunc("/({files:.*}).zip", zipHandler).Methods("GET")
	r.HandleFunc("/({files:.*}).tar", tarHandler).Methods("GET")
	r.HandleFunc("/({files:.*}).tar.gz", tarGzHandler).Methods("GET")
	r.HandleFunc("/download/{token}/{filename}", getHandler).Methods("GET")

	r.HandleFunc("/{token}/{filename}", previewHandler).MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) (match bool) {
		match = false

		// The file will show a preview page when opening the link in browser directly or
		// from external link. If the referer url path and current path are the same it will be
		// downloaded.
		if !acceptsHtml(r.Header) {
			return false
		}

		match = (r.Referer() == "")

		u, err := url.Parse(r.Referer())
		if err != nil {
			log.Fatal(err)
			return
		}

		match = match || (u.Path != r.URL.Path)
		return
	}).Methods("GET")

	r.HandleFunc("/{token}/{filename}", getHandler).Methods("GET")
	r.HandleFunc("/get/{token}/{filename}", getHandler).Methods("GET")
	r.HandleFunc("/{filename}/virustotal", virusTotalHandler).Methods("PUT")
	r.HandleFunc("/{filename}/scan", scanHandler).Methods("PUT")
	r.HandleFunc("/put/{filename}", putHandler).Methods("PUT")
	r.HandleFunc("/upload/{filename}", putHandler).Methods("PUT")
	r.HandleFunc("/{filename}", putHandler).Methods("PUT")
	r.HandleFunc("/health.html", healthHandler).Methods("GET")
	r.HandleFunc("/", postHandler).Methods("POST")
	// r.HandleFunc("/{page}", viewHandler).Methods("GET")
	r.HandleFunc("/", viewHandler).Methods("GET")

	r.NotFoundHandler = http.HandlerFunc(notFoundHandler)

	port := flag.String("port", "8080", "port number, default: 8080")
	temp := flag.String("temp", config.Temp, "")
	basedir := flag.String("basedir", "", "")
	logpath := flag.String("log", "", "")
	provider := flag.String("provider", "s3", "")

	flag.Parse()

	if *logpath != "" {
		f, err := os.OpenFile(*logpath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
		if err != nil {
			log.Fatalf("error opening file: %v", err)
		}

		defer f.Close()

		log.SetOutput(f)
	}

	config.Temp = *temp

	var err error

	switch *provider {
	case "s3":
		storage, err = NewS3Storage()
	case "local":
		if *basedir == "" {
			log.Panic("basedir not set")
		}

		storage, err = NewLocalStorage(*basedir)
	}

	if err != nil {
		log.Panic("Error while creating storage.", err)
	}

	mime.AddExtensionType(".md", "text/x-markdown")
	mime.AddExtensionType(".mkv", "video/webm")

	log.Printf("Transfer.sh server started. :\nlistening on port: %v\nusing temp folder: %s\nusing storage provider: %s", *port, config.Temp, *provider)
	log.Printf("---------------------------")

	s := &http.Server{
		Addr:    fmt.Sprintf(":%s", *port),
		Handler: handlers.PanicHandler(LoveHandler(RedirectHandler(handlers.LogHandler(r, handlers.NewLogOptions(log.Printf, "_default_")))), nil),
	}

	log.Panic(s.ListenAndServe())
	log.Printf("Server stopped.")
}
<|endoftext|>


<commit_before>// Copyright 2013 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 leaktest provides tools to detect leaked goroutines in tests.
// To use it, call "defer leaktest.AfterTest(t)()" at the beginning of each
// test that may use goroutines.
package leaktest

import (
	"runtime"
	"sort"
	"strings"
	"testing"
	"time"

	"github.com/cockroachdb/cockroach/util/timeutil"
)

// interestingGoroutines returns all goroutines we care about for the purpose
// of leak checking. It excludes testing or runtime ones.
func interestingGoroutines() (gs []string) {
	buf := make([]byte, 2<<20)
	buf = buf[:runtime.Stack(buf, true)]
	for _, g := range strings.Split(string(buf), "\n\n") {
		sl := strings.SplitN(g, "\n", 2)
		if len(sl) != 2 {
			continue
		}
		stack := strings.TrimSpace(sl[1])
		if strings.HasPrefix(stack, "testing.RunTests") {
			continue
		}

		if stack == "" ||
			strings.Contains(stack, "github.com/cockroachdb/cockroach/util/log.init") ||
			// TODO(peter): Until https://github.com/grpc/grpc-go/pull/751 or
			// something similar is done, opening a gRPC client connection does not
			// timeout properly. See also
			// https://github.com/cockroachdb/cockroach/issues/7524.
			strings.Contains(stack, "google.golang.org/grpc.NewConn") ||
			// Go1.7 added a goroutine to network dialing that doesn't shut down
			// quickly.
			strings.Contains(stack, "created by net.(*netFD).connect") ||
			// Below are the stacks ignored by the upstream leaktest code.
			strings.Contains(stack, "testing.Main(") ||
			strings.Contains(stack, "testing.tRunner(") ||
			strings.Contains(stack, "runtime.goexit") ||
			strings.Contains(stack, "created by runtime.gc") ||
			strings.Contains(stack, "interestingGoroutines") ||
			strings.Contains(stack, "runtime.MHeap_Scavenger") ||
			strings.Contains(stack, "signal.signal_recv") ||
			strings.Contains(stack, "sigterm.handler") ||
			strings.Contains(stack, "runtime_mcall") ||
			strings.Contains(stack, "goroutine in C code") {
			continue
		}
		gs = append(gs, g)
	}
	sort.Strings(gs)
	return
}

// AfterTest snapshots the currently-running goroutines and returns a
// function to be run at the end of tests to see whether any
// goroutines leaked.
func AfterTest(t testing.TB) func() {
	orig := map[string]bool{}
	for _, g := range interestingGoroutines() {
		orig[g] = true
	}
	return func() {
		if t.Failed() {
			return
		}
		// Loop, waiting for goroutines to shut down.
		// Wait up to 5 seconds, but finish as quickly as possible.
		deadline := timeutil.Now().Add(5 * time.Second)
		for {
			var leaked []string
			for _, g := range interestingGoroutines() {
				if !orig[g] {
					leaked = append(leaked, g)
				}
			}
			if len(leaked) == 0 {
				return
			}
			if timeutil.Now().Before(deadline) {
				time.Sleep(50 * time.Millisecond)
				continue
			}
			for _, g := range leaked {
				t.Errorf("Leaked goroutine: %v", g)
			}
			return
		}
	}
}
<commit_msg>util/leaktest: no-op when called during stack unwinding<commit_after>// Copyright 2013 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 leaktest provides tools to detect leaked goroutines in tests.
// To use it, call "defer leaktest.AfterTest(t)()" at the beginning of each
// test that may use goroutines.
package leaktest

import (
	"runtime"
	"sort"
	"strings"
	"testing"
	"time"

	"github.com/cockroachdb/cockroach/util/timeutil"
)

// interestingGoroutines returns all goroutines we care about for the purpose
// of leak checking. It excludes testing or runtime ones.
func interestingGoroutines() (gs []string) {
	buf := make([]byte, 2<<20)
	buf = buf[:runtime.Stack(buf, true)]
	for _, g := range strings.Split(string(buf), "\n\n") {
		sl := strings.SplitN(g, "\n", 2)
		if len(sl) != 2 {
			continue
		}
		stack := strings.TrimSpace(sl[1])
		if strings.HasPrefix(stack, "testing.RunTests") {
			continue
		}

		if stack == "" ||
			strings.Contains(stack, "github.com/cockroachdb/cockroach/util/log.init") ||
			// TODO(peter): Until https://github.com/grpc/grpc-go/pull/751 or
			// something similar is done, opening a gRPC client connection does not
			// timeout properly. See also
			// https://github.com/cockroachdb/cockroach/issues/7524.
			strings.Contains(stack, "google.golang.org/grpc.NewConn") ||
			// Go1.7 added a goroutine to network dialing that doesn't shut down
			// quickly.
			strings.Contains(stack, "created by net.(*netFD).connect") ||
			// Below are the stacks ignored by the upstream leaktest code.
			strings.Contains(stack, "testing.Main(") ||
			strings.Contains(stack, "testing.tRunner(") ||
			strings.Contains(stack, "runtime.goexit") ||
			strings.Contains(stack, "created by runtime.gc") ||
			strings.Contains(stack, "interestingGoroutines") ||
			strings.Contains(stack, "runtime.MHeap_Scavenger") ||
			strings.Contains(stack, "signal.signal_recv") ||
			strings.Contains(stack, "sigterm.handler") ||
			strings.Contains(stack, "runtime_mcall") ||
			strings.Contains(stack, "goroutine in C code") {
			continue
		}
		gs = append(gs, g)
	}
	sort.Strings(gs)
	return
}

// AfterTest snapshots the currently-running goroutines and returns a
// function to be run at the end of tests to see whether any
// goroutines leaked.
func AfterTest(t testing.TB) func() {
	orig := map[string]bool{}
	for _, g := range interestingGoroutines() {
		orig[g] = true
	}
	return func() {
		if t.Failed() {
			return
		}
		if r := recover(); r != nil {
			panic(r)
		}
		// Loop, waiting for goroutines to shut down.
		// Wait up to 5 seconds, but finish as quickly as possible.
		deadline := timeutil.Now().Add(5 * time.Second)
		for {
			var leaked []string
			for _, g := range interestingGoroutines() {
				if !orig[g] {
					leaked = append(leaked, g)
				}
			}
			if len(leaked) == 0 {
				return
			}
			if timeutil.Now().Before(deadline) {
				time.Sleep(50 * time.Millisecond)
				continue
			}
			for _, g := range leaked {
				t.Errorf("Leaked goroutine: %v", g)
			}
			return
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package options

import (
	"errors"
	"fmt"
	"net"
	"strings"

	apiextensionsapiserver "k8s.io/apiextensions-apiserver/pkg/apiserver"
	genericfeatures "k8s.io/apiserver/pkg/features"
	utilfeature "k8s.io/apiserver/pkg/util/feature"
	aggregatorscheme "k8s.io/kube-aggregator/pkg/apiserver/scheme"
	"k8s.io/kubernetes/pkg/api/legacyscheme"
	"k8s.io/kubernetes/pkg/features"
	netutils "k8s.io/utils/net"
)

// TODO: Longer term we should read this from some config store, rather than a flag.
// validateClusterIPFlags is expected to be called after Complete()
func validateClusterIPFlags(options *ServerRunOptions) []error {
	var errs []error
	// maxCIDRBits is used to define the maximum CIDR size for the cluster ip(s)
	const maxCIDRBits = 20

	// validate that primary has been processed by user provided values or it has been defaulted
	if options.PrimaryServiceClusterIPRange.IP == nil {
		errs = append(errs, errors.New("--service-cluster-ip-range must contain at least one valid cidr"))
	}

	serviceClusterIPRangeList := strings.Split(options.ServiceClusterIPRanges, ",")
	if len(serviceClusterIPRangeList) > 2 {
		errs = append(errs, errors.New("--service-cluster-ip-range must not contain more than two entries"))
	}

	// Complete() expected to have set Primary* and Secondary*
	// primary CIDR validation
	if err := validateMaxCIDRRange(options.PrimaryServiceClusterIPRange, maxCIDRBits, "--service-cluster-ip-range"); err != nil {
		errs = append(errs, err)
	}

	// Secondary IP validation
	// while api-server dualstack bits does not have dependency on EndPointSlice, its
	// a good idea to have validation consistent across all components (ControllerManager
	// needs EndPointSlice + DualStack feature flags).
	secondaryServiceClusterIPRangeUsed := (options.SecondaryServiceClusterIPRange.IP != nil)
	if secondaryServiceClusterIPRangeUsed && (!utilfeature.DefaultFeatureGate.Enabled(features.IPv6DualStack) || !utilfeature.DefaultFeatureGate.Enabled(features.EndpointSlice)) {
		errs = append(errs, fmt.Errorf("secondary service cluster-ip range(--service-cluster-ip-range[1]) can only be used if %v and %v feature is enabled", string(features.IPv6DualStack), string(features.EndpointSlice)))
	}

	// note: While the cluster might be dualstack (i.e. pods with multiple IPs), the user may choose
	// to only ingress traffic within and into the cluster on one IP family only. this family is decided
	// by the range set on --service-cluster-ip-range. If/when the user decides to use dual stack services
	// the Secondary* must be of different IPFamily than --service-cluster-ip-range
	if secondaryServiceClusterIPRangeUsed {
		// Should be dualstack IPFamily(PrimaryServiceClusterIPRange) != IPFamily(SecondaryServiceClusterIPRange)
		dualstack, err := netutils.IsDualStackCIDRs([]*net.IPNet{&options.PrimaryServiceClusterIPRange, &options.SecondaryServiceClusterIPRange})
		if err != nil {
			errs = append(errs, fmt.Errorf("error attempting to validate dualstack for --service-cluster-ip-range value error:%v", err))
		}

		if !dualstack {
			errs = append(errs, errors.New("--service-cluster-ip-range[0] and --service-cluster-ip-range[1] must be of different IP family"))
		}

		if err := validateMaxCIDRRange(options.SecondaryServiceClusterIPRange, maxCIDRBits, "--service-cluster-ip-range[1]"); err != nil {
			errs = append(errs, err)
		}
	}

	return errs
}

func validateMaxCIDRRange(cidr net.IPNet, maxCIDRBits int, cidrFlag string) error {
	// Should be smallish sized cidr, this thing is kept in etcd
	// bigger cidr (specially those offered by IPv6) will add no value
	// significantly increase snapshotting time.
	var ones, bits = cidr.Mask.Size()
	if bits-ones > maxCIDRBits {
		return fmt.Errorf("specified %s is too large; for %d-bit addresses, the mask must be >= %d", cidrFlag, bits, bits-maxCIDRBits)
	}

	return nil
}

func validateServiceNodePort(options *ServerRunOptions) []error {
	var errs []error

	if options.KubernetesServiceNodePort < 0 || options.KubernetesServiceNodePort > 65535 {
		errs = append(errs, fmt.Errorf("--kubernetes-service-node-port %v must be between 0 and 65535, inclusive. If 0, the Kubernetes master service will be of type ClusterIP", options.KubernetesServiceNodePort))
	}

	if options.KubernetesServiceNodePort > 0 && !options.ServiceNodePortRange.Contains(options.KubernetesServiceNodePort) {
		errs = append(errs, fmt.Errorf("kubernetes service port range %v doesn't contain %v", options.ServiceNodePortRange, (options.KubernetesServiceNodePort)))
	}
	return errs
}

func validateTokenRequest(options *ServerRunOptions) []error {
	var errs []error

	enableAttempted := options.ServiceAccountSigningKeyFile != "" ||
		options.Authentication.ServiceAccounts.Issuer != "" ||
		len(options.Authentication.APIAudiences) != 0

	enableSucceeded := options.ServiceAccountIssuer != nil

	if !enableAttempted {
		errs = append(errs, errors.New("--service-account-signing-key-file and --service-account-issuer are required flags"))
	}

	if enableAttempted && !enableSucceeded {
		errs = append(errs, errors.New("--service-account-signing-key-file, --service-account-issuer, and --api-audiences should be specified together"))
	}

	return errs
}

func validateAPIPriorityAndFairness(options *ServerRunOptions) []error {
	if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.APIPriorityAndFairness) && options.GenericServerRunOptions.EnablePriorityAndFairness {
		// If none of the following runtime config options are specified, APF is
		// assumed to be turned on.
		enabledAPIString := options.APIEnablement.RuntimeConfig.String()
		testConfigs := []string{"flowcontrol.apiserver.k8s.io/v1beta1", "api/beta", "api/all"} // in the order of precedence
		for _, testConfig := range testConfigs {
			if strings.Contains(enabledAPIString, fmt.Sprintf("%s=false", testConfig)) {
				return []error{fmt.Errorf("--runtime-config=%s=false conflicts with --enable-priority-and-fairness=true and --feature-gates=APIPriorityAndFairness=true", testConfig)}
			}
			if strings.Contains(enabledAPIString, fmt.Sprintf("%s=true", testConfig)) {
				return nil
			}
		}
	}

	return nil
}

// Validate checks ServerRunOptions and return a slice of found errs.
func (s *ServerRunOptions) Validate() []error {
	var errs []error
	if s.MasterCount <= 0 {
		errs = append(errs, fmt.Errorf("--apiserver-count should be a positive number, but value '%d' provided", s.MasterCount))
	}
	errs = append(errs, s.Etcd.Validate()...)
	errs = append(errs, validateClusterIPFlags(s)...)
	errs = append(errs, validateServiceNodePort(s)...)
	errs = append(errs, validateAPIPriorityAndFairness(s)...)
	errs = append(errs, s.SecureServing.Validate()...)
	errs = append(errs, s.Authentication.Validate()...)
	errs = append(errs, s.Authorization.Validate()...)
	errs = append(errs, s.Audit.Validate()...)
	errs = append(errs, s.Admission.Validate()...)
	errs = append(errs, s.APIEnablement.Validate(legacyscheme.Scheme, apiextensionsapiserver.Scheme, aggregatorscheme.Scheme)...)
	errs = append(errs, validateTokenRequest(s)...)
	errs = append(errs, s.Metrics.Validate()...)
	errs = append(errs, s.Logs.Validate()...)
	if s.IdentityLeaseDurationSeconds <= 0 {
		errs = append(errs, fmt.Errorf("--identity-lease-duration-seconds should be a positive number, but value '%d' provided", s.IdentityLeaseDurationSeconds))
	}
	if s.IdentityLeaseRenewIntervalSeconds <= 0 {
		errs = append(errs, fmt.Errorf("--identity-lease-renew-interval-seconds should be a positive number, but value '%d' provided", s.IdentityLeaseRenewIntervalSeconds))
	}

	return errs
}
<commit_msg>cleanup: wrap the apiserver identity validation<commit_after>/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package options

import (
	"errors"
	"fmt"
	"net"
	"strings"

	apiextensionsapiserver "k8s.io/apiextensions-apiserver/pkg/apiserver"
	genericfeatures "k8s.io/apiserver/pkg/features"
	utilfeature "k8s.io/apiserver/pkg/util/feature"
	aggregatorscheme "k8s.io/kube-aggregator/pkg/apiserver/scheme"
	"k8s.io/kubernetes/pkg/api/legacyscheme"
	"k8s.io/kubernetes/pkg/features"
	netutils "k8s.io/utils/net"
)

// TODO: Longer term we should read this from some config store, rather than a flag.
// validateClusterIPFlags is expected to be called after Complete()
func validateClusterIPFlags(options *ServerRunOptions) []error {
	var errs []error
	// maxCIDRBits is used to define the maximum CIDR size for the cluster ip(s)
	const maxCIDRBits = 20

	// validate that primary has been processed by user provided values or it has been defaulted
	if options.PrimaryServiceClusterIPRange.IP == nil {
		errs = append(errs, errors.New("--service-cluster-ip-range must contain at least one valid cidr"))
	}

	serviceClusterIPRangeList := strings.Split(options.ServiceClusterIPRanges, ",")
	if len(serviceClusterIPRangeList) > 2 {
		errs = append(errs, errors.New("--service-cluster-ip-range must not contain more than two entries"))
	}

	// Complete() expected to have set Primary* and Secondary*
	// primary CIDR validation
	if err := validateMaxCIDRRange(options.PrimaryServiceClusterIPRange, maxCIDRBits, "--service-cluster-ip-range"); err != nil {
		errs = append(errs, err)
	}

	// Secondary IP validation
	// while api-server dualstack bits does not have dependency on EndPointSlice, its
	// a good idea to have validation consistent across all components (ControllerManager
	// needs EndPointSlice + DualStack feature flags).
	secondaryServiceClusterIPRangeUsed := (options.SecondaryServiceClusterIPRange.IP != nil)
	if secondaryServiceClusterIPRangeUsed && (!utilfeature.DefaultFeatureGate.Enabled(features.IPv6DualStack) || !utilfeature.DefaultFeatureGate.Enabled(features.EndpointSlice)) {
		errs = append(errs, fmt.Errorf("secondary service cluster-ip range(--service-cluster-ip-range[1]) can only be used if %v and %v feature is enabled", string(features.IPv6DualStack), string(features.EndpointSlice)))
	}

	// note: While the cluster might be dualstack (i.e. pods with multiple IPs), the user may choose
	// to only ingress traffic within and into the cluster on one IP family only. this family is decided
	// by the range set on --service-cluster-ip-range. If/when the user decides to use dual stack services
	// the Secondary* must be of different IPFamily than --service-cluster-ip-range
	if secondaryServiceClusterIPRangeUsed {
		// Should be dualstack IPFamily(PrimaryServiceClusterIPRange) != IPFamily(SecondaryServiceClusterIPRange)
		dualstack, err := netutils.IsDualStackCIDRs([]*net.IPNet{&options.PrimaryServiceClusterIPRange, &options.SecondaryServiceClusterIPRange})
		if err != nil {
			errs = append(errs, fmt.Errorf("error attempting to validate dualstack for --service-cluster-ip-range value error:%v", err))
		}

		if !dualstack {
			errs = append(errs, errors.New("--service-cluster-ip-range[0] and --service-cluster-ip-range[1] must be of different IP family"))
		}

		if err := validateMaxCIDRRange(options.SecondaryServiceClusterIPRange, maxCIDRBits, "--service-cluster-ip-range[1]"); err != nil {
			errs = append(errs, err)
		}
	}

	return errs
}

func validateMaxCIDRRange(cidr net.IPNet, maxCIDRBits int, cidrFlag string) error {
	// Should be smallish sized cidr, this thing is kept in etcd
	// bigger cidr (specially those offered by IPv6) will add no value
	// significantly increase snapshotting time.
	var ones, bits = cidr.Mask.Size()
	if bits-ones > maxCIDRBits {
		return fmt.Errorf("specified %s is too large; for %d-bit addresses, the mask must be >= %d", cidrFlag, bits, bits-maxCIDRBits)
	}

	return nil
}

func validateServiceNodePort(options *ServerRunOptions) []error {
	var errs []error

	if options.KubernetesServiceNodePort < 0 || options.KubernetesServiceNodePort > 65535 {
		errs = append(errs, fmt.Errorf("--kubernetes-service-node-port %v must be between 0 and 65535, inclusive. If 0, the Kubernetes master service will be of type ClusterIP", options.KubernetesServiceNodePort))
	}

	if options.KubernetesServiceNodePort > 0 && !options.ServiceNodePortRange.Contains(options.KubernetesServiceNodePort) {
		errs = append(errs, fmt.Errorf("kubernetes service port range %v doesn't contain %v", options.ServiceNodePortRange, (options.KubernetesServiceNodePort)))
	}
	return errs
}

func validateTokenRequest(options *ServerRunOptions) []error {
	var errs []error

	enableAttempted := options.ServiceAccountSigningKeyFile != "" ||
		options.Authentication.ServiceAccounts.Issuer != "" ||
		len(options.Authentication.APIAudiences) != 0

	enableSucceeded := options.ServiceAccountIssuer != nil

	if !enableAttempted {
		errs = append(errs, errors.New("--service-account-signing-key-file and --service-account-issuer are required flags"))
	}

	if enableAttempted && !enableSucceeded {
		errs = append(errs, errors.New("--service-account-signing-key-file, --service-account-issuer, and --api-audiences should be specified together"))
	}

	return errs
}

func validateAPIPriorityAndFairness(options *ServerRunOptions) []error {
	if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.APIPriorityAndFairness) && options.GenericServerRunOptions.EnablePriorityAndFairness {
		// If none of the following runtime config options are specified, APF is
		// assumed to be turned on.
		enabledAPIString := options.APIEnablement.RuntimeConfig.String()
		testConfigs := []string{"flowcontrol.apiserver.k8s.io/v1beta1", "api/beta", "api/all"} // in the order of precedence
		for _, testConfig := range testConfigs {
			if strings.Contains(enabledAPIString, fmt.Sprintf("%s=false", testConfig)) {
				return []error{fmt.Errorf("--runtime-config=%s=false conflicts with --enable-priority-and-fairness=true and --feature-gates=APIPriorityAndFairness=true", testConfig)}
			}
			if strings.Contains(enabledAPIString, fmt.Sprintf("%s=true", testConfig)) {
				return nil
			}
		}
	}

	return nil
}

func validateAPIServerIdentity(options *ServerRunOptions) []error {
	var errs []error
	if options.IdentityLeaseDurationSeconds <= 0 {
		errs = append(errs, fmt.Errorf("--identity-lease-duration-seconds should be a positive number, but value '%d' provided", options.IdentityLeaseDurationSeconds))
	}
	if options.IdentityLeaseRenewIntervalSeconds <= 0 {
		errs = append(errs, fmt.Errorf("--identity-lease-renew-interval-seconds should be a positive number, but value '%d' provided", options.IdentityLeaseRenewIntervalSeconds))
	}
	return errs
}

// Validate checks ServerRunOptions and return a slice of found errs.
func (s *ServerRunOptions) Validate() []error {
	var errs []error
	if s.MasterCount <= 0 {
		errs = append(errs, fmt.Errorf("--apiserver-count should be a positive number, but value '%d' provided", s.MasterCount))
	}
	errs = append(errs, s.Etcd.Validate()...)
	errs = append(errs, validateClusterIPFlags(s)...)
	errs = append(errs, validateServiceNodePort(s)...)
	errs = append(errs, validateAPIPriorityAndFairness(s)...)
	errs = append(errs, s.SecureServing.Validate()...)
	errs = append(errs, s.Authentication.Validate()...)
	errs = append(errs, s.Authorization.Validate()...)
	errs = append(errs, s.Audit.Validate()...)
	errs = append(errs, s.Admission.Validate()...)
	errs = append(errs, s.APIEnablement.Validate(legacyscheme.Scheme, apiextensionsapiserver.Scheme, aggregatorscheme.Scheme)...)
	errs = append(errs, validateTokenRequest(s)...)
	errs = append(errs, s.Metrics.Validate()...)
	errs = append(errs, s.Logs.Validate()...)
	errs = append(errs, validateAPIServerIdentity(s)...)

	return errs
}
<|endoftext|>


<commit_before>package gogtm

import (
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/szydell/mstools"
)

func createRoutines(workDir string) {
	// prepare paths
	path, pathO, pathR := generatePaths(workDir)
	// create directory tree for routines
	err := os.MkdirAll(pathR, os.ModePerm)
	mstools.ErrCheck(err) // drop log and fatal close on error
	// create path for objects
	err = os.Mkdir(pathO, os.ModePerm)
	mstools.ErrCheck(err) // drop log and fatal close on error

	// get already configured 'gtmroutines' from environment
	routines := os.Getenv("gtmroutines")
	// concatenate old value with path created for this session
	routines += " " + pathO + "(" + pathR + ")"

	// create file with routines
	generateRoutineFile(pathR)

	// set 'gtmroutines' env variable to access internal gogtm file with routines
	os.Setenv("gtmroutines", routines)

	// prepare path for gtmaccess.ci
	ciPath := filepath.Join(path, "gtmaccess.ci")
	// generate gtmaccess.ci
	generateCiFile(ciPath)
	// set 'GTMCI' env variable to access interface file needed by gt.m api
	os.Setenv("GTMCI", ciPath)

}

func generatePaths(workDir string) (path string, pathO string, pathR string) {
	// add unique directory name for this session (do not mix routines between sessions)
	path = filepath.Join(workDir, "gogtm/"+goSessionID)
	// create directories 'o' for objects, 'r' for routines
	pathR = path + "/r"
	pathO = path + "/o"
	return
}

func cleanRoutines(workDir string) {
	path, _, _ := generatePaths(workDir)

	os.RemoveAll(path)
}

func generateCiFile(path string) {
	data := []byte(`gtminit   : void init^%gtmaccess( O:gtm_char_t* )
gtmset    : void set^%gtmaccess( I:gtm_char_t*, I:gtm_string_t*, O:gtm_char_t*)
gtmget    : void get^%gtmaccess( I:gtm_char_t*, I:gtm_string_t*, O:gtm_char_t*, O:gtm_char_t* )
gtmkill   : void kill^%gtmaccess( I:gtm_char_t*, O:gtm_char_t* )
gtmzkill  : void zkill^%gtmaccess( I:gtm_char_t*, O:gtm_char_t* )
gtmorder  : void order^%gtmaccess( I:gtm_char_t*, I:gtm_char_t*, O:gtm_char_t*, O:gtm_char_t* )
gtmxecute : void xecute^%gtmaccess( I:gtm_char_t*, O:gtm_char_t*, O:gtm_char_t* )
gtmlock   : void lock^%gtmaccess( I:gtm_char_t*, O:gtm_char_t* )
gtmquery  : void query^%gtmaccess( I:gtm_char_t*, O:gtm_char_t*, O:gtm_char_t* )
gvstat    : void gvstat^%gtmaccess( O:gtm_char_t*, O:gtm_char_t* )
`)

	err := ioutil.WriteFile(path, data, 0400)
	mstools.ErrCheck(err)
}

func generateRoutineFile(path string) {
	// routines internally used by gogtm. M language.
	data := []byte(`%gtmaccess    ; entry points to access GT.M
    quit
    ;
init(error)
    set $ztrap="new tmp set error=$ecode set tmp=$piece($ecode,"","",2) quit:$quit $extract(tmp,2,$length(tmp)) quit"
    quit:$quit 0 quit
    ;
set(var,value,error)
    set @var=value
    quit:$quit 0 quit
    ;
get(var,opt,value,error)
    set value=$GET(@var,opt)
    quit:$quit 0 quit
    ;
kill(var,error)
    kill @var
    quit:$quit 0 quit
    ;
zkill(var,error)
    zkill @var
    quit:$quit 0 quit
    ;
xecute(code,value,error)
    xecute code
    quit:$quit 0 quit
    ;
order(var,dir,value,error)
    set value=$order(@var,dir)
    quit:$quit 0 quit
    ;
query(var,value,error)
    set value=$query(@var)
    quit:$quit 0 quit
    ;
lock(var,error)
    lock @var
    quit:$quit 0 quit
    ;
gvstat(stats,error)
    N RET
    S REGION=$V("GVFIRST") S RET=REGION_"->"_$V("GVSTAT",REGION)
    F I=1:1 S REGION=$V("GVNEXT",REGION) Q:REGION=""  S RET=RET_"|"_REGION_"->"_$V("GVSTAT",REGION)
    set stats=RET
`)
	path = filepath.Join(path, "_gtmaccess.m")
	err := ioutil.WriteFile(path, data, 0400)
	mstools.ErrCheck(err)
}
<commit_msg>cleanup, functions in alphabetical order<commit_after>package gogtm

import (
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/szydell/mstools"
)

func createRoutines(workDir string) {
	// prepare paths
	path, pathO, pathR := generatePaths(workDir)
	// create directory tree for routines
	err := os.MkdirAll(pathR, os.ModePerm)
	mstools.ErrCheck(err) // drop log and fatal close on error
	// create path for objects
	err = os.Mkdir(pathO, os.ModePerm)
	mstools.ErrCheck(err) // drop log and fatal close on error

	// get already configured 'gtmroutines' from environment
	routines := os.Getenv("gtmroutines")
	// concatenate old value with path created for this session
	routines += " " + pathO + "(" + pathR + ")"

	// create file with routines
	generateRoutineFile(pathR)

	// set 'gtmroutines' env variable to access internal gogtm file with routines
	os.Setenv("gtmroutines", routines)

	// prepare path for gtmaccess.ci
	ciPath := filepath.Join(path, "gtmaccess.ci")
	// generate gtmaccess.ci
	generateCiFile(ciPath)
	// set 'GTMCI' env variable to access interface file needed by gt.m api
	os.Setenv("GTMCI", ciPath)

}

func generatePaths(workDir string) (path string, pathO string, pathR string) {
	// add unique directory name for this session (do not mix routines between sessions)
	path = filepath.Join(workDir, "gogtm/"+goSessionID)
	// create directories 'o' for objects, 'r' for routines
	pathR = path + "/r"
	pathO = path + "/o"
	return
}

func cleanRoutines(workDir string) {
	path, _, _ := generatePaths(workDir)

	os.RemoveAll(path)
}

func generateCiFile(path string) {
	data := []byte(`gtminit   : void init^%gtmaccess( O:gtm_char_t* )
gtmget    : void get^%gtmaccess( I:gtm_char_t*, I:gtm_string_t*, O:gtm_char_t*, O:gtm_char_t* )
gtmkill   : void kill^%gtmaccess( I:gtm_char_t*, O:gtm_char_t* )
gtmorder  : void order^%gtmaccess( I:gtm_char_t*, I:gtm_char_t*, O:gtm_char_t*, O:gtm_char_t* )
gtmquery  : void query^%gtmaccess( I:gtm_char_t*, O:gtm_char_t*, O:gtm_char_t* )
gtmset    : void set^%gtmaccess( I:gtm_char_t*, I:gtm_string_t*, O:gtm_char_t*)
gtmxecute : void xecute^%gtmaccess( I:gtm_char_t*, O:gtm_char_t*, O:gtm_char_t* )
gtmzkill  : void zkill^%gtmaccess( I:gtm_char_t*, O:gtm_char_t* )
gvstat    : void gvstat^%gtmaccess( O:gtm_char_t*, O:gtm_char_t* )
`)

	err := ioutil.WriteFile(path, data, 0400)
	mstools.ErrCheck(err)
}

func generateRoutineFile(path string) {
	// routines internally used by gogtm. M language.
	data := []byte(`%gtmaccess    ; entry points to access GT.M
    quit
    ;
init(error)
    set $ztrap="new tmp set error=$ecode set tmp=$piece($ecode,"","",2) quit:$quit $extract(tmp,2,$length(tmp)) quit"
    quit:$quit 0 quit
    ;
data(var,value,error)
	set value=$data(@var)
	quit:$quit 0 quit
	;
get(var,opt,value,error)
    set value=$GET(@var,opt)
    quit:$quit 0 quit
    ;
gvstat(stats,error)
    N RET
    S REGION=$V("GVFIRST") S RET=REGION_"->"_$V("GVSTAT",REGION)
    F I=1:1 S REGION=$V("GVNEXT",REGION) Q:REGION=""  S RET=RET_"|"_REGION_"->"_$V("GVSTAT",REGION)
    set stats=RET
    ;
kill(var,error)
    kill @var
    quit:$quit 0 quit
    ;
order(var,dir,value,error)
    set value=$order(@var,dir)
    quit:$quit 0 quit
    ;
query(var,value,error)
    set value=$query(@var)
    quit:$quit 0 quit
    ;
set(var,value,error)
    set @var=value
    quit:$quit 0 quit
    ;
xecute(code,value,error)
    xecute code
    quit:$quit 0 quit
    ;
zkill(var,error)
    zkill @var
    quit:$quit 0 quit
    ;
`)
	path = filepath.Join(path, "_gtmaccess.m")
	err := ioutil.WriteFile(path, data, 0400)
	mstools.ErrCheck(err)
}
<|endoftext|>