<commit_before>/*
Copyright 2019 The Vitess Authors.

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

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

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

package repltracker

import (
	"fmt"
	"sync"
	"time"

	"vitess.io/vitess/go/vt/withddl"

	"golang.org/x/net/context"

	"vitess.io/vitess/go/sqltypes"
	"vitess.io/vitess/go/timer"
	"vitess.io/vitess/go/vt/log"
	"vitess.io/vitess/go/vt/logutil"
	"vitess.io/vitess/go/vt/sqlparser"
	"vitess.io/vitess/go/vt/vttablet/tabletserver/connpool"
	"vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv"

	querypb "vitess.io/vitess/go/vt/proto/query"
	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
)

const (
	sqlCreateSidecarDB      = "create database if not exists %s"
	sqlCreateHeartbeatTable = `CREATE TABLE IF NOT EXISTS %s.heartbeat (
  keyspaceShard VARBINARY(256) NOT NULL PRIMARY KEY,
  tabletUid INT UNSIGNED NOT NULL,
  ts BIGINT UNSIGNED NOT NULL
        ) engine=InnoDB`
	sqlUpsertHeartbeat = "INSERT INTO %s.heartbeat (ts, tabletUid, keyspaceShard) VALUES (%a, %a, %a) ON DUPLICATE KEY UPDATE ts=VALUES(ts), tabletUid=VALUES(tabletUid)"
)

var withDDL = withddl.New([]string{
	fmt.Sprintf(sqlCreateSidecarDB, "_vt"),
	fmt.Sprintf(sqlCreateHeartbeatTable, "_vt"),
})

// heartbeatWriter runs on master tablets and writes heartbeats to the _vt.heartbeat
// table at a regular interval, defined by heartbeat_interval.
type heartbeatWriter struct {
	env tabletenv.Env

	enabled       bool
	interval      time.Duration
	tabletAlias   topodatapb.TabletAlias
	keyspaceShard string
	now           func() time.Time
	errorLog      *logutil.ThrottledLogger

	mu     sync.Mutex
	isOpen bool
	pool   *connpool.Pool
	ticks  *timer.Timer
}

// newHeartbeatWriter creates a new heartbeatWriter.
func newHeartbeatWriter(env tabletenv.Env, alias topodatapb.TabletAlias) *heartbeatWriter {
	config := env.Config()

	// config.EnableLagThrottler is a feature flag for the throttler; if throttler runs, then heartbeat must also run
	if config.ReplicationTracker.Mode != tabletenv.Heartbeat && !config.EnableLagThrottler {
		return &heartbeatWriter{}
	}
	heartbeatInterval := config.ReplicationTracker.HeartbeatIntervalSeconds.Get()
	return &heartbeatWriter{
		env:         env,
		enabled:     true,
		tabletAlias: alias,
		now:         time.Now,
		interval:    heartbeatInterval,
		ticks:       timer.NewTimer(heartbeatInterval),
		errorLog:    logutil.NewThrottledLogger("HeartbeatWriter", 60*time.Second),
		pool: connpool.NewPool(env, "HeartbeatWritePool", tabletenv.ConnPoolConfig{
			Size:               1,
			IdleTimeoutSeconds: env.Config().OltpReadPool.IdleTimeoutSeconds,
		}),
	}
}

// InitDBConfig initializes the target name for the heartbeatWriter.
func (w *heartbeatWriter) InitDBConfig(target querypb.Target) {
	w.keyspaceShard = fmt.Sprintf("%s:%s", target.Keyspace, target.Shard)
}

// Open sets up the heartbeatWriter's db connection and launches the ticker
// responsible for periodically writing to the heartbeat table.
func (w *heartbeatWriter) Open() {
	if !w.enabled {
		return
	}
	w.mu.Lock()
	defer w.mu.Unlock()
	if w.isOpen {
		return
	}
	log.Info("Hearbeat Writer: opening")

	w.pool.Open(w.env.Config().DB.AppWithDB(), w.env.Config().DB.DbaWithDB(), w.env.Config().DB.AppDebugWithDB())
	w.enableWrites(true)
	w.isOpen = true
}

// Close closes the heartbeatWriter's db connection and stops the periodic ticker.
func (w *heartbeatWriter) Close() {
	if !w.enabled {
		return
	}
	w.mu.Lock()
	defer w.mu.Unlock()
	if !w.isOpen {
		return
	}

	w.enableWrites(false)
	w.pool.Close()
	w.isOpen = false
	log.Info("Hearbeat Writer: closed")
}

// bindHeartbeatVars takes a heartbeat write (insert or update) and
// adds the necessary fields to the query as bind vars. This is done
// to protect ourselves against a badly formed keyspace or shard name.
func (w *heartbeatWriter) bindHeartbeatVars(query string) (string, error) {
	bindVars := map[string]*querypb.BindVariable{
		"ks":  sqltypes.StringBindVariable(w.keyspaceShard),
		"ts":  sqltypes.Int64BindVariable(w.now().UnixNano()),
		"uid": sqltypes.Int64BindVariable(int64(w.tabletAlias.Uid)),
	}
	parsed := sqlparser.BuildParsedQuery(query, "_vt", ":ts", ":uid", ":ks")
	bound, err := parsed.GenerateQuery(bindVars, nil)
	if err != nil {
		return "", err
	}
	return bound, nil
}

// writeHeartbeat updates the heartbeat row for this tablet with the current time in nanoseconds.
func (w *heartbeatWriter) writeHeartbeat() {
	if err := w.write(); err != nil {
		w.recordError(err)
		return
	}
	writes.Add(1)
}

func (w *heartbeatWriter) write() error {
	defer w.env.LogError()
	ctx, cancel := context.WithDeadline(context.Background(), w.now().Add(w.interval))
	defer cancel()
	upsert, err := w.bindHeartbeatVars(sqlUpsertHeartbeat)
	if err != nil {
		return err
	}
	conn, err := w.pool.Get(ctx)
	if err != nil {
		return err
	}
	defer conn.Recycle()
	_, err = withDDL.Exec(ctx, upsert, conn.Exec)
	if err != nil {
		return err
	}
	return nil
}

func (w *heartbeatWriter) recordError(err error) {
	w.errorLog.Errorf("%v", err)
	writeErrors.Add(1)
}

// enableWrites actives or deactives heartbeat writes
func (w *heartbeatWriter) enableWrites(enable bool) {
	if enable {
		w.ticks.Start(w.writeHeartbeat)
	} else {
		w.ticks.Stop()
	}
}
<commit_msg>check if ticks is nil<commit_after>/*
Copyright 2019 The Vitess Authors.

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

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

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

package repltracker

import (
	"fmt"
	"sync"
	"time"

	"vitess.io/vitess/go/vt/withddl"

	"golang.org/x/net/context"

	"vitess.io/vitess/go/sqltypes"
	"vitess.io/vitess/go/timer"
	"vitess.io/vitess/go/vt/log"
	"vitess.io/vitess/go/vt/logutil"
	"vitess.io/vitess/go/vt/sqlparser"
	"vitess.io/vitess/go/vt/vttablet/tabletserver/connpool"
	"vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv"

	querypb "vitess.io/vitess/go/vt/proto/query"
	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
)

const (
	sqlCreateSidecarDB      = "create database if not exists %s"
	sqlCreateHeartbeatTable = `CREATE TABLE IF NOT EXISTS %s.heartbeat (
  keyspaceShard VARBINARY(256) NOT NULL PRIMARY KEY,
  tabletUid INT UNSIGNED NOT NULL,
  ts BIGINT UNSIGNED NOT NULL
        ) engine=InnoDB`
	sqlUpsertHeartbeat = "INSERT INTO %s.heartbeat (ts, tabletUid, keyspaceShard) VALUES (%a, %a, %a) ON DUPLICATE KEY UPDATE ts=VALUES(ts), tabletUid=VALUES(tabletUid)"
)

var withDDL = withddl.New([]string{
	fmt.Sprintf(sqlCreateSidecarDB, "_vt"),
	fmt.Sprintf(sqlCreateHeartbeatTable, "_vt"),
})

// heartbeatWriter runs on master tablets and writes heartbeats to the _vt.heartbeat
// table at a regular interval, defined by heartbeat_interval.
type heartbeatWriter struct {
	env tabletenv.Env

	enabled       bool
	interval      time.Duration
	tabletAlias   topodatapb.TabletAlias
	keyspaceShard string
	now           func() time.Time
	errorLog      *logutil.ThrottledLogger

	mu     sync.Mutex
	isOpen bool
	pool   *connpool.Pool
	ticks  *timer.Timer
}

// newHeartbeatWriter creates a new heartbeatWriter.
func newHeartbeatWriter(env tabletenv.Env, alias topodatapb.TabletAlias) *heartbeatWriter {
	config := env.Config()

	// config.EnableLagThrottler is a feature flag for the throttler; if throttler runs, then heartbeat must also run
	if config.ReplicationTracker.Mode != tabletenv.Heartbeat && !config.EnableLagThrottler {
		return &heartbeatWriter{}
	}
	heartbeatInterval := config.ReplicationTracker.HeartbeatIntervalSeconds.Get()
	return &heartbeatWriter{
		env:         env,
		enabled:     true,
		tabletAlias: alias,
		now:         time.Now,
		interval:    heartbeatInterval,
		ticks:       timer.NewTimer(heartbeatInterval),
		errorLog:    logutil.NewThrottledLogger("HeartbeatWriter", 60*time.Second),
		pool: connpool.NewPool(env, "HeartbeatWritePool", tabletenv.ConnPoolConfig{
			Size:               1,
			IdleTimeoutSeconds: env.Config().OltpReadPool.IdleTimeoutSeconds,
		}),
	}
}

// InitDBConfig initializes the target name for the heartbeatWriter.
func (w *heartbeatWriter) InitDBConfig(target querypb.Target) {
	w.keyspaceShard = fmt.Sprintf("%s:%s", target.Keyspace, target.Shard)
}

// Open sets up the heartbeatWriter's db connection and launches the ticker
// responsible for periodically writing to the heartbeat table.
func (w *heartbeatWriter) Open() {
	if !w.enabled {
		return
	}
	w.mu.Lock()
	defer w.mu.Unlock()
	if w.isOpen {
		return
	}
	log.Info("Hearbeat Writer: opening")

	w.pool.Open(w.env.Config().DB.AppWithDB(), w.env.Config().DB.DbaWithDB(), w.env.Config().DB.AppDebugWithDB())
	w.enableWrites(true)
	w.isOpen = true
}

// Close closes the heartbeatWriter's db connection and stops the periodic ticker.
func (w *heartbeatWriter) Close() {
	if !w.enabled {
		return
	}
	w.mu.Lock()
	defer w.mu.Unlock()
	if !w.isOpen {
		return
	}

	w.enableWrites(false)
	w.pool.Close()
	w.isOpen = false
	log.Info("Hearbeat Writer: closed")
}

// bindHeartbeatVars takes a heartbeat write (insert or update) and
// adds the necessary fields to the query as bind vars. This is done
// to protect ourselves against a badly formed keyspace or shard name.
func (w *heartbeatWriter) bindHeartbeatVars(query string) (string, error) {
	bindVars := map[string]*querypb.BindVariable{
		"ks":  sqltypes.StringBindVariable(w.keyspaceShard),
		"ts":  sqltypes.Int64BindVariable(w.now().UnixNano()),
		"uid": sqltypes.Int64BindVariable(int64(w.tabletAlias.Uid)),
	}
	parsed := sqlparser.BuildParsedQuery(query, "_vt", ":ts", ":uid", ":ks")
	bound, err := parsed.GenerateQuery(bindVars, nil)
	if err != nil {
		return "", err
	}
	return bound, nil
}

// writeHeartbeat updates the heartbeat row for this tablet with the current time in nanoseconds.
func (w *heartbeatWriter) writeHeartbeat() {
	if err := w.write(); err != nil {
		w.recordError(err)
		return
	}
	writes.Add(1)
}

func (w *heartbeatWriter) write() error {
	defer w.env.LogError()
	ctx, cancel := context.WithDeadline(context.Background(), w.now().Add(w.interval))
	defer cancel()
	upsert, err := w.bindHeartbeatVars(sqlUpsertHeartbeat)
	if err != nil {
		return err
	}
	conn, err := w.pool.Get(ctx)
	if err != nil {
		return err
	}
	defer conn.Recycle()
	_, err = withDDL.Exec(ctx, upsert, conn.Exec)
	if err != nil {
		return err
	}
	return nil
}

func (w *heartbeatWriter) recordError(err error) {
	w.errorLog.Errorf("%v", err)
	writeErrors.Add(1)
}

// enableWrites actives or deactives heartbeat writes
func (w *heartbeatWriter) enableWrites(enable bool) {
	if w.ticks == nil {
		return
	}
	if enable {
		w.ticks.Start(w.writeHeartbeat)
	} else {
		w.ticks.Stop()
	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

package db

import (
	"bytes"

	"github.com/syndtr/goleveldb/leveldb"
)

// ConvertKeyFormat converts from the v0.11 to the v0.12 database format, to
// avoid having to do rescan. The change is in the key format for folder
// labels, so we basically just iterate over the database rewriting keys as
// necessary and then write out the folder ID mapping at the end.
func ConvertKeyFormat(from, to *leveldb.DB) error {
	l.Infoln("Converting database key format")
	files, globals, unchanged := 0, 0, 0

	dbi := newDBInstance(to)
	i := from.NewIterator(nil, nil)
	for i.Next() {
		key := i.Key()
		switch key[0] {
		case KeyTypeDevice:
			newKey := dbi.deviceKey(oldDeviceKeyFolder(key), oldDeviceKeyDevice(key), oldDeviceKeyName(key))
			if err := to.Put(newKey, i.Value(), nil); err != nil {
				return err
			}
			files++
		case KeyTypeGlobal:
			newKey := dbi.globalKey(oldGlobalKeyFolder(key), oldGlobalKeyName(key))
			if err := to.Put(newKey, i.Value(), nil); err != nil {
				return err
			}
			globals++
		default:
			if err := to.Put(key, i.Value(), nil); err != nil {
				return err
			}
			unchanged++
		}
	}

	l.Infof("Converted %d files, %d globals (%d unchanged).", files, globals, unchanged)

	return nil
}

func oldDeviceKeyFolder(key []byte) []byte {
	folder := key[1 : 1+64]
	izero := bytes.IndexByte(folder, 0)
	if izero < 0 {
		return folder
	}
	return folder[:izero]
}

func oldDeviceKeyDevice(key []byte) []byte {
	return key[1+64 : 1+64+32]
}

func oldDeviceKeyName(key []byte) []byte {
	return key[1+64+32:]
}

func oldGlobalKeyName(key []byte) []byte {
	return key[1+64:]
}

func oldGlobalKeyFolder(key []byte) []byte {
	folder := key[1 : 1+64]
	izero := bytes.IndexByte(folder, 0)
	if izero < 0 {
		return folder
	}
	return folder[:izero]
}
<commit_msg>Remove file that snuck in by mistake<commit_after><|endoftext|>


<commit_before>package plugin

import (
	"bytes"
	"net"
	"net/rpc"
	"testing"

	"google.golang.org/grpc"
)

// The testing file contains test helpers that you can use outside of
// this package for making it easier to test plugins themselves.

// TestConn is a helper function for returning a client and server
// net.Conn connected to each other.
func TestConn(t *testing.T) (net.Conn, net.Conn) {
	// Listen to any local port. This listener will be closed
	// after a single connection is established.
	l, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	// Start a goroutine to accept our client connection
	var serverConn net.Conn
	doneCh := make(chan struct{})
	go func() {
		defer close(doneCh)
		defer l.Close()
		var err error
		serverConn, err = l.Accept()
		if err != nil {
			t.Fatalf("err: %s", err)
		}
	}()

	// Connect to the server
	clientConn, err := net.Dial("tcp", l.Addr().String())
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	// Wait for the server side to acknowledge it has connected
	<-doneCh

	return clientConn, serverConn
}

// TestRPCConn returns a rpc client and server connected to each other.
func TestRPCConn(t *testing.T) (*rpc.Client, *rpc.Server) {
	clientConn, serverConn := TestConn(t)

	server := rpc.NewServer()
	go server.ServeConn(serverConn)

	client := rpc.NewClient(clientConn)
	return client, server
}

// TestPluginRPCConn returns a plugin RPC client and server that are connected
// together and configured.
func TestPluginRPCConn(t *testing.T, ps map[string]Plugin) (*RPCClient, *RPCServer) {
	// Create two net.Conns we can use to shuttle our control connection
	clientConn, serverConn := TestConn(t)

	// Start up the server
	server := &RPCServer{Plugins: ps, Stdout: new(bytes.Buffer), Stderr: new(bytes.Buffer)}
	go server.ServeConn(serverConn)

	// Connect the client to the server
	client, err := NewRPCClient(clientConn, ps)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	return client, server
}

// TestPluginGRPCConn returns a plugin gRPC client and server that are connected
// together and configured. This is used to test gRPC connections.
func TestPluginGRPCConn(t *testing.T, ps map[string]Plugin) (*GRPCClient, *GRPCServer) {
	// Create a listener
	l, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	// Start up the server
	server := &GRPCServer{
		Plugins: ps,
		Server:  DefaultGRPCServer,
		Stdout:  new(bytes.Buffer),
		Stderr:  new(bytes.Buffer),
	}
	if err := server.Init(); err != nil {
		t.Fatalf("err: %s", err)
	}
	go server.Serve(l)

	// Connect to the server
	conn, err := grpc.Dial(
		l.Addr().String(),
		grpc.WithBlock(),
		grpc.WithInsecure())
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	// Connection successful, close the listener
	l.Close()

	// Create the client
	client := &GRPCClient{
		Conn:    conn,
		Plugins: ps,
	}

	return client, server
}
<commit_msg>Remove testing pkg dependency<commit_after>package plugin

import (
	"bytes"
	"net"
	"net/rpc"

	"github.com/mitchellh/go-testing-interface"
	"google.golang.org/grpc"
)

// The testing file contains test helpers that you can use outside of
// this package for making it easier to test plugins themselves.

// TestConn is a helper function for returning a client and server
// net.Conn connected to each other.
func TestConn(t testing.T) (net.Conn, net.Conn) {
	// Listen to any local port. This listener will be closed
	// after a single connection is established.
	l, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	// Start a goroutine to accept our client connection
	var serverConn net.Conn
	doneCh := make(chan struct{})
	go func() {
		defer close(doneCh)
		defer l.Close()
		var err error
		serverConn, err = l.Accept()
		if err != nil {
			t.Fatalf("err: %s", err)
		}
	}()

	// Connect to the server
	clientConn, err := net.Dial("tcp", l.Addr().String())
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	// Wait for the server side to acknowledge it has connected
	<-doneCh

	return clientConn, serverConn
}

// TestRPCConn returns a rpc client and server connected to each other.
func TestRPCConn(t testing.T) (*rpc.Client, *rpc.Server) {
	clientConn, serverConn := TestConn(t)

	server := rpc.NewServer()
	go server.ServeConn(serverConn)

	client := rpc.NewClient(clientConn)
	return client, server
}

// TestPluginRPCConn returns a plugin RPC client and server that are connected
// together and configured.
func TestPluginRPCConn(t testing.T, ps map[string]Plugin) (*RPCClient, *RPCServer) {
	// Create two net.Conns we can use to shuttle our control connection
	clientConn, serverConn := TestConn(t)

	// Start up the server
	server := &RPCServer{Plugins: ps, Stdout: new(bytes.Buffer), Stderr: new(bytes.Buffer)}
	go server.ServeConn(serverConn)

	// Connect the client to the server
	client, err := NewRPCClient(clientConn, ps)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	return client, server
}

// TestPluginGRPCConn returns a plugin gRPC client and server that are connected
// together and configured. This is used to test gRPC connections.
func TestPluginGRPCConn(t testing.T, ps map[string]Plugin) (*GRPCClient, *GRPCServer) {
	// Create a listener
	l, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	// Start up the server
	server := &GRPCServer{
		Plugins: ps,
		Server:  DefaultGRPCServer,
		Stdout:  new(bytes.Buffer),
		Stderr:  new(bytes.Buffer),
	}
	if err := server.Init(); err != nil {
		t.Fatalf("err: %s", err)
	}
	go server.Serve(l)

	// Connect to the server
	conn, err := grpc.Dial(
		l.Addr().String(),
		grpc.WithBlock(),
		grpc.WithInsecure())
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	// Connection successful, close the listener
	l.Close()

	// Create the client
	client := &GRPCClient{
		Conn:    conn,
		Plugins: ps,
	}

	return client, server
}
<|endoftext|>


<commit_before>package unicornhat

// #include "ws2812-RPi.h"
// #include "unicornhat-bridge.h"
import "C"
import "fmt"

func InitHardware() {
	C.initHardware()
}

<commit_msg>Added more interface functions<commit_after>package unicornhat

// #include "ws2812-RPi.h"
// #include "unicornhat-bridge.h"
import "C"
import "fmt"

type Color struct {
	r, g, b byte
}

// initialization of hardware
func InitHardware() {
	C.initHardware()
}

func Initialize(numPixels int) {
	C.init(C.int(numPixels))
}

func StartTransfer() {
	C.startTransfer()
}

// Led updates
func Show() {
	C.show()
}

func GetBrightness() float64 {
	return float64(C.getBrightness())
}
func SetBrightness(brightness float64) byte {
	return byte(C.setBrightness(C.double(brightness)))
}

func ClearPWMBuffer() {
	C.clearPWMBuffer()
}

func Clear() {
	C.clear()
}

func ClearLEDBuffer() {
	C.clearLEDBuffer()
}

func GetPixelColor(pixel uint) Color {
	container := C.getPixelColor(C.uint(pixel))
	return NewColor(byte(container.r), byte(container.g), byte(container.b))
}

func NewColor(r, g, b byte) Color {
	return Color { r: r, g: g, b: b }
}
<|endoftext|>


<commit_before>package verbalexpressions

import (
	"regexp"
	"strconv"
	"strings"
	"log"
)

// VerbalExpression structure to create expression
type VerbalExpression struct {
	re         *regexp.Regexp
	expression string
	anycase    bool
	oneline    bool
}

// quote is an alias to regexp.QuoteMeta
func quote(s string) string {
	return regexp.QuoteMeta(s)
}

// utility function to return only strings
func tostring(i interface{}) string {
	var r string
	switch x := i.(type) {
	case string:
		r = x
	case int64:
		r =  strconv.FormatInt(x, 64)
	case uint:
		r = strconv.FormatUint(uint64(x), 64)
	case int:
		r = strconv.FormatInt(int64(x), 32)
	default:
		log.Panicf("Could not convert %v %t", x, x)
	}
	return r
}

// Instanciate a new VerbalExpression. You should use this method to
// initalize some internal var.
// Example:
//		v := verbalexpression.New().Find("foo")
func New() *VerbalExpression {
	r := new(VerbalExpression)
	r.anycase, r.oneline = false, false
	r.re = &regexp.Regexp{}
	return r
}

// add method, append expresions to the internal string that will be parsed
func (v *VerbalExpression) add(s string) *VerbalExpression {
	v.expression += s
	return v
}

// Anything will match any char
func (v *VerbalExpression) Anything() *VerbalExpression {
	return v.add(`(.*)`)
}

// AnythingBut will match anything excpeting the given string.
// Example:
//		s := "This is a simple test"
//		v := verbalexpressions.New().AnythingBut("ie").RegExp().FindAllString(s, -1)
//		[Th s  s a s mple t st]
func (v *VerbalExpression) AnythingBut(s string) *VerbalExpression {
	return v.add(`([^` + quote(s) + `]*)`)
}

// EndOfLine tells verbalexpressions to match a end of line.
// Warning, to check multiple line, you must use SearchOneLine(true)
func (v *VerbalExpression) EndOfLine() *VerbalExpression {
	return v.add(`$`)
}

// Maybe will search string zero on more times
func (v *VerbalExpression) Maybe(s string) *VerbalExpression {
	return v.add(`(` + quote(s) + `)?`)
}

// StartOfLine seeks the begining of a line. As EndOfLine you should use
// SearchOneLine(true) to test multiple lines
func (v *VerbalExpression) StartOfLine() *VerbalExpression {
	return v.add(`^`)
}

// Find seeks string. The string MUST be there (unlike Maybe() method)
func (v *VerbalExpression) Find(s string) *VerbalExpression {
	return v.add(`(` + quote(s) + `)`)
}

// Alias to Find()
func (v *VerbalExpression) Then(s string) *VerbalExpression {
	return v.Find(s)
}

// Any accepts caracters to be matched
// Example:
//		s := "foo1 foo5 foobar"
//		v := New().Find("foo").Any("1234567890").v.Regex().FindAllString(s, -1)
//		[foo1 foo5]
func (v *VerbalExpression) Any(s string) *VerbalExpression {
	return v.add(`([` + quote(s) + `])`)
}

//AnyOf is an alias to Any
func (v *VerbalExpression) AnyOf(s string) *VerbalExpression {
	return v.Any(s)
}

// LineBreak to find "\n" or "\r\n"
func (v *VerbalExpression) LineBreak() *VerbalExpression {
	return v.add(`(\n|(\r\n))`)
}

// Alias to LineBreak
func (v *VerbalExpression) BR() *VerbalExpression {
	return v.LineBreak()
}

// Range accepts an even number of arguments. Each pair of values defines start and end of range.
// Example:
//		s := "This 1 is 55 a TEST"
//		v := verbalexpressions.New().Range("a","z",0,9)
func (v *VerbalExpression) Range(args ...interface{}) *VerbalExpression {
	parts := make([]string, 3)
	app := ""
	for i := 0; i < len(args); i++ {
		app += tostring(args[i])
		if i%2 != 0 {
			parts = append(parts, app)
			app = ""
		} else {
			app += "-"
		}
	}
	if len(args)%2 != 0 {
		parts = append(parts, tostring(args[len(args)-1]))
	}

	return v.add("[" + strings.Join(parts, "") + "]")
}

// Tab fetch tabulation char (\t)
func (v *VerbalExpression) Tab() *VerbalExpression {
	return v.add(`\t`)
}

// Word matches any word (containing alpha char)
func (v *VerbalExpression) Word() *VerbalExpression {
	return v.add(`(\w+)`)
}

// Or, as the word is meaning...
func (v *VerbalExpression) Or() *VerbalExpression {
	return v.add("|")
}

// WithAnyCase ask verbalexpressions to match with or without case sensitivity
func (v *VerbalExpression) WithAnyCase(sensitive ...bool) *VerbalExpression {
	if len(sensitive) > 1 {
		panic("WithAnyCase: you should give 0 or 1 argument")
	}
	if len(sensitive) == 1 {
		v.anycase = sensitive[0]
	}
	return v
}

// SearchOneLine allow verbalexpressions to match multiline
func (v *VerbalExpression) SearchOneLine(oneline ...bool) *VerbalExpression {
	if len(oneline) > 1 {
		panic("SearchOneLine: you should give 0 or 1 argument")
	}
	if len(oneline) == 1 {
		v.oneline = oneline[0]
	}
	return v
}

// Regex return the regular expression to use to test you string.
func (v *VerbalExpression) Regex() *regexp.Regexp {
	modifier := ""
	if v.anycase {
		modifier = "i"
	}

	if v.oneline {
		modifier = "m"
	}

	if len(modifier) > 0 {
		v.expression = "(?" + modifier + ")" + v.expression
	}

	return regexp.MustCompile(v.expression)
}

/* proxy to regexp.Regexp functions */

// Test return true if you verbalexpressions matches something in "s"
func (v *VerbalExpression) Test(s string) bool {
	return v.Regex().Match([]byte(s))
}
<commit_msg>Error on example<commit_after>package verbalexpressions

import (
	"regexp"
	"strconv"
	"strings"
	"log"
)

// VerbalExpression structure to create expression
type VerbalExpression struct {
	re         *regexp.Regexp
	expression string
	anycase    bool
	oneline    bool
}

// quote is an alias to regexp.QuoteMeta
func quote(s string) string {
	return regexp.QuoteMeta(s)
}

// utility function to return only strings
func tostring(i interface{}) string {
	var r string
	switch x := i.(type) {
	case string:
		r = x
	case int64:
		r =  strconv.FormatInt(x, 64)
	case uint:
		r = strconv.FormatUint(uint64(x), 64)
	case int:
		r = strconv.FormatInt(int64(x), 32)
	default:
		log.Panicf("Could not convert %v %t", x, x)
	}
	return r
}

// Instanciate a new VerbalExpression. You should use this method to
// initalize some internal var.
// Example:
//		v := verbalexpression.New().Find("foo")
func New() *VerbalExpression {
	r := new(VerbalExpression)
	r.anycase, r.oneline = false, false
	r.re = &regexp.Regexp{}
	return r
}

// add method, append expresions to the internal string that will be parsed
func (v *VerbalExpression) add(s string) *VerbalExpression {
	v.expression += s
	return v
}

// Anything will match any char
func (v *VerbalExpression) Anything() *VerbalExpression {
	return v.add(`(.*)`)
}

// AnythingBut will match anything excpeting the given string.
// Example:
//		s := "This is a simple test"
//		v := verbalexpressions.New().AnythingBut("ie").RegExp().FindAllString(s, -1)
//		[Th s  s a s mple t st]
func (v *VerbalExpression) AnythingBut(s string) *VerbalExpression {
	return v.add(`([^` + quote(s) + `]*)`)
}

// EndOfLine tells verbalexpressions to match a end of line.
// Warning, to check multiple line, you must use SearchOneLine(true)
func (v *VerbalExpression) EndOfLine() *VerbalExpression {
	return v.add(`$`)
}

// Maybe will search string zero on more times
func (v *VerbalExpression) Maybe(s string) *VerbalExpression {
	return v.add(`(` + quote(s) + `)?`)
}

// StartOfLine seeks the begining of a line. As EndOfLine you should use
// SearchOneLine(true) to test multiple lines
func (v *VerbalExpression) StartOfLine() *VerbalExpression {
	return v.add(`^`)
}

// Find seeks string. The string MUST be there (unlike Maybe() method)
func (v *VerbalExpression) Find(s string) *VerbalExpression {
	return v.add(`(` + quote(s) + `)`)
}

// Alias to Find()
func (v *VerbalExpression) Then(s string) *VerbalExpression {
	return v.Find(s)
}

// Any accepts caracters to be matched
// Example:
//		s := "foo1 foo5 foobar"
//		v := New().Find("foo").Any("1234567890").Regex().FindAllString(s, -1)
//		[foo1 foo5]
func (v *VerbalExpression) Any(s string) *VerbalExpression {
	return v.add(`([` + quote(s) + `])`)
}

//AnyOf is an alias to Any
func (v *VerbalExpression) AnyOf(s string) *VerbalExpression {
	return v.Any(s)
}

// LineBreak to find "\n" or "\r\n"
func (v *VerbalExpression) LineBreak() *VerbalExpression {
	return v.add(`(\n|(\r\n))`)
}

// Alias to LineBreak
func (v *VerbalExpression) BR() *VerbalExpression {
	return v.LineBreak()
}

// Range accepts an even number of arguments. Each pair of values defines start and end of range.
// Example:
//		s := "This 1 is 55 a TEST"
//		v := verbalexpressions.New().Range("a","z",0,9)
func (v *VerbalExpression) Range(args ...interface{}) *VerbalExpression {
	parts := make([]string, 3)
	app := ""
	for i := 0; i < len(args); i++ {
		app += tostring(args[i])
		if i%2 != 0 {
			parts = append(parts, app)
			app = ""
		} else {
			app += "-"
		}
	}
	if len(args)%2 != 0 {
		parts = append(parts, tostring(args[len(args)-1]))
	}

	return v.add("[" + strings.Join(parts, "") + "]")
}

// Tab fetch tabulation char (\t)
func (v *VerbalExpression) Tab() *VerbalExpression {
	return v.add(`\t`)
}

// Word matches any word (containing alpha char)
func (v *VerbalExpression) Word() *VerbalExpression {
	return v.add(`(\w+)`)
}

// Or, as the word is meaning...
func (v *VerbalExpression) Or() *VerbalExpression {
	return v.add("|")
}

// WithAnyCase ask verbalexpressions to match with or without case sensitivity
func (v *VerbalExpression) WithAnyCase(sensitive ...bool) *VerbalExpression {
	if len(sensitive) > 1 {
		panic("WithAnyCase: you should give 0 or 1 argument")
	}
	if len(sensitive) == 1 {
		v.anycase = sensitive[0]
	}
	return v
}

// SearchOneLine allow verbalexpressions to match multiline
func (v *VerbalExpression) SearchOneLine(oneline ...bool) *VerbalExpression {
	if len(oneline) > 1 {
		panic("SearchOneLine: you should give 0 or 1 argument")
	}
	if len(oneline) == 1 {
		v.oneline = oneline[0]
	}
	return v
}

// Regex return the regular expression to use to test you string.
func (v *VerbalExpression) Regex() *regexp.Regexp {
	modifier := ""
	if v.anycase {
		modifier = "i"
	}

	if v.oneline {
		modifier = "m"
	}

	if len(modifier) > 0 {
		v.expression = "(?" + modifier + ")" + v.expression
	}

	return regexp.MustCompile(v.expression)
}

/* proxy to regexp.Regexp functions */

// Test return true if you verbalexpressions matches something in "s"
func (v *VerbalExpression) Test(s string) bool {
	return v.Regex().Match([]byte(s))
}
<|endoftext|>


<commit_before>// Copyright 2016 The Upspin 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 grpcauth

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"testing"

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

	"upspin.io/auth"
	prototest "upspin.io/auth/grpcauth/testdata"
	"upspin.io/cloud/https"
	"upspin.io/context"
	"upspin.io/errors"
	"upspin.io/factotum"
	"upspin.io/log"
	"upspin.io/upspin"
)

var (
	joePublic  = upspin.PublicKey("p256\n104278369061367353805983276707664349405797936579880352274235000127123465616334\n26941412685198548642075210264642864401950753555952207894712845271039438170192\n")
	user       = upspin.UserName("joe@blow.com")
	grpcServer SecureServer
	srv        *server
	cli        *client
)

type server struct {
	SecureServer
	t         *testing.T
	iteration int
}

func lookup(userName upspin.UserName) (upspin.PublicKey, error) {
	if userName == user {
		return upspin.PublicKey(joePublic), nil
	}
	return "", errors.Str("No user here")
}

func pickPort() (port string) {
	listener, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		log.Fatalf("Failed to listen: %v", err)
	}
	_, port, err = net.SplitHostPort(listener.Addr().String())
	if err != nil {
		log.Fatalf("Failed to parse listener address: %v", err)
	}
	listener.Close()
	return port
}

func startServer() (port string) {
	config := auth.Config{
		Lookup: lookup,
	}
	var err error
	grpcServer, err = NewSecureServer(config)
	if err != nil {
		log.Fatal(err)
	}
	srv = &server{
		SecureServer: grpcServer,
	}
	port = pickPort()
	prototest.RegisterTestServiceServer(grpcServer.GRPCServer(), srv)
	log.Printf("Starting e2e server on port %s", port)
	http.Handle("/", grpcServer.GRPCServer())
	go https.ListenAndServe("test", fmt.Sprintf("localhost:%s", port), nil)
	return port
}

func (s *server) Echo(ctx gContext.Context, req *prototest.EchoRequest) (*prototest.EchoResponse, error) {
	// Validate that we have a session. If not, it's an auth error.
	session, err := s.GetSessionFromContext(ctx)
	if err != nil {
		s.t.Fatal(err)
	}
	if session.User() != user {
		s.t.Fatalf("Expected user %q, got %q", user, session.User())
	}
	if req.Payload == payloads[s.iteration] {
		resp := &prototest.EchoResponse{
			Payload: payloads[s.iteration],
		}
		log.Printf("Server: Echo response: %q", resp.Payload)
		s.iteration++
		return resp, nil
	}
	s.t.Fatalf("iteration %d: invalid request %q", s.iteration, req.Payload)
	return nil, nil // not reached
}

type client struct {
	*AuthClientService // For handling Ping and Close.
	grpcClient         prototest.TestServiceClient
	reqCount           int
}

func (c *client) Echo(t *testing.T, payload string) (response string) {
	gCtx, callOpt, finishAuth, err := c.NewAuthContext()
	if err != nil {
		t.Fatal(err)
	}
	req := &prototest.EchoRequest{
		Payload: payload,
	}
	log.Printf("Client: Echo request: %q", req.Payload)
	resp, err := c.grpcClient.Echo(gCtx, req, callOpt)
	err = finishAuth(err)
	if err != nil {
		t.Fatal(err)
	}
	c.reqCount++
	return resp.Payload
}

func startClient(port string) {
	ctx := context.SetUserName(context.New(), user)

	f, err := factotum.NewFromDir(repo("key/testdata/joe"))
	if err != nil {
		log.Fatal(err)
	}
	ctx = context.SetFactotum(ctx, f)

	pem, err := ioutil.ReadFile("testdata/cert.pem")
	if err != nil {
		log.Fatal(err)
	}
	pool := ctx.CertPool()
	if ok := pool.AppendCertsFromPEM(pem); !ok {
		log.Fatal("could not add certificates to pool")
	}
	ctx = context.SetCertPool(ctx, pool)

	authClient, err := NewGRPCClient(ctx, upspin.NetAddr("localhost:"+port), KeepAliveInterval, Secure, upspin.Endpoint{})
	if err != nil {
		log.Fatal(err)
	}
	grpcClient := prototest.NewTestServiceClient(authClient.GRPCConn())
	authClient.SetService(grpcClient)
	cli = &client{
		AuthClientService: authClient,
		grpcClient:        grpcClient,
	}
}

func TestAll(t *testing.T) {
	// Inject testing into the server.
	srv.t = t

	if len(payloads) < 1 {
		t.Fatalf("Programmer error. Make at least one demand!")
	}
	for i := range payloads {
		response := cli.Echo(t, payloads[i])
		if response != payloads[i] {
			t.Errorf("Payload %d: Expected response %q, got %q", i, payloads[i], response)
		}
	}

	// Verify server and client changed state.
	if srv.iteration != len(payloads) {
		t.Errorf("Expected server to be on iteration %d, was on %d", len(payloads), srv.iteration)
	}
	if cli.reqCount != srv.iteration {
		t.Errorf("Expected client to be on iteration %d, was on %d", srv.iteration, cli.reqCount)
	}

	if cli.lastActivity().IsZero() {
		t.Errorf("Expected keep alive go routine to be alive.")
	}
}

var (
	payloads = []string{
		"The wren",
		"Earns his living",
		"Noiselessly.",
		// - Kobayahsi Issa
	}
)

func TestMain(m *testing.M) {
	port := startServer()
	startClient(port) // Blocks until it's connected to the server.

	// Start testing.
	code := m.Run()

	// Terminate cleanly.
	log.Printf("Finishing...")
	cli.Close()
	srv.Stop()

	// Report test results.
	log.Printf("Finishing e2e tests: %d", code)
	os.Exit(code)
}

// repo returns the local pathname of a file in the upspin repository.
func repo(dir string) string {
	gopath := os.Getenv("GOPATH")
	if len(gopath) == 0 {
		log.Fatal("no GOPATH")
	}
	return filepath.Join(gopath, "src/upspin.io/"+dir)
}
<commit_msg>auth/grpcauth: make client wait for server in test.<commit_after>// Copyright 2016 The Upspin 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 grpcauth

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"testing"
	"time"

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

	"upspin.io/auth"
	prototest "upspin.io/auth/grpcauth/testdata"
	"upspin.io/cloud/https"
	"upspin.io/context"
	"upspin.io/errors"
	"upspin.io/factotum"
	"upspin.io/log"
	"upspin.io/upspin"
)

var (
	joePublic  = upspin.PublicKey("p256\n104278369061367353805983276707664349405797936579880352274235000127123465616334\n26941412685198548642075210264642864401950753555952207894712845271039438170192\n")
	user       = upspin.UserName("joe@blow.com")
	grpcServer SecureServer
	srv        *server
	cli        *client
)

type server struct {
	SecureServer
	t         *testing.T
	iteration int
}

func lookup(userName upspin.UserName) (upspin.PublicKey, error) {
	if userName == user {
		return upspin.PublicKey(joePublic), nil
	}
	return "", errors.Str("No user here")
}

func pickPort() (port string) {
	listener, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		log.Fatalf("Failed to listen: %v", err)
	}
	_, port, err = net.SplitHostPort(listener.Addr().String())
	if err != nil {
		log.Fatalf("Failed to parse listener address: %v", err)
	}
	listener.Close()
	return port
}

func startServer() (port string) {
	config := auth.Config{
		Lookup: lookup,
	}
	var err error
	grpcServer, err = NewSecureServer(config)
	if err != nil {
		log.Fatal(err)
	}
	srv = &server{
		SecureServer: grpcServer,
	}
	port = pickPort()
	prototest.RegisterTestServiceServer(grpcServer.GRPCServer(), srv)
	log.Printf("Starting e2e server on port %s", port)
	http.Handle("/", grpcServer.GRPCServer())
	go https.ListenAndServe("test", fmt.Sprintf("localhost:%s", port), nil)
	return port
}

func (s *server) Echo(ctx gContext.Context, req *prototest.EchoRequest) (*prototest.EchoResponse, error) {
	// Validate that we have a session. If not, it's an auth error.
	session, err := s.GetSessionFromContext(ctx)
	if err != nil {
		s.t.Fatal(err)
	}
	if session.User() != user {
		s.t.Fatalf("Expected user %q, got %q", user, session.User())
	}
	if req.Payload == payloads[s.iteration] {
		resp := &prototest.EchoResponse{
			Payload: payloads[s.iteration],
		}
		log.Printf("Server: Echo response: %q", resp.Payload)
		s.iteration++
		return resp, nil
	}
	s.t.Fatalf("iteration %d: invalid request %q", s.iteration, req.Payload)
	return nil, nil // not reached
}

type client struct {
	*AuthClientService // For handling Ping and Close.
	grpcClient         prototest.TestServiceClient
	reqCount           int
}

func (c *client) Echo(t *testing.T, payload string) (response string) {
	gCtx, callOpt, finishAuth, err := c.NewAuthContext()
	if err != nil {
		t.Fatal(err)
	}
	req := &prototest.EchoRequest{
		Payload: payload,
	}
	log.Printf("Client: Echo request: %q", req.Payload)
	resp, err := c.grpcClient.Echo(gCtx, req, callOpt)
	err = finishAuth(err)
	if err != nil {
		t.Fatal(err)
	}
	c.reqCount++
	return resp.Payload
}

func startClient(port string) {
	ctx := context.SetUserName(context.New(), user)

	f, err := factotum.NewFromDir(repo("key/testdata/joe"))
	if err != nil {
		log.Fatal(err)
	}
	ctx = context.SetFactotum(ctx, f)

	pem, err := ioutil.ReadFile("testdata/cert.pem")
	if err != nil {
		log.Fatal(err)
	}
	pool := ctx.CertPool()
	if ok := pool.AppendCertsFromPEM(pem); !ok {
		log.Fatal("could not add certificates to pool")
	}
	ctx = context.SetCertPool(ctx, pool)

	// Try a few times because the server may not be up yet.
	var authClient *AuthClientService
	for i := 0; i < 10; i++ {
		authClient, err = NewGRPCClient(ctx, upspin.NetAddr("localhost:"+port), KeepAliveInterval, Secure, upspin.Endpoint{})
		if err == nil {
			break
		}
		time.Sleep(50 * time.Millisecond)
	}
	if err != nil {
		log.Fatal(err)
	}
	grpcClient := prototest.NewTestServiceClient(authClient.GRPCConn())
	authClient.SetService(grpcClient)
	cli = &client{
		AuthClientService: authClient,
		grpcClient:        grpcClient,
	}
}

func TestAll(t *testing.T) {
	// Inject testing into the server.
	srv.t = t

	if len(payloads) < 1 {
		t.Fatalf("Programmer error. Make at least one demand!")
	}
	for i := range payloads {
		response := cli.Echo(t, payloads[i])
		if response != payloads[i] {
			t.Errorf("Payload %d: Expected response %q, got %q", i, payloads[i], response)
		}
	}

	// Verify server and client changed state.
	if srv.iteration != len(payloads) {
		t.Errorf("Expected server to be on iteration %d, was on %d", len(payloads), srv.iteration)
	}
	if cli.reqCount != srv.iteration {
		t.Errorf("Expected client to be on iteration %d, was on %d", srv.iteration, cli.reqCount)
	}

	if cli.lastActivity().IsZero() {
		t.Errorf("Expected keep alive go routine to be alive.")
	}
}

var (
	payloads = []string{
		"The wren",
		"Earns his living",
		"Noiselessly.",
		// - Kobayahsi Issa
	}
)

func TestMain(m *testing.M) {
	port := startServer()
	startClient(port) // Blocks until it's connected to the server.

	// Start testing.
	code := m.Run()

	// Terminate cleanly.
	log.Printf("Finishing...")
	cli.Close()
	srv.Stop()

	// Report test results.
	log.Printf("Finishing e2e tests: %d", code)
	os.Exit(code)
}

// repo returns the local pathname of a file in the upspin repository.
func repo(dir string) string {
	gopath := os.Getenv("GOPATH")
	if len(gopath) == 0 {
		log.Fatal("no GOPATH")
	}
	return filepath.Join(gopath, "src/upspin.io/"+dir)
}
<|endoftext|>


<commit_before>package git

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/abhinav/git-fu/gateway"

	"go.uber.org/multierr"
)

// Gateway is a git gateway.
type Gateway struct {
	dir string
}

var _ gateway.Git = (*Gateway)(nil)

// NewGateway builds a new Git gateway.
func NewGateway(startDir string) (*Gateway, error) {
	if startDir == "" {
		dir, err := os.Getwd()
		if err != nil {
			return nil, fmt.Errorf(
				"failed to determine current working directory: %v", err)
		}
		startDir = dir
	} else {
		dir, err := filepath.Abs(startDir)
		if err != nil {
			return nil, fmt.Errorf(
				"failed to determine absolute path of %v: %v", startDir, err)
		}
		startDir = dir
	}

	dir := startDir
	for {
		_, err := os.Stat(filepath.Join(dir, ".git"))
		if err == nil {
			break
		}
		newDir := filepath.Dir(dir)
		if dir == newDir {
			return nil, fmt.Errorf(
				"could not find git repository at %v", startDir)
		}
		dir = newDir
	}

	return &Gateway{dir: dir}, nil
}

// CurrentBranch determines the current branch name.
func (g *Gateway) CurrentBranch() (string, error) {
	out, err := g.output("rev-parse", "--abbrev-ref", "HEAD")
	if err != nil {
		return "", fmt.Errorf("could not determine current branch: %v", err)
	}
	return strings.TrimSpace(out), nil
}

// DoesBranchExist checks if this branch exists locally.
func (g *Gateway) DoesBranchExist(name string) bool {
	err := g.cmd("show-ref", "--verify", "--quiet", "refs/heads/"+name).Run()
	return err == nil
}

// CreateBranch creates a branch with the given name and head but does not
// check it out.
func (g *Gateway) CreateBranch(name, head string) error {
	if err := g.cmd("branch", name, head).Run(); err != nil {
		return fmt.Errorf("failed to create branch %q at ref %q: %v", name, head, err)
	}
	return nil
}

// CreateBranchAndSwitch checks out a new branch with the given name and head.
func (g *Gateway) CreateBranchAndSwitch(name, head string) error {
	if err := g.cmd("checkout", "-b", name, head).Run(); err != nil {
		return fmt.Errorf("failed to create branch %q at ref %q: %v", name, head, err)
	}
	return nil
}

// SHA1 gets the SHA1 hash for the given ref.
func (g *Gateway) SHA1(ref string) (string, error) {
	out, err := g.output("rev-parse", ref)
	if err != nil {
		return "", fmt.Errorf("could not resolve ref %q: %v", ref, err)
	}
	return strings.TrimSpace(out), nil
}

// DeleteBranch deletes the given branch.
func (g *Gateway) DeleteBranch(name string) error {
	if err := g.cmd("branch", "-D", name).Run(); err != nil {
		return fmt.Errorf("failed to delete branch %q: %v", name, err)
	}
	return nil
}

// DeleteRemoteTrackingBranch deletes the remote tracking branch with the
// given name.
func (g *Gateway) DeleteRemoteTrackingBranch(remote, name string) error {
	if err := g.cmd("branch", "-dr", remote+"/"+name).Run(); err != nil {
		return fmt.Errorf("failed to delete remote tracking branch %q: %v", name, err)
	}
	return nil
}

// Checkout checks the given branch out.
func (g *Gateway) Checkout(name string) error {
	if err := g.cmd("checkout", name).Run(); err != nil {
		err = fmt.Errorf("failed to checkout branch %q: %v", name, err)
	}
	return nil
}

// Fetch a git ref
func (g *Gateway) Fetch(req *gateway.FetchRequest) error {
	ref := req.RemoteRef
	if req.LocalRef != "" {
		ref = ref + ":" + req.LocalRef
	}

	if err := g.cmd("fetch", req.Remote, ref).Run(); err != nil {
		return fmt.Errorf("failed to fetch %q from %q: %v", ref, req.Remote, err)
	}
	return nil
}

// Push a branch
func (g *Gateway) Push(req *gateway.PushRequest) error {
	err := g.PushMany(&gateway.PushManyRequest{
		Remote: req.Remote,
		Force:  req.Force,
		Refs:   map[string]string{req.LocalRef: req.RemoteRef},
	})
	if err != nil {
		err = fmt.Errorf("failed to push %q to %q: %v", req.LocalRef, req.Remote, err)
	}
	return err
}

// PushMany pushes multiple refs to a remote
func (g *Gateway) PushMany(req *gateway.PushManyRequest) error {
	if len(req.Refs) == 0 {
		return nil
	}

	args := append(make([]string, 0, len(req.Refs)+2), "push")
	if req.Force {
		args = append(args, "-f")
	}
	args = append(args, req.Remote)

	for ref, remote := range req.Refs {
		if remote != "" {
			ref = ref + ":" + remote
		}
		args = append(args, ref)
	}

	if err := g.cmd(args...).Run(); err != nil {
		return fmt.Errorf("failed to push refs to %q: %v", req.Remote, err)
	}
	return nil
}

// Pull pulls the given branch.
func (g *Gateway) Pull(remote, name string) error {
	if err := g.cmd("pull", remote, name).Run(); err != nil {
		return fmt.Errorf("failed to pull %q from %q: %v", name, remote, err)
	}
	return nil
}

// ApplyPatches applies the given patch.
func (g *Gateway) ApplyPatches(patches string) error {
	cmd := g.cmd("am")
	cmd.Stdin = strings.NewReader(patches)
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("failed to apply patches: %v", err)
	}
	return nil
}

// Rebase a branch.
func (g *Gateway) Rebase(req *gateway.RebaseRequest) error {
	var _args [5]string

	args := append(_args[:0], "rebase")
	if req.Onto != "" {
		args = append(args, "--onto", req.Onto)
	}
	if req.From != "" {
		args = append(args, req.From)
	}
	args = append(args, req.Branch)

	if err := g.cmd(args...).Run(); err != nil {
		return multierr.Append(
			fmt.Errorf("failed to rebase %q: %v", req.Branch, err),
			// If this failed, abort the rebase so that we're not left in a
			// bad state.
			g.cmd("rebase", "--abort").Run(),
		)
	}
	return nil
}

// ResetBranch resets the given branch to the given head.
func (g *Gateway) ResetBranch(branch, head string) error {
	curr, err := g.CurrentBranch()
	if err != nil {
		return fmt.Errorf("could not reset %q to %q: %v", branch, head, err)
	}

	if curr == branch {
		err = g.cmd("reset", "--hard", head).Run()
	} else {
		err = g.cmd("branch", "-f", branch, head).Run()
	}

	if err != nil {
		err = fmt.Errorf("could not reset %q to %q: %v", branch, head, err)
	}
	return err
}

// RemoteURL gets the URL for the given remote.
func (g *Gateway) RemoteURL(name string) (string, error) {
	out, err := g.output("remote", "get-url", name)
	if err != nil {
		return "", fmt.Errorf("failed to get URL for remote %q: %v", name, err)
	}
	return strings.TrimSpace(out), nil
}

// run the given git command.
func (g *Gateway) cmd(args ...string) *exec.Cmd {
	cmd := exec.Command("git", args...)
	cmd.Dir = g.dir
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	return cmd
}

func (g *Gateway) output(args ...string) (string, error) {
	var stdout bytes.Buffer
	cmd := g.cmd(args...)
	cmd.Stdout = &stdout
	err := cmd.Run()
	return stdout.String(), err
}
<commit_msg>git: Make Gateway thread-safe (#52)<commit_after>package git

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"

	"github.com/abhinav/git-fu/gateway"

	"go.uber.org/multierr"
)

// Gateway is a git gateway.
type Gateway struct {
	mu sync.RWMutex

	dir string
}

var _ gateway.Git = (*Gateway)(nil)

// NewGateway builds a new Git gateway.
func NewGateway(startDir string) (*Gateway, error) {
	if startDir == "" {
		dir, err := os.Getwd()
		if err != nil {
			return nil, fmt.Errorf(
				"failed to determine current working directory: %v", err)
		}
		startDir = dir
	} else {
		dir, err := filepath.Abs(startDir)
		if err != nil {
			return nil, fmt.Errorf(
				"failed to determine absolute path of %v: %v", startDir, err)
		}
		startDir = dir
	}

	dir := startDir
	for {
		_, err := os.Stat(filepath.Join(dir, ".git"))
		if err == nil {
			break
		}
		newDir := filepath.Dir(dir)
		if dir == newDir {
			return nil, fmt.Errorf(
				"could not find git repository at %v", startDir)
		}
		dir = newDir
	}

	return &Gateway{dir: dir}, nil
}

// CurrentBranch determines the current branch name.
func (g *Gateway) CurrentBranch() (string, error) {
	g.mu.RLock()
	defer g.mu.RUnlock()

	out, err := g.output("rev-parse", "--abbrev-ref", "HEAD")
	if err != nil {
		return "", fmt.Errorf("could not determine current branch: %v", err)
	}
	return strings.TrimSpace(out), nil
}

// DoesBranchExist checks if this branch exists locally.
func (g *Gateway) DoesBranchExist(name string) bool {
	g.mu.RLock()
	defer g.mu.RUnlock()

	err := g.cmd("show-ref", "--verify", "--quiet", "refs/heads/"+name).Run()
	return err == nil
}

// CreateBranch creates a branch with the given name and head but does not
// check it out.
func (g *Gateway) CreateBranch(name, head string) error {
	g.mu.Lock()
	defer g.mu.Unlock()

	if err := g.cmd("branch", name, head).Run(); err != nil {
		return fmt.Errorf("failed to create branch %q at ref %q: %v", name, head, err)
	}
	return nil
}

// CreateBranchAndSwitch checks out a new branch with the given name and head.
func (g *Gateway) CreateBranchAndSwitch(name, head string) error {
	g.mu.Lock()
	defer g.mu.Unlock()

	if err := g.cmd("checkout", "-b", name, head).Run(); err != nil {
		return fmt.Errorf("failed to create branch %q at ref %q: %v", name, head, err)
	}
	return nil
}

// SHA1 gets the SHA1 hash for the given ref.
func (g *Gateway) SHA1(ref string) (string, error) {
	g.mu.RLock()
	defer g.mu.RUnlock()

	out, err := g.output("rev-parse", ref)
	if err != nil {
		return "", fmt.Errorf("could not resolve ref %q: %v", ref, err)
	}
	return strings.TrimSpace(out), nil
}

// DeleteBranch deletes the given branch.
func (g *Gateway) DeleteBranch(name string) error {
	g.mu.Lock()
	defer g.mu.Unlock()

	if err := g.cmd("branch", "-D", name).Run(); err != nil {
		return fmt.Errorf("failed to delete branch %q: %v", name, err)
	}
	return nil
}

// DeleteRemoteTrackingBranch deletes the remote tracking branch with the
// given name.
func (g *Gateway) DeleteRemoteTrackingBranch(remote, name string) error {
	g.mu.Lock()
	defer g.mu.Unlock()

	if err := g.cmd("branch", "-dr", remote+"/"+name).Run(); err != nil {
		return fmt.Errorf("failed to delete remote tracking branch %q: %v", name, err)
	}
	return nil
}

// Checkout checks the given branch out.
func (g *Gateway) Checkout(name string) error {
	g.mu.Lock()
	defer g.mu.Unlock()

	if err := g.cmd("checkout", name).Run(); err != nil {
		err = fmt.Errorf("failed to checkout branch %q: %v", name, err)
	}
	return nil
}

// Fetch a git ref
func (g *Gateway) Fetch(req *gateway.FetchRequest) error {
	g.mu.Lock()
	defer g.mu.Unlock()

	ref := req.RemoteRef
	if req.LocalRef != "" {
		ref = ref + ":" + req.LocalRef
	}

	if err := g.cmd("fetch", req.Remote, ref).Run(); err != nil {
		return fmt.Errorf("failed to fetch %q from %q: %v", ref, req.Remote, err)
	}
	return nil
}

// Push a branch
func (g *Gateway) Push(req *gateway.PushRequest) error {
	g.mu.Lock()
	defer g.mu.Unlock()

	err := g.PushMany(&gateway.PushManyRequest{
		Remote: req.Remote,
		Force:  req.Force,
		Refs:   map[string]string{req.LocalRef: req.RemoteRef},
	})
	if err != nil {
		err = fmt.Errorf("failed to push %q to %q: %v", req.LocalRef, req.Remote, err)
	}
	return err
}

// PushMany pushes multiple refs to a remote
func (g *Gateway) PushMany(req *gateway.PushManyRequest) error {
	if len(req.Refs) == 0 {
		return nil
	}

	g.mu.Lock()
	defer g.mu.Unlock()

	args := append(make([]string, 0, len(req.Refs)+2), "push")
	if req.Force {
		args = append(args, "-f")
	}
	args = append(args, req.Remote)

	for ref, remote := range req.Refs {
		if remote != "" {
			ref = ref + ":" + remote
		}
		args = append(args, ref)
	}

	if err := g.cmd(args...).Run(); err != nil {
		return fmt.Errorf("failed to push refs to %q: %v", req.Remote, err)
	}
	return nil
}

// Pull pulls the given branch.
func (g *Gateway) Pull(remote, name string) error {
	g.mu.Lock()
	defer g.mu.Unlock()

	if err := g.cmd("pull", remote, name).Run(); err != nil {
		return fmt.Errorf("failed to pull %q from %q: %v", name, remote, err)
	}
	return nil
}

// ApplyPatches applies the given patch.
func (g *Gateway) ApplyPatches(patches string) error {
	g.mu.Lock()
	defer g.mu.Unlock()

	cmd := g.cmd("am")
	cmd.Stdin = strings.NewReader(patches)
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("failed to apply patches: %v", err)
	}
	return nil
}

// Rebase a branch.
func (g *Gateway) Rebase(req *gateway.RebaseRequest) error {
	g.mu.Lock()
	defer g.mu.Unlock()

	var _args [5]string

	args := append(_args[:0], "rebase")
	if req.Onto != "" {
		args = append(args, "--onto", req.Onto)
	}
	if req.From != "" {
		args = append(args, req.From)
	}
	args = append(args, req.Branch)

	if err := g.cmd(args...).Run(); err != nil {
		return multierr.Append(
			fmt.Errorf("failed to rebase %q: %v", req.Branch, err),
			// If this failed, abort the rebase so that we're not left in a
			// bad state.
			g.cmd("rebase", "--abort").Run(),
		)
	}
	return nil
}

// ResetBranch resets the given branch to the given head.
func (g *Gateway) ResetBranch(branch, head string) error {
	g.mu.Lock()
	defer g.mu.Unlock()

	curr, err := g.CurrentBranch()
	if err != nil {
		return fmt.Errorf("could not reset %q to %q: %v", branch, head, err)
	}

	if curr == branch {
		err = g.cmd("reset", "--hard", head).Run()
	} else {
		err = g.cmd("branch", "-f", branch, head).Run()
	}

	if err != nil {
		err = fmt.Errorf("could not reset %q to %q: %v", branch, head, err)
	}
	return err
}

// RemoteURL gets the URL for the given remote.
func (g *Gateway) RemoteURL(name string) (string, error) {
	g.mu.RLock()
	defer g.mu.RUnlock()

	out, err := g.output("remote", "get-url", name)
	if err != nil {
		return "", fmt.Errorf("failed to get URL for remote %q: %v", name, err)
	}
	return strings.TrimSpace(out), nil
}

// run the given git command.
func (g *Gateway) cmd(args ...string) *exec.Cmd {
	cmd := exec.Command("git", args...)
	cmd.Dir = g.dir
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	return cmd
}

func (g *Gateway) output(args ...string) (string, error) {
	var stdout bytes.Buffer
	cmd := g.cmd(args...)
	cmd.Stdout = &stdout
	err := cmd.Run()
	return stdout.String(), err
}
<|endoftext|>


<commit_before>package reviewdog

import (
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"testing"

	"github.com/google/go-github/github"
	"github.com/kylelemons/godebug/pretty"
	"golang.org/x/oauth2"
)

const notokenSkipTestMes = "skipping test (requires actual Personal access tokens. export REVIEWDOG_TEST_GITHUB_API_TOKEN=<GitHub Personal Access Token>)"

func setupGitHubClient() *github.Client {
	token := os.Getenv("REVIEWDOG_TEST_GITHUB_API_TOKEN")
	if token == "" {
		return nil
	}
	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: token},
	)
	tc := oauth2.NewClient(oauth2.NoContext, ts)
	return github.NewClient(tc)
}

func TestGitHubPullRequest_Post(t *testing.T) {
	t.Skip("skipping test which post comments actually")
	client := setupGitHubClient()
	if client == nil {
		t.Skip(notokenSkipTestMes)
	}

	// https://github.com/haya14busa/reviewdog/pull/2
	owner := "haya14busa"
	repo := "reviewdog"
	pr := 2
	sha := "cce89afa9ac5519a7f5b1734db2e3aa776b138a7"

	g := NewGitHubPullReqest(client, owner, repo, pr, sha)
	comment := &Comment{
		CheckResult: &CheckResult{
			Path: "watchdogs.go",
		},
		LnumDiff: 17,
		Body:     "[reviewdog] test",
	}
	// https://github.com/haya14busa/reviewdog/pull/2/files#diff-ed1d019a10f54464cfaeaf6a736b7d27L20
	if err := g.Post(context.Background(), comment); err != nil {
		t.Error(err)
	}
	if err := g.Flash(context.Background()); err != nil {
		t.Error(err)
	}
}

func TestGitHubPullRequest_Diff(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test which contains actual API requests in short mode")
	}
	client := setupGitHubClient()
	if client == nil {
		t.Skip(notokenSkipTestMes)
	}

	want := `diff --git a/diff.go b/diff.go
index b380b67..6abc0f1 100644
--- a/diff.go
+++ b/diff.go
@@ -4,6 +4,9 @@ import (
 	"os/exec"
 )

+func TestNewExportedFunc() {
+}
+
 var _ DiffService = &DiffString{}

 type DiffString struct {
diff --git a/reviewdog.go b/reviewdog.go
index 61450f3..f63f149 100644
--- a/reviewdog.go
+++ b/reviewdog.go
@@ -10,18 +10,18 @@ import (
 	"github.com/haya14busa/reviewdog/diff"
 )

+var TestExportedVarWithoutComment = 1
+
+func NewReviewdog(p Parser, c CommentService, d DiffService) *Reviewdog {
+	return &Reviewdog{p: p, c: c, d: d}
+}
+
 type Reviewdog struct {
 	p Parser
 	c CommentService
 	d DiffService
 }

-func NewReviewdog(p Parser, c CommentService, d DiffService) *Reviewdog {
-	return &Reviewdog{p: p, c: c, d: d}
-}
-
-// CheckResult represents a checked result of static analysis tools.
-// :h error-file-format
 type CheckResult struct {
 	Path    string   // file path
 	Lnum    int      // line number
`

	// https://github.com/haya14busa/reviewdog/pull/2
	owner := "haya14busa"
	repo := "reviewdog"
	pr := 2
	g := NewGitHubPullReqest(client, owner, repo, pr, "")
	b, err := g.Diff(context.Background())
	if err != nil {
		t.Fatal(err)
	}
	if got := string(b); got != want {
		t.Errorf("got:\n%v\nwant:\n%v", got, want)
	}
}

func TestGitHubPullRequest_comment(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test which contains actual API requests in short mode")
	}
	client := setupGitHubClient()
	if client == nil {
		t.Skip(notokenSkipTestMes)
	}
	// https://github.com/haya14busa/reviewdog/pull/2
	owner := "haya14busa"
	repo := "reviewdog"
	pr := 2
	g := NewGitHubPullReqest(client, owner, repo, pr, "")
	comments, err := g.comment(context.Background())
	if err != nil {
		t.Fatal(err)
	}
	for _, c := range comments {
		t.Log("---")
		t.Log(*c.Body)
		t.Log(*c.Path)
		if c.Position != nil {
			t.Log(*c.Position)
		}
		t.Log(*c.CommitID)
	}
}

func TestGitHubPullRequest_Post_Flash_mock(t *testing.T) {
	apiCalled := 0
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.String() != "/repos/haya14busa/reviewdog/pulls/2/comments" {
			t.Errorf("unexpected access: %v %v", r.Method, r.URL)
			return
		}

		switch r.Method {
		case "GET":
		case "POST":
			var v github.PullRequestComment
			if err := json.NewDecoder(r.Body).Decode(&v); err != nil {
				t.Error(err)
			}
			body := *v.Body
			want := `reported by [reviewdog](https://github.com/haya14busa/reviewdog) :dog:
[reviewdog] test`
			if body != want {
				t.Errorf("body: got %v, want %v", body, want)
			}
		default:
			t.Errorf("unexpected access: %v %v", r.Method, r.URL)
		}
		apiCalled++
	}))
	defer ts.Close()

	cli := github.NewClient(nil)
	cli.BaseURL, _ = url.Parse(ts.URL)

	// https://github.com/haya14busa/reviewdog/pull/2
	owner := "haya14busa"
	repo := "reviewdog"
	pr := 2
	sha := "cce89afa9ac5519a7f5b1734db2e3aa776b138a7"

	g := NewGitHubPullReqest(cli, owner, repo, pr, sha)
	comment := &Comment{
		CheckResult: &CheckResult{
			Path: "reviewdog.go",
		},
		LnumDiff: 17,
		Body:     "[reviewdog] test",
	}
	// https://github.com/haya14busa/reviewdog/pull/2/files#diff-ed1d019a10f54464cfaeaf6a736b7d27L20
	if err := g.Post(context.Background(), comment); err != nil {
		t.Error(err)
	}
	if err := g.Flash(context.Background()); err != nil {
		t.Error(err)
	}
	if apiCalled != 2 {
		t.Errorf("API should be called 2 times, but %v times", apiCalled)
	}
}

func TestGitHubPullRequest_Post_Flash_review_api(t *testing.T) {
	apiCalled := 0
	mux := http.NewServeMux()
	mux.HandleFunc("/repos/o/r/pulls/14/comments", func(w http.ResponseWriter, r *http.Request) {
		apiCalled++
		if r.Method != "GET" {
			t.Errorf("unexpected access: %v %v", r.Method, r.URL)
		}
		cs := []*github.PullRequestComment{
			{
				Path:     github.String("reviewdog.go"),
				Position: github.Int(1),
				Body:     github.String(bodyPrefix + "\nalready commented"),
			},
		}
		if err := json.NewEncoder(w).Encode(cs); err != nil {
			t.Fatal(err)
		}
	})
	mux.HandleFunc("/repos/o/r/pulls/14/reviews", func(w http.ResponseWriter, r *http.Request) {
		apiCalled++
		if r.Method != "POST" {
			t.Errorf("unexpected access: %v %v", r.Method, r.URL)
		}
		var req github.PullRequestReviewRequest
		if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
			t.Error(err)
		}
		if *req.Event != "COMMENT" {
			t.Errorf("PullRequestReviewRequest.Event = %v, want COMMENT", *req.Event)
		}
		if req.Body != nil {
			t.Errorf("PullRequestReviewRequest.Body = %v, want empty", *req.Body)
		}
		want := []*github.DraftReviewComment{
			{
				Path:     github.String("reviewdog.go"),
				Position: github.Int(14),
				Body:     github.String(bodyPrefix + "\nnew comment"),
			},
		}
		if diff := pretty.Compare(want, req.Comments); diff != "" {
			t.Errorf("req.Comments diff: (-got +want)\n%s", diff)
		}
	})
	ts := httptest.NewServer(mux)
	defer ts.Close()

	// modify githubAPIHost to use GitHub Review API
	defer func(h string) { githubAPIHost = h }(githubAPIHost)
	u, _ := url.Parse(ts.URL)
	githubAPIHost = u.Host

	cli := github.NewClient(nil)
	cli.BaseURL, _ = url.Parse(ts.URL)
	g := NewGitHubPullReqest(cli, "o", "r", 14, "")
	comments := []*Comment{
		{
			CheckResult: &CheckResult{
				Path: "reviewdog.go",
			},
			LnumDiff: 1,
			Body:     "already commented",
		},
		{
			CheckResult: &CheckResult{
				Path: "reviewdog.go",
			},
			LnumDiff: 14,
			Body:     "new comment",
		},
	}
	for _, c := range comments {
		if err := g.Post(context.Background(), c); err != nil {
			t.Error(err)
		}
	}
	if err := g.Flash(context.Background()); err != nil {
		t.Error(err)
	}
	if apiCalled != 2 {
		t.Errorf("GitHub API should be called once; called %v times", apiCalled)
	}
}
<commit_msg>fix test<commit_after>package reviewdog

import (
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"testing"

	"github.com/google/go-github/github"
	"github.com/kylelemons/godebug/pretty"
	"golang.org/x/oauth2"
)

const notokenSkipTestMes = "skipping test (requires actual Personal access tokens. export REVIEWDOG_TEST_GITHUB_API_TOKEN=<GitHub Personal Access Token>)"

func setupGitHubClient() *github.Client {
	token := os.Getenv("REVIEWDOG_TEST_GITHUB_API_TOKEN")
	if token == "" {
		return nil
	}
	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: token},
	)
	tc := oauth2.NewClient(oauth2.NoContext, ts)
	return github.NewClient(tc)
}

func TestGitHubPullRequest_Post(t *testing.T) {
	t.Skip("skipping test which post comments actually")
	client := setupGitHubClient()
	if client == nil {
		t.Skip(notokenSkipTestMes)
	}

	// https://github.com/haya14busa/reviewdog/pull/2
	owner := "haya14busa"
	repo := "reviewdog"
	pr := 2
	sha := "cce89afa9ac5519a7f5b1734db2e3aa776b138a7"

	g, err := NewGitHubPullReqest(client, owner, repo, pr, sha)
	if err != nil {
		t.Fatal(err)
	}
	comment := &Comment{
		CheckResult: &CheckResult{
			Path: "watchdogs.go",
		},
		LnumDiff: 17,
		Body:     "[reviewdog] test",
	}
	// https://github.com/haya14busa/reviewdog/pull/2/files#diff-ed1d019a10f54464cfaeaf6a736b7d27L20
	if err := g.Post(context.Background(), comment); err != nil {
		t.Error(err)
	}
	if err := g.Flash(context.Background()); err != nil {
		t.Error(err)
	}
}

func TestGitHubPullRequest_Diff(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test which contains actual API requests in short mode")
	}
	client := setupGitHubClient()
	if client == nil {
		t.Skip(notokenSkipTestMes)
	}

	want := `diff --git a/diff.go b/diff.go
index b380b67..6abc0f1 100644
--- a/diff.go
+++ b/diff.go
@@ -4,6 +4,9 @@ import (
 	"os/exec"
 )

+func TestNewExportedFunc() {
+}
+
 var _ DiffService = &DiffString{}

 type DiffString struct {
diff --git a/reviewdog.go b/reviewdog.go
index 61450f3..f63f149 100644
--- a/reviewdog.go
+++ b/reviewdog.go
@@ -10,18 +10,18 @@ import (
 	"github.com/haya14busa/reviewdog/diff"
 )

+var TestExportedVarWithoutComment = 1
+
+func NewReviewdog(p Parser, c CommentService, d DiffService) *Reviewdog {
+	return &Reviewdog{p: p, c: c, d: d}
+}
+
 type Reviewdog struct {
 	p Parser
 	c CommentService
 	d DiffService
 }

-func NewReviewdog(p Parser, c CommentService, d DiffService) *Reviewdog {
-	return &Reviewdog{p: p, c: c, d: d}
-}
-
-// CheckResult represents a checked result of static analysis tools.
-// :h error-file-format
 type CheckResult struct {
 	Path    string   // file path
 	Lnum    int      // line number
`

	// https://github.com/haya14busa/reviewdog/pull/2
	owner := "haya14busa"
	repo := "reviewdog"
	pr := 2
	g, err := NewGitHubPullReqest(client, owner, repo, pr, "")
	if err != nil {
		t.Fatal(err)
	}
	b, err := g.Diff(context.Background())
	if err != nil {
		t.Fatal(err)
	}
	if got := string(b); got != want {
		t.Errorf("got:\n%v\nwant:\n%v", got, want)
	}
}

func TestGitHubPullRequest_comment(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test which contains actual API requests in short mode")
	}
	client := setupGitHubClient()
	if client == nil {
		t.Skip(notokenSkipTestMes)
	}
	// https://github.com/haya14busa/reviewdog/pull/2
	owner := "haya14busa"
	repo := "reviewdog"
	pr := 2
	g, err := NewGitHubPullReqest(client, owner, repo, pr, "")
	if err != nil {
		t.Fatal(err)
	}
	comments, err := g.comment(context.Background())
	if err != nil {
		t.Fatal(err)
	}
	for _, c := range comments {
		t.Log("---")
		t.Log(*c.Body)
		t.Log(*c.Path)
		if c.Position != nil {
			t.Log(*c.Position)
		}
		t.Log(*c.CommitID)
	}
}

func TestGitHubPullRequest_Post_Flash_mock(t *testing.T) {
	apiCalled := 0
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.String() != "/repos/haya14busa/reviewdog/pulls/2/comments" {
			t.Errorf("unexpected access: %v %v", r.Method, r.URL)
			return
		}

		switch r.Method {
		case "GET":
		case "POST":
			var v github.PullRequestComment
			if err := json.NewDecoder(r.Body).Decode(&v); err != nil {
				t.Error(err)
			}
			body := *v.Body
			want := `reported by [reviewdog](https://github.com/haya14busa/reviewdog) :dog:
[reviewdog] test`
			if body != want {
				t.Errorf("body: got %v, want %v", body, want)
			}
		default:
			t.Errorf("unexpected access: %v %v", r.Method, r.URL)
		}
		apiCalled++
	}))
	defer ts.Close()

	cli := github.NewClient(nil)
	cli.BaseURL, _ = url.Parse(ts.URL)

	// https://github.com/haya14busa/reviewdog/pull/2
	owner := "haya14busa"
	repo := "reviewdog"
	pr := 2
	sha := "cce89afa9ac5519a7f5b1734db2e3aa776b138a7"

	g, err := NewGitHubPullReqest(cli, owner, repo, pr, sha)
	if err != nil {
		t.Fatal(err)
	}
	comment := &Comment{
		CheckResult: &CheckResult{
			Path: "reviewdog.go",
		},
		LnumDiff: 17,
		Body:     "[reviewdog] test",
	}
	// https://github.com/haya14busa/reviewdog/pull/2/files#diff-ed1d019a10f54464cfaeaf6a736b7d27L20
	if err := g.Post(context.Background(), comment); err != nil {
		t.Error(err)
	}
	if err := g.Flash(context.Background()); err != nil {
		t.Error(err)
	}
	if apiCalled != 2 {
		t.Errorf("API should be called 2 times, but %v times", apiCalled)
	}
}

func TestGitHubPullRequest_Post_Flash_review_api(t *testing.T) {
	apiCalled := 0
	mux := http.NewServeMux()
	mux.HandleFunc("/repos/o/r/pulls/14/comments", func(w http.ResponseWriter, r *http.Request) {
		apiCalled++
		if r.Method != "GET" {
			t.Errorf("unexpected access: %v %v", r.Method, r.URL)
		}
		cs := []*github.PullRequestComment{
			{
				Path:     github.String("reviewdog.go"),
				Position: github.Int(1),
				Body:     github.String(bodyPrefix + "\nalready commented"),
			},
		}
		if err := json.NewEncoder(w).Encode(cs); err != nil {
			t.Fatal(err)
		}
	})
	mux.HandleFunc("/repos/o/r/pulls/14/reviews", func(w http.ResponseWriter, r *http.Request) {
		apiCalled++
		if r.Method != "POST" {
			t.Errorf("unexpected access: %v %v", r.Method, r.URL)
		}
		var req github.PullRequestReviewRequest
		if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
			t.Error(err)
		}
		if *req.Event != "COMMENT" {
			t.Errorf("PullRequestReviewRequest.Event = %v, want COMMENT", *req.Event)
		}
		if req.Body != nil {
			t.Errorf("PullRequestReviewRequest.Body = %v, want empty", *req.Body)
		}
		want := []*github.DraftReviewComment{
			{
				Path:     github.String("reviewdog.go"),
				Position: github.Int(14),
				Body:     github.String(bodyPrefix + "\nnew comment"),
			},
		}
		if diff := pretty.Compare(want, req.Comments); diff != "" {
			t.Errorf("req.Comments diff: (-got +want)\n%s", diff)
		}
	})
	ts := httptest.NewServer(mux)
	defer ts.Close()

	// modify githubAPIHost to use GitHub Review API
	defer func(h string) { githubAPIHost = h }(githubAPIHost)
	u, _ := url.Parse(ts.URL)
	githubAPIHost = u.Host

	cli := github.NewClient(nil)
	cli.BaseURL, _ = url.Parse(ts.URL)
	g, err := NewGitHubPullReqest(cli, "o", "r", 14, "")
	if err != nil {
		t.Fatal(err)
	}
	comments := []*Comment{
		{
			CheckResult: &CheckResult{
				Path: "reviewdog.go",
			},
			LnumDiff: 1,
			Body:     "already commented",
		},
		{
			CheckResult: &CheckResult{
				Path: "reviewdog.go",
			},
			LnumDiff: 14,
			Body:     "new comment",
		},
	}
	for _, c := range comments {
		if err := g.Post(context.Background(), c); err != nil {
			t.Error(err)
		}
	}
	if err := g.Flash(context.Background()); err != nil {
		t.Error(err)
	}
	if apiCalled != 2 {
		t.Errorf("GitHub API should be called once; called %v times", apiCalled)
	}
}
<|endoftext|>


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

package gob

// TODO(rsc): When garbage collector changes, revisit
// the allocations in this file that use unsafe.Pointer.

import (
	"gob";
	"io";
	"math";
	"os";
	"reflect";
	"unsafe";
)

// The global execution state of an instance of the decoder.
type DecState struct {
	r	io.Reader;
	err	os.Error;
	base	uintptr;
	fieldnum	int;	// the last field number read.
	buf [1]byte;	// buffer used by the decoder; here to avoid allocation.
}

// DecodeUint reads an encoded unsigned integer from state.r.
// Sets state.err.  If state.err is already non-nil, it does nothing.
func DecodeUint(state *DecState) (x uint64) {
	if state.err != nil {
		return
	}
	for shift := uint(0);; shift += 7 {
		var n int;
		n, state.err = state.r.Read(&state.buf);
		if n != 1 {
			return 0
		}
		b := uint64(state.buf[0]);
		x |= b << shift;
		if b&0x80 != 0 {
			x &^= 0x80 << shift;
			break
		}
	}
	return x;
}

// DecodeInt reads an encoded signed integer from state.r.
// Sets state.err.  If state.err is already non-nil, it does nothing.
func DecodeInt(state *DecState) int64 {
	x := DecodeUint(state);
	if state.err != nil {
		return 0
	}
	if x & 1 != 0 {
		return ^int64(x>>1)
	}
	return int64(x >> 1)
}

type decInstr struct
type decOp func(i *decInstr, state *DecState, p unsafe.Pointer);

// The 'instructions' of the decoding machine
type decInstr struct {
	op	decOp;
	field		int;	// field number
	indir	int;	// how many pointer indirections to reach the value in the struct
	offset	uintptr;	// offset in the structure of the field to encode
}

// Since the encoder writes no zeros, if we arrive at a decoder we have
// a value to extract and store.  The field number has already been read
// (it's how we knew to call this decoder).
// Each decoder is responsible for handling any indirections associated
// with the data structure.  If any pointer so reached is nil, allocation must
// be done.

// Walk the pointer hierarchy, allocating if we find a nil.  Stop one before the end.
func decIndirect(p unsafe.Pointer, indir int) unsafe.Pointer {
	for ; indir > 1; indir-- {
		if *(*unsafe.Pointer)(p) == nil {
			// Allocation required
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(unsafe.Pointer));
		}
		p = *(*unsafe.Pointer)(p);
	}
	return p
}

func decBool(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(bool));
		}
		p = *(*unsafe.Pointer)(p);
	}
	v := int(DecodeInt(state));
	if state.err == nil {
		*(*bool)(p) = v != 0;
	}
}

func decInt(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(int));
		}
		p = *(*unsafe.Pointer)(p);
	}
	v := int(DecodeInt(state));
	if state.err == nil {
		*(*int)(p) = v;
	}
}

func decUint(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint));
		}
		p = *(*unsafe.Pointer)(p);
	}
	v := uint(DecodeUint(state));
	if state.err == nil {
		*(*uint)(p) = v;
	}
}

func decInt8(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(int8));
		}
		p = *(*unsafe.Pointer)(p);
	}
	v := int8(DecodeInt(state));
	if state.err == nil {
		*(*int8)(p) = v;
	}
}

func decUint8(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint8));
		}
		p = *(*unsafe.Pointer)(p);
	}
	v := uint8(DecodeUint(state));
	if state.err == nil {
		*(*uint8)(p) = v;
	}
}

func decInt16(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(int16));
		}
		p = *(*unsafe.Pointer)(p);
	}
	v := int16(DecodeInt(state));
	if state.err == nil {
		*(*int16)(p) = v;
	}
}

func decUint16(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint16));
		}
		p = *(*unsafe.Pointer)(p);
	}
	v := uint16(DecodeUint(state));
	if state.err == nil {
		*(*uint16)(p) = v;
	}
}

func decInt32(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(int32));
		}
		p = *(*unsafe.Pointer)(p);
	}
	v := int32(DecodeInt(state));
	if state.err == nil {
		*(*int32)(p) = v;
	}
}

func decUint32(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint32));
		}
		p = *(*unsafe.Pointer)(p);
	}
	v := uint32(DecodeUint(state));
	if state.err == nil {
		*(*uint32)(p) = v;
	}
}

func decInt64(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(int64));
		}
		p = *(*unsafe.Pointer)(p);
	}
	v := int64(DecodeInt(state));
	if state.err == nil {
		*(*int64)(p) = v;
	}
}

func decUint64(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint64));
		}
		p = *(*unsafe.Pointer)(p);
	}
	v := uint64(DecodeUint(state));
	if state.err == nil {
		*(*uint64)(p) = v;
	}
}

// Floating-point numbers are transmitted as uint64s holding the bits
// of the underlying representation.  They are sent byte-reversed, with
// the exponent end coming out first, so integer floating point numbers
// (for example) transmit more compactly.  This routine does the
// unswizzling.
func floatFromBits(u uint64) float64 {
	var v uint64;
	for i := 0; i < 8; i++ {
		v <<= 8;
		v |= u & 0xFF;
		u >>= 8;
	}
	return math.Float64frombits(v);
}

func decFloat(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(float));
		}
		p = *(*unsafe.Pointer)(p);
	}
	v := float(floatFromBits(uint64(DecodeUint(state))));
	if state.err == nil {
		*(*float)(p) = v;
	}
}

func decFloat32(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(float32));
		}
		p = *(*unsafe.Pointer)(p);
	}
	v := float32(floatFromBits(uint64(DecodeUint(state))));
	if state.err == nil {
		*(*float32)(p) = v;
	}
}

func decFloat64(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(float64));
		}
		p = *(*unsafe.Pointer)(p);
	}
	v := floatFromBits(uint64(DecodeUint(state)));
	if state.err == nil {
		*(*float64)(p) = v;
	}
}

// Execution engine

// The encoder engine is an array of instructions indexed by field number of the incoming
// data.  It is executed with random access according to field number.
type decEngine struct {
	instr	[]decInstr
}

var decEngineMap = make(map[reflect.Type] *decEngine)
var decOpMap = map[int] decOp {
	 reflect.BoolKind: decBool,
	 reflect.IntKind: decInt,
	 reflect.Int8Kind: decInt8,
	 reflect.Int16Kind: decInt16,
	 reflect.Int32Kind: decInt32,
	 reflect.Int64Kind: decInt64,
	 reflect.UintKind: decUint,
	 reflect.Uint8Kind: decUint8,
	 reflect.Uint16Kind: decUint16,
	 reflect.Uint32Kind: decUint32,
	 reflect.Uint64Kind: decUint64,
	 reflect.FloatKind: decFloat,
	 reflect.Float32Kind: decFloat32,
	 reflect.Float64Kind: decFloat64,
}

func compileDec(rt reflect.Type, typ Type) *decEngine {
	srt, ok1 := rt.(reflect.StructType);
	styp, ok2 := typ.(*structType);
	if !ok1 || !ok2 {
		panicln("TODO: can't handle non-structs");
	}
	engine := new(decEngine);
	engine.instr = make([]decInstr, len(styp.field));
	for fieldnum := 0; fieldnum < len(styp.field); fieldnum++ {
		field := styp.field[fieldnum];
		// TODO(r): verify compatibility with corresponding field of data.
		// For now, assume perfect correspondence between struct and gob.
		_name, ftyp, _tag, offset := srt.Field(fieldnum);
		// How many indirections to the underlying data?
		indir := 0;
		for {
			pt, ok := ftyp.(reflect.PtrType);
			if !ok {
				break
			}
			ftyp = pt.Sub();
			indir++;
		}
		op, ok := decOpMap[ftyp.Kind()];
		if !ok {
			panicln("can't handle decode for type", ftyp.String());
		}
		engine.instr[fieldnum] = decInstr{op, fieldnum, indir, uintptr(offset)};
	}
	return engine;
}

func getDecEngine(rt reflect.Type) *decEngine {
	engine, ok := decEngineMap[rt];
	if !ok {
		return compileDec(rt, newType(rt.Name(), rt));
		decEngineMap[rt] = engine;
	}
	return engine;
}

func (engine *decEngine) decode(r io.Reader, v reflect.Value) os.Error {
	sv, ok := v.(reflect.StructValue);
	if !ok {
		panicln("decoder can't handle non-struct values yet");
	}
	state := new(DecState);
	state.r = r;
	state.base = uintptr(sv.Addr());
	state.fieldnum = -1;
	for state.err == nil {
		delta := int(DecodeUint(state));
		if state.err != nil || delta == 0 {	// struct terminator is zero delta fieldnum
			break
		}
		fieldnum := state.fieldnum + delta;
		if fieldnum >= len(engine.instr) {
			panicln("TODO(r): need to handle unknown data");
		}
		instr := &engine.instr[fieldnum];
		p := unsafe.Pointer(state.base+instr.offset);
		if instr.indir > 1 {
			p = decIndirect(p, instr.indir);
		}
		instr.op(instr, state, p);
		state.fieldnum = fieldnum;
	}
	return state.err
}

func Decode(r io.Reader, e interface{}) os.Error {
	// Dereference down to the underlying object.
	rt := reflect.Typeof(e);
	v := reflect.NewValue(e);
	for {
		pt, ok := rt.(reflect.PtrType);
		if !ok {
			break
		}
		rt = pt.Sub();
		v = reflect.Indirect(v);
	}
	typeLock.Lock();
	engine := getDecEngine(rt);
	typeLock.Unlock();
	return engine.decode(r, v);
}
<commit_msg>simplify decoders.  error checking is done higher up. if there is an error, we will write one more value into the struct but in return we do fewer tests in the decode.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gob

// TODO(rsc): When garbage collector changes, revisit
// the allocations in this file that use unsafe.Pointer.

import (
	"gob";
	"io";
	"math";
	"os";
	"reflect";
	"unsafe";
)

// The global execution state of an instance of the decoder.
type DecState struct {
	r	io.Reader;
	err	os.Error;
	base	uintptr;
	fieldnum	int;	// the last field number read.
	buf [1]byte;	// buffer used by the decoder; here to avoid allocation.
}

// DecodeUint reads an encoded unsigned integer from state.r.
// Sets state.err.  If state.err is already non-nil, it does nothing.
func DecodeUint(state *DecState) (x uint64) {
	if state.err != nil {
		return
	}
	for shift := uint(0);; shift += 7 {
		var n int;
		n, state.err = state.r.Read(&state.buf);
		if n != 1 {
			return 0
		}
		b := uint64(state.buf[0]);
		x |= b << shift;
		if b&0x80 != 0 {
			x &^= 0x80 << shift;
			break
		}
	}
	return x;
}

// DecodeInt reads an encoded signed integer from state.r.
// Sets state.err.  If state.err is already non-nil, it does nothing.
func DecodeInt(state *DecState) int64 {
	x := DecodeUint(state);
	if state.err != nil {
		return 0
	}
	if x & 1 != 0 {
		return ^int64(x>>1)
	}
	return int64(x >> 1)
}

type decInstr struct
type decOp func(i *decInstr, state *DecState, p unsafe.Pointer);

// The 'instructions' of the decoding machine
type decInstr struct {
	op	decOp;
	field		int;	// field number
	indir	int;	// how many pointer indirections to reach the value in the struct
	offset	uintptr;	// offset in the structure of the field to encode
}

// Since the encoder writes no zeros, if we arrive at a decoder we have
// a value to extract and store.  The field number has already been read
// (it's how we knew to call this decoder).
// Each decoder is responsible for handling any indirections associated
// with the data structure.  If any pointer so reached is nil, allocation must
// be done.

// Walk the pointer hierarchy, allocating if we find a nil.  Stop one before the end.
func decIndirect(p unsafe.Pointer, indir int) unsafe.Pointer {
	for ; indir > 1; indir-- {
		if *(*unsafe.Pointer)(p) == nil {
			// Allocation required
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(unsafe.Pointer));
		}
		p = *(*unsafe.Pointer)(p);
	}
	return p
}

func decBool(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(bool));
		}
		p = *(*unsafe.Pointer)(p);
	}
	*(*bool)(p) = DecodeInt(state) != 0;
}

func decInt(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(int));
		}
		p = *(*unsafe.Pointer)(p);
	}
	*(*int)(p) = int(DecodeInt(state));
}

func decUint(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint));
		}
		p = *(*unsafe.Pointer)(p);
	}
	*(*uint)(p) = uint(DecodeUint(state));
}

func decInt8(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(int8));
		}
		p = *(*unsafe.Pointer)(p);
	}
	*(*int8)(p) = int8(DecodeInt(state));
}

func decUint8(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint8));
		}
		p = *(*unsafe.Pointer)(p);
	}
	*(*uint8)(p) = uint8(DecodeUint(state));
}

func decInt16(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(int16));
		}
		p = *(*unsafe.Pointer)(p);
	}
	*(*int16)(p) = int16(DecodeInt(state));
}

func decUint16(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint16));
		}
		p = *(*unsafe.Pointer)(p);
	}
	*(*uint16)(p) = uint16(DecodeUint(state));
}

func decInt32(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(int32));
		}
		p = *(*unsafe.Pointer)(p);
	}
	*(*int32)(p) = int32(DecodeInt(state));
}

func decUint32(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint32));
		}
		p = *(*unsafe.Pointer)(p);
	}
	*(*uint32)(p) = uint32(DecodeUint(state));
}

func decInt64(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(int64));
		}
		p = *(*unsafe.Pointer)(p);
	}
	*(*int64)(p) = int64(DecodeInt(state));
}

func decUint64(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint64));
		}
		p = *(*unsafe.Pointer)(p);
	}
	*(*uint64)(p) = uint64(DecodeUint(state));
}

// Floating-point numbers are transmitted as uint64s holding the bits
// of the underlying representation.  They are sent byte-reversed, with
// the exponent end coming out first, so integer floating point numbers
// (for example) transmit more compactly.  This routine does the
// unswizzling.
func floatFromBits(u uint64) float64 {
	var v uint64;
	for i := 0; i < 8; i++ {
		v <<= 8;
		v |= u & 0xFF;
		u >>= 8;
	}
	return math.Float64frombits(v);
}

func decFloat(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(float));
		}
		p = *(*unsafe.Pointer)(p);
	}
	*(*float)(p) = float(floatFromBits(uint64(DecodeUint(state))));
}

func decFloat32(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(float32));
		}
		p = *(*unsafe.Pointer)(p);
	}
	*(*float32)(p) = float32(floatFromBits(uint64(DecodeUint(state))));
}

func decFloat64(i *decInstr, state *DecState, p unsafe.Pointer) {
	if i.indir > 0 {
		if *(*unsafe.Pointer)(p) == nil {
			*(*unsafe.Pointer)(p) = unsafe.Pointer(new(float64));
		}
		p = *(*unsafe.Pointer)(p);
	}
	*(*float64)(p) = floatFromBits(uint64(DecodeUint(state)));
}

// Execution engine

// The encoder engine is an array of instructions indexed by field number of the incoming
// data.  It is executed with random access according to field number.
type decEngine struct {
	instr	[]decInstr
}

var decEngineMap = make(map[reflect.Type] *decEngine)
var decOpMap = map[int] decOp {
	 reflect.BoolKind: decBool,
	 reflect.IntKind: decInt,
	 reflect.Int8Kind: decInt8,
	 reflect.Int16Kind: decInt16,
	 reflect.Int32Kind: decInt32,
	 reflect.Int64Kind: decInt64,
	 reflect.UintKind: decUint,
	 reflect.Uint8Kind: decUint8,
	 reflect.Uint16Kind: decUint16,
	 reflect.Uint32Kind: decUint32,
	 reflect.Uint64Kind: decUint64,
	 reflect.FloatKind: decFloat,
	 reflect.Float32Kind: decFloat32,
	 reflect.Float64Kind: decFloat64,
}

func compileDec(rt reflect.Type, typ Type) *decEngine {
	srt, ok1 := rt.(reflect.StructType);
	styp, ok2 := typ.(*structType);
	if !ok1 || !ok2 {
		panicln("TODO: can't handle non-structs");
	}
	engine := new(decEngine);
	engine.instr = make([]decInstr, len(styp.field));
	for fieldnum := 0; fieldnum < len(styp.field); fieldnum++ {
		field := styp.field[fieldnum];
		// TODO(r): verify compatibility with corresponding field of data.
		// For now, assume perfect correspondence between struct and gob.
		_name, ftyp, _tag, offset := srt.Field(fieldnum);
		// How many indirections to the underlying data?
		indir := 0;
		for {
			pt, ok := ftyp.(reflect.PtrType);
			if !ok {
				break
			}
			ftyp = pt.Sub();
			indir++;
		}
		op, ok := decOpMap[ftyp.Kind()];
		if !ok {
			panicln("can't handle decode for type", ftyp.String());
		}
		engine.instr[fieldnum] = decInstr{op, fieldnum, indir, uintptr(offset)};
	}
	return engine;
}

func getDecEngine(rt reflect.Type) *decEngine {
	engine, ok := decEngineMap[rt];
	if !ok {
		return compileDec(rt, newType(rt.Name(), rt));
		decEngineMap[rt] = engine;
	}
	return engine;
}

func (engine *decEngine) decode(r io.Reader, v reflect.Value) os.Error {
	sv, ok := v.(reflect.StructValue);
	if !ok {
		panicln("decoder can't handle non-struct values yet");
	}
	state := new(DecState);
	state.r = r;
	state.base = uintptr(sv.Addr());
	state.fieldnum = -1;
	for state.err == nil {
		delta := int(DecodeUint(state));
		if state.err != nil || delta == 0 {	// struct terminator is zero delta fieldnum
			break
		}
		fieldnum := state.fieldnum + delta;
		if fieldnum >= len(engine.instr) {
			panicln("TODO(r): need to handle unknown data");
		}
		instr := &engine.instr[fieldnum];
		p := unsafe.Pointer(state.base+instr.offset);
		if instr.indir > 1 {
			p = decIndirect(p, instr.indir);
		}
		instr.op(instr, state, p);
		state.fieldnum = fieldnum;
	}
	return state.err
}

func Decode(r io.Reader, e interface{}) os.Error {
	// Dereference down to the underlying object.
	rt := reflect.Typeof(e);
	v := reflect.NewValue(e);
	for {
		pt, ok := rt.(reflect.PtrType);
		if !ok {
			break
		}
		rt = pt.Sub();
		v = reflect.Indirect(v);
	}
	typeLock.Lock();
	engine := getDecEngine(rt);
	typeLock.Unlock();
	return engine.decode(r, v);
}
<|endoftext|>


<commit_before>// Copyright (C) 2013-2015 by Maxim Bublis <b@codemonkey.ru>
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// Package uuid provides implementation of Universally Unique Identifier (UUID).
// Supported versions are 1, 3, 4 and 5 (as specified in RFC 4122) and
// version 2 (as specified in DCE 1.1).
package rrutils

import (
	"flag"
	"fmt"
)

func check() {
	if !flag.Parsed() {
		flag.Parse()
	}
}

func FlagHelp() {
	flag.PrintDefaults()
}

func FlagDump() string {
	check()
	var ret string
	fn := func(f *flag.Flag) {
		ret += f.Name + "=" + f.Value.String() + "\n"
	}
	flag.Visit(fn)
	return ret
}

func FlagGetInt() int {
	return 0
}

func FlagGetString(option string) (string, error) {
	if op := flag.Lookup(option); op != nil {
		return op.Value.String(), nil
	} else {
		return "", fmt.Errorf("no option %s", option)
	}
}
<commit_msg>fix flag<commit_after>// Copyright (C) 2013-2015 by Maxim Bublis <b@codemonkey.ru>
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// Package uuid provides implementation of Universally Unique Identifier (UUID).
// Supported versions are 1, 3, 4 and 5 (as specified in RFC 4122) and
// version 2 (as specified in DCE 1.1).
package rrutils

import (
	"flag"
	"fmt"
)

func check() {
	if !flag.Parsed() {
		flag.Parse()
	}
}

func FlagHelp() {
	flag.PrintDefaults()
}

func FlagDump() string {
	check()
	var ret string
	fn := func(f *flag.Flag) {
		ret += f.Name + "=" + f.Value.String() + "\n"
	}
	flag.Visit(fn)
	return ret
}

func FlagIsSet(name string) bool {
	check()
	ret := false
	fn := func(f *flag.Flag) {
		if f.Name == name {
			ret = true
			return
		}
	}
	flag.Visit(fn)
	return ret
}

func FlagGetInt() int {
	return 0
}

func FlagGetString(option string) (string, error) {
	if op := flag.Lookup(option); op != nil {
		return op.Value.String(), nil
	} else {
		return "", fmt.Errorf("no option %s", option)
	}
}

func FlagGetBool(option string) (bool, error) {
	if op := flag.Lookup(option); op != nil {
		v := op.Value.String()
		if v == "true" {
			return true, nil
		}
		return false, nil
	} else {
		return false, fmt.Errorf("no option %s", option)
	}
}
<|endoftext|>


<commit_before>package utils

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"time"
)

type RestClient struct {
	Headers map[string]string

	client           *http.Client
	lastResponse     http.Response
	lastResponseBody []byte
}

func NewRestClient() *RestClient {
	timeout := time.Duration(5 * time.Second)
	return &RestClient{nil, &http.Client{Timeout: timeout}, http.Response{}, nil}
}

func (c *RestClient) Client() *http.Client {
	return c.Client()
}

func (c *RestClient) LastResponseBody() []byte {
	return c.lastResponseBody
}

func (c *RestClient) LastResponseStatus() int {
	return c.lastResponse.StatusCode
}

func doRequest(c *RestClient, req *http.Request) error {
	for name, value := range c.Headers {
		req.Header.Add(name, value)
	}
	response, err := c.client.Do(req)
	if err != nil {
		return err
	}
	defer response.Body.Close()
	c.lastResponse = *response
	c.lastResponseBody, err = ioutil.ReadAll(response.Body)
	return err
}

func (c *RestClient) GetWithBytes(url string, byteData []byte) error {
	req, err := http.NewRequest("GET", url, bytes.NewBuffer(byteData))
	if err != nil {
		return err
	}

	return doRequest(c, req)
}

func (c *RestClient) Get(url string) error {
	return c.GetWithBytes(url, nil)
}

func (c *RestClient) Post(url string, data io.Reader) error {

	req, err := http.NewRequest("POST", url, data)
	if err != nil {
		return err
	}

	return doRequest(c, req)
}

func (c *RestClient) PostString(url string, data string) error {
	return c.Post(url, bytes.NewBufferString(data))
}

func (c *RestClient) PostJson(url string, data interface{}) error {

	byteData, err := json.Marshal(data)
	if err != nil {
		return err
	}
	return c.Post(url, bytes.NewBuffer(byteData))
}

func (c *RestClient) Put(url string, data io.Reader) error {

	req, err := http.NewRequest("PUT", url, data)
	if err != nil {
		return err
	}

	return doRequest(c, req)
}

func (c *RestClient) PutString(url string, data string) error {
	return c.Put(url, bytes.NewBufferString(data))
}

func (c *RestClient) PutJson(url string, data interface{}) error {

	byteData, err := json.Marshal(data)
	if err != nil {
		return err
	}
	return c.Put(url, bytes.NewBuffer(byteData))
}
<commit_msg>Rest client can now set transport opts<commit_after>package utils

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"time"
)

type RestClient struct {
	Headers map[string]string

	client           *http.Client
	lastResponse     http.Response
	lastResponseBody []byte
}

type ClientOptsFunc func(*http.Client)

func NewRestClient(optFuncs ...ClientOptsFunc) *RestClient {
	timeout := time.Duration(5 * time.Second)
	c := &http.Client{Timeout: timeout}
	for _, f := range optFuncs {
		f(c)
	}
	return &RestClient{nil, c, http.Response{}, nil}
}

func (c *RestClient) Client() *http.Client {
	return c.Client()
}

func (c *RestClient) LastResponseBody() []byte {
	return c.lastResponseBody
}

func (c *RestClient) LastResponseStatus() int {
	return c.lastResponse.StatusCode
}

func doRequest(c *RestClient, req *http.Request) error {
	for name, value := range c.Headers {
		req.Header.Add(name, value)
	}
	response, err := c.client.Do(req)
	if err != nil {
		return err
	}
	defer response.Body.Close()
	c.lastResponse = *response
	c.lastResponseBody, err = ioutil.ReadAll(response.Body)
	return err
}

func (c *RestClient) GetWithBytes(url string, byteData []byte) error {
	req, err := http.NewRequest("GET", url, bytes.NewBuffer(byteData))
	if err != nil {
		return err
	}

	return doRequest(c, req)
}

func (c *RestClient) Get(url string) error {
	return c.GetWithBytes(url, nil)
}

func (c *RestClient) Post(url string, data io.Reader) error {

	req, err := http.NewRequest("POST", url, data)
	if err != nil {
		return err
	}

	return doRequest(c, req)
}

func (c *RestClient) PostString(url string, data string) error {
	return c.Post(url, bytes.NewBufferString(data))
}

func (c *RestClient) PostJson(url string, data interface{}) error {

	byteData, err := json.Marshal(data)
	if err != nil {
		return err
	}
	return c.Post(url, bytes.NewBuffer(byteData))
}

func (c *RestClient) Put(url string, data io.Reader) error {

	req, err := http.NewRequest("PUT", url, data)
	if err != nil {
		return err
	}

	return doRequest(c, req)
}

func (c *RestClient) PutString(url string, data string) error {
	return c.Put(url, bytes.NewBufferString(data))
}

func (c *RestClient) PutJson(url string, data interface{}) error {

	byteData, err := json.Marshal(data)
	if err != nil {
		return err
	}
	return c.Put(url, bytes.NewBuffer(byteData))
}
<|endoftext|>