<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/miku/stardust"
)

func main() {
	app := cli.NewApp()
	app.Name = "stardust"
	app.Usage = "String similarity measures for tab separated values."
	app.Author = "Martin Czygan"
	app.Email = "martin.czygan@gmail.com"
	app.Version = "0.1.0"

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "f",
			Value: "1,2",
			Usage: "c1,c2 the two columns to use for the comparison",
		},
		cli.StringFlag{
			Name:  "delimiter, d",
			Value: "\t",
			Usage: "column delimiter (defaults to tab)",
		},
	}

	app.Commands = []cli.Command{
		{
			Name:        "ngram",
			Usage:       "Ngram distance",
			Description: "Compute Ngram distance, which lies between 0 and 1 (equal).",
			Action: func(c *cli.Context) {
				records := stardust.RecordGenerator(c)
				for r := range records {
					measure, err := stardust.NgramDistanceSize(r.Left(), r.Right(), c.Int("size"))
					if err != nil {
						log.Fatal(err)
					}
					fmt.Printf("%s\t%v\n", strings.Join(r.Fields, "\t"), measure)
				}
			},
			Flags: []cli.Flag{
				cli.IntFlag{
					Name:  "size, s",
					Value: 3,
					Usage: "value of n",
				},
			},
		},
		{
			Name:  "hamming",
			Usage: "Hamming distance",
			Action: func(c *cli.Context) {
				records := stardust.RecordGenerator(c)
				for r := range records {
					measure, _ := stardust.HammingDistance(r.Left(), r.Right())
					fmt.Printf("%s\t%v\n", strings.Join(r.Fields, "\t"), measure)
				}
			},
		},
		{
			Name:  "levenshtein",
			Usage: "Levenshtein distance",
			Action: func(c *cli.Context) {
				records := stardust.RecordGenerator(c)
				for r := range records {
					measure, _ := stardust.LevenshteinDistance(r.Left(), r.Right())
					fmt.Printf("%s\t%v\n", strings.Join(r.Fields, "\t"), measure)
				}
			},
		},
		{
			Name:        "jaro",
			Usage:       "Jaro distance",
			Description: "Similar to Ngram, but faster.",
			Action: func(c *cli.Context) {
				records := stardust.RecordGenerator(c)
				for r := range records {
					measure, _ := stardust.JaroDistance(r.Left(), r.Right())
					fmt.Printf("%s\t%v\n", strings.Join(r.Fields, "\t"), measure)
				}
			},
		},
		{
			Name:        "jaro-winkler",
			Usage:       "Jaro-Winkler distance",
			Description: "It is a variant of the Jaro distance metric.",
			Action: func(c *cli.Context) {
				records := stardust.RecordGenerator(c)
				for r := range records {
					measure, _ := stardust.JaroWinklerDistance(r.Left(), r.Right(), c.Float64("boost"), c.Int("size"))
					fmt.Printf("%s\t%v\n", strings.Join(r.Fields, "\t"), measure)
				}
			},
			Flags: []cli.Flag{
				cli.Float64Flag{
					Name:  "boost, b",
					Value: 0.5,
					Usage: "boost factor",
				},
				cli.IntFlag{
					Name:  "size, p",
					Value: 3,
					Usage: "prefix size",
				},
			},
		},
		{
			Name:  "plain",
			Usage: "Plain passthrough (for IO benchmarks)",
			Action: func(c *cli.Context) {
				records := stardust.RecordGenerator(c)
				for r := range records {
					fmt.Printf("%s\n", strings.Join(r.Fields, "\t"))
				}
			},
		},
	}
	app.Run(os.Args)
}
<commit_msg>actually check for errors<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/miku/stardust"
)

func main() {
	app := cli.NewApp()
	app.Name = "stardust"
	app.Usage = "String similarity measures for tab separated values."
	app.Author = "Martin Czygan"
	app.Email = "martin.czygan@gmail.com"
	app.Version = "0.1.0"

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "f",
			Value: "1,2",
			Usage: "c1,c2 the two columns to use for the comparison",
		},
		cli.StringFlag{
			Name:  "delimiter, d",
			Value: "\t",
			Usage: "column delimiter (defaults to tab)",
		},
	}

	app.Commands = []cli.Command{
		{
			Name:        "ngram",
			Usage:       "Ngram distance",
			Description: "Compute Ngram distance, which lies between 0 and 1 (equal).",
			Action: func(c *cli.Context) {
				records := stardust.RecordGenerator(c)
				for r := range records {
					measure, err := stardust.NgramDistanceSize(r.Left(), r.Right(), c.Int("size"))
					if err != nil {
						log.Fatal(err)
					}
					fmt.Printf("%s\t%v\n", strings.Join(r.Fields, "\t"), measure)
				}
			},
			Flags: []cli.Flag{
				cli.IntFlag{
					Name:  "size, s",
					Value: 3,
					Usage: "value of n",
				},
			},
		},
		{
			Name:  "hamming",
			Usage: "Hamming distance",
			Action: func(c *cli.Context) {
				records := stardust.RecordGenerator(c)
				for r := range records {
					measure, err := stardust.HammingDistance(r.Left(), r.Right())
					if err != nil {
						log.Fatal(err)
					}
					fmt.Printf("%s\t%v\n", strings.Join(r.Fields, "\t"), measure)
				}
			},
		},
		{
			Name:  "levenshtein",
			Usage: "Levenshtein distance",
			Action: func(c *cli.Context) {
				records := stardust.RecordGenerator(c)
				for r := range records {
					measure, err := stardust.LevenshteinDistance(r.Left(), r.Right())
					if err != nil {
						log.Fatal(err)
					}
					fmt.Printf("%s\t%v\n", strings.Join(r.Fields, "\t"), measure)
				}
			},
		},
		{
			Name:        "jaro",
			Usage:       "Jaro distance",
			Description: "Similar to Ngram, but faster.",
			Action: func(c *cli.Context) {
				records := stardust.RecordGenerator(c)
				for r := range records {
					measure, err := stardust.JaroDistance(r.Left(), r.Right())
					if err != nil {
						log.Fatal(err)
					}
					fmt.Printf("%s\t%v\n", strings.Join(r.Fields, "\t"), measure)
				}
			},
		},
		{
			Name:        "jaro-winkler",
			Usage:       "Jaro-Winkler distance",
			Description: "It is a variant of the Jaro distance metric.",
			Action: func(c *cli.Context) {
				records := stardust.RecordGenerator(c)
				for r := range records {
					measure, err := stardust.JaroWinklerDistance(r.Left(), r.Right(), c.Float64("boost"), c.Int("size"))
					if err != nil {
						log.Fatal(err)
					}
					fmt.Printf("%s\t%v\n", strings.Join(r.Fields, "\t"), measure)
				}
			},
			Flags: []cli.Flag{
				cli.Float64Flag{
					Name:  "boost, b",
					Value: 0.5,
					Usage: "boost factor",
				},
				cli.IntFlag{
					Name:  "size, p",
					Value: 3,
					Usage: "prefix size",
				},
			},
		},
		{
			Name:  "plain",
			Usage: "Plain passthrough (for IO benchmarks)",
			Action: func(c *cli.Context) {
				records := stardust.RecordGenerator(c)
				for r := range records {
					fmt.Printf("%s\n", strings.Join(r.Fields, "\t"))
				}
			},
		},
	}
	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package mpd

import (
	"os"
	"strconv"
	"testing"
)

var host = "localhost"
var port = 0
var timeoutms = 0

func init() {
	if env_host := os.Getenv("GOMPD_HOST"); env_host != "" {
		host = env_host
	}

	if env_port := os.Getenv("GOMPD_PORT"); env_port != "" {
		port, _ = strconv.Atoi(env_port)
	}

	if env_timeout_ms := os.Getenv("GOMPD_TIMEOUTMS"); env_timeout_ms != "" {
		timeoutms, _ = strconv.Atoi(env_timeout_ms)
	}
}

func TestClientInit(t *testing.T) {
	if client, err := Init(host, port, timeoutms); err != nil {
		t.Errorf("Init failed: %v", err)
	} else {
		client.Close()
	}
}
<commit_msg>Test GetCurrentSong<commit_after>package mpd

import (
	"os"
	"strconv"
	"testing"
)

var host = "localhost"
var port = 0
var timeoutms = 0

func init() {
	if env_host := os.Getenv("GOMPD_HOST"); env_host != "" {
		host = env_host
	}

	if env_port := os.Getenv("GOMPD_PORT"); env_port != "" {
		port, _ = strconv.Atoi(env_port)
	}

	if env_timeout_ms := os.Getenv("GOMPD_TIMEOUTMS"); env_timeout_ms != "" {
		timeoutms, _ = strconv.Atoi(env_timeout_ms)
	}
}

func TestClientInit(t *testing.T) {
	if client, err := Init(host, port, timeoutms); err != nil {
		t.Errorf("Init failed: %v", err)
	} else {
		client.Close()
	}
}

func TestGetCurrentSong(t *testing.T) {
  client, _ := Init(host, port, timeoutms)

  if song, err := client.GetCurrentSong(); err != nil {
    t.Errorf("GetCurrentSong failed: %v", err)
  } else {
    if song.Artist != "Kenny Beltrey" && song.Title != "Hydrate - Kenny Beltrey" {
      t.Fail()
    }
  }
}
<|endoftext|>


<commit_before>package web

import (
	"net/http"

	"github.com/concourse/go-concourse/concourse"
)

type ClientFactory interface {
	Build(request *http.Request) concourse.Client
}

type clientFactory struct {
	apiEndpoint string
}

func NewClientFactory(apiEndpoint string) ClientFactory {
	return &clientFactory{
		apiEndpoint: apiEndpoint,
	}
}

func (cf *clientFactory) Build(r *http.Request) concourse.Client {
	transport := authorizationTransport{
		Authorization: r.Header.Get("Authorization"),

		Base: &http.Transport{
			// disable connection pooling
			DisableKeepAlives: true,
		},
	}

	httpClient := &http.Client{
		Transport: transport,
	}

	return concourse.NewClient(cf.apiEndpoint, httpClient)
}

type authorizationTransport struct {
	Base          http.RoundTripper
	Authorization string
}

func (transport authorizationTransport) RoundTrip(r *http.Request) (*http.Response, error) {
	r.Header.Set("Authorization", transport.Authorization)
	return transport.Base.RoundTrip(r)
}
<commit_msg>Use external_url when TLS enabled or IP address otherwise - Allow self-signed certificates only when in development mode<commit_after>package web

import (
	"crypto/tls"
	"net/http"

	"github.com/concourse/go-concourse/concourse"
)

type ClientFactory interface {
	Build(request *http.Request) concourse.Client
}

type clientFactory struct {
	apiEndpoint                 string
	allowSelfSignedCertificates bool
}

func NewClientFactory(apiEndpoint string, allowSelfSignedCertificates bool) ClientFactory {
	return &clientFactory{
		apiEndpoint:                 apiEndpoint,
		allowSelfSignedCertificates: allowSelfSignedCertificates,
	}
}

func (cf *clientFactory) Build(r *http.Request) concourse.Client {
	transport := authorizationTransport{
		Authorization: r.Header.Get("Authorization"),

		Base: &http.Transport{

			DisableKeepAlives: true, // disable connection pooling
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: cf.allowSelfSignedCertificates,
			},
		},
	}

	httpClient := &http.Client{
		Transport: transport,
	}

	return concourse.NewClient(cf.apiEndpoint, httpClient)
}

type authorizationTransport struct {
	Base          http.RoundTripper
	Authorization string
}

func (transport authorizationTransport) RoundTrip(r *http.Request) (*http.Response, error) {
	r.Header.Set("Authorization", transport.Authorization)
	return transport.Base.RoundTrip(r)
}
<|endoftext|>


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

package clientv3

import (
	"sync"
	"time"

	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
	"github.com/coreos/etcd/lease"
)

type (
	LeaseCreateResponse    pb.LeaseCreateResponse
	LeaseRevokeResponse    pb.LeaseRevokeResponse
	LeaseKeepAliveResponse pb.LeaseKeepAliveResponse
)

const (
	// a small buffer to store unsent lease responses.
	leaseResponseChSize = 16
)

type Lease interface {
	// Create creates a new lease.
	Create(ctx context.Context, ttl int64) (*LeaseCreateResponse, error)

	// Revoke revokes the given lease.
	Revoke(ctx context.Context, id lease.LeaseID) (*LeaseRevokeResponse, error)

	// KeepAlive keeps the given lease alive forever.
	KeepAlive(ctx context.Context, id lease.LeaseID) (<-chan *LeaseKeepAliveResponse, error)

	// KeepAliveOnce renews the lease once. In most of the cases, Keepalive
	// should be used instead of KeepAliveOnce.
	KeepAliveOnce(ctx context.Context, id lease.LeaseID) (*LeaseKeepAliveResponse, error)

	// Lease keeps internal routines and connections for efficient communication with etcd server.
	// After using Lease, call Close() to release all related resources.
	Close() error
}

type lessor struct {
	c *Client

	mu     sync.Mutex       // guards all fields
	conn   *grpc.ClientConn // conn in-use
	remote pb.LeaseClient

	stream       pb.Lease_LeaseKeepAliveClient
	streamCancel context.CancelFunc

	stopCtx    context.Context
	stopCancel context.CancelFunc

	keepAlives map[lease.LeaseID]chan *LeaseKeepAliveResponse
	deadlines  map[lease.LeaseID]time.Time
}

func NewLease(c *Client) Lease {
	l := &lessor{
		c:    c,
		conn: c.ActiveConnection(),

		keepAlives: make(map[lease.LeaseID]chan *LeaseKeepAliveResponse),
		deadlines:  make(map[lease.LeaseID]time.Time),
	}

	l.remote = pb.NewLeaseClient(l.conn)
	l.stopCtx, l.stopCancel = context.WithCancel(context.Background())
	go l.recvKeepAliveLoop()
	go l.sendKeepAliveLoop()

	return l
}

func (l *lessor) Create(ctx context.Context, ttl int64) (*LeaseCreateResponse, error) {
	cctx, cancel := context.WithCancel(ctx)
	done := cancelWhenStop(cancel, l.stopCtx.Done())
	defer close(done)

	for {
		r := &pb.LeaseCreateRequest{TTL: ttl}
		resp, err := l.getRemote().LeaseCreate(cctx, r)
		if err == nil {
			return (*LeaseCreateResponse)(resp), nil
		}

		if isRPCError(err) {
			return nil, err
		}

		if nerr := l.switchRemoteAndStream(err); nerr != nil {
			return nil, nerr
		}
	}
}

func (l *lessor) Revoke(ctx context.Context, id lease.LeaseID) (*LeaseRevokeResponse, error) {
	cctx, cancel := context.WithCancel(ctx)
	done := cancelWhenStop(cancel, l.stopCtx.Done())
	defer close(done)

	for {
		r := &pb.LeaseRevokeRequest{ID: int64(id)}
		resp, err := l.getRemote().LeaseRevoke(cctx, r)

		if err == nil {
			return (*LeaseRevokeResponse)(resp), nil
		}

		if isRPCError(err) {
			return nil, err
		}

		if nerr := l.switchRemoteAndStream(err); nerr != nil {
			return nil, nerr
		}
	}
}

func (l *lessor) KeepAlive(ctx context.Context, id lease.LeaseID) (<-chan *LeaseKeepAliveResponse, error) {
	lc := make(chan *LeaseKeepAliveResponse, leaseResponseChSize)

	// todo: add concellation based on the passed in ctx

	l.mu.Lock()
	_, ok := l.keepAlives[id]
	if !ok {
		l.keepAlives[id] = lc
		l.deadlines[id] = time.Now()
		l.mu.Unlock()
		return lc, nil
	}
	l.mu.Unlock()

	resp, err := l.KeepAliveOnce(ctx, id)
	if err != nil {
		return nil, err
	}
	lc <- resp
	return lc, nil
}

func (l *lessor) KeepAliveOnce(ctx context.Context, id lease.LeaseID) (*LeaseKeepAliveResponse, error) {
	cctx, cancel := context.WithCancel(ctx)
	done := cancelWhenStop(cancel, l.stopCtx.Done())
	defer close(done)

	for {
		resp, err := l.keepAliveOnce(cctx, id)
		if err == nil {
			return resp, err
		}

		nerr := l.switchRemoteAndStream(err)
		if nerr != nil {
			return nil, nerr
		}
	}
}

func (l *lessor) Close() error {
	l.mu.Lock()
	defer l.mu.Unlock()

	l.stopCancel()
	l.stream = nil
	return nil
}

func (l *lessor) keepAliveOnce(ctx context.Context, id lease.LeaseID) (*LeaseKeepAliveResponse, error) {
	stream, err := l.getRemote().LeaseKeepAlive(ctx)
	if err != nil {
		return nil, err
	}

	err = stream.Send(&pb.LeaseKeepAliveRequest{ID: int64(id)})
	if err != nil {
		return nil, err
	}

	resp, rerr := stream.Recv()
	if rerr != nil {
		return nil, rerr
	}
	return (*LeaseKeepAliveResponse)(resp), nil
}

func (l *lessor) recvKeepAliveLoop() {
	if !l.initStream() {
		l.Close()
		return
	}

	for {
		stream := l.getKeepAliveStream()

		resp, err := stream.Recv()
		if err != nil {
			err := l.switchRemoteAndStream(err)
			if err != nil {
				l.Close()
				return
			}
			continue
		}

		l.mu.Lock()
		lch, ok := l.keepAlives[lease.LeaseID(resp.ID)]
		if !ok {
			l.mu.Unlock()
			continue
		}

		if resp.TTL <= 0 {
			close(lch)
			delete(l.deadlines, lease.LeaseID(resp.ID))
			delete(l.keepAlives, lease.LeaseID(resp.ID))
		} else {
			select {
			case lch <- (*LeaseKeepAliveResponse)(resp):
				l.deadlines[lease.LeaseID(resp.ID)] =
					time.Now().Add(1 + time.Duration(resp.TTL/3)*time.Second)
			default:
			}
		}
		l.mu.Unlock()
	}
}

func (l *lessor) sendKeepAliveLoop() {
	if !l.initStream() {
		l.Close()
		return
	}

	for {
		select {
		case <-time.After(500 * time.Millisecond):
		case <-l.stopCtx.Done():
			return
		}

		tosend := make([]lease.LeaseID, 0)

		now := time.Now()
		l.mu.Lock()
		for id, d := range l.deadlines {
			if d.Before(now) {
				tosend = append(tosend, id)
			}
		}
		l.mu.Unlock()

		stream := l.getKeepAliveStream()

		var err error
		for _, id := range tosend {
			r := &pb.LeaseKeepAliveRequest{ID: int64(id)}
			err := stream.Send(r)
			if err != nil {
				break
			}
		}

		if err != nil {
			err := l.switchRemoteAndStream(err)
			if err != nil {
				l.Close()
				return
			}
		}
	}
}

func (l *lessor) getRemote() pb.LeaseClient {
	l.mu.Lock()
	defer l.mu.Unlock()
	return l.remote
}

func (l *lessor) getKeepAliveStream() pb.Lease_LeaseKeepAliveClient {
	l.mu.Lock()
	defer l.mu.Unlock()
	return l.stream
}

func (l *lessor) switchRemoteAndStream(prevErr error) error {
	l.mu.Lock()
	conn := l.conn
	l.mu.Unlock()

	var (
		err     error
		newConn *grpc.ClientConn
	)

	if prevErr != nil {
		conn.Close()
		newConn, err = l.c.retryConnection(conn, prevErr)
		if err != nil {
			return err
		}
	}

	l.mu.Lock()
	if newConn != nil {
		l.conn = newConn
	}

	l.remote = pb.NewLeaseClient(l.conn)
	l.mu.Unlock()

	serr := l.newStream()
	if serr != nil {
		return serr
	}
	return nil
}

func (l *lessor) newStream() error {
	sctx, cancel := context.WithCancel(l.stopCtx)
	stream, err := l.getRemote().LeaseKeepAlive(sctx)
	if err != nil {
		cancel()
		return err
	}

	l.mu.Lock()
	defer l.mu.Unlock()
	if l.stream != nil && l.streamCancel != nil {
		l.stream.CloseSend()
		l.streamCancel()
	}

	l.streamCancel = cancel
	l.stream = stream
	return nil
}

func (l *lessor) initStream() bool {
	if l.getKeepAliveStream() != nil {
		return true
	}

	err := l.switchRemoteAndStream(nil)
	if err == nil {
		return true
	}
	return false
}

// cancelWhenStop calls cancel when the given stopc fires. It returns a done chan. done
// should be closed when the work is finished. When done fires, cancelWhenStop will release
// its internal resource.
func cancelWhenStop(cancel context.CancelFunc, stopc <-chan struct{}) chan<- struct{} {
	done := make(chan struct{}, 1)

	go func() {
		select {
		case <-stopc:
		case <-done:
		}
		cancel()
	}()

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

package clientv3

import (
	"sync"
	"time"

	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
	"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
	"github.com/coreos/etcd/lease"
)

type (
	LeaseCreateResponse    pb.LeaseCreateResponse
	LeaseRevokeResponse    pb.LeaseRevokeResponse
	LeaseKeepAliveResponse pb.LeaseKeepAliveResponse
)

const (
	// a small buffer to store unsent lease responses.
	leaseResponseChSize = 16
)

type Lease interface {
	// Create creates a new lease.
	Create(ctx context.Context, ttl int64) (*LeaseCreateResponse, error)

	// Revoke revokes the given lease.
	Revoke(ctx context.Context, id lease.LeaseID) (*LeaseRevokeResponse, error)

	// KeepAlive keeps the given lease alive forever.
	KeepAlive(ctx context.Context, id lease.LeaseID) (<-chan *LeaseKeepAliveResponse, error)

	// KeepAliveOnce renews the lease once. In most of the cases, Keepalive
	// should be used instead of KeepAliveOnce.
	KeepAliveOnce(ctx context.Context, id lease.LeaseID) (*LeaseKeepAliveResponse, error)

	// Lease keeps internal routines and connections for efficient communication with etcd server.
	// After using Lease, call Close() to release all related resources.
	Close() error
}

type lessor struct {
	c *Client

	mu      sync.Mutex       // guards all fields
	conn    *grpc.ClientConn // conn in-use
	initedc chan bool

	remote pb.LeaseClient

	stream       pb.Lease_LeaseKeepAliveClient
	streamCancel context.CancelFunc

	stopCtx    context.Context
	stopCancel context.CancelFunc

	keepAlives map[lease.LeaseID]chan *LeaseKeepAliveResponse
	deadlines  map[lease.LeaseID]time.Time
}

func NewLease(c *Client) Lease {
	l := &lessor{
		c:    c,
		conn: c.ActiveConnection(),

		initedc: make(chan bool, 1),

		keepAlives: make(map[lease.LeaseID]chan *LeaseKeepAliveResponse),
		deadlines:  make(map[lease.LeaseID]time.Time),
	}

	l.remote = pb.NewLeaseClient(l.conn)
	l.stopCtx, l.stopCancel = context.WithCancel(context.Background())

	l.initedc <- false

	go l.recvKeepAliveLoop()
	go l.sendKeepAliveLoop()

	return l
}

func (l *lessor) Create(ctx context.Context, ttl int64) (*LeaseCreateResponse, error) {
	cctx, cancel := context.WithCancel(ctx)
	done := cancelWhenStop(cancel, l.stopCtx.Done())
	defer close(done)

	for {
		r := &pb.LeaseCreateRequest{TTL: ttl}
		resp, err := l.getRemote().LeaseCreate(cctx, r)
		if err == nil {
			return (*LeaseCreateResponse)(resp), nil
		}

		if isRPCError(err) {
			return nil, err
		}
		if nerr := l.switchRemoteAndStream(err); nerr != nil {
			return nil, nerr
		}
	}
}

func (l *lessor) Revoke(ctx context.Context, id lease.LeaseID) (*LeaseRevokeResponse, error) {
	cctx, cancel := context.WithCancel(ctx)
	done := cancelWhenStop(cancel, l.stopCtx.Done())
	defer close(done)

	for {
		r := &pb.LeaseRevokeRequest{ID: int64(id)}
		resp, err := l.getRemote().LeaseRevoke(cctx, r)

		if err == nil {
			return (*LeaseRevokeResponse)(resp), nil
		}

		if isRPCError(err) {
			return nil, err
		}

		if nerr := l.switchRemoteAndStream(err); nerr != nil {
			return nil, nerr
		}
	}
}

func (l *lessor) KeepAlive(ctx context.Context, id lease.LeaseID) (<-chan *LeaseKeepAliveResponse, error) {
	lc := make(chan *LeaseKeepAliveResponse, leaseResponseChSize)

	// todo: add concellation based on the passed in ctx

	l.mu.Lock()
	_, ok := l.keepAlives[id]
	if !ok {
		l.keepAlives[id] = lc
		l.deadlines[id] = time.Now()
		l.mu.Unlock()
		return lc, nil
	}
	l.mu.Unlock()

	resp, err := l.KeepAliveOnce(ctx, id)
	if err != nil {
		return nil, err
	}
	lc <- resp
	return lc, nil
}

func (l *lessor) KeepAliveOnce(ctx context.Context, id lease.LeaseID) (*LeaseKeepAliveResponse, error) {
	cctx, cancel := context.WithCancel(ctx)
	done := cancelWhenStop(cancel, l.stopCtx.Done())
	defer close(done)

	for {
		resp, err := l.keepAliveOnce(cctx, id)
		if err == nil {
			return resp, err
		}

		nerr := l.switchRemoteAndStream(err)
		if nerr != nil {
			return nil, nerr
		}
	}
}

func (l *lessor) Close() error {
	l.mu.Lock()
	defer l.mu.Unlock()

	l.stopCancel()
	l.stream = nil
	return nil
}

func (l *lessor) keepAliveOnce(ctx context.Context, id lease.LeaseID) (*LeaseKeepAliveResponse, error) {
	stream, err := l.getRemote().LeaseKeepAlive(ctx)
	if err != nil {
		return nil, err
	}

	err = stream.Send(&pb.LeaseKeepAliveRequest{ID: int64(id)})
	if err != nil {
		return nil, err
	}

	resp, rerr := stream.Recv()
	if rerr != nil {
		return nil, rerr
	}
	return (*LeaseKeepAliveResponse)(resp), nil
}

func (l *lessor) recvKeepAliveLoop() {
	if !l.initStream() {
		l.Close()
		return
	}

	for {
		stream := l.getKeepAliveStream()

		resp, err := stream.Recv()
		if err != nil {
			err := l.switchRemoteAndStream(err)
			if err != nil {
				l.Close()
				return
			}
			continue
		}

		l.mu.Lock()
		lch, ok := l.keepAlives[lease.LeaseID(resp.ID)]
		if !ok {
			l.mu.Unlock()
			continue
		}

		if resp.TTL <= 0 {
			close(lch)
			delete(l.deadlines, lease.LeaseID(resp.ID))
			delete(l.keepAlives, lease.LeaseID(resp.ID))
		} else {
			select {
			case lch <- (*LeaseKeepAliveResponse)(resp):
				l.deadlines[lease.LeaseID(resp.ID)] =
					time.Now().Add(1 + time.Duration(resp.TTL/3)*time.Second)
			default:
			}
		}
		l.mu.Unlock()
	}
}

func (l *lessor) sendKeepAliveLoop() {
	if !l.initStream() {
		l.Close()
		return
	}

	for {
		select {
		case <-time.After(500 * time.Millisecond):
		case <-l.stopCtx.Done():
			return
		}

		tosend := make([]lease.LeaseID, 0)

		now := time.Now()
		l.mu.Lock()
		for id, d := range l.deadlines {
			if d.Before(now) {
				tosend = append(tosend, id)
			}
		}
		l.mu.Unlock()

		stream := l.getKeepAliveStream()

		var err error
		for _, id := range tosend {
			r := &pb.LeaseKeepAliveRequest{ID: int64(id)}
			err := stream.Send(r)
			if err != nil {
				break
			}
		}

		if err != nil {
			err := l.switchRemoteAndStream(err)
			if err != nil {
				l.Close()
				return
			}
		}
	}
}

func (l *lessor) getRemote() pb.LeaseClient {
	l.mu.Lock()
	defer l.mu.Unlock()
	return l.remote
}

func (l *lessor) getKeepAliveStream() pb.Lease_LeaseKeepAliveClient {
	l.mu.Lock()
	defer l.mu.Unlock()
	return l.stream
}

func (l *lessor) switchRemoteAndStream(prevErr error) error {
	l.mu.Lock()
	conn := l.conn
	l.mu.Unlock()

	var (
		err     error
		newConn *grpc.ClientConn
	)

	if prevErr != nil {
		conn.Close()
		newConn, err = l.c.retryConnection(conn, prevErr)
		if err != nil {
			return err
		}
	}

	l.mu.Lock()
	if newConn != nil {
		l.conn = newConn
	}

	l.remote = pb.NewLeaseClient(l.conn)
	l.mu.Unlock()

	serr := l.newStream()
	if serr != nil {
		return serr
	}
	return nil
}

func (l *lessor) newStream() error {
	sctx, cancel := context.WithCancel(l.stopCtx)
	stream, err := l.getRemote().LeaseKeepAlive(sctx)
	if err != nil {
		cancel()
		return err
	}

	l.mu.Lock()
	defer l.mu.Unlock()
	if l.stream != nil && l.streamCancel != nil {
		l.stream.CloseSend()
		l.streamCancel()
	}

	l.streamCancel = cancel
	l.stream = stream
	return nil
}

func (l *lessor) initStream() bool {
	ok := <-l.initedc
	if ok {
		return true
	}

	err := l.switchRemoteAndStream(nil)
	if err == nil {
		l.initedc <- true
		return true
	}
	l.initedc <- false
	return false
}

// cancelWhenStop calls cancel when the given stopc fires. It returns a done chan. done
// should be closed when the work is finished. When done fires, cancelWhenStop will release
// its internal resource.
func cancelWhenStop(cancel context.CancelFunc, stopc <-chan struct{}) chan<- struct{} {
	done := make(chan struct{}, 1)

	go func() {
		select {
		case <-stopc:
		case <-done:
		}
		cancel()
	}()

	return done
}
<|endoftext|>


<commit_before>package flux

import (
	"fmt"
	"strings"
	"regexp"
)

// TODO add something like a toString() Method

type Flux struct {
	pattern   []string
	prefixes  []string
	suffixes  []string
	modifiers []string
}

// regexp.Compile
func (f *Flux) Compile() (*regexp.Regexp, error) {
	return regexp.Compile(f.String())
}

// To reuse the compiled regexp
// regexp.MustCompile
func (f *Flux) MustCompile() (*regexp.Regexp) {
	return regexp.MustCompile(f.String())
}

// concatenate prefixes/pattern/suffixes/modifiers into a regular expression
// prints the current String representation from the regex
func (f *Flux) String() string {
	pattern   := strings.Join(f.pattern, "")
	prefixes  := strings.Join(f.prefixes, "")
	suffixes  := strings.Join(f.suffixes, "")
	modifiers := strings.Join(f.modifiers, "")

	plainRegex := fmt.Sprintf("%s%s%s", prefixes, pattern, suffixes)
	if len(modifiers) > 0 {
		plainRegex = fmt.Sprintf("(?%s)%s", modifiers, plainRegex)
	}
	return plainRegex
}

func (f *Flux) Replace(src, repl string) string {
	return regexp.MustCompile(f.String()).ReplaceAllString(src, repl)
}

func (f *Flux) Match(value string) (bool, error) {
	r, err := regexp.Compile(f.String())

	if err == nil {
		return r.MatchString(value), nil
	}
	return false, err
}

// returns a map with all named matches
// experimental.... (Currently Only for groups added with #NamedGroup(name, rawGroup))
func (f *Flux)NamedMatches(s string) (map[string]string, error) {
	captures := make(map[string]string)

	r, err := f.Compile()
	if err != nil {
		return captures, err
	}

	match := r.FindStringSubmatch(s)
	if match == nil {
		return captures, nil
	}

	// get all named captures
	for i, name := range r.SubexpNames() {
		// Ignore the whole regexp match and unnamed groups
		if i == 0 || name == "" {
			continue
		}
		captures[name] = match[i]
	}

	return captures, nil
}

// Clears all pattern components to create a fresh expression
func (f *Flux) Clear() (*Flux) {
	f.pattern   = f.pattern[0:0]
	f.prefixes  = f.prefixes[0:0]
	f.suffixes  = f.suffixes[0:0]
	f.modifiers  = f.modifiers[0:0]

	return f
}

func (f *Flux) RawGroup(value string) (*Flux) {
	return add(f, value, "(%s)")
}

//very experimental
func (f *Flux) NamedGroup(name, value string) (*Flux) {
	return raw(f, value, fmt.Sprintf("(?P<%s>%s)", name, "%s"))
}

// alias for Min(1)
func (f *Flux) Once() (*Flux) {
	return f.Length(1, 0)
}

func (f *Flux) Min(min int) (*Flux) {
	return f.Length(min, min - 1)
}

func (f *Flux) Length(min, max int) (*Flux) {
	lastSegmentKey := getLastSegmentKey(f)
	var lengthPattern string

	if max > min {
		lengthPattern = fmt.Sprintf("{%d,%d}", min, max)
	} else {
		lengthPattern = fmt.Sprintf("{%d}", min)
	}

	return replaceQuantifierByKey(f, lastSegmentKey, lengthPattern)

}

//--------------------------------------------------------------------------------
// MODIFIERS
//--------------------------------------------------------------------------------
// Helper for the ^ prefix
func (f *Flux) StartOfLine() (*Flux) {
	return addPrefix(f, "^")
}

// Helper for the $ suffix
func (f *Flux) EndOfLine() (*Flux) {
	return addSuffix(f, "$")
}

// Adds a modifier to ignore cases
func (f *Flux) IgnoreCase() (*Flux) {
	return addModifier(f, "i")
}

// Removes the 'm' modifier if it exists
func (f *Flux) OneLine() (*Flux) {
	return removeModifier(f, "m")
}

// Adds the 'm' modifier
func (f *Flux) Multiline() (*Flux) {
	return addModifier(f, "m")
}

func (f *Flux) MatchNewLine() (*Flux) {
	return addModifier(f, "s")
}

//--------------------------------------------------------------------------------
// @=LANGUAGE
//--------------------------------------------------------------------------------
// Alias to Flux#then
func (f *Flux) Find(value string) (*Flux) {
	return f.Then(value)
}

// Adds a search parameter
func (f *Flux) Then(value string) (*Flux) {
	return add(f, value, "(%s)")
}

// Optional search parameter
func (f *Flux) Maybe(value string) (*Flux) {
	return add(f, value, "(%s)?")
}

// Takes multiple arguments are creates an OR list.
// Output would be one|two|three etc
func (f *Flux) Either(values ...string) (*Flux) {
	return raw(f, strings.Join(values, "|"), "(%s)")
}

// Creates a [%s] search param
func (f *Flux) Any(value string) (*Flux) {
	return add(f, value, "([%s])")
}

// Adds a wildcard parameter
func (f *Flux) Anything() (*Flux) {
	return raw(f, ".*", "(%s)")
}

// Matches anything but the given arguments
func (f *Flux) AnythingBut(value string) (*Flux) {
	return add(f, value, "([^%s]*)")
}

func (f *Flux) LineBreak() (*Flux) {
	return raw(f, "(\\n|\\r\\n)", "%s")
}

func (f *Flux) Tab() (*Flux) {
	return raw(f, "(\\t)", "%s")
}

func (f *Flux) Word() (*Flux) {
	return raw(f, "(\\w+)", "%s")
}

func (f *Flux) Letters() (*Flux) {
	return raw(f, "([a-zA-Z]+)", "%s")
}

func (f *Flux) Digits() (*Flux) {
	return raw(f, "(\\d+)", "%s")
}

// experimental...
// This is bound to change
func (f *Flux) OrTry() (*Flux) {
	addPrefix(f, "(")
	addSuffix(f, ")")
	return raw(f, "", ")|(%s")
}

// Creates a range character class
// You can create a-z0-9 by calling Flux.range("a", "z", "0", "9")
func (f *Flux) Range(values ...string) (*Flux) {
	// validate pramas
	if len(values) % 2 != 0 {
		return f
	}

	ranges := []string{}
	for i := 1; i < len(values); i += 2 {
			ranges = append(ranges, fmt.Sprintf("%s-%s", values[i - 1], values[i]))
	}
	return raw(f, strings.Join(ranges, ""), "([%s])")
}

// creates a new Flux instance
func NewFlux() *Flux {
	newFlux := Flux{}
	return &newFlux
}

//--------------------------------------------------------------------------------
// HELPER FUNCTIONS
//--------------------------------------------------------------------------------

func add(f *Flux, value, format string) (*Flux) {
	f.pattern = append(f.pattern, fmt.Sprintf(format, regexp.QuoteMeta(value)))
	return f
}

func raw(f *Flux, value, format string) (*Flux) {
	f.pattern = append(f.pattern, fmt.Sprintf(format, value))
	return f
}

func addPrefix(f *Flux, prefix string) (*Flux) {
	if !stringInSlice(prefix, f.prefixes) {
		f.prefixes = append(f.prefixes, strings.TrimSpace(prefix))
	}
	return f
}

func addSuffix(f *Flux, suffix string) (*Flux) {
	if !stringInSlice(suffix, f.suffixes) {
		f.suffixes = append(f.suffixes, strings.TrimSpace(suffix))
	}
	return f
}

func addModifier(f *Flux, modifier string) (*Flux) {
	if !stringInSlice(modifier, f.modifiers) {
		f.modifiers = append(f.modifiers, strings.TrimSpace(modifier))
	}
	return f
}

func removeModifier(f *Flux, modifier string) (*Flux) {
	for i, mod := range f.modifiers {
		if mod == modifier {
			f.modifiers = append(f.modifiers[:i], f.modifiers[i+1:]...)
		}
	}
	return f
}

func getLastSegmentKey(f *Flux) (int) {
	return len(f.pattern) - 1
}

func replaceQuantifierByKey(f *Flux, key int, replacement string) (*Flux) {
	subject := f.pattern[key]
	replacementPattern := "%s%s"

	if strings.LastIndex(subject, ")") != -1 {
		subject = strings.TrimRight(subject, ")")
		replacementPattern += ")"
	}

	subject = removeQuantifier(f, subject)
	f.pattern[key] = fmt.Sprintf(replacementPattern, subject, replacement);
	return f

}

func removeQuantifier(f *Flux, pattern string) string {
	if strings.LastIndex(pattern, "+") != -1 && strings.LastIndex(pattern, "\\+") == -1 {
		return strings.TrimRight(pattern, "+")
	} else if strings.LastIndex(pattern, "*") != -1 && strings.LastIndex(pattern, "\\*") == -1 {
		return strings.TrimRight(pattern, "*")
	} else if strings.LastIndex(pattern, "?") != -1 && strings.LastIndex(pattern, "\\?") == -1 {
		return strings.TrimRight(pattern, "?")
	}
	return pattern
}

// checks if the given string is in the given slice
func stringInSlice(a string, list []string) bool {
	for _, b := range list {
		if b == a {
			return true
		}
	}
	return false
}
<commit_msg>#3 cache compiled regex<commit_after>package flux

import (
	"fmt"
	"strings"
	"regexp"
)

// TODO add something like a toString() Method

type Flux struct {
	pattern   []string
	prefixes  []string
	suffixes  []string
	modifiers []string

	regex *regexp.Regexp
}

// regexp.Compile
func (f *Flux) Compile() (*regexp.Regexp, error) {
	if f.regex == nil {
		if reg, err := regexp.Compile(f.String()); err != nil {
			f.regex = nil
			return nil, err
		} else {
			f.regex = reg
		}
	}
	return f.regex, nil
}

// To reuse the compiled regexp
// regexp.MustCompile
func (f *Flux) MustCompile() (*regexp.Regexp) {
	return regexp.MustCompile(f.String())
}

// concatenate prefixes/pattern/suffixes/modifiers into a regular expression
// prints the current String representation from the regex
func (f *Flux) String() string {
	pattern   := strings.Join(f.pattern, "")
	prefixes  := strings.Join(f.prefixes, "")
	suffixes  := strings.Join(f.suffixes, "")
	modifiers := strings.Join(f.modifiers, "")

	plainRegex := fmt.Sprintf("%s%s%s", prefixes, pattern, suffixes)
	if len(modifiers) > 0 {
		plainRegex = fmt.Sprintf("(?%s)%s", modifiers, plainRegex)
	}
	return plainRegex
}

func (f *Flux) Replace(src, repl string) string {
	return regexp.MustCompile(f.String()).ReplaceAllString(src, repl)
}

func (f *Flux) Match(value string) (bool, error) {
	r, err := regexp.Compile(f.String())

	if err == nil {
		return r.MatchString(value), nil
	}
	return false, err
}

// returns a map with all named matches
// experimental.... (Currently Only for groups added with #NamedGroup(name, rawGroup))
func (f *Flux)NamedMatches(s string) (map[string]string, error) {
	captures := make(map[string]string)

	r, err := f.Compile()
	if err != nil {
		return captures, err
	}

	match := r.FindStringSubmatch(s)
	if match == nil {
		return captures, nil
	}

	// get all named captures
	for i, name := range r.SubexpNames() {
		// Ignore the whole regexp match and unnamed groups
		if i == 0 || name == "" {
			continue
		}
		captures[name] = match[i]
	}

	return captures, nil
}

// Clears all pattern components to create a fresh expression
func (f *Flux) Clear() (*Flux) {
	f.pattern   = f.pattern[0:0]
	f.prefixes  = f.prefixes[0:0]
	f.suffixes  = f.suffixes[0:0]
	f.modifiers  = f.modifiers[0:0]

	return resetCachedRegex(f)
}

func (f *Flux) RawGroup(value string) (*Flux) {
	return add(f, value, "(%s)")
}

//very experimental
func (f *Flux) NamedGroup(name, value string) (*Flux) {
	return raw(f, value, fmt.Sprintf("(?P<%s>%s)", name, "%s"))
}

// alias for Min(1)
func (f *Flux) Once() (*Flux) {
	return f.Length(1, 0)
}

func (f *Flux) Min(min int) (*Flux) {
	return f.Length(min, min - 1)
}

func (f *Flux) Length(min, max int) (*Flux) {
	lastSegmentKey := getLastSegmentKey(f)
	var lengthPattern string

	if max > min {
		lengthPattern = fmt.Sprintf("{%d,%d}", min, max)
	} else {
		lengthPattern = fmt.Sprintf("{%d}", min)
	}

	return replaceQuantifierByKey(f, lastSegmentKey, lengthPattern)

}

//--------------------------------------------------------------------------------
// MODIFIERS
//--------------------------------------------------------------------------------
// Helper for the ^ prefix
func (f *Flux) StartOfLine() (*Flux) {
	return addPrefix(f, "^")
}

// Helper for the $ suffix
func (f *Flux) EndOfLine() (*Flux) {
	return addSuffix(f, "$")
}

// Adds a modifier to ignore cases
func (f *Flux) IgnoreCase() (*Flux) {
	return addModifier(f, "i")
}

// Removes the 'm' modifier if it exists
func (f *Flux) OneLine() (*Flux) {
	return removeModifier(f, "m")
}

// Adds the 'm' modifier
func (f *Flux) Multiline() (*Flux) {
	return addModifier(f, "m")
}

func (f *Flux) MatchNewLine() (*Flux) {
	return addModifier(f, "s")
}

//--------------------------------------------------------------------------------
// @=LANGUAGE
//--------------------------------------------------------------------------------
// Alias to Flux#then
func (f *Flux) Find(value string) (*Flux) {
	return f.Then(value)
}

// Adds a search parameter
func (f *Flux) Then(value string) (*Flux) {
	return add(f, value, "(%s)")
}

// Optional search parameter
func (f *Flux) Maybe(value string) (*Flux) {
	return add(f, value, "(%s)?")
}

// Takes multiple arguments are creates an OR list.
// Output would be one|two|three etc
func (f *Flux) Either(values ...string) (*Flux) {
	return raw(f, strings.Join(values, "|"), "(%s)")
}

// Creates a [%s] search param
func (f *Flux) Any(value string) (*Flux) {
	return add(f, value, "([%s])")
}

// Adds a wildcard parameter
func (f *Flux) Anything() (*Flux) {
	return raw(f, ".*", "(%s)")
}

// Matches anything but the given arguments
func (f *Flux) AnythingBut(value string) (*Flux) {
	return add(f, value, "([^%s]*)")
}

func (f *Flux) LineBreak() (*Flux) {
	return raw(f, "(\\n|\\r\\n)", "%s")
}

func (f *Flux) Tab() (*Flux) {
	return raw(f, "(\\t)", "%s")
}

func (f *Flux) Word() (*Flux) {
	return raw(f, "(\\w+)", "%s")
}

func (f *Flux) Letters() (*Flux) {
	return raw(f, "([a-zA-Z]+)", "%s")
}

func (f *Flux) Digits() (*Flux) {
	return raw(f, "(\\d+)", "%s")
}

// experimental...
// This is bound to change
func (f *Flux) OrTry() (*Flux) {
	addPrefix(f, "(")
	addSuffix(f, ")")
	return raw(f, "", ")|(%s")
}

// Creates a range character class
// You can create a-z0-9 by calling Flux.range("a", "z", "0", "9")
func (f *Flux) Range(values ...string) (*Flux) {
	// validate pramas
	if len(values) % 2 != 0 {
		return f
	}

	ranges := []string{}
	for i := 1; i < len(values); i += 2 {
			ranges = append(ranges, fmt.Sprintf("%s-%s", values[i - 1], values[i]))
	}
	return raw(f, strings.Join(ranges, ""), "([%s])")
}

// creates a new Flux instance
func NewFlux() *Flux {
	newFlux := Flux{}
	return &newFlux
}

//--------------------------------------------------------------------------------
// HELPER FUNCTIONS
//--------------------------------------------------------------------------------

func add(f *Flux, value, format string) (*Flux) {
	f.pattern = append(f.pattern, fmt.Sprintf(format, regexp.QuoteMeta(value)))
	return resetCachedRegex(f)
}

func raw(f *Flux, value, format string) (*Flux) {
	f.pattern = append(f.pattern, fmt.Sprintf(format, value))
	return resetCachedRegex(f)
}

func addPrefix(f *Flux, prefix string) (*Flux) {
	if !stringInSlice(prefix, f.prefixes) {
		f.prefixes = append(f.prefixes, strings.TrimSpace(prefix))
	}
	return resetCachedRegex(f)
}

func addSuffix(f *Flux, suffix string) (*Flux) {
	if !stringInSlice(suffix, f.suffixes) {
		f.suffixes = append(f.suffixes, strings.TrimSpace(suffix))
	}
	return resetCachedRegex(f)
}

func addModifier(f *Flux, modifier string) (*Flux) {
	if !stringInSlice(modifier, f.modifiers) {
		f.modifiers = append(f.modifiers, strings.TrimSpace(modifier))
	}
	return resetCachedRegex(f)
}

func removeModifier(f *Flux, modifier string) (*Flux) {
	for i, mod := range f.modifiers {
		if mod == modifier {
			f.modifiers = append(f.modifiers[:i], f.modifiers[i+1:]...)
		}
	}
	return resetCachedRegex(f)
}

func getLastSegmentKey(f *Flux) (int) {
	return len(f.pattern) - 1
}

func replaceQuantifierByKey(f *Flux, key int, replacement string) (*Flux) {
	subject := f.pattern[key]
	replacementPattern := "%s%s"

	if strings.LastIndex(subject, ")") != -1 {
		subject = strings.TrimRight(subject, ")")
		replacementPattern += ")"
	}

	subject = removeQuantifier(f, subject)
	f.pattern[key] = fmt.Sprintf(replacementPattern, subject, replacement);
	return resetCachedRegex(f)

}

func removeQuantifier(f *Flux, pattern string) string {
	if strings.LastIndex(pattern, "+") != -1 && strings.LastIndex(pattern, "\\+") == -1 {
		return strings.TrimRight(pattern, "+")
	} else if strings.LastIndex(pattern, "*") != -1 && strings.LastIndex(pattern, "\\*") == -1 {
		return strings.TrimRight(pattern, "*")
	} else if strings.LastIndex(pattern, "?") != -1 && strings.LastIndex(pattern, "\\?") == -1 {
		return strings.TrimRight(pattern, "?")
	}
	return pattern
}

// checks if the given string is in the given slice
func stringInSlice(a string, list []string) bool {
	for _, b := range list {
		if b == a {
			return true
		}
	}
	return false
}

func resetCachedRegex(f *Flux) *Flux {
	f.regex = nil
	return f
}
<|endoftext|>


<commit_before>package cluster

import (
	"errors"
	"sync"
	"time"

	"github.com/flynn/flynn-host/types"
	"github.com/flynn/go-discoverd"
	"github.com/flynn/go-flynn/attempt"
	"github.com/flynn/rpcplus"
)

// ErrNoServers is returned if no host servers are found
var ErrNoServers = errors.New("cluster: no servers found")

// Attempts is the attempt strategy that is used to connect to the leader.
// It must not be modified after the first call to NewClient.
var Attempts = attempt.Strategy{
	Min:   5,
	Total: 5 * time.Second,
	Delay: 200 * time.Millisecond,
}

func NewClient() (*Client, error) {
	return NewClientWithDial(nil, nil)
}

func NewClientWithDial(dial rpcplus.DialFunc, services func(name string) (discoverd.ServiceSet, error)) (*Client, error) {
	if services == nil {
		services = discoverd.NewServiceSet
	}
	ss, err := services("flynn-host")
	if err != nil {
		return nil, err
	}
	client := &Client{dial: dial, service: ss}
	firstErr := make(chan error)
	go client.followLeader(firstErr)
	return client, <-firstErr
}

func (c *Client) followLeader(firstErr chan<- error) {
	for update := range c.service.Leaders() {
		if update == nil {
			if firstErr != nil {
				firstErr <- ErrNoServers
				c.Close()
				return
			}
			continue
		}
		c.mtx.Lock()
		if c.c != nil {
			c.c.Close()
		}
		c.leaderID = update.Attrs["id"]
		c.err = Attempts.Run(func() (err error) {
			c.c, err = rpcplus.DialHTTPPath("tcp", update.Addr, rpcplus.DefaultRPCPath, c.dial)
			return
		})
		c.mtx.Unlock()
		if firstErr != nil {
			firstErr <- c.err
			if c.err != nil {
				c.Close()
				return
			}
			firstErr = nil
		}
	}
	// TODO: reconnect to discoverd here
}

type Client struct {
	service  discoverd.ServiceSet
	leaderID string

	dial rpcplus.DialFunc
	c    RPCClient
	mtx  sync.RWMutex
	err  error
}

func (c *Client) Close() error {
	c.mtx.Lock()
	defer c.mtx.Unlock()
	if c.c != nil {
		c.c.Close()
	}
	return c.service.Close()
}

func (c *Client) LeaderID() string {
	c.mtx.RLock()
	defer c.mtx.RUnlock()
	return c.leaderID
}

func (c *Client) ListHosts() (map[string]host.Host, error) {
	c.mtx.RLock()
	if err := c.err; err != nil {
		c.mtx.RUnlock()
		return nil, err
	}
	client := c.c
	c.mtx.RUnlock()

	var state map[string]host.Host
	err := client.Call("Cluster.ListHosts", struct{}{}, &state)
	return state, err
}

func (c *Client) AddJobs(req *host.AddJobsReq) (*host.AddJobsRes, error) {
	c.mtx.RLock()
	if err := c.err; err != nil {
		c.mtx.RUnlock()
		return nil, err
	}
	client := c.c
	c.mtx.RUnlock()

	var res host.AddJobsRes
	err := client.Call("Cluster.AddJobs", req, &res)
	return &res, err
}

func (c *Client) ConnectHost(id string) (Host, error) {
	// TODO: reuse connection if leader id == id
	services := c.service.Select(map[string]string{"id": id})
	if len(services) == 0 {
		return nil, ErrNoServers
	}
	rc, err := rpcplus.DialHTTPPath("tcp", services[0].Addr, rpcplus.DefaultRPCPath, c.dial)
	return newHostClient(c.service, rc, c.dial), err
}

func (c *Client) RPCClient() (RPCClient, error) {
	c.mtx.RLock()
	defer c.mtx.RUnlock()
	return c.c, c.err
}

type RPCClient interface {
	Call(serviceMethod string, args interface{}, reply interface{}) error
	Go(serviceMethod string, args interface{}, reply interface{}, done chan *rpcplus.Call) *rpcplus.Call
	StreamGo(serviceMethod string, args interface{}, replyStream interface{}) *rpcplus.Call
	Close() error
}
<commit_msg>cluster: Rename ConnectHost to DialHost<commit_after>package cluster

import (
	"errors"
	"sync"
	"time"

	"github.com/flynn/flynn-host/types"
	"github.com/flynn/go-discoverd"
	"github.com/flynn/go-flynn/attempt"
	"github.com/flynn/rpcplus"
)

// ErrNoServers is returned if no host servers are found
var ErrNoServers = errors.New("cluster: no servers found")

// Attempts is the attempt strategy that is used to connect to the leader.
// It must not be modified after the first call to NewClient.
var Attempts = attempt.Strategy{
	Min:   5,
	Total: 5 * time.Second,
	Delay: 200 * time.Millisecond,
}

func NewClient() (*Client, error) {
	return NewClientWithDial(nil, nil)
}

func NewClientWithDial(dial rpcplus.DialFunc, services func(name string) (discoverd.ServiceSet, error)) (*Client, error) {
	if services == nil {
		services = discoverd.NewServiceSet
	}
	ss, err := services("flynn-host")
	if err != nil {
		return nil, err
	}
	client := &Client{dial: dial, service: ss}
	firstErr := make(chan error)
	go client.followLeader(firstErr)
	return client, <-firstErr
}

func (c *Client) followLeader(firstErr chan<- error) {
	for update := range c.service.Leaders() {
		if update == nil {
			if firstErr != nil {
				firstErr <- ErrNoServers
				c.Close()
				return
			}
			continue
		}
		c.mtx.Lock()
		if c.c != nil {
			c.c.Close()
		}
		c.leaderID = update.Attrs["id"]
		c.err = Attempts.Run(func() (err error) {
			c.c, err = rpcplus.DialHTTPPath("tcp", update.Addr, rpcplus.DefaultRPCPath, c.dial)
			return
		})
		c.mtx.Unlock()
		if firstErr != nil {
			firstErr <- c.err
			if c.err != nil {
				c.Close()
				return
			}
			firstErr = nil
		}
	}
	// TODO: reconnect to discoverd here
}

type Client struct {
	service  discoverd.ServiceSet
	leaderID string

	dial rpcplus.DialFunc
	c    RPCClient
	mtx  sync.RWMutex
	err  error
}

func (c *Client) Close() error {
	c.mtx.Lock()
	defer c.mtx.Unlock()
	if c.c != nil {
		c.c.Close()
	}
	return c.service.Close()
}

func (c *Client) LeaderID() string {
	c.mtx.RLock()
	defer c.mtx.RUnlock()
	return c.leaderID
}

func (c *Client) ListHosts() (map[string]host.Host, error) {
	c.mtx.RLock()
	if err := c.err; err != nil {
		c.mtx.RUnlock()
		return nil, err
	}
	client := c.c
	c.mtx.RUnlock()

	var state map[string]host.Host
	err := client.Call("Cluster.ListHosts", struct{}{}, &state)
	return state, err
}

func (c *Client) AddJobs(req *host.AddJobsReq) (*host.AddJobsRes, error) {
	c.mtx.RLock()
	if err := c.err; err != nil {
		c.mtx.RUnlock()
		return nil, err
	}
	client := c.c
	c.mtx.RUnlock()

	var res host.AddJobsRes
	err := client.Call("Cluster.AddJobs", req, &res)
	return &res, err
}

func (c *Client) DialHost(id string) (Host, error) {
	// TODO: reuse connection if leader id == id
	services := c.service.Select(map[string]string{"id": id})
	if len(services) == 0 {
		return nil, ErrNoServers
	}
	rc, err := rpcplus.DialHTTPPath("tcp", services[0].Addr, rpcplus.DefaultRPCPath, c.dial)
	return newHostClient(c.service, rc, c.dial), err
}

func (c *Client) RPCClient() (RPCClient, error) {
	c.mtx.RLock()
	defer c.mtx.RUnlock()
	return c.c, c.err
}

type RPCClient interface {
	Call(serviceMethod string, args interface{}, reply interface{}) error
	Go(serviceMethod string, args interface{}, reply interface{}, done chan *rpcplus.Call) *rpcplus.Call
	StreamGo(serviceMethod string, args interface{}, replyStream interface{}) *rpcplus.Call
	Close() error
}
<|endoftext|>


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

package cmac_test

import (
	"encoding/hex"
	"github.com/jacobsa/aes/cmac"
	aes_testing "github.com/jacobsa/aes/testing"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestHash(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func runCmac(key []byte, msg []byte) []byte {
	h, err := cmac.New(key)
	AssertEq(nil, err)

	_, err = h.Write(msg)
	AssertEq(nil, err)

	return h.Sum([]byte{})
}

type HashTest struct{}

func init() { RegisterTestSuite(&HashTest{}) }

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *HashTest) NilKey() {
	_, err := cmac.New(nil)
	ExpectThat(err, Error(HasSubstr("16-")))
	ExpectThat(err, Error(HasSubstr("24-")))
	ExpectThat(err, Error(HasSubstr("32-")))
}

func (t *HashTest) ShortKey() {
	_, err := cmac.New(make([]byte, 15))
	ExpectThat(err, Error(HasSubstr("16-")))
	ExpectThat(err, Error(HasSubstr("24-")))
	ExpectThat(err, Error(HasSubstr("32-")))
}

func (t *HashTest) LongKey() {
	_, err := cmac.New(make([]byte, 33))
	ExpectThat(err, Error(HasSubstr("16-")))
	ExpectThat(err, Error(HasSubstr("24-")))
	ExpectThat(err, Error(HasSubstr("32-")))
}

func (t *HashTest) SumAppendsToSlice() {
	// Grab a test case.
	cases := aes_testing.CmacCases()
	AssertGt(len(cases), 10)
	c := cases[10]

	// Create a hash and feed it the test case's data.
	h, err := cmac.New(c.Key)
	AssertEq(nil, err)

	_, err = h.Write(c.Msg)
	AssertEq(nil, err)

	// Ask it to append to a non-empty slice.
	prefix := []byte{0xde, 0xad, 0xbe, 0xef}
	mac := h.Sum(prefix)

	AssertEq(20, len(mac))
	ExpectThat(mac[0:4], DeepEquals(prefix))
	ExpectThat(mac[4:], DeepEquals(c.Mac))
}

func (t *HashTest) SumDoesntAffectState() {
	// Grab a test case.
	cases := aes_testing.CmacCases()
	AssertGt(len(cases), 10)
	c := cases[10]

	// Create a hash and feed it some of the test case's data.
	h, err := cmac.New(c.Key)
	AssertEq(nil, err)

	AssertGt(len(c.Msg), 5)
	_, err = h.Write(c.Msg[0:5])
	AssertEq(nil, err)

	// Call Sum.
	AssertEq(16, len(h.Sum([]byte{})))

	// Feed the rest of the data and call Sum again. We should get the correct
	// result.
	_, err = h.Write(c.Msg[5:])
	AssertEq(nil, err)

	ExpectThat(h.Sum([]byte{}), DeepEquals(c.Mac))

	// Calling repeatedly should also work.
	ExpectThat(h.Sum([]byte{}), DeepEquals(c.Mac))
	ExpectThat(h.Sum([]byte{}), DeepEquals(c.Mac))
	ExpectThat(h.Sum([]byte{}), DeepEquals(c.Mac))
}

func (t *HashTest) Reset() {
	// Grab a test case.
	cases := aes_testing.CmacCases()
	AssertGt(len(cases), 10)
	c := cases[10]

	// Create a hash and feed it some data, then reset it.
	h, err := cmac.New(c.Key)
	AssertEq(nil, err)

	_, err = h.Write([]byte{0xde, 0xad})
	AssertEq(nil, err)

	h.Reset()

	// Feed the hash the test case's data and make sure the result is correct.
	_, err = h.Write(c.Msg)
	AssertEq(nil, err)

	ExpectThat(h.Sum([]byte{}), DeepEquals(c.Mac))
}

func (t *HashTest) Size() {
	h, err := cmac.New(make([]byte, 16))
	AssertEq(nil, err)
	ExpectEq(16, h.Size())
}

func (t *HashTest) BlockSize() {
	h, err := cmac.New(make([]byte, 16))
	AssertEq(nil, err)
	ExpectEq(16, h.BlockSize())
}

func (t *HashTest) NilMessage() {
	key := aes_testing.FromRfcHex("2b7e1516 28aed2a6 abf71588 09cf4f3c")

	var msg []byte = nil

	expectedMac, err := hex.DecodeString("bb1d6929e95937287fa37d129b756746")
	AssertEq(nil, err)

	mac := runCmac(key, msg)
	ExpectThat(mac, DeepEquals(expectedMac))
}

func (t *HashTest) Rfc4493GoldenTestCase1() {
	key := aes_testing.FromRfcHex("2b7e1516 28aed2a6 abf71588 09cf4f3c")

	msg, err := hex.DecodeString("")
	AssertEq(nil, err)

	expectedMac, err := hex.DecodeString("bb1d6929e95937287fa37d129b756746")
	AssertEq(nil, err)

	mac := runCmac(key, msg)
	ExpectThat(mac, DeepEquals(expectedMac))
}

func (t *HashTest) Rfc4493GoldenTestCase2() {
	key := aes_testing.FromRfcHex("2b7e1516 28aed2a6 abf71588 09cf4f3c")

	msg, err := hex.DecodeString("6bc1bee22e409f96e93d7e117393172a")
	AssertEq(nil, err)

	expectedMac, err := hex.DecodeString("070a16b46b4d4144f79bdd9dd04a287c")
	AssertEq(nil, err)

	mac := runCmac(key, msg)
	ExpectThat(mac, DeepEquals(expectedMac))
}

func (t *HashTest) Rfc4493GoldenTestCase3() {
	key := aes_testing.FromRfcHex("2b7e1516 28aed2a6 abf71588 09cf4f3c")

	msg, err := hex.DecodeString(
		"6bc1bee22e409f96e93d7e117393172a" +
			"ae2d8a571e03ac9c9eb76fac45af8e51" +
			"30c81c46a35ce411")
	AssertEq(nil, err)

	expectedMac, err := hex.DecodeString("dfa66747de9ae63030ca32611497c827")
	AssertEq(nil, err)

	mac := runCmac(key, msg)
	ExpectThat(mac, DeepEquals(expectedMac))
}

func (t *HashTest) Rfc4493GoldenTestCase4() {
	key := aes_testing.FromRfcHex("2b7e1516 28aed2a6 abf71588 09cf4f3c")

	msg, err := hex.DecodeString(
		"6bc1bee22e409f96e93d7e117393172a" +
			"ae2d8a571e03ac9c9eb76fac45af8e51" +
			"30c81c46a35ce411e5fbc1191a0a52ef" +
			"f69f2445df4f9b17ad2b417be66c3710")
	AssertEq(nil, err)

	expectedMac, err := hex.DecodeString("51f0bebf7e3b9d92fc49741779363cfe")
	AssertEq(nil, err)

	mac := runCmac(key, msg)
	ExpectThat(mac, DeepEquals(expectedMac))
}

func (t *HashTest) GeneratedTestCases() {
	cases := aes_testing.CmacCases()
	AssertGe(len(cases), 100)

	for i, c := range cases {
		mac := runCmac(c.Key, c.Msg)
		ExpectThat(mac, DeepEquals(c.Mac), "Test case %d: %v", i, c)
	}
}
<commit_msg>Switched to FromRfcHex elsewhere.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmac_test

import (
	"encoding/hex"
	"github.com/jacobsa/aes/cmac"
	aes_testing "github.com/jacobsa/aes/testing"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestHash(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func runCmac(key []byte, msg []byte) []byte {
	h, err := cmac.New(key)
	AssertEq(nil, err)

	_, err = h.Write(msg)
	AssertEq(nil, err)

	return h.Sum([]byte{})
}

type HashTest struct{}

func init() { RegisterTestSuite(&HashTest{}) }

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *HashTest) NilKey() {
	_, err := cmac.New(nil)
	ExpectThat(err, Error(HasSubstr("16-")))
	ExpectThat(err, Error(HasSubstr("24-")))
	ExpectThat(err, Error(HasSubstr("32-")))
}

func (t *HashTest) ShortKey() {
	_, err := cmac.New(make([]byte, 15))
	ExpectThat(err, Error(HasSubstr("16-")))
	ExpectThat(err, Error(HasSubstr("24-")))
	ExpectThat(err, Error(HasSubstr("32-")))
}

func (t *HashTest) LongKey() {
	_, err := cmac.New(make([]byte, 33))
	ExpectThat(err, Error(HasSubstr("16-")))
	ExpectThat(err, Error(HasSubstr("24-")))
	ExpectThat(err, Error(HasSubstr("32-")))
}

func (t *HashTest) SumAppendsToSlice() {
	// Grab a test case.
	cases := aes_testing.CmacCases()
	AssertGt(len(cases), 10)
	c := cases[10]

	// Create a hash and feed it the test case's data.
	h, err := cmac.New(c.Key)
	AssertEq(nil, err)

	_, err = h.Write(c.Msg)
	AssertEq(nil, err)

	// Ask it to append to a non-empty slice.
	prefix := []byte{0xde, 0xad, 0xbe, 0xef}
	mac := h.Sum(prefix)

	AssertEq(20, len(mac))
	ExpectThat(mac[0:4], DeepEquals(prefix))
	ExpectThat(mac[4:], DeepEquals(c.Mac))
}

func (t *HashTest) SumDoesntAffectState() {
	// Grab a test case.
	cases := aes_testing.CmacCases()
	AssertGt(len(cases), 10)
	c := cases[10]

	// Create a hash and feed it some of the test case's data.
	h, err := cmac.New(c.Key)
	AssertEq(nil, err)

	AssertGt(len(c.Msg), 5)
	_, err = h.Write(c.Msg[0:5])
	AssertEq(nil, err)

	// Call Sum.
	AssertEq(16, len(h.Sum([]byte{})))

	// Feed the rest of the data and call Sum again. We should get the correct
	// result.
	_, err = h.Write(c.Msg[5:])
	AssertEq(nil, err)

	ExpectThat(h.Sum([]byte{}), DeepEquals(c.Mac))

	// Calling repeatedly should also work.
	ExpectThat(h.Sum([]byte{}), DeepEquals(c.Mac))
	ExpectThat(h.Sum([]byte{}), DeepEquals(c.Mac))
	ExpectThat(h.Sum([]byte{}), DeepEquals(c.Mac))
}

func (t *HashTest) Reset() {
	// Grab a test case.
	cases := aes_testing.CmacCases()
	AssertGt(len(cases), 10)
	c := cases[10]

	// Create a hash and feed it some data, then reset it.
	h, err := cmac.New(c.Key)
	AssertEq(nil, err)

	_, err = h.Write([]byte{0xde, 0xad})
	AssertEq(nil, err)

	h.Reset()

	// Feed the hash the test case's data and make sure the result is correct.
	_, err = h.Write(c.Msg)
	AssertEq(nil, err)

	ExpectThat(h.Sum([]byte{}), DeepEquals(c.Mac))
}

func (t *HashTest) Size() {
	h, err := cmac.New(make([]byte, 16))
	AssertEq(nil, err)
	ExpectEq(16, h.Size())
}

func (t *HashTest) BlockSize() {
	h, err := cmac.New(make([]byte, 16))
	AssertEq(nil, err)
	ExpectEq(16, h.BlockSize())
}

func (t *HashTest) NilMessage() {
	key := aes_testing.FromRfcHex("2b7e1516 28aed2a6 abf71588 09cf4f3c")

	var msg []byte = nil

	expectedMac, err := hex.DecodeString("bb1d6929e95937287fa37d129b756746")
	AssertEq(nil, err)

	mac := runCmac(key, msg)
	ExpectThat(mac, DeepEquals(expectedMac))
}

func (t *HashTest) Rfc4493GoldenTestCase1() {
	key := aes_testing.FromRfcHex("2b7e1516 28aed2a6 abf71588 09cf4f3c")
	msg := aes_testing.FromRfcHex("")
	expectedMac := aes_testing.FromRfcHex("bb1d6929 e9593728 7fa37d12 9b756746")

	mac := runCmac(key, msg)
	ExpectThat(mac, DeepEquals(expectedMac))
}

func (t *HashTest) Rfc4493GoldenTestCase2() {
	key := aes_testing.FromRfcHex("2b7e1516 28aed2a6 abf71588 09cf4f3c")
	msg := aes_testing.FromRfcHex("6bc1bee2 2e409f96 e93d7e11 7393172a")
	expectedMac := aes_testing.FromRfcHex("070a16b4 6b4d4144 f79bdd9d d04a287c")

	mac := runCmac(key, msg)
	ExpectThat(mac, DeepEquals(expectedMac))
}

func (t *HashTest) Rfc4493GoldenTestCase3() {
	key := aes_testing.FromRfcHex("2b7e1516 28aed2a6 abf71588 09cf4f3c")

	msg := aes_testing.FromRfcHex(
		"6bc1bee2 2e409f96 e93d7e11 7393172a" +
		"ae2d8a57 1e03ac9c 9eb76fac 45af8e51" +
		"30c81c46 a35ce411")

	expectedMac := aes_testing.FromRfcHex("dfa66747 de9ae630 30ca3261 1497c827")

	mac := runCmac(key, msg)
	ExpectThat(mac, DeepEquals(expectedMac))
}

func (t *HashTest) Rfc4493GoldenTestCase4() {
	key := aes_testing.FromRfcHex("2b7e1516 28aed2a6 abf71588 09cf4f3c")

	msg := aes_testing.FromRfcHex(
		"6bc1bee2 2e409f96 e93d7e11 7393172a" +
		"ae2d8a57 1e03ac9c 9eb76fac 45af8e51" +
		"30c81c46 a35ce411 e5fbc119 1a0a52ef" +
		"f69f2445 df4f9b17 ad2b417b e66c3710")

	expectedMac := aes_testing.FromRfcHex("51f0bebf 7e3b9d92 fc497417 79363cfe")

	mac := runCmac(key, msg)
	ExpectThat(mac, DeepEquals(expectedMac))
}

func (t *HashTest) GeneratedTestCases() {
	cases := aes_testing.CmacCases()
	AssertGe(len(cases), 100)

	for i, c := range cases {
		mac := runCmac(c.Key, c.Msg)
		ExpectThat(mac, DeepEquals(c.Mac), "Test case %d: %v", i, c)
	}
}
<|endoftext|>


<commit_before>/*
This package is just a collection of test cases
*/
package main

import (
	"fmt"
	"github.com/codegangsta/cli"
	"os"
	"ripe-atlas"
	"strconv"
)

// main is the starting point (and everything)
func main() {
	app := cli.NewApp()
	app.Name = "atlas"
	app.Commands = []cli.Command{
		{
			Name: "probes",
			Aliases: []string{
				"p",
				"pb",
			},
			Usage:       "use it to see a description",
			Description: "This is how we describe hello the function",
			Subcommands: []cli.Command{
				{
					Name:        "list",
					Aliases:     []string{"ls"},
					Usage:       "lists all probes",
					Description: "greets someone in english",
					Action: func(c *cli.Context) error {
						q, err := atlas.GetProbes()
						if err != nil {
							fmt.Printf("err: %v", err)
							os.Exit(1)
						}
						fmt.Printf("q: %#v\n", q)

						return nil
					},
				},
				{
					Name:        "info",
					Usage:       "info for one probe",
					Description: "gives info for one probe",
					Flags: []cli.Flag{
						cli.IntFlag{
							Name:  "id",
							Value: 0,
							Usage: "id of the probe",
						},
					},
					Action: func(c *cli.Context) error {
						args := c.Args()
						id, _ := strconv.ParseInt(args[0], 10, 32)

						p, err := atlas.GetProbe(int(id))
						if err != nil {
							fmt.Printf("err: %v", err)
							os.Exit(1)
						}
						fmt.Printf("p: %#v\n", p)

						return nil
					},
				},
			},
		},
	}
	app.Run(os.Args)

}
<commit_msg>Add an "ip" command as shortcut.<commit_after>/*
This package is just a collection of test cases
*/
package main

import (
	"fmt"
	"github.com/codegangsta/cli"
	"os"
	"ripe-atlas"
	"strconv"
)

// main is the starting point (and everything)
func main() {
	app := cli.NewApp()
	app.Name = "atlas"
	app.Commands = []cli.Command{
		{
			Name: "probes",
			Aliases: []string{
				"p",
				"pb",
			},
			Usage:       "use it to see a description",
			Description: "This is how we describe hello the function",
			Subcommands: []cli.Command{
				{
					Name:        "list",
					Aliases:     []string{"ls"},
					Usage:       "lists all probes",
					Description: "greets someone in english",
					Action: func(c *cli.Context) error {
						q, err := atlas.GetProbes()
						if err != nil {
							fmt.Printf("err: %v", err)
							os.Exit(1)
						}
						fmt.Printf("q: %#v\n", q)

						return nil
					},
				},
				{
					Name:        "info",
					Usage:       "info for one probe",
					Description: "gives info for one probe",
					Flags: []cli.Flag{
						cli.IntFlag{
							Name:  "id",
							Value: 0,
							Usage: "id of the probe",
						},
					},
					Action: func(c *cli.Context) error {
						args := c.Args()
						id, _ := strconv.ParseInt(args[0], 10, 32)

						p, err := atlas.GetProbe(int(id))
						if err != nil {
							fmt.Printf("err: %v", err)
							os.Exit(1)
						}
						fmt.Printf("p: %#v\n", p)

						return nil
					},
				},
			},
		},
		{
			Name:        "ip",
			Usage:       "returns current ip",
			Description: "shorthand for getting current ip",
			Action: func(c *cli.Context) error {
				args := c.Args()
				id, _ := strconv.ParseInt(args[0], 10, 32)

				p, err := atlas.GetProbe(int(id))
				if err != nil {
					fmt.Printf("err: %v", err)
					os.Exit(1)
				}
				fmt.Printf("IPv4: %v - IPv6: %v", p.AddressV4, p.AddressV6)
				return nil
			},
		},

	}
	app.Run(os.Args)

}
<|endoftext|>


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

package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/build"
	"log"
	"path/filepath"
	"strings"

	"github.com/golang/dep"
	"github.com/golang/dep/internal/fs"
	"github.com/golang/dep/internal/gps"
	"github.com/golang/dep/internal/gps/pkgtree"
	"github.com/pkg/errors"
)

const ensureShortHelp = `Ensure a dependency is safely vendored in the project`
const ensureLongHelp = `
Ensure is used to fetch project dependencies into the vendor folder, as well as
to set version constraints for specific dependencies. It takes user input,
solves the updated dependency graph of the project, writes any changes to the
lock file, and places dependencies in the vendor folder.

Package spec:

  <path>[:alt location][@<version specifier>]

Examples:

  dep ensure                            Populate vendor from existing manifest and lock
  dep ensure github.com/pkg/foo@^1.0.1  Update a specific dependency to a specific version

For more detailed usage examples, see dep ensure -examples.
`
const ensureExamples = `
dep ensure

    Solve the project's dependency graph, and place all dependencies in the
    vendor folder. If a dependency is in the lock file, use the version
    specified there. Otherwise, use the most recent version that can satisfy the
    constraints in the manifest file.

dep ensure -update

    Update all dependencies to the latest versions allowed by the manifest,
    ignoring any versions specified in the lock file. Update the lock file with
    any changes.

dep ensure -update github.com/pkg/foo github.com/pkg/bar

    Update a list of dependencies to the latest versions allowed by the manifest,
    ignoring any versions specified in the lock file. Update the lock file with
    any changes.

dep ensure github.com/pkg/foo@^1.0.1

    Constrain pkg/foo to the latest release matching >= 1.0.1, < 2.0.0, and
    place that release in the vendor folder. If a constraint was previously set
    in the manifest, this resets it. This form of constraint strikes a good
    balance of safety and flexibility, and should be preferred for libraries.

dep ensure github.com/pkg/foo@~1.0.1

    Same as above, but choose any release matching 1.0.x, preferring latest.

dep ensure github.com/pkg/foo:git.internal.com/alt/foo

    Fetch the dependency from a different location.

dep ensure -override github.com/pkg/foo@^1.0.1

    Forcefully and transitively override any constraint for this dependency.
    Overrides are powerful, but harmful in the long term. They should be used as
    a last resort, especially if your project may be imported by others.
`

func (cmd *ensureCommand) Name() string      { return "ensure" }
func (cmd *ensureCommand) Args() string      { return "[spec...]" }
func (cmd *ensureCommand) ShortHelp() string { return ensureShortHelp }
func (cmd *ensureCommand) LongHelp() string  { return ensureLongHelp }
func (cmd *ensureCommand) Hidden() bool      { return false }

func (cmd *ensureCommand) Register(fs *flag.FlagSet) {
	fs.BoolVar(&cmd.examples, "examples", false, "print detailed usage examples")
	fs.BoolVar(&cmd.update, "update", false, "ensure dependencies are at the latest version allowed by the manifest")
	fs.BoolVar(&cmd.dryRun, "n", false, "dry run, don't actually ensure anything")
	fs.Var(&cmd.overrides, "override", "specify an override constraint spec (repeatable)")
}

type ensureCommand struct {
	examples  bool
	update    bool
	dryRun    bool
	overrides stringSlice
}

func (cmd *ensureCommand) Run(ctx *dep.Ctx, args []string) error {
	if cmd.examples {
		ctx.Err.Println(strings.TrimSpace(ensureExamples))
		return nil
	}

	p, err := ctx.LoadProject()
	if err != nil {
		return err
	}

	sm, err := ctx.SourceManager()
	if err != nil {
		return err
	}
	sm.UseDefaultSignalHandling()
	defer sm.Release()

	params := p.MakeParams()
	if ctx.Verbose {
		params.TraceLogger = ctx.Err
	}

	params.RootPackageTree, err = pkgtree.ListPackages(p.ResolvedAbsRoot, string(p.ImportRoot))
	if err != nil {
		return errors.Wrap(err, "ensure ListPackage for project")
	}

	if err := checkErrors(params.RootPackageTree.Packages); err != nil {
		return err
	}

	if cmd.update {
		applyUpdateArgs(args, &params)
	} else {
		err := applyEnsureArgs(ctx.Err, args, cmd.overrides, p, sm, &params)
		if err != nil {
			return err
		}
	}

	solver, err := gps.Prepare(params, sm)
	if err != nil {
		return errors.Wrap(err, "ensure Prepare")
	}
	solution, err := solver.Solve()
	if err != nil {
		handleAllTheFailuresOfTheWorld(err)
		return errors.Wrap(err, "ensure Solve()")
	}

	// check if vendor exists, because if the locks are the same but
	// vendor does not exist we should write vendor
	vendorExists, err := fs.IsNonEmptyDir(filepath.Join(p.AbsRoot, "vendor"))
	if err != nil {
		return errors.Wrap(err, "ensure vendor is a directory")
	}
	writeV := dep.VendorOnChanged
	if !vendorExists && solution != nil {
		writeV = dep.VendorAlways
	}

	newLock := dep.LockFromSolution(solution)
	sw, err := dep.NewSafeWriter(nil, p.Lock, newLock, writeV)
	if err != nil {
		return err
	}
	if cmd.dryRun {
		return sw.PrintPreparedActions(ctx.Out)
	}

	return errors.Wrap(sw.Write(p.AbsRoot, sm, false), "grouped write of manifest, lock and vendor")
}

func applyUpdateArgs(args []string, params *gps.SolveParameters) {
	// When -update is specified without args, allow every project to change versions, regardless of the lock file
	if len(args) == 0 {
		params.ChangeAll = true
		return
	}

	// Allow any of specified project versions to change, regardless of the lock file
	for _, arg := range args {
		params.ToChange = append(params.ToChange, gps.ProjectRoot(arg))
	}
}

func applyEnsureArgs(logger *log.Logger, args []string, overrides stringSlice, p *dep.Project, sm gps.SourceManager, params *gps.SolveParameters) error {
	var errs []error
	for _, arg := range args {
		pc, err := getProjectConstraint(arg, sm)
		if err != nil {
			errs = append(errs, err)
			continue
		}

		if gps.IsAny(pc.Constraint) && pc.Ident.Source == "" {
			// If the input specified neither a network name nor a constraint,
			// then the strict thing to do would be to remove the entry
			// entirely. But that would probably be quite surprising for users,
			// and it's what rm is for, so just ignore the input.
			//
			// TODO(sdboyer): for this case - or just in general - do we want to
			// add project args to the requires list temporarily for this run?
			if _, has := p.Manifest.Constraints[pc.Ident.ProjectRoot]; !has {
				logger.Printf("dep: No constraint or alternate source specified for %q, omitting from manifest\n", pc.Ident.ProjectRoot)
			}
			// If it's already in the manifest, no need to log
			continue
		}

		p.Manifest.Constraints[pc.Ident.ProjectRoot] = gps.ProjectProperties{
			Source:     pc.Ident.Source,
			Constraint: pc.Constraint,
		}
	}

	for _, ovr := range overrides {
		pc, err := getProjectConstraint(ovr, sm)
		if err != nil {
			errs = append(errs, err)
			continue
		}

		// Empty overrides are fine (in contrast to deps), because they actually
		// carry meaning - they force the constraints entirely open for a given
		// project. Inadvisable, but meaningful.

		p.Manifest.Ovr[pc.Ident.ProjectRoot] = gps.ProjectProperties{
			Source:     pc.Ident.Source,
			Constraint: pc.Constraint,
		}
	}

	if len(errs) > 0 {
		var buf bytes.Buffer
		for _, err := range errs {
			fmt.Fprintln(&buf, err)
		}

		return errors.New(buf.String())
	}

	return nil
}

type stringSlice []string

func (s *stringSlice) String() string {
	if len(*s) == 0 {
		return "<none>"
	}
	return strings.Join(*s, ", ")
}

func (s *stringSlice) Set(value string) error {
	*s = append(*s, value)
	return nil
}

func getProjectConstraint(arg string, sm gps.SourceManager) (gps.ProjectConstraint, error) {
	emptyPC := gps.ProjectConstraint{
		Constraint: gps.Any(), // default to any; avoids panics later
	}

	// try to split on '@'
	// When there is no `@`, use any version
	versionStr := "*"
	atIndex := strings.Index(arg, "@")
	if atIndex > 0 {
		parts := strings.SplitN(arg, "@", 2)
		arg = parts[0]
		versionStr = parts[1]
	}

	// TODO: if we decide to keep equals.....

	// split on colon if there is a network location
	var source string
	colonIndex := strings.Index(arg, ":")
	if colonIndex > 0 {
		parts := strings.SplitN(arg, ":", 2)
		arg = parts[0]
		source = parts[1]
	}

	pr, err := sm.DeduceProjectRoot(arg)
	if err != nil {
		return emptyPC, errors.Wrapf(err, "could not infer project root from dependency path: %s", arg) // this should go through to the user
	}

	if string(pr) != arg {
		return emptyPC, errors.Errorf("dependency path %s is not a project root, try %s instead", arg, pr)
	}

	pi := gps.ProjectIdentifier{ProjectRoot: pr, Source: source}
	c, err := sm.InferConstraint(versionStr, pi)
	if err != nil {
		return emptyPC, err
	}
	return gps.ProjectConstraint{Ident: pi, Constraint: c}, nil
}

func checkErrors(m map[string]pkgtree.PackageOrErr) error {
	buildErrors, noGoErrors := []string{}, []string{}
	for importPath, poe := range m {
		if poe.Err != nil {
			switch poe.Err.(type) {
			case *build.NoGoError:
				noGoErrors = append(noGoErrors, fmt.Sprintf("%s: no go code", importPath))
			default:
				buildErrors = append(buildErrors, poe.Err.Error())
			}
		}
	}

	buildErrors = append(buildErrors, noGoErrors...)

	if len(buildErrors) > 0 {
		return errors.Errorf("Found %d errors:\n\n%s", len(buildErrors), strings.Join(buildErrors, "\n"))
	}

	return nil
}
<commit_msg>Avoid unnecessary allocations in checkErrors<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/build"
	"log"
	"path/filepath"
	"strings"

	"github.com/golang/dep"
	"github.com/golang/dep/internal/fs"
	"github.com/golang/dep/internal/gps"
	"github.com/golang/dep/internal/gps/pkgtree"
	"github.com/pkg/errors"
)

const ensureShortHelp = `Ensure a dependency is safely vendored in the project`
const ensureLongHelp = `
Ensure is used to fetch project dependencies into the vendor folder, as well as
to set version constraints for specific dependencies. It takes user input,
solves the updated dependency graph of the project, writes any changes to the
lock file, and places dependencies in the vendor folder.

Package spec:

  <path>[:alt location][@<version specifier>]

Examples:

  dep ensure                            Populate vendor from existing manifest and lock
  dep ensure github.com/pkg/foo@^1.0.1  Update a specific dependency to a specific version

For more detailed usage examples, see dep ensure -examples.
`
const ensureExamples = `
dep ensure

    Solve the project's dependency graph, and place all dependencies in the
    vendor folder. If a dependency is in the lock file, use the version
    specified there. Otherwise, use the most recent version that can satisfy the
    constraints in the manifest file.

dep ensure -update

    Update all dependencies to the latest versions allowed by the manifest,
    ignoring any versions specified in the lock file. Update the lock file with
    any changes.

dep ensure -update github.com/pkg/foo github.com/pkg/bar

    Update a list of dependencies to the latest versions allowed by the manifest,
    ignoring any versions specified in the lock file. Update the lock file with
    any changes.

dep ensure github.com/pkg/foo@^1.0.1

    Constrain pkg/foo to the latest release matching >= 1.0.1, < 2.0.0, and
    place that release in the vendor folder. If a constraint was previously set
    in the manifest, this resets it. This form of constraint strikes a good
    balance of safety and flexibility, and should be preferred for libraries.

dep ensure github.com/pkg/foo@~1.0.1

    Same as above, but choose any release matching 1.0.x, preferring latest.

dep ensure github.com/pkg/foo:git.internal.com/alt/foo

    Fetch the dependency from a different location.

dep ensure -override github.com/pkg/foo@^1.0.1

    Forcefully and transitively override any constraint for this dependency.
    Overrides are powerful, but harmful in the long term. They should be used as
    a last resort, especially if your project may be imported by others.
`

func (cmd *ensureCommand) Name() string      { return "ensure" }
func (cmd *ensureCommand) Args() string      { return "[spec...]" }
func (cmd *ensureCommand) ShortHelp() string { return ensureShortHelp }
func (cmd *ensureCommand) LongHelp() string  { return ensureLongHelp }
func (cmd *ensureCommand) Hidden() bool      { return false }

func (cmd *ensureCommand) Register(fs *flag.FlagSet) {
	fs.BoolVar(&cmd.examples, "examples", false, "print detailed usage examples")
	fs.BoolVar(&cmd.update, "update", false, "ensure dependencies are at the latest version allowed by the manifest")
	fs.BoolVar(&cmd.dryRun, "n", false, "dry run, don't actually ensure anything")
	fs.Var(&cmd.overrides, "override", "specify an override constraint spec (repeatable)")
}

type ensureCommand struct {
	examples  bool
	update    bool
	dryRun    bool
	overrides stringSlice
}

func (cmd *ensureCommand) Run(ctx *dep.Ctx, args []string) error {
	if cmd.examples {
		ctx.Err.Println(strings.TrimSpace(ensureExamples))
		return nil
	}

	p, err := ctx.LoadProject()
	if err != nil {
		return err
	}

	sm, err := ctx.SourceManager()
	if err != nil {
		return err
	}
	sm.UseDefaultSignalHandling()
	defer sm.Release()

	params := p.MakeParams()
	if ctx.Verbose {
		params.TraceLogger = ctx.Err
	}

	params.RootPackageTree, err = pkgtree.ListPackages(p.ResolvedAbsRoot, string(p.ImportRoot))
	if err != nil {
		return errors.Wrap(err, "ensure ListPackage for project")
	}

	if err := checkErrors(params.RootPackageTree.Packages); err != nil {
		return err
	}

	if cmd.update {
		applyUpdateArgs(args, &params)
	} else {
		err := applyEnsureArgs(ctx.Err, args, cmd.overrides, p, sm, &params)
		if err != nil {
			return err
		}
	}

	solver, err := gps.Prepare(params, sm)
	if err != nil {
		return errors.Wrap(err, "ensure Prepare")
	}
	solution, err := solver.Solve()
	if err != nil {
		handleAllTheFailuresOfTheWorld(err)
		return errors.Wrap(err, "ensure Solve()")
	}

	// check if vendor exists, because if the locks are the same but
	// vendor does not exist we should write vendor
	vendorExists, err := fs.IsNonEmptyDir(filepath.Join(p.AbsRoot, "vendor"))
	if err != nil {
		return errors.Wrap(err, "ensure vendor is a directory")
	}
	writeV := dep.VendorOnChanged
	if !vendorExists && solution != nil {
		writeV = dep.VendorAlways
	}

	newLock := dep.LockFromSolution(solution)
	sw, err := dep.NewSafeWriter(nil, p.Lock, newLock, writeV)
	if err != nil {
		return err
	}
	if cmd.dryRun {
		return sw.PrintPreparedActions(ctx.Out)
	}

	return errors.Wrap(sw.Write(p.AbsRoot, sm, false), "grouped write of manifest, lock and vendor")
}

func applyUpdateArgs(args []string, params *gps.SolveParameters) {
	// When -update is specified without args, allow every project to change versions, regardless of the lock file
	if len(args) == 0 {
		params.ChangeAll = true
		return
	}

	// Allow any of specified project versions to change, regardless of the lock file
	for _, arg := range args {
		params.ToChange = append(params.ToChange, gps.ProjectRoot(arg))
	}
}

func applyEnsureArgs(logger *log.Logger, args []string, overrides stringSlice, p *dep.Project, sm gps.SourceManager, params *gps.SolveParameters) error {
	var errs []error
	for _, arg := range args {
		pc, err := getProjectConstraint(arg, sm)
		if err != nil {
			errs = append(errs, err)
			continue
		}

		if gps.IsAny(pc.Constraint) && pc.Ident.Source == "" {
			// If the input specified neither a network name nor a constraint,
			// then the strict thing to do would be to remove the entry
			// entirely. But that would probably be quite surprising for users,
			// and it's what rm is for, so just ignore the input.
			//
			// TODO(sdboyer): for this case - or just in general - do we want to
			// add project args to the requires list temporarily for this run?
			if _, has := p.Manifest.Constraints[pc.Ident.ProjectRoot]; !has {
				logger.Printf("dep: No constraint or alternate source specified for %q, omitting from manifest\n", pc.Ident.ProjectRoot)
			}
			// If it's already in the manifest, no need to log
			continue
		}

		p.Manifest.Constraints[pc.Ident.ProjectRoot] = gps.ProjectProperties{
			Source:     pc.Ident.Source,
			Constraint: pc.Constraint,
		}
	}

	for _, ovr := range overrides {
		pc, err := getProjectConstraint(ovr, sm)
		if err != nil {
			errs = append(errs, err)
			continue
		}

		// Empty overrides are fine (in contrast to deps), because they actually
		// carry meaning - they force the constraints entirely open for a given
		// project. Inadvisable, but meaningful.

		p.Manifest.Ovr[pc.Ident.ProjectRoot] = gps.ProjectProperties{
			Source:     pc.Ident.Source,
			Constraint: pc.Constraint,
		}
	}

	if len(errs) > 0 {
		var buf bytes.Buffer
		for _, err := range errs {
			fmt.Fprintln(&buf, err)
		}

		return errors.New(buf.String())
	}

	return nil
}

type stringSlice []string

func (s *stringSlice) String() string {
	if len(*s) == 0 {
		return "<none>"
	}
	return strings.Join(*s, ", ")
}

func (s *stringSlice) Set(value string) error {
	*s = append(*s, value)
	return nil
}

func getProjectConstraint(arg string, sm gps.SourceManager) (gps.ProjectConstraint, error) {
	emptyPC := gps.ProjectConstraint{
		Constraint: gps.Any(), // default to any; avoids panics later
	}

	// try to split on '@'
	// When there is no `@`, use any version
	versionStr := "*"
	atIndex := strings.Index(arg, "@")
	if atIndex > 0 {
		parts := strings.SplitN(arg, "@", 2)
		arg = parts[0]
		versionStr = parts[1]
	}

	// TODO: if we decide to keep equals.....

	// split on colon if there is a network location
	var source string
	colonIndex := strings.Index(arg, ":")
	if colonIndex > 0 {
		parts := strings.SplitN(arg, ":", 2)
		arg = parts[0]
		source = parts[1]
	}

	pr, err := sm.DeduceProjectRoot(arg)
	if err != nil {
		return emptyPC, errors.Wrapf(err, "could not infer project root from dependency path: %s", arg) // this should go through to the user
	}

	if string(pr) != arg {
		return emptyPC, errors.Errorf("dependency path %s is not a project root, try %s instead", arg, pr)
	}

	pi := gps.ProjectIdentifier{ProjectRoot: pr, Source: source}
	c, err := sm.InferConstraint(versionStr, pi)
	if err != nil {
		return emptyPC, err
	}
	return gps.ProjectConstraint{Ident: pi, Constraint: c}, nil
}

func checkErrors(m map[string]pkgtree.PackageOrErr) error {
	var buildErrors, noGoErrors []string

	for importPath, poe := range m {
		if poe.Err != nil {
			switch poe.Err.(type) {
			case *build.NoGoError:
				noGoErrors = append(noGoErrors, fmt.Sprintf("%s: no go code", importPath))
			default:
				buildErrors = append(buildErrors, poe.Err.Error())
			}
		}
	}

	buildErrors = append(buildErrors, noGoErrors...)

	if len(buildErrors) > 0 {
		return errors.Errorf("Found %d errors:\n\n%s", len(buildErrors), strings.Join(buildErrors, "\n"))
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"runtime/pprof"

	"github.com/dim13/golyb"
	"github.com/dim13/golyb/dynamic"
	"github.com/dim13/golyb/optimize"
	"github.com/dim13/golyb/static"
)

type Storage struct {
	Name string
	New  func(io.Reader, io.Writer) golyb.Storage
}

func (s *Storage) Set(v string) error {
	for _, st := range storages {
		if st.Name == v {
			*s = st
			return nil
		}
	}
	return errors.New("unknown tape type")
}

func (s Storage) String() string {
	return s.Name
}

var storages = []Storage{
	{Name: "static", New: static.NewTape},
	{Name: "dynamic", New: dynamic.NewTape},
}

var (
	file    = flag.String("file", "", "Source file (required)")
	in      = flag.String("in", "", "Input file")
	out     = flag.String("out", "", "Output file or /dev/null")
	profile = flag.String("profile", "", "Write CPU profile to file")
	dump    = flag.Bool("dump", false, "Dump AST and terminate")
	noop    = flag.Bool("noop", false, "Disable optimization")
	show    = flag.Bool("show", false, "Dump tape cells")
	tape    = storages[0]
)

func init() {
	flag.Var(&tape, "tape", "Tape type: static or dynamic")
	flag.Parse()
}

func main() {
	defer func() {
		if r := recover(); r != nil {
			log.Fatal(r)
		}
	}()

	if *profile != "" {
		f, err := os.Create(*profile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	program, err := golyb.ParseFile(*file)
	if err != nil {
		log.Fatal(err)
	}

	if !*noop {
		program = optimize.All(program)
	}

	if *dump {
		fmt.Print(program)
		return
	}

	var r io.Reader
	if *in != "" {
		r, err = os.Open(*in)
		if err != nil {
			log.Fatal(err)
		}
	}

	var w io.Writer
	if *out != "" {
		w, err = os.Create(*out)
		if err != nil {
			log.Fatal(err)
		}
	}

	mem := tape.New(r, w)
	program.Execute(mem)

	if *show {
		fmt.Println(mem)
	}
}
<commit_msg>stdin/out<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"runtime/pprof"

	"github.com/dim13/golyb"
	"github.com/dim13/golyb/dynamic"
	"github.com/dim13/golyb/optimize"
	"github.com/dim13/golyb/static"
)

type Storage struct {
	Name string
	New  func(io.Reader, io.Writer) golyb.Storage
}

func (s *Storage) Set(v string) error {
	for _, st := range storages {
		if st.Name == v {
			*s = st
			return nil
		}
	}
	return errors.New("unknown tape type")
}

func (s Storage) String() string {
	return s.Name
}

var storages = []Storage{
	{Name: "static", New: static.NewTape},
	{Name: "dynamic", New: dynamic.NewTape},
}

var (
	file    = flag.String("file", "", "Source file (required)")
	in      = flag.String("in", "", "Input file")
	out     = flag.String("out", "", "Output file or /dev/null")
	profile = flag.String("profile", "", "Write CPU profile to file")
	dump    = flag.Bool("dump", false, "Dump AST and terminate")
	noop    = flag.Bool("noop", false, "Disable optimization")
	show    = flag.Bool("show", false, "Dump tape cells")
	tape    = storages[0]
)

func init() {
	flag.Var(&tape, "tape", "Tape type: static or dynamic")
	flag.Parse()
}

func main() {
	defer func() {
		if r := recover(); r != nil {
			log.Fatal(r)
		}
	}()

	if *profile != "" {
		f, err := os.Create(*profile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	program, err := golyb.ParseFile(*file)
	if err != nil {
		log.Fatal(err)
	}

	if !*noop {
		program = optimize.All(program)
	}

	if *dump {
		fmt.Print(program)
		return
	}

	var r io.Reader
	if *in != "" && *in != "-" {
		r, err = os.Open(*in)
		if err != nil {
			log.Fatal(err)
		}
	}

	var w io.Writer
	if *out != "" && *out != "-" {
		w, err = os.Create(*out)
		if err != nil {
			log.Fatal(err)
		}
	}

	mem := tape.New(r, w)
	program.Execute(mem)

	if *show {
		fmt.Println(mem)
	}
}
<|endoftext|>