<commit_before>// Copyright 2016 Apcera Inc. All rights reserved.

package bench

import (
	"bytes"
	"encoding/csv"
	"fmt"
	"log"
	"math"
	"strconv"
	"time"

	"github.com/nats-io/nats"
	"github.com/nats-io/nuid"
)

// A Sample for a particular client
type Sample struct {
	JobMsgCnt int
	MsgCnt    uint64
	MsgBytes  uint64
	IOBytes   uint64
	Start     time.Time
	End       time.Time
}

// SampleGroup for a number of samples, the group is a Sample itself agregating the values the Samples
type SampleGroup struct {
	Sample
	Samples []*Sample
}

// Benchmark to hold the various Samples organized by publishers and subscribers
type Benchmark struct {
	Sample
	Name       string
	RunID      string
	Pubs       *SampleGroup
	Subs       *SampleGroup
	subChannel chan *Sample
	pubChannel chan *Sample
}

// NewBenchmark initializes a Benchmark. After creating a bench call AddSubSample/AddPubSample.
// When done collecting samples, call EndBenchmark
func NewBenchmark(name string, subCnt, pubCnt int) *Benchmark {
	bm := Benchmark{Name: name, RunID: nuid.Next()}
	bm.Subs = NewSampleGroup()
	bm.Pubs = NewSampleGroup()
	bm.subChannel = make(chan *Sample, subCnt)
	bm.pubChannel = make(chan *Sample, pubCnt)
	return &bm
}

// Close organizes collected Samples and calculates aggregates. After Close(), no more samples can be added.
func (bm *Benchmark) Close() {
	close(bm.subChannel)
	close(bm.pubChannel)

	for s := range bm.subChannel {
		bm.Subs.AddSample(s)
	}
	for s := range bm.pubChannel {
		bm.Pubs.AddSample(s)
	}

	if bm.Subs.HasSamples() {
		bm.Start = bm.Subs.Start
		bm.End = bm.Subs.End
	} else {
		bm.Start = bm.Pubs.Start
		bm.End = bm.Pubs.End
	}

	if bm.Subs.HasSamples() && bm.Pubs.HasSamples() {
		if bm.Start.After(bm.Subs.Start) {
			bm.Start = bm.Subs.Start
		}
		if bm.Start.After(bm.Pubs.Start) {
			bm.Start = bm.Pubs.Start
		}

		if bm.End.Before(bm.Subs.End) {
			bm.End = bm.Subs.End
		}
		if bm.End.Before(bm.Pubs.End) {
			bm.End = bm.Pubs.End
		}
	}

	bm.MsgBytes = bm.Pubs.MsgBytes + bm.Subs.MsgBytes
	bm.IOBytes = bm.Pubs.IOBytes + bm.Subs.IOBytes
	bm.MsgCnt = bm.Pubs.MsgCnt + bm.Subs.MsgCnt
	bm.JobMsgCnt = bm.Pubs.JobMsgCnt + bm.Subs.JobMsgCnt
}

// AddSubSample to the benchmark
func (bm *Benchmark) AddSubSample(s *Sample) {
	bm.subChannel <- s
}

// AddPubSample to the benchmark
func (bm *Benchmark) AddPubSample(s *Sample) {
	bm.pubChannel <- s
}

// CSV generates a csv report of all the samples collected
func (bm *Benchmark) CSV() string {
	var buffer bytes.Buffer
	writer := csv.NewWriter(&buffer)
	headers := []string{"#RunID", "ClientID", "MsgCount", "MsgBytes", "MsgsPerSec", "BytesPerSec", "DurationSecs"}
	if err := writer.Write(headers); err != nil {
		log.Fatalf("Error while serializing headers %q: %v", headers, err)
	}
	groups := []*SampleGroup{bm.Subs, bm.Pubs}
	pre := "S"
	for i, g := range groups {
		if i == 1 {
			pre = "P"
		}
		for j, c := range g.Samples {
			r := []string{bm.RunID, fmt.Sprintf("%s%d", pre, j), fmt.Sprintf("%d", c.MsgCnt), fmt.Sprintf("%d", c.MsgBytes), fmt.Sprintf("%d", c.Rate()), fmt.Sprintf("%f", c.Throughput()), fmt.Sprintf("%f", c.Duration().Seconds())}
			if err := writer.Write(r); err != nil {
				log.Fatalf("Error while serializing %v: %v", c, err)
			}
		}
	}

	writer.Flush()
	return buffer.String()
}

// NewSample creates a new Sample initialized to the provided values. The nats.Conn information captured
func NewSample(jobCount int, msgSize int, start, end time.Time, nc *nats.Conn) *Sample {
	s := Sample{JobMsgCnt: jobCount, Start: start, End: end}
	s.MsgBytes = uint64(msgSize * jobCount)
	s.MsgCnt = nc.OutMsgs + nc.InMsgs
	s.IOBytes = nc.OutBytes + nc.InBytes
	return &s
}

// Throughput of bytes per second
func (s *Sample) Throughput() float64 {
	return float64(s.MsgBytes) / s.Duration().Seconds()
}

// Rate of meessages in the job per second
func (s *Sample) Rate() int64 {
	return int64(float64(s.JobMsgCnt) / s.Duration().Seconds())
}

func (s *Sample) String() string {
	rate := commaFormat(s.Rate())
	throughput := HumanBytes(s.Throughput(), false)
	return fmt.Sprintf("%s msgs/sec ~ %s/sec", rate, throughput)
}

// Duration that the sample was active
func (s *Sample) Duration() time.Duration {
	return s.End.Sub(s.Start)
}

// Seconds that the sample or samples were active
func (s *Sample) Seconds() float64 {
	return s.Duration().Seconds()
}

// NewSampleGroup initializer
func NewSampleGroup() *SampleGroup {
	s := new(SampleGroup)
	s.Samples = make([]*Sample, 0, 0)
	return s
}

// Statistics information of the sample group (min, average, max and standard deviation)
func (sg *SampleGroup) Statistics() string {
	return fmt.Sprintf("min %s | avg %s | max %s | stddev %s msgs", commaFormat(sg.MinRate()), commaFormat(sg.AvgRate()), commaFormat(sg.MaxRate()), commaFormat(int64(sg.StdDev())))
}

// MinRate returns the smallest message rate in the SampleGroup
func (sg *SampleGroup) MinRate() int64 {
	m := int64(0)
	for i, s := range sg.Samples {
		if i == 0 {
			m = s.Rate()
		}
		m = min(m, s.Rate())
	}
	return m
}

// MaxRate returns the largest message rate in the SampleGroup
func (sg *SampleGroup) MaxRate() int64 {
	m := int64(0)
	for i, s := range sg.Samples {
		if i == 0 {
			m = s.Rate()
		}
		m = max(m, s.Rate())
	}
	return m
}

// AvgRate returns the average of all the message rates in the SampleGroup
func (sg *SampleGroup) AvgRate() int64 {
	sum := uint64(0)
	for _, s := range sg.Samples {
		sum += uint64(s.Rate())
	}
	return int64(sum / uint64(len(sg.Samples)))
}

// StdDev returns the standard deviation the message rates in the SampleGroup
func (sg *SampleGroup) StdDev() float64 {
	avg := float64(sg.AvgRate())
	sum := float64(0)
	for _, c := range sg.Samples {
		sum += math.Pow(float64(c.Rate())-avg, 2)
	}
	variance := sum / float64(len(sg.Samples))
	return math.Sqrt(variance)
}

// AddSample adds a Sample to the SampleGroup. After adding a Sample it shouldn't be modified.
func (sg *SampleGroup) AddSample(e *Sample) {
	sg.Samples = append(sg.Samples, e)

	if len(sg.Samples) == 1 {
		sg.Start = e.Start
		sg.End = e.End
	}
	sg.IOBytes += e.IOBytes
	sg.JobMsgCnt += e.JobMsgCnt
	sg.MsgCnt += e.MsgCnt
	sg.MsgBytes += e.MsgBytes

	if e.Start.Before(sg.Start) {
		sg.Start = e.Start
	}

	if e.End.After(sg.End) {
		sg.End = e.End
	}
}

// HasSamples returns true if the group has samples
func (sg *SampleGroup) HasSamples() bool {
	return len(sg.Samples) > 0
}

// Report returns a human readable report of the samples taken in the Benchmark
func (bm *Benchmark) Report() string {
	var buffer bytes.Buffer

	indent := ""
	if bm.Pubs.HasSamples() && bm.Subs.HasSamples() {
		buffer.WriteString(fmt.Sprintf("%s Pub/Sub stats: %s\n", bm.Name, bm))
		indent += " "
	}
	if bm.Pubs.HasSamples() {
		maybeTitle := ""
		if !bm.Subs.HasSamples() {
			maybeTitle = bm.Name + " "
		}
		buffer.WriteString(fmt.Sprintf("%s%sPub stats: %s\n", indent, maybeTitle, bm.Pubs))
		if len(bm.Pubs.Samples) > 1 {
			for i, stat := range bm.Pubs.Samples {
				buffer.WriteString(fmt.Sprintf("%s [%d] %v (%d msgs)\n", indent, i+1, stat, stat.JobMsgCnt))
			}
			buffer.WriteString(fmt.Sprintf("%s %s\n", indent, bm.Pubs.Statistics()))
		}
	}

	if bm.Subs.HasSamples() {
		maybeTitle := ""
		if !bm.Subs.HasSamples() {
			maybeTitle = bm.Name + " "
		}
		buffer.WriteString(fmt.Sprintf("%s%sSub stats: %s\n", indent, maybeTitle, bm.Subs))
		if len(bm.Subs.Samples) > 1 {
			for i, stat := range bm.Subs.Samples {
				buffer.WriteString(fmt.Sprintf("%s [%d] %v (%d msgs)\n", indent, i+1, stat, stat.JobMsgCnt))
			}
			buffer.WriteString(fmt.Sprintf("%s %s\n", indent, bm.Subs.Statistics()))
		}
	}
	return buffer.String()
}

func commaFormat(n int64) string {
	in := strconv.FormatInt(n, 10)
	out := make([]byte, len(in)+(len(in)-2+int(in[0]/'0'))/3)
	if in[0] == '-' {
		in, out[0] = in[1:], '-'
	}
	for i, j, k := len(in)-1, len(out)-1, 0; ; i, j = i-1, j-1 {
		out[j] = in[i]
		if i == 0 {
			return string(out)
		}
		if k++; k == 3 {
			j, k = j-1, 0
			out[j] = ','
		}
	}
}

// HumanBytes formats bytes as a human readable string
func HumanBytes(bytes float64, si bool) string {
	var base = 1024
	pre := []string{"K", "M", "G", "T", "P", "E"}
	var post = "B"
	if si {
		base = 1000
		pre = []string{"k", "M", "G", "T", "P", "E"}
		post = "iB"
	}
	if bytes < float64(base) {
		return fmt.Sprintf("%.2f B", bytes)
	}
	exp := int(math.Log(bytes) / math.Log(float64(base)))
	index := exp - 1
	units := pre[index] + post
	return fmt.Sprintf("%.2f %s", bytes/math.Pow(float64(base), float64(exp)), units)
}

func min(x, y int64) int64 {
	if x < y {
		return x
	}
	return y
}

func max(x, y int64) int64 {
	if x > y {
		return x
	}
	return y
}

// MsgsPerClient divides the number of messages by the number of clients and tries to distribute them as evenly as possible
func MsgsPerClient(numMsgs, numClients int) []int {
	var counts []int
	if numClients == 0 || numMsgs == 0 {
		return counts
	}
	counts = make([]int, numClients)
	mc := numMsgs / numClients
	for i := 0; i < numClients; i++ {
		counts[i] = mc
	}
	extra := numMsgs % numClients
	for i := 0; i < extra; i++ {
		counts[i]++
	}
	return counts
}
<commit_msg>Removed dead code from previous iteration.<commit_after>// Copyright 2016 Apcera Inc. All rights reserved.

package bench

import (
	"bytes"
	"encoding/csv"
	"fmt"
	"log"
	"math"
	"strconv"
	"time"

	"github.com/nats-io/nats"
	"github.com/nats-io/nuid"
)

// A Sample for a particular client
type Sample struct {
	JobMsgCnt int
	MsgCnt    uint64
	MsgBytes  uint64
	IOBytes   uint64
	Start     time.Time
	End       time.Time
}

// SampleGroup for a number of samples, the group is a Sample itself agregating the values the Samples
type SampleGroup struct {
	Sample
	Samples []*Sample
}

// Benchmark to hold the various Samples organized by publishers and subscribers
type Benchmark struct {
	Sample
	Name       string
	RunID      string
	Pubs       *SampleGroup
	Subs       *SampleGroup
	subChannel chan *Sample
	pubChannel chan *Sample
}

// NewBenchmark initializes a Benchmark. After creating a bench call AddSubSample/AddPubSample.
// When done collecting samples, call EndBenchmark
func NewBenchmark(name string, subCnt, pubCnt int) *Benchmark {
	bm := Benchmark{Name: name, RunID: nuid.Next()}
	bm.Subs = NewSampleGroup()
	bm.Pubs = NewSampleGroup()
	bm.subChannel = make(chan *Sample, subCnt)
	bm.pubChannel = make(chan *Sample, pubCnt)
	return &bm
}

// Close organizes collected Samples and calculates aggregates. After Close(), no more samples can be added.
func (bm *Benchmark) Close() {
	close(bm.subChannel)
	close(bm.pubChannel)

	for s := range bm.subChannel {
		bm.Subs.AddSample(s)
	}
	for s := range bm.pubChannel {
		bm.Pubs.AddSample(s)
	}

	if bm.Subs.HasSamples() {
		bm.Start = bm.Subs.Start
		bm.End = bm.Subs.End
	} else {
		bm.Start = bm.Pubs.Start
		bm.End = bm.Pubs.End
	}

	if bm.Subs.HasSamples() && bm.Pubs.HasSamples() {
		if bm.Start.After(bm.Subs.Start) {
			bm.Start = bm.Subs.Start
		}
		if bm.Start.After(bm.Pubs.Start) {
			bm.Start = bm.Pubs.Start
		}

		if bm.End.Before(bm.Subs.End) {
			bm.End = bm.Subs.End
		}
		if bm.End.Before(bm.Pubs.End) {
			bm.End = bm.Pubs.End
		}
	}

	bm.MsgBytes = bm.Pubs.MsgBytes + bm.Subs.MsgBytes
	bm.IOBytes = bm.Pubs.IOBytes + bm.Subs.IOBytes
	bm.MsgCnt = bm.Pubs.MsgCnt + bm.Subs.MsgCnt
	bm.JobMsgCnt = bm.Pubs.JobMsgCnt + bm.Subs.JobMsgCnt
}

// AddSubSample to the benchmark
func (bm *Benchmark) AddSubSample(s *Sample) {
	bm.subChannel <- s
}

// AddPubSample to the benchmark
func (bm *Benchmark) AddPubSample(s *Sample) {
	bm.pubChannel <- s
}

// CSV generates a csv report of all the samples collected
func (bm *Benchmark) CSV() string {
	var buffer bytes.Buffer
	writer := csv.NewWriter(&buffer)
	headers := []string{"#RunID", "ClientID", "MsgCount", "MsgBytes", "MsgsPerSec", "BytesPerSec", "DurationSecs"}
	if err := writer.Write(headers); err != nil {
		log.Fatalf("Error while serializing headers %q: %v", headers, err)
	}
	groups := []*SampleGroup{bm.Subs, bm.Pubs}
	pre := "S"
	for i, g := range groups {
		if i == 1 {
			pre = "P"
		}
		for j, c := range g.Samples {
			r := []string{bm.RunID, fmt.Sprintf("%s%d", pre, j), fmt.Sprintf("%d", c.MsgCnt), fmt.Sprintf("%d", c.MsgBytes), fmt.Sprintf("%d", c.Rate()), fmt.Sprintf("%f", c.Throughput()), fmt.Sprintf("%f", c.Duration().Seconds())}
			if err := writer.Write(r); err != nil {
				log.Fatalf("Error while serializing %v: %v", c, err)
			}
		}
	}

	writer.Flush()
	return buffer.String()
}

// NewSample creates a new Sample initialized to the provided values. The nats.Conn information captured
func NewSample(jobCount int, msgSize int, start, end time.Time, nc *nats.Conn) *Sample {
	s := Sample{JobMsgCnt: jobCount, Start: start, End: end}
	s.MsgBytes = uint64(msgSize * jobCount)
	s.MsgCnt = nc.OutMsgs + nc.InMsgs
	s.IOBytes = nc.OutBytes + nc.InBytes
	return &s
}

// Throughput of bytes per second
func (s *Sample) Throughput() float64 {
	return float64(s.MsgBytes) / s.Duration().Seconds()
}

// Rate of meessages in the job per second
func (s *Sample) Rate() int64 {
	return int64(float64(s.JobMsgCnt) / s.Duration().Seconds())
}

func (s *Sample) String() string {
	rate := commaFormat(s.Rate())
	throughput := HumanBytes(s.Throughput(), false)
	return fmt.Sprintf("%s msgs/sec ~ %s/sec", rate, throughput)
}

// Duration that the sample was active
func (s *Sample) Duration() time.Duration {
	return s.End.Sub(s.Start)
}

// Seconds that the sample or samples were active
func (s *Sample) Seconds() float64 {
	return s.Duration().Seconds()
}

// NewSampleGroup initializer
func NewSampleGroup() *SampleGroup {
	s := new(SampleGroup)
	s.Samples = make([]*Sample, 0, 0)
	return s
}

// Statistics information of the sample group (min, average, max and standard deviation)
func (sg *SampleGroup) Statistics() string {
	return fmt.Sprintf("min %s | avg %s | max %s | stddev %s msgs", commaFormat(sg.MinRate()), commaFormat(sg.AvgRate()), commaFormat(sg.MaxRate()), commaFormat(int64(sg.StdDev())))
}

// MinRate returns the smallest message rate in the SampleGroup
func (sg *SampleGroup) MinRate() int64 {
	m := int64(0)
	for i, s := range sg.Samples {
		if i == 0 {
			m = s.Rate()
		}
		m = min(m, s.Rate())
	}
	return m
}

// MaxRate returns the largest message rate in the SampleGroup
func (sg *SampleGroup) MaxRate() int64 {
	m := int64(0)
	for i, s := range sg.Samples {
		if i == 0 {
			m = s.Rate()
		}
		m = max(m, s.Rate())
	}
	return m
}

// AvgRate returns the average of all the message rates in the SampleGroup
func (sg *SampleGroup) AvgRate() int64 {
	sum := uint64(0)
	for _, s := range sg.Samples {
		sum += uint64(s.Rate())
	}
	return int64(sum / uint64(len(sg.Samples)))
}

// StdDev returns the standard deviation the message rates in the SampleGroup
func (sg *SampleGroup) StdDev() float64 {
	avg := float64(sg.AvgRate())
	sum := float64(0)
	for _, c := range sg.Samples {
		sum += math.Pow(float64(c.Rate())-avg, 2)
	}
	variance := sum / float64(len(sg.Samples))
	return math.Sqrt(variance)
}

// AddSample adds a Sample to the SampleGroup. After adding a Sample it shouldn't be modified.
func (sg *SampleGroup) AddSample(e *Sample) {
	sg.Samples = append(sg.Samples, e)

	if len(sg.Samples) == 1 {
		sg.Start = e.Start
		sg.End = e.End
	}
	sg.IOBytes += e.IOBytes
	sg.JobMsgCnt += e.JobMsgCnt
	sg.MsgCnt += e.MsgCnt
	sg.MsgBytes += e.MsgBytes

	if e.Start.Before(sg.Start) {
		sg.Start = e.Start
	}

	if e.End.After(sg.End) {
		sg.End = e.End
	}
}

// HasSamples returns true if the group has samples
func (sg *SampleGroup) HasSamples() bool {
	return len(sg.Samples) > 0
}

// Report returns a human readable report of the samples taken in the Benchmark
func (bm *Benchmark) Report() string {
	var buffer bytes.Buffer

	indent := ""
	if !bm.Pubs.HasSamples() && !bm.Subs.HasSamples() {
		return "No publisher or subscribers. Nothing to report."
	}

	if bm.Pubs.HasSamples() && bm.Subs.HasSamples() {
		buffer.WriteString(fmt.Sprintf("%s Pub/Sub stats: %s\n", bm.Name, bm))
		indent += " "
	}
	if bm.Pubs.HasSamples() {
		buffer.WriteString(fmt.Sprintf("%sPub stats: %s\n", indent, bm.Pubs))
		if len(bm.Pubs.Samples) > 1 {
			for i, stat := range bm.Pubs.Samples {
				buffer.WriteString(fmt.Sprintf("%s [%d] %v (%d msgs)\n", indent, i+1, stat, stat.JobMsgCnt))
			}
			buffer.WriteString(fmt.Sprintf("%s %s\n", indent, bm.Pubs.Statistics()))
		}
	}

	if bm.Subs.HasSamples() {
		buffer.WriteString(fmt.Sprintf("%sSub stats: %s\n", indent, bm.Subs))
		if len(bm.Subs.Samples) > 1 {
			for i, stat := range bm.Subs.Samples {
				buffer.WriteString(fmt.Sprintf("%s [%d] %v (%d msgs)\n", indent, i+1, stat, stat.JobMsgCnt))
			}
			buffer.WriteString(fmt.Sprintf("%s %s\n", indent, bm.Subs.Statistics()))
		}
	}
	return buffer.String()
}

func commaFormat(n int64) string {
	in := strconv.FormatInt(n, 10)
	out := make([]byte, len(in)+(len(in)-2+int(in[0]/'0'))/3)
	if in[0] == '-' {
		in, out[0] = in[1:], '-'
	}
	for i, j, k := len(in)-1, len(out)-1, 0; ; i, j = i-1, j-1 {
		out[j] = in[i]
		if i == 0 {
			return string(out)
		}
		if k++; k == 3 {
			j, k = j-1, 0
			out[j] = ','
		}
	}
}

// HumanBytes formats bytes as a human readable string
func HumanBytes(bytes float64, si bool) string {
	var base = 1024
	pre := []string{"K", "M", "G", "T", "P", "E"}
	var post = "B"
	if si {
		base = 1000
		pre = []string{"k", "M", "G", "T", "P", "E"}
		post = "iB"
	}
	if bytes < float64(base) {
		return fmt.Sprintf("%.2f B", bytes)
	}
	exp := int(math.Log(bytes) / math.Log(float64(base)))
	index := exp - 1
	units := pre[index] + post
	return fmt.Sprintf("%.2f %s", bytes/math.Pow(float64(base), float64(exp)), units)
}

func min(x, y int64) int64 {
	if x < y {
		return x
	}
	return y
}

func max(x, y int64) int64 {
	if x > y {
		return x
	}
	return y
}

// MsgsPerClient divides the number of messages by the number of clients and tries to distribute them as evenly as possible
func MsgsPerClient(numMsgs, numClients int) []int {
	var counts []int
	if numClients == 0 || numMsgs == 0 {
		return counts
	}
	counts = make([]int, numClients)
	mc := numMsgs / numClients
	for i := 0; i < numClients; i++ {
		counts[i] = mc
	}
	extra := numMsgs % numClients
	for i := 0; i < extra; i++ {
		counts[i]++
	}
	return counts
}
<|endoftext|>


<commit_before>package main

import (
    "github.com/fzzbt/radix/redis"
	"flag"
	"fmt"
	"time"
	"os"
	"strings"
)

var connections *int = flag.Int("c", 50, "number of connections")
var requests *int = flag.Int("n", 10000, "number of request")
var dsize *int = flag.Int("d", 3, "data size")
//var cpuprof *string = flag.String("cpuprof", "", "filename for cpuprof")
//var memprof *string = flag.String("memprof", "", "filename for memprof")

// handleReplyError prints an error message for the given reply.
func handleReplyError(rep *redis.Reply) {
	if rep.Error != nil {
		fmt.Println("redis: " + rep.Error.Error())
	} else {
		fmt.Println("redis: unexpected reply type")
	}
}

// benchmark benchmarks the given function.
func benchmark(data string, handle func(string, *redis.Client, chan struct{})) time.Duration {
	c, err := redis.NewClient(redis.Configuration{
		Database: 8,
		Path: "/tmp/redis.sock",
		PoolSize: *connections,
	})

	if err != nil {
		fmt.Printf("NewClient failed: %s\n", err)
		os.Exit(1)
	}

	rep := c.Flushdb()
	if rep.Error != nil {
		handleReplyError(rep)
		os.Exit(1)
	}

	ch := make(chan struct{})
	start := time.Now()

    for i := 0; i < *connections; i++ {
        go handle(data, c, ch)
    }

    for i := 0; i < *requests; i++ {
        ch <- struct{}{}
    }

	dur := time.Now().Sub(start)
	c.Close()
	return dur
}

func run(name string, data string) {
    test, ok := tests[name]

    if !ok {
        fmt.Fprintf(os.Stderr, "test: `%s` does not exists\n", name)
        os.Exit(1)
    }

    fmt.Printf("===== %s =====\n", strings.ToUpper(name))
	duration := benchmark(data, test)
	rps := float64(*requests) / duration.Seconds()
	fmt.Println("Requests per second: ", rps)
	fmt.Println("Duration: ", duration)
	fmt.Println()
}

func main() {
	var data string

    flag.Parse()

	for i := 0; i < *dsize; i++ {
		data += "0"
	}

    fmt.Printf(
		"Connections: %d, Requests: %d Payload size: %d\n\n",
		*connections,
		*requests,
		*dsize)

	args := flag.Args()
	if len(args) == 0 {
		// run all tests by default
		for k, _ := range tests {
			run(k, data)
		}
	} else {
		for _, name := range flag.Args() {
			run(name, data)
		}
	}
}
<commit_msg>bench: data 0 -> x<commit_after>package main

import (
    "github.com/fzzbt/radix/redis"
	"flag"
	"fmt"
	"time"
	"os"
	"strings"
)

var connections *int = flag.Int("c", 50, "number of connections")
var requests *int = flag.Int("n", 10000, "number of request")
var dsize *int = flag.Int("d", 3, "data size")
//var cpuprof *string = flag.String("cpuprof", "", "filename for cpuprof")
//var memprof *string = flag.String("memprof", "", "filename for memprof")

// handleReplyError prints an error message for the given reply.
func handleReplyError(rep *redis.Reply) {
	if rep.Error != nil {
		fmt.Println("redis: " + rep.Error.Error())
	} else {
		fmt.Println("redis: unexpected reply type")
	}
}

// benchmark benchmarks the given function.
func benchmark(data string, handle func(string, *redis.Client, chan struct{})) time.Duration {
	c, err := redis.NewClient(redis.Configuration{
		Database: 8,
		Path: "/tmp/redis.sock",
		PoolSize: *connections,
	})

	if err != nil {
		fmt.Printf("NewClient failed: %s\n", err)
		os.Exit(1)
	}

	rep := c.Flushdb()
	if rep.Error != nil {
		handleReplyError(rep)
		os.Exit(1)
	}

	ch := make(chan struct{})
	start := time.Now()

    for i := 0; i < *connections; i++ {
        go handle(data, c, ch)
    }

    for i := 0; i < *requests; i++ {
        ch <- struct{}{}
    }

	dur := time.Now().Sub(start)
	c.Close()
	return dur
}

func run(name string, data string) {
    test, ok := tests[name]

    if !ok {
        fmt.Fprintf(os.Stderr, "test: `%s` does not exists\n", name)
        os.Exit(1)
    }

    fmt.Printf("===== %s =====\n", strings.ToUpper(name))
	duration := benchmark(data, test)
	rps := float64(*requests) / duration.Seconds()
	fmt.Println("Requests per second: ", rps)
	fmt.Println("Duration: ", duration)
	fmt.Println()
}

func main() {
	var data string

    flag.Parse()

	for i := 0; i < *dsize; i++ {
		data += "x"
	}

    fmt.Printf(
		"Connections: %d, Requests: %d Payload size: %d\n\n",
		*connections,
		*requests,
		*dsize)

	args := flag.Args()
	if len(args) == 0 {
		// run all tests by default
		for k, _ := range tests {
			run(k, data)
		}
	} else {
		for _, name := range flag.Args() {
			run(name, data)
		}
	}
}
<|endoftext|>


<commit_before>package provision

import (
	"bytes"
	"fmt"
	"text/template"

	"github.com/docker/machine/drivers"
	"github.com/docker/machine/libmachine/auth"
	"github.com/docker/machine/libmachine/engine"
	"github.com/docker/machine/libmachine/provision/pkgaction"
	"github.com/docker/machine/libmachine/swarm"
	"github.com/docker/machine/log"
	"github.com/docker/machine/utils"
)

func init() {
	Register("openSUSE", &RegisteredProvisioner{
		New: NewOpenSUSEProvisioner,
	})
	Register("SUSE Linux Enterprise Desktop", &RegisteredProvisioner{
		New: NewSLEDProvisioner,
	})
	Register("SUSE Linux Enterprise Server", &RegisteredProvisioner{
		New: NewSLESProvisioner,
	})
}

func NewOpenSUSEProvisioner(d drivers.Driver) Provisioner {
	return &SUSEProvisioner{
		GenericProvisioner{
			DockerOptionsDir:  "/etc/docker",
			DaemonOptionsFile: "/etc/sysconfig/docker",
			OsReleaseId:       "opensuse",
			Packages: []string{
				"curl",
			},
			Driver: d,
		},
	}
}

func NewSLEDProvisioner(d drivers.Driver) Provisioner {
	return &SUSEProvisioner{
		GenericProvisioner{
			DockerOptionsDir:  "/etc/docker",
			DaemonOptionsFile: "/etc/sysconfig/docker",
			OsReleaseId:       "sled",
			Packages: []string{
				"curl",
			},
			Driver: d,
		},
	}
}

func NewSLESProvisioner(d drivers.Driver) Provisioner {
	return &SUSEProvisioner{
		GenericProvisioner{
			DockerOptionsDir:  "/etc/docker",
			DaemonOptionsFile: "/etc/sysconfig/docker",
			OsReleaseId:       "sles",
			Packages: []string{
				"curl",
			},
			Driver: d,
		},
	}
}

type SUSEProvisioner struct {
	GenericProvisioner
}

func (provisioner *SUSEProvisioner) Service(name string, action pkgaction.ServiceAction) error {
	reloadDaemon := false
	switch action {
	case pkgaction.Start, pkgaction.Restart:
		reloadDaemon = true
	}

	// systemd needs reloaded when config changes on disk; we cannot
	// be sure exactly when it changes from the provisioner so
	// we call a reload on every restart to be safe
	if reloadDaemon {
		if _, err := provisioner.SSHCommand("sudo systemctl daemon-reload"); err != nil {
			return err
		}
	}

	command := fmt.Sprintf("sudo systemctl %s %s", action.String(), name)

	if _, err := provisioner.SSHCommand(command); err != nil {
		return err
	}

	return nil
}

func (provisioner *SUSEProvisioner) Package(name string, action pkgaction.PackageAction) error {
	var packageAction string

	switch action {
	case pkgaction.Install:
		packageAction = "install"
	case pkgaction.Remove:
		packageAction = "remove"
	case pkgaction.Upgrade:
		packageAction = "upgrade"
	}

	command := fmt.Sprintf("sudo -E zypper -n %s %s", packageAction, name)

	if _, err := provisioner.SSHCommand(command); err != nil {
		return err
	}

	return nil
}

func (provisioner *SUSEProvisioner) dockerDaemonResponding() bool {
	if _, err := provisioner.SSHCommand("sudo docker version"); err != nil {
		log.Warnf("Error getting SSH command to check if the daemon is up: %s", err)
		return false
	}

	// The daemon is up if the command worked.  Carry on.
	return true
}

func (provisioner *SUSEProvisioner) Provision(swarmOptions swarm.SwarmOptions, authOptions auth.AuthOptions, engineOptions engine.EngineOptions) error {
	provisioner.SwarmOptions = swarmOptions
	provisioner.AuthOptions = authOptions
	provisioner.EngineOptions = engineOptions

	if err := provisioner.SetHostname(provisioner.Driver.GetMachineName()); err != nil {
		return err
	}

	for _, pkg := range provisioner.Packages {
		if err := provisioner.Package(pkg, pkgaction.Install); err != nil {
			return err
		}
	}

	// update OS -- this is needed for libdevicemapper and the docker install
	if _, err := provisioner.SSHCommand("sudo zypper ref"); err != nil {
		return err
	}
	if _, err := provisioner.SSHCommand("sudo zypper -n update"); err != nil {
		return err
	}

	if err := installDockerGeneric(provisioner, engineOptions.InstallURL); err != nil {
		return err
	}

	if _, err := provisioner.SSHCommand("sudo systemctl start docker"); err != nil {
		return err
	}

	if err := utils.WaitFor(provisioner.dockerDaemonResponding); err != nil {
		return err
	}

	if _, err := provisioner.SSHCommand("sudo systemctl stop docker"); err != nil {
		return err
	}

	// open firewall port required by docker
	if _, err := provisioner.SSHCommand("sudo /sbin/yast2 firewall services add ipprotocol=tcp tcpport=2376 zone=EXT"); err != nil {
		return err
	}

	if err := makeDockerOptionsDir(provisioner); err != nil {
		return err
	}

	provisioner.AuthOptions = setRemoteAuthOptions(provisioner)

	if err := ConfigureAuth(provisioner); err != nil {
		return err
	}

	if err := configureSwarm(provisioner, swarmOptions, provisioner.AuthOptions); err != nil {
		return err
	}

	return nil
}

func (provisioner *SUSEProvisioner) GenerateDockerOptions(dockerPort int) (*DockerOptions, error) {
	var (
		engineCfg  bytes.Buffer
		configPath = provisioner.DaemonOptionsFile
	)

	// remove existing
	if _, err := provisioner.SSHCommand(fmt.Sprintf("sudo rm %s", configPath)); err != nil {
		return nil, err
	}

	driverNameLabel := fmt.Sprintf("provider=%s", provisioner.Driver.DriverName())
	provisioner.EngineOptions.Labels = append(provisioner.EngineOptions.Labels, driverNameLabel)

	engineConfigTmpl := `# File automatically generated by docker-machine
DOCKER_OPTS=' -H tcp://0.0.0.0:{{.DockerPort}} {{ if .EngineOptions.StorageDriver }} --storage-driver {{.EngineOptions.StorageDriver}} {{ end }} --tlsverify --tlscacert {{.AuthOptions.CaCertRemotePath}} --tlscert {{.AuthOptions.ServerCertRemotePath}} --tlskey {{.AuthOptions.ServerKeyRemotePath}} {{ range .EngineOptions.Labels }}--label {{.}} {{ end }}{{ range .EngineOptions.InsecureRegistry }}--insecure-registry {{.}} {{ end }}{{ range .EngineOptions.RegistryMirror }}--registry-mirror {{.}} {{ end }}{{ range .EngineOptions.ArbitraryFlags }}--{{.}} {{ end }}'
`
	t, err := template.New("engineConfig").Parse(engineConfigTmpl)
	if err != nil {
		return nil, err
	}

	engineConfigContext := EngineConfigContext{
		DockerPort:       dockerPort,
		AuthOptions:      provisioner.AuthOptions,
		EngineOptions:    provisioner.EngineOptions,
		DockerOptionsDir: provisioner.DockerOptionsDir,
	}

	t.Execute(&engineCfg, engineConfigContext)

	daemonOptsDir := configPath
	return &DockerOptions{
		EngineOptions:     engineCfg.String(),
		EngineOptionsPath: daemonOptsDir,
	}, nil
}
<commit_msg>Revert "Add SUSE Enterprise Linux and openSUSE provision"<commit_after><|endoftext|>


<commit_before>package aranGO

import (
	"errors"
  "strconv"
)

// Aql query
type Query struct {
	// mandatory
	Aql string `json:"query,omitempty"`
	//Optional values
	Batch    int                    `json:"batchSize,omitempty"`
	Count    bool                   `json:"count,omitempty"`
	BindVars map[string]interface{} `json:"bindVars,omitempty"`
	Options  map[string]interface{} `json:"options,omitempty"`
  // opetions fullCount bool
  // Note that the fullCount sub-attribute will only be present in the result if the query has a LIMIT clause and the LIMIT clause is actually used in the query.

	// Control
	Validate bool   `json:"-"`
	ErrorMsg string `json:"errorMessage,omitempty"`
}

func NewQuery(query string) *Query {
  var q Query
  // alocate maps
  q.Options = make(map[string]interface{})
  q.BindVars= make(map[string]interface{})

	if query == "" {
		return &q
	} else {
		q.Aql = query
		return &q
	}
}

func (q *Query) Modify(query string) error {
	if query == "" {
		return errors.New("query must not be empty")
	} else {
		q.Aql = query
		return nil
	}
}

// Validate query before execution
func (q *Query) MustCheck() {
	q.Validate = true
	return
}

type AqlStructer interface{
  Generate()     string
}

// Basic structure
type AqlStruct struct {
  // main loop var
  main        string
  list        string
  lines       []AqlStructer
  vars        map[string]string
  //Collect
  Groups      Collect                   `json:"groups"`
  // Return
  // could be string or AqlStruct
  View        `json:"view"`
}

func (aq *AqlStruct) Generate() string{
  q:= "FOR "+aq.main+" IN "+aq.list

  for _,line :=range(aq.lines){
    q+= line.Generate()
  }

  // Add default view
  if aq.View == nil {
    q+= `
RETURN `+aq.main
  }else{
    // Generate view
    q+= aq.View.Generate()
  }

  return q
}

type View map[string]interface{}

func (v View) Generate() string{
  q:= ""
  return q
}

type Collects struct{
  // COLLECT key = Obj.Var,..., INTO Gro
  Collect map[string]Group  `json:"collect"`
  Gro   string              `json:"group"`
}

type Group struct{
  Obj   string  `json:"obj"`
  Var   string  `json:"var"`
}

type Limits struct{
  Skip   int64
  Limit  int64
}

func (l Limits) Generate() string {
  skip := strconv.FormatInt(l.Skip,10)
  limit:= strconv.FormatInt(l.Limit,10)
  li := `
LIMIT `+skip+`,`+limit
  return li
}

func (aq *AqlStruct) AddLimit(skip,limit int64) *AqlStruct{
  var l Limits
  l.Skip = skip
  l.Limit = limit
  aq.lines = append(aq.lines,l)
  return aq
}

type Lets struct {
  list    map[string]interface{}    `json:"lets"`
}

type Filters struct{
  Key    string  `json:"key"`
  Filter []Pair  `json:"filters"`
}

type Pair struct {
  Obj     string      `json:"obj"`
  Logic   string      `json:"log"`
  Value   interface{} `json:"val"`
}

func (f Filters) Generate() string{
  // check if filters available
  if len(f.Filter) == 0 {
    return ""
  }
  var oper      string

  lenmap := 0
  q := ""

  if f.Filter == nil{
    return ""
  }

  pairs := f.Filter
  key   := f.Key
  // iterate over filters
  // first
  q += `
FILTER (`
  oper = "||"

  for i,pair := range(pairs){
    if i == len(pairs) -1 {
      oper = ""
    }
    switch pair.Value.(type) {
      case bool:
        q += key+"."+pair.Obj+" "+pair.Logic+" "+strconv.FormatBool(pair.Value.(bool))+" "+oper+" "
      case int:
        q += key+"."+pair.Obj+" "+pair.Logic+" "+strconv.Itoa(pair.Value.(int))+" "+oper+" "
      case int64:
        q += key+"."+pair.Obj+" "+pair.Logic+" "+strconv.FormatInt(pair.Value.(int64),10)+" "+oper+" "
      case string:
        q += key+"."+pair.Obj+" "+pair.Logic+" '"+pair.Value.(string)+"' "+oper+" "
      case float32,float64:
        q += key+"."+pair.Obj+" "+pair.Logic+" "+strconv.FormatFloat(pair.Value.(float64),'f',6,64)+" "+oper+" "
      case Var:
        q += key+"."+pair.Obj+" "+pair.Logic+" "+pair.Value.(Var).Obj+"."+pair.Value.(Var).Name+" "+oper+" "
    }
    if i == len(pairs)-1{
      q += ")"
    }
  }
  // next key
  lenmap++
  return q
}

// Variable into document
type Var  struct {
  Obj     string      `json:"obj"`
  Name    string      `json:"name"`
}

//If collect set, vars are reset to context vars
type Collect struct {
  Groups   map[string]string   `json:"groups"`
  Into     string              `json:"into"`
}

/*
func (aq *AqlStruct) ToString() string{
  q := ""
  aq.vars = make(map[string]string)
  // Start with list
  if len(aq.List) == 1 {
    for key,list := range(aq.List){
      aq.vars[key] = ""
      q += "FOR "+key+" IN "+list+" "
    }
  }
  // add filters
  if len(aq.Filters) > 0{
    q += aq.filters()+`
    `
  }
  //
  // view
  q += aq.view()
  return q
}
*/

func (f AqlStruct) view() string{
  if len(f.View) == 0{
    return "RETURN "+f.main
  }
  return ""
}

func (aq *AqlStruct) SetList(obj string,list string) *AqlStruct{
  aq.main = obj
  aq.list = list
  return aq
}

func (aq *AqlStruct) AddFilter(key string,values []Pair) *AqlStruct{
  var fil Filters
  if key != "" && values != nil{
    fil.Key = key
    fil.Filter = values
    aq.lines = append(aq.lines,fil)
  }
  return aq
}

<commit_msg>some more lines<commit_after>package aranGO

import (
	"errors"
  "strconv"
)

// Aql query
type Query struct {
	// mandatory
	Aql string `json:"query,omitempty"`
	//Optional values
	Batch    int                    `json:"batchSize,omitempty"`
	Count    bool                   `json:"count,omitempty"`
	BindVars map[string]interface{} `json:"bindVars,omitempty"`
	Options  map[string]interface{} `json:"options,omitempty"`
  // opetions fullCount bool
  // Note that the fullCount sub-attribute will only be present in the result if the query has a LIMIT clause and the LIMIT clause is actually used in the query.

	// Control
	Validate bool   `json:"-"`
	ErrorMsg string `json:"errorMessage,omitempty"`
}

func NewQuery(query string) *Query {
  var q Query
  // alocate maps
  q.Options = make(map[string]interface{})
  q.BindVars= make(map[string]interface{})

	if query == "" {
		return &q
	} else {
		q.Aql = query
		return &q
	}
}

func (q *Query) Modify(query string) error {
	if query == "" {
		return errors.New("query must not be empty")
	} else {
		q.Aql = query
		return nil
	}
}

// Validate query before execution
func (q *Query) MustCheck() {
	q.Validate = true
	return
}

type AqlStructer interface{
  Generate()     string
}

// Basic structure
type AqlStruct struct {
  // main loop var
  main        string
  list        string
  lines       []AqlStructer
  vars        map[string]string
  // Return
  // could be string or AqlStruct
  //View        `json:"view"`
}

func (aq *AqlStruct) Generate() string{
  q:= "FOR "+aq.main+" IN "+aq.list

  for _,line :=range(aq.lines){
    q+= line.Generate()
  }

  return q
}

func (aq *AqlStruct) AddLoop(v string,list string) *AqlStruct {
  var l Loop
  if v != "" {
    l.Var = v
    l.List = list
  }
  aq.lines = append(aq.lines,l)
  return aq
}

func (aq *AqlStruct) SetView(v map[string]interface{}) *AqlStruct {
  var vie View
  vie = v
  aq.lines = append(aq.lines,vie)
  return aq
}

func (aq *AqlStruct) AddGroup(gs map[string]Var,into string) *AqlStruct{
  if gs != nil {
    var c Collects
    c.Collect = gs
    if into != ""{
      c.Gro = into
    }
    aq.lines = append(aq.lines,c)
  }
  return aq
}

func (aq *AqlStruct) SetList(obj string,list string) *AqlStruct{
  aq.main = obj
  aq.list = list
  return aq
}

func (aq *AqlStruct) AddFilter(key string,values []Pair) *AqlStruct{
  var fil Filters
  if key != "" && values != nil{
    fil.Key = key
    fil.Filter = values
    aq.lines = append(aq.lines,fil)
  }
  return aq
}

type View map[string]interface{}

func (v View) Generate() string{
  q:= `
RETURN { `
  i:=0
  for key,inte := range(v) {
    q += key+":"
    switch inte.(type) {
      case Var:
        q += inte.(Var).Obj+"."+inte.(Var).Name
      case string:
        q += "'"+inte.(string)+"'"
      case int:
        q += strconv.Itoa(inte.(int))
      case int32:
        q += strconv.FormatInt(inte.(int64),10)
      case int64:
        q += strconv.FormatInt(inte.(int64),10)
      case AqlStruct,*AqlStruct:
        q += "( "+inte.(*AqlStruct).Generate()+" )"
    }
    if len(v)-1 != i {
      q+=","
    }
    i++
  }
  q+= " }"
  return q
}

type Collects struct{
  // COLLECT key = Obj.Var,..., INTO Gro
  Collect map[string]Var `json:"collect"`
  Gro   string              `json:"group"`
}

type Group struct{
  Obj   string  `json:"obj"`
  Var   string  `json:"var"`
}

func (c Collects) Generate() string{
  if c.Collect == nil {
    return ""
  }
  q:= `
COLLECT `
  i:= 0
  for key,group := range(c.Collect){
    if i == len(c.Collect)-1 {
      q += key +"="+group.Obj+"."+group.Name
    }

    if i < len(c.Collect)-1 {
      q += key +"="+group.Obj+"."+group.Name+","
    }

    i++
  }
  if c.Gro != ""{
    q += " INTO "+c.Gro
  }
  return q
}

type Limits struct{
  Skip   int64 `json:"skip"`
  Limit  int64 `json:"limit"`
}

func (l Limits) Generate() string {
  skip := strconv.FormatInt(l.Skip,10)
  limit:= strconv.FormatInt(l.Limit,10)
  li := `
LIMIT `+skip+`,`+limit
  return li
}

func (aq *AqlStruct) AddLimit(skip,limit int64) *AqlStruct{
  var l Limits
  l.Skip = skip
  l.Limit = limit
  aq.lines = append(aq.lines,l)
  return aq
}

func (aq *AqlStruct) AddLet(v string,i interface{}) *AqlStruct{
  switch i.(type){
    case string:
    case *AqlStruct:
    default:
      return aq
  }
  var f Lets
  if v != ""{
    f.Var = v
    f.Comm = i
  }
  aq.lines = append(aq.lines,f)
  return aq
}

type Lets struct {
  Var     string         `json:"var"`
  Comm    interface{}    `json:"comm"`
}

func (l Lets) Generate() string {
  q := `
LET `+l.Var+` = (`
  switch l.Comm.(type) {
    case string:
        q += l.Comm.(string)
    case *AqlStruct:
        q += l.Comm.(*AqlStruct).Generate()
  }
  q += `)`
  return q
}

type Filters struct{
  Key    string  `json:"key"`
  Filter []Pair  `json:"filters"`
}

type Pair struct {
  Obj     string      `json:"obj"`
  Logic   string      `json:"op"`
  Value   interface{} `json:"val"`
}

func (f Filters) Generate() string{
  // check if filters available
  if len(f.Filter) == 0 {
    return ""
  }
  var oper      string

  lenmap := 0
  q := ""

  if f.Filter == nil{
    return ""
  }

  pairs := f.Filter
  key   := f.Key
  // iterate over filters
  // first
  q += `
FILTER ( `
  oper = "||"

  for i,pair := range(pairs){
    if i == len(pairs) -1 {
      oper = ""
    }
    switch pair.Value.(type) {
      case bool:
        q += key+"."+pair.Obj+" "+pair.Logic+" "+strconv.FormatBool(pair.Value.(bool))+" "+oper
      case int:
        q += key+"."+pair.Obj+" "+pair.Logic+" "+strconv.Itoa(pair.Value.(int))+" "+oper
      case int64:
        q += key+"."+pair.Obj+" "+pair.Logic+" "+strconv.FormatInt(pair.Value.(int64),10)+" "+oper
      case string:
        q += key+"."+pair.Obj+" "+pair.Logic+" '"+pair.Value.(string)+"' "+oper
      case float32,float64:
        q += key+"."+pair.Obj+" "+pair.Logic+" "+strconv.FormatFloat(pair.Value.(float64),'f',6,64)+" "+oper
      case Var:
        q += key+"."+pair.Obj+" "+pair.Logic+" "+pair.Value.(Var).Obj+"."+pair.Value.(Var).Name+" "+oper
    }
    if i == len(pairs)-1{
      q += ")"
    }
  }
  // next key
  lenmap++
  return q
}

type Loop struct {
  Var  string
  List string
}

func (l Loop) Generate() string{
  q := `
FOR `+l.Var+` IN `+l.List
  return q
}

// Variable into document
type Var  struct {
  Obj     string      `json:"obj"`
  Name    string      `json:"name"`
}
<|endoftext|>


<commit_before>package ari

import (
	"sync"

	"golang.org/x/net/context"
)

// ALL signifies that the subscriber wants all events
const ALL string = "all"

// Bus is an event bus for ARI events.  It receives and
// redistributes events based on a subscription
// model.
type Bus struct {
	subs []*Subscription // The list of subscriptions

	mu sync.Mutex
}

func (b *Bus) addSubscription(s *Subscription) {
	b.mu.Lock()
	b.subs = append(b.subs, s)
	b.mu.Unlock()
}

func (b *Bus) removeSubscription(s *Subscription) {
	b.mu.Lock()
	defer b.mu.Unlock()
	for i, si := range b.subs {
		if s == si {
			// Subs are pointers, so we have to explicitly remove them
			// to prevent memory leaks
			b.subs[i] = b.subs[len(b.subs)-1] // replace the current with the end
			b.subs[len(b.subs)-1] = nil       // remove the end
			b.subs = b.subs[:len(b.subs)-1]   // lop off the end
			return
		}
	}
}

func (b *Bus) send(msg *Message) {
	var e Eventer
	switch msg.Type {
	case "BridgeAttendedTransfer":
		e = &BridgeAttendedTransfer{}
	case "BridgeBlindTransfer":
		e = &BridgeBlindTransfer{}
	case "BridgeCreated":
		e = &BridgeCreated{}
	case "BridgeDestroyed":
		e = &BridgeDestroyed{}
	case "BridgeMerged":
		e = &BridgeMerged{}
	case "ChannelCallerId":
		e = &ChannelCallerId{}
	case "ChannelConnectedLine":
		e = &ChannelConnectedLine{}
	case "ChannelCreated":
		e = &ChannelCreated{}
	case "ChannelDestroyed":
		e = &ChannelDestroyed{}
	case "ChannelDialplan":
		e = &ChannelDialplan{}
	case "ChannelDtmfReceived":
		e = &ChannelDtmfReceived{}
	case "ChannelEnteredBridge":
		e = &ChannelEnteredBridge{}
	case "ChannelHangupRequest":
		e = &ChannelHangupRequest{}
	case "ChannelHold":
		e = &ChannelHold{}
	case "ChannelLeftBridge":
		e = &ChannelLeftBridge{}
	case "ChannelStateChange":
		e = &ChannelStateChange{}
	case "ChannelTalkingFinished":
		e = &ChannelTalkingFinished{}
	case "ChannelTalkingStarted":
		e = &ChannelTalkingStarted{}
	case "ChannelUnhold":
		e = &ChannelUnhold{}
	case "ChannelUserevent":
		e = &ChannelUserevent{}
	case "ChannelVarset":
		e = &ChannelVarset{}
	case "ContactStatusChanged":
		e = &ContactStatusChanged{}
	case "DeviceStateChanged":
		e = &DeviceStateChanged{}
	case "Dial":
		e = &Dial{}
	case "EndpointStateChange":
		e = &EndpointStateChange{}
	case "PeerStatusChange":
		e = &PeerStatusChange{}
	case "PlaybackFinished":
		e = &PlaybackFinished{}
	case "PlaybackStarted":
		e = &PlaybackStarted{}
	case "RecordingFailed":
		e = &RecordingFailed{}
	case "RecordingFinished":
		e = &RecordingFinished{}
	case "RecordingStarted":
		e = &RecordingStarted{}
	case "StasisEnd":
		e = &StasisEnd{}
	case "StasisStart":
		e = &StasisStart{}
	case "TextMessageReceived":
		e = &TextMessageReceived{}
	default:
		Logger.Debug("Unhandled event received:", "type", msg.Type)
		e = &Event{}
	}
	err := msg.DecodeAs(e)
	if err != nil {
		Logger.Error("Failed to decode message", "error", err)
		return
	}
	Logger.Debug("Received event", "event", e)

	// Disseminate the message to the subscribers
	for _, s := range b.subs {
		for _, topic := range s.events {
			if topic == e.GetType() || topic == ALL {
				select {
				case s.C <- e:
				default: // never block
				}
			}
		}
	}
}

// StartBus creates and returns the event bus.
func StartBus(ctx context.Context) *Bus {
	b := &Bus{
		subs: []*Subscription{},
	}

	// Listen for stop and shut down subscriptions, as required
	go func() {
		<-ctx.Done()
		b.Stop()
		return
	}()

	return b
}

// Stop the bus.  Cancels all subscriptions
// and stops listening for events.
func (b *Bus) Stop() {
	// Close all subscriptions
	b.mu.Lock()
	if b.subs != nil {
		for i, s := range b.subs {
			s.Cancel()
			b.subs[i] = nil
		}
		b.subs = nil
	}
	b.mu.Unlock()
}

// A Subscription is a wrapped channel for receiving
// events from the ARI event bus.
type Subscription struct {
	b      *Bus         // reference to the event bus
	events []string     // list of events to listen for
	C      chan Eventer // channel for sending events to the subscriber
	mu     sync.Mutex
}

// Subscribe returns a subscription to the given list
// of event types
func (b *Bus) Subscribe(eTypes ...string) *Subscription {
	s := &Subscription{
		b:      b,
		events: eTypes,
		C:      make(chan Eventer, 1),
	}
	b.addSubscription(s)
	return s
}

// Next blocks for the next event in the subscription,
// returning that event when it arrives or nil if
// the subscription is canceled.
// Normally, one would listen to subscription.C directly,
// but this is a convenience function for providing a
// context to alternately cancel.
func (s *Subscription) Next(ctx context.Context) Eventer {
	select {
	case <-ctx.Done():
		return nil
	case e := <-s.C:
		return e
	}
}

func (s *Subscription) closeChan() {
	s.mu.Lock()
	if s.C != nil {
		close(s.C)
		s.C = nil
	}
	s.mu.Unlock()
}

// Cancel cancels the subscription and removes it from
// the event bus.
func (s *Subscription) Cancel() {
	s.b.removeSubscription(s)
	s.closeChan()
}

// Once listens for the first event of the provided types,
// returning a channel which supplies that event.
func (b *Bus) Once(ctx context.Context, eTypes ...string) <-chan Eventer {
	s := b.Subscribe(eTypes...)
	ret := make(chan Eventer, 1)

	// Stop subscription after one event
	go func() {
		select {
		case ret <- <-s.C:
		case <-ctx.Done():
		}
		close(ret)
		s.Cancel()
	}()
	return ret
}
<commit_msg>fix deadlock in bus stop<commit_after>package ari

import (
	"sync"

	"golang.org/x/net/context"
)

// ALL signifies that the subscriber wants all events
const ALL string = "all"

// Bus is an event bus for ARI events.  It receives and
// redistributes events based on a subscription
// model.
type Bus struct {
	subs []*Subscription // The list of subscriptions

	mu sync.Mutex
}

func (b *Bus) addSubscription(s *Subscription) {
	b.mu.Lock()
	b.subs = append(b.subs, s)
	b.mu.Unlock()
}

func (b *Bus) removeSubscription(s *Subscription) {
	b.mu.Lock()
	defer b.mu.Unlock()
	for i, si := range b.subs {
		if s == si {
			// Subs are pointers, so we have to explicitly remove them
			// to prevent memory leaks
			b.subs[i] = b.subs[len(b.subs)-1] // replace the current with the end
			b.subs[len(b.subs)-1] = nil       // remove the end
			b.subs = b.subs[:len(b.subs)-1]   // lop off the end
			return
		}
	}
}

func (b *Bus) send(msg *Message) {
	var e Eventer
	switch msg.Type {
	case "BridgeAttendedTransfer":
		e = &BridgeAttendedTransfer{}
	case "BridgeBlindTransfer":
		e = &BridgeBlindTransfer{}
	case "BridgeCreated":
		e = &BridgeCreated{}
	case "BridgeDestroyed":
		e = &BridgeDestroyed{}
	case "BridgeMerged":
		e = &BridgeMerged{}
	case "ChannelCallerId":
		e = &ChannelCallerId{}
	case "ChannelConnectedLine":
		e = &ChannelConnectedLine{}
	case "ChannelCreated":
		e = &ChannelCreated{}
	case "ChannelDestroyed":
		e = &ChannelDestroyed{}
	case "ChannelDialplan":
		e = &ChannelDialplan{}
	case "ChannelDtmfReceived":
		e = &ChannelDtmfReceived{}
	case "ChannelEnteredBridge":
		e = &ChannelEnteredBridge{}
	case "ChannelHangupRequest":
		e = &ChannelHangupRequest{}
	case "ChannelHold":
		e = &ChannelHold{}
	case "ChannelLeftBridge":
		e = &ChannelLeftBridge{}
	case "ChannelStateChange":
		e = &ChannelStateChange{}
	case "ChannelTalkingFinished":
		e = &ChannelTalkingFinished{}
	case "ChannelTalkingStarted":
		e = &ChannelTalkingStarted{}
	case "ChannelUnhold":
		e = &ChannelUnhold{}
	case "ChannelUserevent":
		e = &ChannelUserevent{}
	case "ChannelVarset":
		e = &ChannelVarset{}
	case "ContactStatusChanged":
		e = &ContactStatusChanged{}
	case "DeviceStateChanged":
		e = &DeviceStateChanged{}
	case "Dial":
		e = &Dial{}
	case "EndpointStateChange":
		e = &EndpointStateChange{}
	case "PeerStatusChange":
		e = &PeerStatusChange{}
	case "PlaybackFinished":
		e = &PlaybackFinished{}
	case "PlaybackStarted":
		e = &PlaybackStarted{}
	case "RecordingFailed":
		e = &RecordingFailed{}
	case "RecordingFinished":
		e = &RecordingFinished{}
	case "RecordingStarted":
		e = &RecordingStarted{}
	case "StasisEnd":
		e = &StasisEnd{}
	case "StasisStart":
		e = &StasisStart{}
	case "TextMessageReceived":
		e = &TextMessageReceived{}
	default:
		Logger.Debug("Unhandled event received:", "type", msg.Type)
		e = &Event{}
	}
	err := msg.DecodeAs(e)
	if err != nil {
		Logger.Error("Failed to decode message", "error", err)
		return
	}
	Logger.Debug("Received event", "event", e)

	// Disseminate the message to the subscribers
	for _, s := range b.subs {
		for _, topic := range s.events {
			if topic == e.GetType() || topic == ALL {
				select {
				case s.C <- e:
				default: // never block
				}
			}
		}
	}
}

// StartBus creates and returns the event bus.
func StartBus(ctx context.Context) *Bus {
	b := &Bus{
		subs: []*Subscription{},
	}

	// Listen for stop and shut down subscriptions, as required
	go func() {
		<-ctx.Done()
		b.Stop()
		return
	}()

	return b
}

// Stop the bus.  Cancels all subscriptions
// and stops listening for events.
func (b *Bus) Stop() {
	// Close all subscriptions
	b.mu.Lock()
	if b.subs != nil {
		for i, s := range b.subs {
			s.closeChan()
			b.subs[i] = nil
		}
		b.subs = nil
	}
	b.mu.Unlock()
}

// A Subscription is a wrapped channel for receiving
// events from the ARI event bus.
type Subscription struct {
	b      *Bus         // reference to the event bus
	events []string     // list of events to listen for
	C      chan Eventer // channel for sending events to the subscriber
	mu     sync.Mutex
}

// Subscribe returns a subscription to the given list
// of event types
func (b *Bus) Subscribe(eTypes ...string) *Subscription {
	s := &Subscription{
		b:      b,
		events: eTypes,
		C:      make(chan Eventer, 1),
	}
	b.addSubscription(s)
	return s
}

// Next blocks for the next event in the subscription,
// returning that event when it arrives or nil if
// the subscription is canceled.
// Normally, one would listen to subscription.C directly,
// but this is a convenience function for providing a
// context to alternately cancel.
func (s *Subscription) Next(ctx context.Context) Eventer {
	select {
	case <-ctx.Done():
		return nil
	case e := <-s.C:
		return e
	}
}

func (s *Subscription) closeChan() {
	s.mu.Lock()
	if s.C != nil {
		close(s.C)
		s.C = nil
	}
	s.mu.Unlock()
}

// Cancel cancels the subscription and removes it from
// the event bus.
func (s *Subscription) Cancel() {
	s.b.removeSubscription(s)
	s.closeChan()
}

// Once listens for the first event of the provided types,
// returning a channel which supplies that event.
func (b *Bus) Once(ctx context.Context, eTypes ...string) <-chan Eventer {
	s := b.Subscribe(eTypes...)
	ret := make(chan Eventer, 1)

	// Stop subscription after one event
	go func() {
		select {
		case ret <- <-s.C:
		case <-ctx.Done():
		}
		close(ret)
		s.Cancel()
	}()
	return ret
}
<|endoftext|>


<commit_before>package ccg

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/format"
	"go/token"
	"io"

	"golang.org/x/tools/go/loader"
	"golang.org/x/tools/go/types"
	"golang.org/x/tools/imports"
)

var (
	pt = fmt.Printf
)

type Config struct {
	From    string
	Params  map[string]string
	Renames map[string]string
	Writer  io.Writer
	Package string
	Decls   []ast.Decl
}

func Copy(config Config) error {
	// load package
	var loadConf loader.Config
	loadConf.Import(config.From)
	program, err := loadConf.Load()
	if err != nil {
		return fmt.Errorf("ccg: load package %v", err)
	}
	info := program.Imported[config.From]

	// remove param declarations
	for _, f := range info.Files {
		f.Decls = AstDecls(f.Decls).Filter(func(decl ast.Decl) (ret bool) {
			if decl, ok := decl.(*ast.GenDecl); !ok {
				return true
			} else {
				if decl.Tok == token.TYPE {
					decl.Specs = AstSpecs(decl.Specs).Filter(func(spec ast.Spec) bool {
						name := spec.(*ast.TypeSpec).Name.Name
						_, exists := config.Params[name]
						return !exists
					})
					ret = len(decl.Specs) > 0
				} else if decl.Tok == token.VAR {
					decl.Specs = AstSpecs(decl.Specs).Filter(func(sp ast.Spec) bool {
						spec := sp.(*ast.ValueSpec)
						names := []*ast.Ident{}
						values := []ast.Expr{}
						for i, name := range spec.Names {
							if _, exists := config.Params[name.Name]; !exists {
								names = append(names, name)
								if i < len(spec.Values) {
									values = append(values, spec.Values[i])
								}
							}
						}
						spec.Names = names
						if len(values) == 0 {
							spec.Values = nil
						} else {
							spec.Values = values
						}
						return len(spec.Names) > 0
					})
					ret = len(decl.Specs) > 0
				}
				//TODO token.CONST
			}
			return
		})
	}

	// collect objects to rename
	objects := make(map[types.Object]string)
	collectObjects := func(mapping map[string]string) error {
		for from, to := range mapping {
			obj := info.Pkg.Scope().Lookup(from)
			if obj == nil {
				return fmt.Errorf("ccg: name not found %s", from)
			}
			objects[obj] = to
		}
		return nil
	}
	if err := collectObjects(config.Params); err != nil {
		return err
	}
	if err := collectObjects(config.Renames); err != nil {
		return err
	}

	// rename
	rename := func(defs map[*ast.Ident]types.Object) {
		for id, obj := range defs {
			if to, ok := objects[obj]; ok {
				id.Name = to
			}
		}
	}
	rename(info.Defs)
	rename(info.Uses)

	// collect existing decls
	existingVars := make(map[string]func(expr ast.Expr))
	existingTypes := make(map[string]func(expr ast.Expr))
	existingFuncs := make(map[string]func(fn *ast.FuncDecl))
	for i, decl := range config.Decls {
		switch decl := decl.(type) {
		case *ast.GenDecl:
			switch decl.Tok {
			case token.VAR:
				for _, spec := range decl.Specs {
					spec := spec.(*ast.ValueSpec)
					for i, name := range spec.Names {
						i := i
						spec := spec
						existingVars[name.Name] = func(expr ast.Expr) {
							spec.Values[i] = expr
						}
					}
				}
			case token.TYPE:
				for i, spec := range decl.Specs {
					spec := spec.(*ast.TypeSpec)
					i := i
					decl := decl
					existingTypes[spec.Name.Name] = func(expr ast.Expr) {
						decl.Specs[i].(*ast.TypeSpec).Type = expr
					}
				}
			}
		case *ast.FuncDecl:
			name := decl.Name.Name
			if decl.Recv != nil {
				name = decl.Recv.List[0].Type.(*ast.Ident).Name + "." + name
			}
			i := i
			existingFuncs[name] = func(fndecl *ast.FuncDecl) {
				config.Decls[i] = fndecl
			}
		}
	}

	// collect output declarations
	decls := []ast.Decl{}
	for _, f := range info.Files {
		for _, decl := range f.Decls {
			switch decl := decl.(type) {
			case *ast.GenDecl:
				switch decl.Tok {
				case token.VAR:
					newDecl := &ast.GenDecl{
						Tok: token.VAR,
					}
					for _, spec := range decl.Specs {
						spec := spec.(*ast.ValueSpec)
						for i, name := range spec.Names {
							if mutator, ok := existingVars[name.Name]; ok {
								mutator(spec.Values[i])
							} else {
								newDecl.Specs = append(newDecl.Specs, spec)
							}
						}
					}
					if len(newDecl.Specs) > 0 {
						decls = append(decls, newDecl)
					}
				case token.TYPE:
					newDecl := &ast.GenDecl{
						Tok: token.TYPE,
					}
					for _, spec := range decl.Specs {
						name := spec.(*ast.TypeSpec).Name.Name
						if mutator, ok := existingTypes[name]; ok {
							mutator(spec.(*ast.TypeSpec).Type)
						} else {
							newDecl.Specs = append(newDecl.Specs, spec)
						}
					}
					if len(newDecl.Specs) > 0 {
						decls = append(decls, newDecl)
					}
				}
			case *ast.FuncDecl:
				name := decl.Name.Name
				if decl.Recv != nil {
					name = decl.Recv.List[0].Type.(*ast.Ident).Name + "." + name
				}
				if mutator, ok := existingFuncs[name]; ok {
					mutator(decl)
				} else {
					config.Decls = append(config.Decls, decl)
				}
			}
		}
	}
	decls = append(decls, config.Decls...)

	// output
	if config.Writer != nil {
		if config.Package != "" { // output complete file
			file := &ast.File{
				Name:  ast.NewIdent(config.Package),
				Decls: decls,
			}
			buf := new(bytes.Buffer)
			err = format.Node(buf, program.Fset, file)
			if err != nil {
				return fmt.Errorf("ccg: format output %v", err)
			}
			bs, err := imports.Process("", buf.Bytes(), nil)
			if err != nil {
				return fmt.Errorf("ccg: format output %v", err)
			}
			config.Writer.Write(bs)
		} else { // output decls only
			err = format.Node(config.Writer, program.Fset, decls)
			if err != nil {
				return fmt.Errorf("ccg: format output %v", err)
			}
		}
	}

	return nil
}
<commit_msg>add NOCOVER directives<commit_after>package ccg

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/format"
	"go/token"
	"io"

	"golang.org/x/tools/go/loader"
	"golang.org/x/tools/go/types"
	"golang.org/x/tools/imports"
)

var (
	pt = fmt.Printf
)

type Config struct {
	From    string
	Params  map[string]string
	Renames map[string]string
	Writer  io.Writer
	Package string
	Decls   []ast.Decl
}

func Copy(config Config) error {
	// load package
	var loadConf loader.Config
	loadConf.Import(config.From)
	program, err := loadConf.Load()
	if err != nil {
		return fmt.Errorf("ccg: load package %v", err)
	}
	info := program.Imported[config.From]

	// remove param declarations
	for _, f := range info.Files {
		f.Decls = AstDecls(f.Decls).Filter(func(decl ast.Decl) (ret bool) {
			if decl, ok := decl.(*ast.GenDecl); !ok {
				return true
			} else {
				if decl.Tok == token.TYPE {
					decl.Specs = AstSpecs(decl.Specs).Filter(func(spec ast.Spec) bool {
						name := spec.(*ast.TypeSpec).Name.Name
						_, exists := config.Params[name]
						return !exists
					})
					ret = len(decl.Specs) > 0
				} else if decl.Tok == token.VAR {
					decl.Specs = AstSpecs(decl.Specs).Filter(func(sp ast.Spec) bool {
						spec := sp.(*ast.ValueSpec)
						names := []*ast.Ident{}
						values := []ast.Expr{}
						for i, name := range spec.Names {
							if _, exists := config.Params[name.Name]; !exists {
								names = append(names, name)
								if i < len(spec.Values) {
									values = append(values, spec.Values[i])
								}
							}
						}
						spec.Names = names
						if len(values) == 0 {
							spec.Values = nil
						} else {
							spec.Values = values
						}
						return len(spec.Names) > 0
					})
					ret = len(decl.Specs) > 0
				}
				//TODO token.CONST
			}
			return
		})
	}

	// collect objects to rename
	objects := make(map[types.Object]string)
	collectObjects := func(mapping map[string]string) error {
		for from, to := range mapping {
			obj := info.Pkg.Scope().Lookup(from)
			if obj == nil {
				return fmt.Errorf("ccg: name not found %s", from)
			}
			objects[obj] = to
		}
		return nil
	}
	if err := collectObjects(config.Params); err != nil {
		return err
	}
	if err := collectObjects(config.Renames); err != nil {
		return err
	}

	// rename
	rename := func(defs map[*ast.Ident]types.Object) {
		for id, obj := range defs {
			if to, ok := objects[obj]; ok {
				id.Name = to
			}
		}
	}
	rename(info.Defs)
	rename(info.Uses)

	// collect existing decls
	existingVars := make(map[string]func(expr ast.Expr))
	existingTypes := make(map[string]func(expr ast.Expr))
	existingFuncs := make(map[string]func(fn *ast.FuncDecl))
	for i, decl := range config.Decls {
		switch decl := decl.(type) {
		case *ast.GenDecl:
			switch decl.Tok {
			case token.VAR:
				for _, spec := range decl.Specs {
					spec := spec.(*ast.ValueSpec)
					for i, name := range spec.Names {
						i := i
						spec := spec
						existingVars[name.Name] = func(expr ast.Expr) {
							spec.Values[i] = expr
						}
					}
				}
			case token.TYPE:
				for i, spec := range decl.Specs {
					spec := spec.(*ast.TypeSpec)
					i := i
					decl := decl
					existingTypes[spec.Name.Name] = func(expr ast.Expr) {
						decl.Specs[i].(*ast.TypeSpec).Type = expr
					}
				}
			}
		case *ast.FuncDecl:
			name := decl.Name.Name
			if decl.Recv != nil {
				name = decl.Recv.List[0].Type.(*ast.Ident).Name + "." + name
			}
			i := i
			existingFuncs[name] = func(fndecl *ast.FuncDecl) {
				config.Decls[i] = fndecl
			}
		}
	}

	// collect output declarations
	decls := []ast.Decl{}
	for _, f := range info.Files {
		for _, decl := range f.Decls {
			switch decl := decl.(type) {
			case *ast.GenDecl:
				switch decl.Tok {
				case token.VAR:
					newDecl := &ast.GenDecl{
						Tok: token.VAR,
					}
					for _, spec := range decl.Specs {
						spec := spec.(*ast.ValueSpec)
						for i, name := range spec.Names {
							if mutator, ok := existingVars[name.Name]; ok {
								mutator(spec.Values[i])
							} else {
								newDecl.Specs = append(newDecl.Specs, spec)
							}
						}
					}
					if len(newDecl.Specs) > 0 {
						decls = append(decls, newDecl)
					}
				case token.TYPE:
					newDecl := &ast.GenDecl{
						Tok: token.TYPE,
					}
					for _, spec := range decl.Specs {
						name := spec.(*ast.TypeSpec).Name.Name
						if mutator, ok := existingTypes[name]; ok {
							mutator(spec.(*ast.TypeSpec).Type)
						} else {
							newDecl.Specs = append(newDecl.Specs, spec)
						}
					}
					if len(newDecl.Specs) > 0 {
						decls = append(decls, newDecl)
					}
				}
			case *ast.FuncDecl:
				name := decl.Name.Name
				if decl.Recv != nil {
					name = decl.Recv.List[0].Type.(*ast.Ident).Name + "." + name
				}
				if mutator, ok := existingFuncs[name]; ok {
					mutator(decl)
				} else {
					config.Decls = append(config.Decls, decl)
				}
			}
		}
	}
	decls = append(decls, config.Decls...)

	// output
	if config.Writer != nil {
		if config.Package != "" { // output complete file
			file := &ast.File{
				Name:  ast.NewIdent(config.Package),
				Decls: decls,
			}
			buf := new(bytes.Buffer)
			err = format.Node(buf, program.Fset, file)
			if err != nil { //NOCOVER
				return fmt.Errorf("ccg: format output %v", err)
			}
			bs, err := imports.Process("", buf.Bytes(), nil)
			if err != nil { //NOCOVER
				return fmt.Errorf("ccg: format output %v", err)
			}
			config.Writer.Write(bs)
		} else { // output decls only
			err = format.Node(config.Writer, program.Fset, decls)
			if err != nil { //NOCOVER
				return fmt.Errorf("ccg: format output %v", err)
			}
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package migrations

import "github.com/concourse/atc/db/migration"

func AddUniqueWorkerResourceCacheIDToVolumes(tx migration.LimitedTx) error {
	_, err := tx.Exec(`
		WITH distinct_vols AS (
			SELECT DISTINCT ON (worker_resource_cache_id) id
			FROM volumes
			WHERE worker_resource_cache_id IS NOT NULL
		)
		DELETE FROM volumes
		WHERE worker_resource_cache_id IS NOT NULL
		AND id NOT IN (SELECT id FROM distinct_vols)
	`)
	if err != nil {
		return err
	}

	_, err = tx.Exec(`
		CREATE UNIQUE INDEX volumes_worker_resource_cache_unique
		ON volumes (worker_resource_cache_id)
	`)
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>nullify, rather than drop, duplicate volumes<commit_after>package migrations

import "github.com/concourse/atc/db/migration"

func AddUniqueWorkerResourceCacheIDToVolumes(tx migration.LimitedTx) error {
	// handle initialized volumes first to avoid
	// 'cannot_invalidate_during_initialization'
	_, err := tx.Exec(`
		WITH distinct_vols AS (
			SELECT DISTINCT ON (worker_resource_cache_id) id
			FROM volumes
			WHERE worker_resource_cache_id IS NOT NULL
		)
		UPDATE volumes
		SET worker_resource_cache_id = NULL, state = 'destroying'
		WHERE worker_resource_cache_id IS NOT NULL
		AND state = 'creating'
		AND id NOT IN (SELECT id FROM distinct_vols)
	`)
	if err != nil {
		return err
	}

	_, err = tx.Exec(`
		WITH distinct_vols AS (
			SELECT DISTINCT ON (worker_resource_cache_id) id
			FROM volumes
			WHERE worker_resource_cache_id IS NOT NULL
		)
		UPDATE volumes
		SET worker_resource_cache_id = NULL
		WHERE worker_resource_cache_id IS NOT NULL
		AND id NOT IN (SELECT id FROM distinct_vols)
	`)
	if err != nil {
		return err
	}

	_, err = tx.Exec(`
		CREATE UNIQUE INDEX volumes_worker_resource_cache_unique
		ON volumes (worker_resource_cache_id)
	`)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>//
// Package chi is a small, idiomatic and composable router for building HTTP services.
//
// chi requires Go 1.7 or newer.
//
// Example:
//  package main
//
//  import (
//  	"net/http"
//
//  	"github.com/pressly/chi"
//  	"github.com/pressly/chi/middleware"
//  )
//
//  func main() {
//  	r := chi.NewRouter()
//  	r.Use(middleware.Logger)
//  	r.Use(middleware.Recoverer)
//
//  	r.Get("/", func(w http.ResponseWriter, r *http.Request) {
//  		w.Write([]byte("root."))
//  	})
//
//  	http.ListenAndServe(":3333", r)
//  }
//
// See github.com/pressly/chi/_examples/ for more in-depth examples.
//
package chi

import "net/http"

// NewRouter returns a new Mux object that implements the Router interface.
func NewRouter() *Mux {
	return NewMux()
}

// Router consisting of the core routing methods used by chi's Mux,
// using only the standard net/http.
type Router interface {
	http.Handler
	Routes

	// Use appends one of more middlewares onto the Router stack.
	Use(middlewares ...func(http.Handler) http.Handler)

	// With adds inline middlewares for an endpoint handler.
	With(middlewares ...func(http.Handler) http.Handler) Router

	// Group adds a new inline-Router along the current routing
	// path, with a fresh middleware stack for the inline-Router.
	Group(fn func(r Router)) Router

	// Route mounts a sub-Router along a `pattern`` string.
	Route(pattern string, fn func(r Router)) Router

	// Mount attaches another http.Handler along ./pattern/*
	Mount(pattern string, h http.Handler)

	// Handle and HandleFunc adds routes for `pattern` that matches
	// all HTTP methods.
	Handle(pattern string, h http.Handler)
	HandleFunc(pattern string, h http.HandlerFunc)

	// HTTP-method routing along `pattern`
	Connect(pattern string, h http.HandlerFunc)
	Delete(pattern string, h http.HandlerFunc)
	Get(pattern string, h http.HandlerFunc)
	Head(pattern string, h http.HandlerFunc)
	Options(pattern string, h http.HandlerFunc)
	Patch(pattern string, h http.HandlerFunc)
	Post(pattern string, h http.HandlerFunc)
	Put(pattern string, h http.HandlerFunc)
	Trace(pattern string, h http.HandlerFunc)

	// NotFound defines a handler to respond whenever a route could
	// not be found.
	NotFound(h http.HandlerFunc)
}

// Routes interface adds two methods for router traversal, which is also
// used by the `docgen` subpackage to generation documentation for Routers.
type Routes interface {
	// Routes returns the routing tree in an easily traversable structure.
	Routes() []Route

	// Middlewares returns the list of middlewares in use by the router.
	Middlewares() Middlewares
}

// Middlewares type is a slice of standard middleware handlers with methods
// to compose middleware chains and http.Handler's.
type Middlewares []func(http.Handler) http.Handler
<commit_msg>Fix missing MethodNotAllowed in Router interface<commit_after>//
// Package chi is a small, idiomatic and composable router for building HTTP services.
//
// chi requires Go 1.7 or newer.
//
// Example:
//  package main
//
//  import (
//  	"net/http"
//
//  	"github.com/pressly/chi"
//  	"github.com/pressly/chi/middleware"
//  )
//
//  func main() {
//  	r := chi.NewRouter()
//  	r.Use(middleware.Logger)
//  	r.Use(middleware.Recoverer)
//
//  	r.Get("/", func(w http.ResponseWriter, r *http.Request) {
//  		w.Write([]byte("root."))
//  	})
//
//  	http.ListenAndServe(":3333", r)
//  }
//
// See github.com/pressly/chi/_examples/ for more in-depth examples.
//
package chi

import "net/http"

// NewRouter returns a new Mux object that implements the Router interface.
func NewRouter() *Mux {
	return NewMux()
}

// Router consisting of the core routing methods used by chi's Mux,
// using only the standard net/http.
type Router interface {
	http.Handler
	Routes

	// Use appends one of more middlewares onto the Router stack.
	Use(middlewares ...func(http.Handler) http.Handler)

	// With adds inline middlewares for an endpoint handler.
	With(middlewares ...func(http.Handler) http.Handler) Router

	// Group adds a new inline-Router along the current routing
	// path, with a fresh middleware stack for the inline-Router.
	Group(fn func(r Router)) Router

	// Route mounts a sub-Router along a `pattern`` string.
	Route(pattern string, fn func(r Router)) Router

	// Mount attaches another http.Handler along ./pattern/*
	Mount(pattern string, h http.Handler)

	// Handle and HandleFunc adds routes for `pattern` that matches
	// all HTTP methods.
	Handle(pattern string, h http.Handler)
	HandleFunc(pattern string, h http.HandlerFunc)

	// HTTP-method routing along `pattern`
	Connect(pattern string, h http.HandlerFunc)
	Delete(pattern string, h http.HandlerFunc)
	Get(pattern string, h http.HandlerFunc)
	Head(pattern string, h http.HandlerFunc)
	Options(pattern string, h http.HandlerFunc)
	Patch(pattern string, h http.HandlerFunc)
	Post(pattern string, h http.HandlerFunc)
	Put(pattern string, h http.HandlerFunc)
	Trace(pattern string, h http.HandlerFunc)

	// NotFound defines a handler to respond whenever a route could
	// not be found.
	NotFound(h http.HandlerFunc)

	// MethodNotAllowed defines a handler to respond whenever a method is
	// not allowed.
	MethodNotAllowed(h http.HandlerFunc)
}

// Routes interface adds two methods for router traversal, which is also
// used by the `docgen` subpackage to generation documentation for Routers.
type Routes interface {
	// Routes returns the routing tree in an easily traversable structure.
	Routes() []Route

	// Middlewares returns the list of middlewares in use by the router.
	Middlewares() Middlewares
}

// Middlewares type is a slice of standard middleware handlers with methods
// to compose middleware chains and http.Handler's.
type Middlewares []func(http.Handler) http.Handler
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/urfave/cli"
	"golang.org/x/net/context"
)

func main() {
	app := cli.NewApp()
	app.Name = "blocks-gcs-proxy"
	app.Usage = "github.com/groovenauts/blocks-gcs-proxy"
	app.Version = VERSION

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "config, c",
			Usage: "Load configuration from `FILE`",
		},
	}

	app.Action = run

	app.Run(os.Args)
}

func run(c *cli.Context) error {
	config, err := LoadProcessConfig(configPath(c))
	if err != nil {
		fmt.Printf("Error to load %v cause of %v\n", configPath, err)
		os.Exit(1)
	}
	config.setup(os.Args[1:])

	ctx := context.Background()

	p := &Process{config: config}
	err = p.setup(ctx)
	if err != nil {
		fmt.Printf("Error to setup Process cause of %v\n", err)
		os.Exit(1)
	}

	err = p.run()
	if err != nil {
		fmt.Printf("Error to run cause of %v\n", err)
		os.Exit(1)
	}
	return nil
}

func configPath(c *cli.Context) string {
	r := c.String("config")
	if r == "" {
		r = "./config.json"
	}
	return r
}
<commit_msg>:recycle: Extract LoadAndSetupProcessConfig<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/urfave/cli"
	"golang.org/x/net/context"
)

func main() {
	app := cli.NewApp()
	app.Name = "blocks-gcs-proxy"
	app.Usage = "github.com/groovenauts/blocks-gcs-proxy"
	app.Version = VERSION

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "config, c",
			Usage: "Load configuration from `FILE`",
		},
	}

	app.Action = run

	app.Run(os.Args)
}

func run(c *cli.Context) error {
	config := LoadAndSetupProcessConfig(c)

	ctx := context.Background()

	p := &Process{config: config}
	err := p.setup(ctx)
	if err != nil {
		fmt.Printf("Error to setup Process cause of %v\n", err)
		os.Exit(1)
	}

	err = p.run()
	if err != nil {
		fmt.Printf("Error to run cause of %v\n", err)
		os.Exit(1)
	}
	return nil
}

func LoadAndSetupProcessConfig(c *cli.Context) *ProcessConfig {
	path := configPath(c)
	config, err := LoadProcessConfig(path)
	if err != nil {
		fmt.Printf("Error to load %v cause of %v\n", path, err)
		os.Exit(1)
	}
	err = config.setup(os.Args[1:])
	if err != nil {
		fmt.Printf("Error to setup %v cause of %v\n", path, err)
		os.Exit(1)
	}
	return config
}

func configPath(c *cli.Context) string {
	r := c.String("config")
	if r == "" {
		r = "./config.json"
	}
	return r
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"

	"github.com/codegangsta/cli"
	"github.com/mikebeyer/clc-cli/aa"
	"github.com/mikebeyer/clc-cli/alert"
	"github.com/mikebeyer/clc-cli/group"
	"github.com/mikebeyer/clc-cli/lb"
	"github.com/mikebeyer/clc-cli/server"
	"github.com/mikebeyer/clc-cli/status"
	"github.com/mikebeyer/clc-sdk"
	"github.com/mikebeyer/clc-sdk/api"
)

func main() {

	app := cli.NewApp()
	app.Name = "clc"
	app.Usage = "clc v2 api cli"
	app.Version = "0.0.1"
	app.Authors = []cli.Author{
		cli.Author{
			Name:  "Mike Beyer",
			Email: "michael.beyer@ctl.io",
		},
	}
	app.Flags = []cli.Flag{
		cli.BoolFlag{Name: "default-config", Usage: "create template configuration file"},
	}
	var config api.Config
	var configErr error
	app.Action = func(c *cli.Context) {
		fmt.Println("here")
		if c.Bool("default-config") {

			conf := api.NewConfig("USERNAME", "PASSWORD", "DEFAULT-ALIAS")
			b, err := json.MarshalIndent(conf, "", "  ")
			if err != nil {
				fmt.Printf("unable to generate config template.")
			}

			err = ioutil.WriteFile("./config.json", b, 0666)
			if err != nil {
				fmt.Printf("unable to generate config template.")
			}
			fmt.Printf("config template written to config.json")
			return
		} else if c.String("config") != "" {
			config, configErr = api.FileConfig(c.String("config"))
			if configErr != nil {
				fmt.Printf("unable to find/parse config: %s\n", c.String("config"))
			}
		} else if !c.Args().Present() {
			cli.ShowAppHelp(c)
		}
	}
	if !config.Valid() {
		config, configErr = api.EnvConfig()
		if configErr != nil {
			config, configErr = api.FileConfig("./config.json")
			if configErr != nil {
				fmt.Printf("failed to find necessary environment variables or default config location (./config.json)\n")
				return
			}
		}
	}

	client := clc.New(config)
	app.Commands = []cli.Command{
		server.Commands(client),
		status.Commands(client),
		aa.Commands(client),
		alert.Commands(client),
		lb.Commands(client),
		group.Commands(client),
	}
	app.Run(os.Args)
}
<commit_msg>updated cli to do more sensible things around help flags<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"

	"github.com/codegangsta/cli"
	"github.com/mikebeyer/clc-cli/aa"
	"github.com/mikebeyer/clc-cli/alert"
	"github.com/mikebeyer/clc-cli/group"
	"github.com/mikebeyer/clc-cli/lb"
	"github.com/mikebeyer/clc-cli/server"
	"github.com/mikebeyer/clc-cli/status"
	"github.com/mikebeyer/clc-sdk"
	"github.com/mikebeyer/clc-sdk/api"
)

func main() {
	app := cli.NewApp()
	app.Name = "clc"
	app.Usage = "clc v2 api cli"
	app.Version = "0.0.1"
	app.Authors = []cli.Author{
		cli.Author{
			Name:  "Mike Beyer",
			Email: "michael.beyer@ctl.io",
		},
	}
	app.Flags = []cli.Flag{
		cli.BoolFlag{Name: "gen-config", Usage: "create template configuration file"},
	}
	var config api.Config
	var client *clc.Client
	var configErr error
	app.Action = func(c *cli.Context) {
		if c.Bool("gen-config") {
			conf := api.NewConfig("USERNAME", "PASSWORD", "DEFAULT-ALIAS")
			b, err := json.MarshalIndent(conf, "", "  ")
			if err != nil {
				fmt.Printf("unable to generate config template.")
			}

			err = ioutil.WriteFile("./config.json", b, 0666)
			if err != nil {
				fmt.Printf("unable to generate config template.")
			}
			fmt.Printf("config template written to config.json")
			return
		} else if c.String("config") != "" {
			config, configErr = api.FileConfig(c.String("config"))
			if configErr != nil {
				fmt.Printf("unable to find/parse config: %s\n", c.String("config"))
			}
		} else if c.Bool("help") {
			cli.ShowAppHelp(c)
		} else if !c.Args().Present() {
			if !config.Valid() {
				config, configErr = api.EnvConfig()
				if configErr != nil {
					config, configErr = api.FileConfig("./config.json")
					if configErr != nil {
						fmt.Printf("failed to find necessary environment variables or default config location (./config.json)\n")
						return
					}
				}
			}
			client = clc.New(config)
		}
	}

	app.Commands = []cli.Command{
		server.Commands(client),
		status.Commands(client),
		aa.Commands(client),
		alert.Commands(client),
		lb.Commands(client),
		group.Commands(client),
	}
	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main // import "github.com/justone/dockviz"

import (
	"fmt"
	"os"

	"github.com/jessevdk/go-flags"
)

type GlobalOptions struct {
	TLSCaCert string `long:"tlscacert" value-name:"~/.docker/ca.pem" description:"Trust certs signed only by this CA"`
	TLSCert   string `long:"tlscert" value-name:"~/.docker/cert.pem" description:"Path to TLS certificate file"`
	TLSKey    string `long:"tlskey" value-name:"~/.docker/key.pem" description:"Path to TLS key file"`
	TLSVerify bool   `long:"tlsverify" description:"Use TLS and verify the remote"`
	Host      string `long:"host" short:"H" value-name:"unix:///var/run/docker.sock" description:"Docker host to connect to"`
	Version   func() `long:"version" short:"v" description:"Display version information."`
}

var globalOptions GlobalOptions
var parser = flags.NewParser(&globalOptions, flags.Default)

var version = "v0.2.2"

func main() {
	globalOptions.Version = func() {
		fmt.Println("dockviz", version)
		os.Exit(0)
	}
	if _, err := parser.Parse(); err != nil {
		os.Exit(1)
	}
}
<commit_msg>bump version to v0.3<commit_after>package main // import "github.com/justone/dockviz"

import (
	"fmt"
	"os"

	"github.com/jessevdk/go-flags"
)

type GlobalOptions struct {
	TLSCaCert string `long:"tlscacert" value-name:"~/.docker/ca.pem" description:"Trust certs signed only by this CA"`
	TLSCert   string `long:"tlscert" value-name:"~/.docker/cert.pem" description:"Path to TLS certificate file"`
	TLSKey    string `long:"tlskey" value-name:"~/.docker/key.pem" description:"Path to TLS key file"`
	TLSVerify bool   `long:"tlsverify" description:"Use TLS and verify the remote"`
	Host      string `long:"host" short:"H" value-name:"unix:///var/run/docker.sock" description:"Docker host to connect to"`
	Version   func() `long:"version" short:"v" description:"Display version information."`
}

var globalOptions GlobalOptions
var parser = flags.NewParser(&globalOptions, flags.Default)

var version = "v0.3"

func main() {
	globalOptions.Version = func() {
		fmt.Println("dockviz", version)
		os.Exit(0)
	}
	if _, err := parser.Parse(); err != nil {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import "os"

func main() {
	app := App{
		Name:        "math",
		Description: "a simple command line math utility",
		Commands: []Command{
			{
				Name:        "add",
				Description: "Add 2 and 2",
				Action:      DoAdd},
			{
				Name:        "subtract",
				Description: "Subtract 2 and 2",
				Action:      DoSubtract},
			{
				Name:        "multiply",
				Description: "Multiply 2 and 2",
				Action:      DoMultiply},
			{
				Name:        "divide",
				Description: "Divide 2 and 2",
				Action:      DoDivide}}}

	app.Run(os.Args[1])
}

func DoAdd(name string) {
	println("2+2=", 2+2)
}

func DoSubtract(name string) {
	println("2-2=", 2-2)
}

func DoMultiply(name string) {
	println("2*2=", 2*2)
}

func DoDivide(name string) {
	println("2/2=", 2/2)
}

type App struct {
	Name        string
	Description string
	Commands    []Command
}

type Command struct {
	Name        string
	Description string
	Action      Action
}

type Action func(name string)

func (a App) Run(command string) {
	for _, c := range a.Commands {
		if c.Name == command {
			c.Action(command)
		}
	}
}
<commit_msg>Attempting to make the composite literals pretty<commit_after>package main

import "os"

func main() {
	app := App{
		Name:        "math",
		Description: "a simple command line math utility",
		Commands: []Command{{
			Name:        "add",
			Description: "Add 2 and 2",
			Action:      DoAdd,
		}, {
			Name:        "subtract",
			Description: "Subtract 2 and 2",
			Action:      DoSubtract,
		}, {
			Name:        "multiply",
			Description: "Multiply 2 and 2",
			Action:      DoMultiply,
		}, {
			Name:        "divide",
			Description: "Divide 2 and 2",
			Action:      DoDivide,
		}},
	}

	app.Run(os.Args[1])
}

func DoAdd(name string) {
	println("2+2=", 2+2)
}

func DoSubtract(name string) {
	println("2-2=", 2-2)
}

func DoMultiply(name string) {
	println("2*2=", 2*2)
}

func DoDivide(name string) {
	println("2/2=", 2/2)
}

type App struct {
	Name        string
	Description string
	Commands    []Command
}

type Command struct {
	Name        string
	Description string
	Action      Action
}

type Action func(name string)

func (a App) Run(command string) {
	for _, c := range a.Commands {
		if c.Name == command {
			c.Action(command)
		}
	}
}
<|endoftext|>


<commit_before><commit_msg>Also skip the test if the OS creates the file but mangles the name.<commit_after><|endoftext|>


<commit_before>package gitcli

import (
//	"io"
	"os/exec"
	"bytes"
	"fmt"
)

func (r *Repo) cmd(args ...string) ( string, string,  error) {
	var err error
	var stdout bytes.Buffer
	var stderr bytes.Buffer
	var cmdArgs []string
	cmdArgs = append(cmdArgs, `--work-tree` , r.workDir, `--git-dir` , r.gitDir)
	cmdArgs = append(cmdArgs, args...)
//	res = exec.Command(gitCmd, cmdArgs...)
	//	cmd := exec.Command(`git` ,`version`)
	// make commands consistent
	if r.debug {
		fmt.Printf("debug: executing git command: %+v",cmdArgs)
	}
	cmd := exec.Command(`git` ,cmdArgs...)
	// make commands consistent
	cmd.Env = r.filteredEnv
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	cmd.Dir = r.workDir
	if r.debug {
		fmt.Printf("git command finished. stdout [%s], stderr [%s]",stdout.String(),stderr.String())
	}
	if err := cmd.Start(); err != nil {
		return "", "", err
	}
	if err := cmd.Wait(); err != nil {
			return stdout.String(), stderr.String(), err
	}
	return stdout.String(), stderr.String(), err
}
<commit_msg>add newlines<commit_after>package gitcli

import (
//	"io"
	"os/exec"
	"bytes"
	"fmt"
)

func (r *Repo) cmd(args ...string) ( string, string,  error) {
	var err error
	var stdout bytes.Buffer
	var stderr bytes.Buffer
	var cmdArgs []string
	cmdArgs = append(cmdArgs, `--work-tree` , r.workDir, `--git-dir` , r.gitDir)
	cmdArgs = append(cmdArgs, args...)
//	res = exec.Command(gitCmd, cmdArgs...)
	//	cmd := exec.Command(`git` ,`version`)
	// make commands consistent
	if r.debug {
		fmt.Printf("debug: executing git command: %+v\n",cmdArgs)
	}
	cmd := exec.Command(`git` ,cmdArgs...)
	// make commands consistent
	cmd.Env = r.filteredEnv
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	cmd.Dir = r.workDir
	if r.debug {
		fmt.Printf("git command finished. stdout [%s], stderr [%s]\n",stdout.String(),stderr.String())
	}
	if err := cmd.Start(); err != nil {
		return "", "", err
	}
	if err := cmd.Wait(); err != nil {
			return stdout.String(), stderr.String(), err
	}
	return stdout.String(), stderr.String(), err
}
<|endoftext|>


<commit_before>/*
 This package is used to implement a "line oriented command interpreter", inspired by the python package with
 the same name http://docs.python.org/2/library/cmd.html

 Usage:

	 commander := &Cmd{...}
	 commander.Init()

	 commander.Add(Command{...})
	 commander.Add(Command{...})

	 commander.CmdLoop()
*/
package cmd

import (
	"github.com/gobs/args"
	"github.com/gobs/readline"

	"fmt"
	"os"
	"os/exec"
	"path"
	"strings"
)

//
// This is used to describe a new command
//
type Command struct {
	// command name
	Name string
	// command description
	Help string
	// the function to call to execute the command
	Call func(string) bool
}

//
// The context for command completion
//
type Completer struct {
	// the list of words to match on
	Words []string
	// the list of current matches
	Matches []string
}

//
// Return a word matching the prefix
// If there are multiple matches, index selects which one to pick
//
func (c *Completer) Complete(prefix string, index int) string {
	if index == 0 {
		c.Matches = c.Matches[:0]

		for _, w := range c.Words {
			if strings.HasPrefix(w, prefix) {
				c.Matches = append(c.Matches, w)
			}
		}
	}

	if index < len(c.Matches) {
		return c.Matches[index]
	} else {
		return ""
	}
}

//
// Create a Completer and initialize with list of words
//
func NewCompleter(words []string) (c *Completer) {
	c = new(Completer)
	c.Words = words
	c.Matches = make([]string, 0, len(c.Words))
	return
}

//
// This the the "context" for the command interpreter
//
type Cmd struct {
	// the prompt string
	Prompt string

	// the history file
	HistoryFile string

	// this function is called before starting the command loop
	PreLoop func()

	// this function is called before terminating the command loop
	PostLoop func()

	// this function is called before executing the selected command
	PreCmd func(string)

	// this function is called after a command has been executed
	// return true to terminate the interpreter, false to continue
	PostCmd func(string, bool) bool

	// this function is called if the last typed command was an empty line
	EmptyLine func()

	// this function is called if the command line doesn't match any existing command
	// by default it displays an error message
	Default func(string)

	// this function is called to implement command completion.
	// it should return a list of words that match the input text
	Complete func(string, string, int, int) []string

	// if true, enable shell commands
	EnableShell bool

	// this is the list of available commands indexed by command name
	Commands map[string]Command

	///////// private stuff /////////////
	completer *Completer
}

func (cmd *Cmd) readHistoryFile() {
	if len(cmd.HistoryFile) == 0 {
		// no history file
		return
	}

	filepath := cmd.HistoryFile // start with current directory
	if _, err := os.Stat(filepath); err == nil {
		if err := readline.ReadHistoryFile(filepath); err != nil {
			fmt.Println(err)
		}

		return
	}

	filepath = path.Join(os.Getenv("HOME"), filepath) // then check home directory
	if _, err := os.Stat(filepath); err == nil {
		if err := readline.ReadHistoryFile(filepath); err != nil {
			fmt.Println(err)
		}
	}

	// update HistoryFile with home path
	cmd.HistoryFile = filepath
}

func (cmd *Cmd) writeHistoryFile() {
	if len(cmd.HistoryFile) == 0 {
		// no history file
		return
	}

	if err := readline.WriteHistoryFile(cmd.HistoryFile); err != nil {
		fmt.Println(err)
	}
}

//
// Initialize the command interpreter context
//
func (cmd *Cmd) Init() {
	if cmd.PreLoop == nil {
		cmd.PreLoop = func() {}
	}
	if cmd.PostLoop == nil {
		cmd.PostLoop = func() {}
	}
	if cmd.PreCmd == nil {
		cmd.PreCmd = func(string) {}
	}
	if cmd.PostCmd == nil {
		cmd.PostCmd = func(line string, stop bool) bool { return stop }
	}
	if cmd.EmptyLine == nil {
		cmd.EmptyLine = func() {}
	}
	if cmd.Default == nil {
		cmd.Default = func(line string) { fmt.Printf("invalid command: %v\n", line) }
	}

	cmd.Commands = make(map[string]Command)
	cmd.Add(Command{"help", `list available commands`, cmd.Help})
}

//
// Add a completer that matches on command names
//
func (cmd *Cmd) addCommandCompleter() {
	names := make([]string, 0, len(cmd.Commands))

	for n, _ := range cmd.Commands {
		names = append(names, n)
	}

	cmd.completer = NewCompleter(names)
	//readline.SetCompletionEntryFunction(completer.Complete)

	readline.SetAttemptedCompletionFunction(cmd.attemptedCompletion)
}

func (cmd *Cmd) attemptedCompletion(text string, start, end int) []string {
	if start == 0 { // this is the command to match
		return readline.CompletionMatches(text, cmd.completer.Complete)
	} else if cmd.Complete != nil {
		return cmd.Complete(text, readline.GetLineBuffer(), start, end)
	} else {
		return nil
	}
}

//
// execute shell command
//
func shellExec(command string) {
	args := args.GetArgs(command)
	if len(args) < 1 {
		fmt.Println("No command to exec")
	} else {
		cmd := exec.Command(args[0])
		cmd.Args = args
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr

		if err := cmd.Run(); err != nil {
			fmt.Println(err)
		}
	}
}

// Add a command to the command interpreter.
// Overrides a command with the same name, if there was one
//
func (cmd *Cmd) Add(command Command) {
	cmd.Commands[command.Name] = command
}

//
// Default help command.
// It lists all available commands or it displays the help for the specified command
//
func (cmd *Cmd) Help(line string) (stop bool) {
	if len(line) == 0 {
		fmt.Println("Available commands:")

		for k, _ := range cmd.Commands {
			fmt.Println("    ", k)
		}
	} else {
		c, ok := cmd.Commands[line]
		if ok {
			if len(c.Help) > 0 {
				fmt.Println(c.Help)
			} else {
				fmt.Println("No help for ", line)
			}
		} else {
			fmt.Println("unknown command")
		}
	}
	return
}

//
// This method executes one command
//
func (cmd *Cmd) OneCmd(line string) (stop bool) {

	if cmd.EnableShell && strings.HasPrefix(line, "!") {
		shellExec(line[1:])
		return
	}

	parts := strings.SplitN(line, " ", 2)
	cname := parts[0]

	command, ok := cmd.Commands[cname]

	if ok {
		var params string

		if len(parts) > 1 {
			params = strings.TrimSpace(parts[1])
		}

		stop = command.Call(params)
	} else {
		cmd.Default(line)
	}

	return
}

//
// This is the command interpreter entry point.
// It displays a prompt, waits for a command and executes it until the selected command returns true
//
func (cmd *Cmd) CmdLoop() {
	if len(cmd.Prompt) == 0 {
		cmd.Prompt = "> "
	}

	cmd.addCommandCompleter()

	cmd.PreLoop()

	cmd.readHistoryFile()

	// loop until ReadLine returns nil (signalling EOF)
	for {
		result := readline.ReadLine(&cmd.Prompt)
		if result == nil {
			break
		}

		line := strings.TrimSpace(*result)
		if line == "" {
			cmd.EmptyLine()
			continue
		}

		readline.AddHistory(*result) // allow user to recall this line

		cmd.PreCmd(line)

		stop := cmd.OneCmd(line)
		stop = cmd.PostCmd(line, stop)

		if stop {
			break
		}
	}

	cmd.writeHistoryFile()

	cmd.PostLoop()
}
<commit_msg>Added "go" command (guess what it does)<commit_after>/*
 This package is used to implement a "line oriented command interpreter", inspired by the python package with
 the same name http://docs.python.org/2/library/cmd.html

 Usage:

	 commander := &Cmd{...}
	 commander.Init()

	 commander.Add(Command{...})
	 commander.Add(Command{...})

	 commander.CmdLoop()
*/
package cmd

import (
	"github.com/gobs/args"
	"github.com/gobs/readline"

	"fmt"
	"os"
	"os/exec"
	"path"
	"strings"
)

//
// This is used to describe a new command
//
type Command struct {
	// command name
	Name string
	// command description
	Help string
	// the function to call to execute the command
	Call func(string) bool
}

//
// The context for command completion
//
type Completer struct {
	// the list of words to match on
	Words []string
	// the list of current matches
	Matches []string
}

//
// Return a word matching the prefix
// If there are multiple matches, index selects which one to pick
//
func (c *Completer) Complete(prefix string, index int) string {
	if index == 0 {
		c.Matches = c.Matches[:0]

		for _, w := range c.Words {
			if strings.HasPrefix(w, prefix) {
				c.Matches = append(c.Matches, w)
			}
		}
	}

	if index < len(c.Matches) {
		return c.Matches[index]
	} else {
		return ""
	}
}

//
// Create a Completer and initialize with list of words
//
func NewCompleter(words []string) (c *Completer) {
	c = new(Completer)
	c.Words = words
	c.Matches = make([]string, 0, len(c.Words))
	return
}

//
// This the the "context" for the command interpreter
//
type Cmd struct {
	// the prompt string
	Prompt string

	// the history file
	HistoryFile string

	// this function is called before starting the command loop
	PreLoop func()

	// this function is called before terminating the command loop
	PostLoop func()

	// this function is called before executing the selected command
	PreCmd func(string)

	// this function is called after a command has been executed
	// return true to terminate the interpreter, false to continue
	PostCmd func(string, bool) bool

	// this function is called if the last typed command was an empty line
	EmptyLine func()

	// this function is called if the command line doesn't match any existing command
	// by default it displays an error message
	Default func(string)

	// this function is called to implement command completion.
	// it should return a list of words that match the input text
	Complete func(string, string, int, int) []string

	// if true, enable shell commands
	EnableShell bool

	// this is the list of available commands indexed by command name
	Commands map[string]Command

	///////// private stuff /////////////
	completer *Completer
}

func (cmd *Cmd) readHistoryFile() {
	if len(cmd.HistoryFile) == 0 {
		// no history file
		return
	}

	filepath := cmd.HistoryFile // start with current directory
	if _, err := os.Stat(filepath); err == nil {
		if err := readline.ReadHistoryFile(filepath); err != nil {
			fmt.Println(err)
		}

		return
	}

	filepath = path.Join(os.Getenv("HOME"), filepath) // then check home directory
	if _, err := os.Stat(filepath); err == nil {
		if err := readline.ReadHistoryFile(filepath); err != nil {
			fmt.Println(err)
		}
	}

	// update HistoryFile with home path
	cmd.HistoryFile = filepath
}

func (cmd *Cmd) writeHistoryFile() {
	if len(cmd.HistoryFile) == 0 {
		// no history file
		return
	}

	if err := readline.WriteHistoryFile(cmd.HistoryFile); err != nil {
		fmt.Println(err)
	}
}

//
// Initialize the command interpreter context
//
func (cmd *Cmd) Init() {
	if cmd.PreLoop == nil {
		cmd.PreLoop = func() {}
	}
	if cmd.PostLoop == nil {
		cmd.PostLoop = func() {}
	}
	if cmd.PreCmd == nil {
		cmd.PreCmd = func(string) {}
	}
	if cmd.PostCmd == nil {
		cmd.PostCmd = func(line string, stop bool) bool { return stop }
	}
	if cmd.EmptyLine == nil {
		cmd.EmptyLine = func() {}
	}
	if cmd.Default == nil {
		cmd.Default = func(line string) { fmt.Printf("invalid command: %v\n", line) }
	}

	cmd.Commands = make(map[string]Command)
	cmd.Add(Command{"help", `list available commands`, cmd.Help})
	cmd.Add(Command{"go", `go cmd: asynchronous execution of cmd`, cmd.Go})
}

//
// Add a completer that matches on command names
//
func (cmd *Cmd) addCommandCompleter() {
	names := make([]string, 0, len(cmd.Commands))

	for n, _ := range cmd.Commands {
		names = append(names, n)
	}

	cmd.completer = NewCompleter(names)
	//readline.SetCompletionEntryFunction(completer.Complete)

	readline.SetAttemptedCompletionFunction(cmd.attemptedCompletion)
}

func (cmd *Cmd) attemptedCompletion(text string, start, end int) []string {
	if start == 0 { // this is the command to match
		return readline.CompletionMatches(text, cmd.completer.Complete)
	} else if cmd.Complete != nil {
		return cmd.Complete(text, readline.GetLineBuffer(), start, end)
	} else {
		return nil
	}
}

//
// execute shell command
//
func shellExec(command string) {
	args := args.GetArgs(command)
	if len(args) < 1 {
		fmt.Println("No command to exec")
	} else {
		cmd := exec.Command(args[0])
		cmd.Args = args
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr

		if err := cmd.Run(); err != nil {
			fmt.Println(err)
		}
	}
}

// Add a command to the command interpreter.
// Overrides a command with the same name, if there was one
//
func (cmd *Cmd) Add(command Command) {
	cmd.Commands[command.Name] = command
}

//
// Default help command.
// It lists all available commands or it displays the help for the specified command
//
func (cmd *Cmd) Help(line string) (stop bool) {
	if len(line) == 0 {
		fmt.Println("Available commands:")

		for k, _ := range cmd.Commands {
			fmt.Println("    ", k)
		}
	} else {
		c, ok := cmd.Commands[line]
		if ok {
			if len(c.Help) > 0 {
				fmt.Println(c.Help)
			} else {
				fmt.Println("No help for ", line)
			}
		} else {
			fmt.Println("unknown command")
		}
	}
	return
}

func (cmd *Cmd) Go(line string) (stop bool) {
	if strings.HasPrefix(line, "go ") {
		fmt.Println("Don't go go me!")
	} else {
		go cmd.OneCmd(line)
	}

	return
}

//
// This method executes one command
//
func (cmd *Cmd) OneCmd(line string) (stop bool) {

	if cmd.EnableShell && strings.HasPrefix(line, "!") {
		shellExec(line[1:])
		return
	}

	parts := strings.SplitN(line, " ", 2)
	cname := parts[0]

	command, ok := cmd.Commands[cname]

	if ok {
		var params string

		if len(parts) > 1 {
			params = strings.TrimSpace(parts[1])
		}

		stop = command.Call(params)
	} else {
		cmd.Default(line)
	}

	return
}

//
// This is the command interpreter entry point.
// It displays a prompt, waits for a command and executes it until the selected command returns true
//
func (cmd *Cmd) CmdLoop() {
	if len(cmd.Prompt) == 0 {
		cmd.Prompt = "> "
	}

	cmd.addCommandCompleter()

	cmd.PreLoop()

	cmd.readHistoryFile()

	// loop until ReadLine returns nil (signalling EOF)
	for {
		result := readline.ReadLine(&cmd.Prompt)
		if result == nil {
			break
		}

		line := strings.TrimSpace(*result)
		if line == "" {
			cmd.EmptyLine()
			continue
		}

		readline.AddHistory(*result) // allow user to recall this line

		cmd.PreCmd(line)

		stop := cmd.OneCmd(line)
		stop = cmd.PostCmd(line, stop)

		if stop {
			break
		}
	}

	cmd.writeHistoryFile()

	cmd.PostLoop()
}
<|endoftext|>