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

package binloginfo_test

import (
	"net"
	"os"
	"sync"
	"testing"
	"time"

	"github.com/ngaut/log"
	. "github.com/pingcap/check"
	"github.com/pingcap/tidb"
	"github.com/pingcap/tidb/kv"
	"github.com/pingcap/tidb/sessionctx/binloginfo"
	"github.com/pingcap/tidb/store/tikv"
	"github.com/pingcap/tidb/util/codec"
	"github.com/pingcap/tidb/util/testkit"
	"github.com/pingcap/tidb/util/types"
	"github.com/pingcap/tipb/go-binlog"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
)

func TestT(t *testing.T) {
	TestingT(t)
}

type mockBinlogPump struct {
	mu struct {
		sync.Mutex
		payloads [][]byte
	}
}

func (p *mockBinlogPump) WriteBinlog(ctx context.Context, req *binlog.WriteBinlogReq) (*binlog.WriteBinlogResp, error) {
	p.mu.Lock()
	p.mu.payloads = append(p.mu.payloads, req.Payload)
	p.mu.Unlock()
	return &binlog.WriteBinlogResp{}, nil
}

// PullBinlogs implements PumpServer interface.
func (p *mockBinlogPump) PullBinlogs(ctx context.Context, req *binlog.PullBinlogReq) (*binlog.PullBinlogResp, error) {
	return &binlog.PullBinlogResp{}, nil
}

var _ = Suite(&testBinlogSuite{})

type testBinlogSuite struct {
	store    kv.Storage
	unixFile string
	serv     *grpc.Server
	pump     *mockBinlogPump
}

func (s *testBinlogSuite) SetUpSuite(c *C) {
	logLevel := os.Getenv("log_level")
	log.SetLevelByString(logLevel)
	store, err := tikv.NewMockTikvStore()
	c.Assert(err, IsNil)
	s.store = store
	tidb.SetSchemaLease(0)
	s.unixFile = "/tmp/mock-binlog-pump"
	l, err := net.Listen("unix", s.unixFile)
	c.Assert(err, IsNil)
	s.serv = grpc.NewServer()
	s.pump = new(mockBinlogPump)
	binlog.RegisterPumpServer(s.serv, s.pump)
	go s.serv.Serve(l)
	opt := grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
		return net.DialTimeout("unix", addr, timeout)
	})
	clientCon, err := grpc.Dial(s.unixFile, opt, grpc.WithInsecure())
	c.Assert(err, IsNil)
	c.Assert(clientCon, NotNil)
	binloginfo.PumpClient = binlog.NewPumpClient(clientCon)
}

func (s *testBinlogSuite) TearDownSuite(c *C) {
	binloginfo.PumpClient = nil
	s.serv.Stop()
	os.Remove(s.unixFile)
	s.store.Close()
}

func (s *testBinlogSuite) TestBinlog(c *C) {
	tk := testkit.NewTestKit(c, s.store)
	tk.MustExec("use test")
	pump := s.pump
	tk.MustExec("drop table if exists local_binlog")
	ddlQuery := "create table local_binlog (id int primary key, name varchar(10))"
	tk.MustExec(ddlQuery)
	time.Sleep(time.Millisecond)
	checkLatestBinlogDDL(c, pump, ddlQuery)

	tk.MustExec("insert local_binlog values (1, 'abc'), (2, 'cde')")
	prewriteVal := getLatestBinlogPrewriteValue(c, pump)
	c.Assert(prewriteVal.SchemaVersion, Greater, int64(0))
	c.Assert(prewriteVal.Mutations[0].TableId, Greater, int64(0))
	expected := [][]types.Datum{
		{types.NewIntDatum(1), types.NewStringDatum("abc")},
		{types.NewIntDatum(2), types.NewStringDatum("cde")},
	}
	gotRows := mutationRowsToRows(c, prewriteVal.Mutations[0].InsertedRows, 0, 2)
	c.Assert(gotRows, DeepEquals, expected)

	tk.MustExec("update local_binlog set name = 'xyz' where id = 2")
	prewriteVal = getLatestBinlogPrewriteValue(c, pump)
	expected = [][]types.Datum{
		{types.NewIntDatum(2), types.NewStringDatum("xyz")},
	}
	gotRows = mutationRowsToRows(c, prewriteVal.Mutations[0].UpdatedRows, 2, 4)
	c.Assert(gotRows, DeepEquals, expected)

	tk.MustExec("delete from local_binlog where id = 1")
	prewriteVal = getLatestBinlogPrewriteValue(c, pump)
	c.Assert(prewriteVal.Mutations[0].DeletedIds, DeepEquals, []int64{1})

	// Test table primary key is not integer.
	tk.MustExec("create table local_binlog2 (name varchar(64) primary key, age int)")
	tk.MustExec("insert local_binlog2 values ('abc', 16), ('def', 18)")
	tk.MustExec("delete from local_binlog2 where name = 'def'")
	prewriteVal = getLatestBinlogPrewriteValue(c, pump)
	_, deletedPK, _ := codec.DecodeOne(prewriteVal.Mutations[0].DeletedPks[0])
	c.Assert(deletedPK.GetString(), Equals, "def")

	// Test Table don't have primary key.
	tk.MustExec("create table local_binlog3 (c1 int, c2 int)")
	tk.MustExec("insert local_binlog3 values (1, 2), (1, 3), (2, 3)")
	tk.MustExec("update local_binlog3 set c1 = 3 where c1 = 2")
	prewriteVal = getLatestBinlogPrewriteValue(c, pump)
	gotRows = mutationRowsToRows(c, prewriteVal.Mutations[0].UpdatedRows, 5, 7)
	expected = [][]types.Datum{
		{types.NewIntDatum(3), types.NewIntDatum(3)},
	}
	c.Assert(gotRows, DeepEquals, expected)

	tk.MustExec("delete from local_binlog3 where c1 = 3 and c2 = 3")
	prewriteVal = getLatestBinlogPrewriteValue(c, pump)
	gotRows = mutationRowsToRows(c, prewriteVal.Mutations[0].DeletedRows, 1, 3)
	expected = [][]types.Datum{
		{types.NewIntDatum(3), types.NewIntDatum(3)},
	}
	c.Assert(gotRows, DeepEquals, expected)

	checkBinlogCount(c, pump)

	pump.mu.Lock()
	originBinlogLen := len(pump.mu.payloads)
	pump.mu.Unlock()
	tk.MustExec("set @@global.autocommit = 0")
	tk.MustExec("set @@global.autocommit = 1")
	pump.mu.Lock()
	newBinlogLen := len(pump.mu.payloads)
	pump.mu.Unlock()
	c.Assert(newBinlogLen, Equals, originBinlogLen)
}

func getLatestBinlogPrewriteValue(c *C, pump *mockBinlogPump) *binlog.PrewriteValue {
	var bin *binlog.Binlog
	pump.mu.Lock()
	for i := len(pump.mu.payloads) - 1; i >= 0; i-- {
		payload := pump.mu.payloads[i]
		bin = new(binlog.Binlog)
		bin.Unmarshal(payload)
		if bin.Tp == binlog.BinlogType_Prewrite {
			break
		}
	}
	pump.mu.Unlock()
	c.Assert(bin, NotNil)
	preVal := new(binlog.PrewriteValue)
	preVal.Unmarshal(bin.PrewriteValue)
	return preVal
}

func checkLatestBinlogDDL(c *C, pump *mockBinlogPump, ddlQuery string) {
	var preDDL, commitDDL *binlog.Binlog
	pump.mu.Lock()
	for i := len(pump.mu.payloads) - 1; i >= 0; i-- {
		payload := pump.mu.payloads[i]
		bin := new(binlog.Binlog)
		bin.Unmarshal(payload)
		if bin.Tp == binlog.BinlogType_Commit && bin.DdlJobId > 0 {
			commitDDL = bin
		}
		if bin.Tp == binlog.BinlogType_Prewrite && bin.DdlJobId != 0 {
			preDDL = bin
		}
		if preDDL != nil && commitDDL != nil {
			break
		}
	}
	pump.mu.Unlock()
	c.Assert(preDDL.DdlJobId, Greater, int64(0))
	c.Assert(preDDL.StartTs, Greater, int64(0))
	c.Assert(preDDL.CommitTs, Equals, int64(0))
	c.Assert(string(preDDL.DdlQuery), Equals, ddlQuery)
	c.Assert(commitDDL.StartTs, Equals, preDDL.StartTs)
	c.Assert(commitDDL.CommitTs, Greater, commitDDL.StartTs)
	c.Assert(commitDDL.DdlJobId, Equals, preDDL.DdlJobId)
	return
}

func checkBinlogCount(c *C, pump *mockBinlogPump) {
	var bin *binlog.Binlog
	prewriteCount := 0
	ddlCount := 0
	pump.mu.Lock()
	length := len(pump.mu.payloads)
	for i := length - 1; i >= 0; i-- {
		payload := pump.mu.payloads[i]
		bin = new(binlog.Binlog)
		bin.Unmarshal(payload)
		if bin.Tp == binlog.BinlogType_Prewrite {
			if bin.DdlJobId != 0 {
				ddlCount++
			} else {
				prewriteCount++
			}
		}
	}
	pump.mu.Unlock()
	c.Assert(ddlCount, Greater, 0)
	match := false
	for i := 0; i < 10; i++ {
		pump.mu.Lock()
		length = len(pump.mu.payloads)
		pump.mu.Unlock()
		if (prewriteCount+ddlCount)*2 == length {
			match = true
			break
		}
		time.Sleep(time.Millisecond * 10)
	}
	c.Assert(match, IsTrue)
}

func mutationRowsToRows(c *C, mutationRows [][]byte, firstColumn, secondColumn int) [][]types.Datum {
	var rows [][]types.Datum
	for _, mutationRow := range mutationRows {
		datums, err := codec.Decode(mutationRow, 5)
		c.Assert(err, IsNil)
		for i := range datums {
			if i != firstColumn && i != secondColumn {
				// Column ID or handle
				c.Assert(datums[i].GetInt64(), Greater, int64(0))
			}
			if datums[i].Kind() == types.KindBytes {
				datums[i].SetBytesAsString(datums[i].GetBytes())
			}
		}
		row := []types.Datum{datums[firstColumn], datums[secondColumn]}
		rows = append(rows, row)
	}
	return rows
}
<commit_msg>sessionctx/binloginfo: fix test. (#1926)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package binloginfo_test

import (
	"net"
	"os"
	"sync"
	"testing"
	"time"

	"github.com/ngaut/log"
	. "github.com/pingcap/check"
	"github.com/pingcap/tidb"
	"github.com/pingcap/tidb/kv"
	"github.com/pingcap/tidb/sessionctx/binloginfo"
	"github.com/pingcap/tidb/store/tikv"
	"github.com/pingcap/tidb/util/codec"
	"github.com/pingcap/tidb/util/testkit"
	"github.com/pingcap/tidb/util/types"
	"github.com/pingcap/tipb/go-binlog"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
)

func TestT(t *testing.T) {
	TestingT(t)
}

type mockBinlogPump struct {
	mu struct {
		sync.Mutex
		payloads [][]byte
	}
}

func (p *mockBinlogPump) WriteBinlog(ctx context.Context, req *binlog.WriteBinlogReq) (*binlog.WriteBinlogResp, error) {
	p.mu.Lock()
	p.mu.payloads = append(p.mu.payloads, req.Payload)
	p.mu.Unlock()
	return &binlog.WriteBinlogResp{}, nil
}

// PullBinlogs implements PumpServer interface.
func (p *mockBinlogPump) PullBinlogs(ctx context.Context, req *binlog.PullBinlogReq) (*binlog.PullBinlogResp, error) {
	return &binlog.PullBinlogResp{}, nil
}

var _ = Suite(&testBinlogSuite{})

type testBinlogSuite struct {
	store    kv.Storage
	unixFile string
	serv     *grpc.Server
	pump     *mockBinlogPump
}

func (s *testBinlogSuite) SetUpSuite(c *C) {
	logLevel := os.Getenv("log_level")
	log.SetLevelByString(logLevel)
	store, err := tikv.NewMockTikvStore()
	c.Assert(err, IsNil)
	s.store = store
	tidb.SetSchemaLease(0)
	s.unixFile = "/tmp/mock-binlog-pump"
	l, err := net.Listen("unix", s.unixFile)
	c.Assert(err, IsNil)
	s.serv = grpc.NewServer()
	s.pump = new(mockBinlogPump)
	binlog.RegisterPumpServer(s.serv, s.pump)
	go s.serv.Serve(l)
	opt := grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
		return net.DialTimeout("unix", addr, timeout)
	})
	clientCon, err := grpc.Dial(s.unixFile, opt, grpc.WithInsecure())
	c.Assert(err, IsNil)
	c.Assert(clientCon, NotNil)
	binloginfo.PumpClient = binlog.NewPumpClient(clientCon)
}

func (s *testBinlogSuite) TearDownSuite(c *C) {
	binloginfo.PumpClient = nil
	s.serv.Stop()
	os.Remove(s.unixFile)
	s.store.Close()
}

func (s *testBinlogSuite) TestBinlog(c *C) {
	tk := testkit.NewTestKit(c, s.store)
	tk.MustExec("use test")
	pump := s.pump
	tk.MustExec("drop table if exists local_binlog")
	ddlQuery := "create table local_binlog (id int primary key, name varchar(10))"
	tk.MustExec(ddlQuery)
	var matched bool // got matched pre DDL and commit DDL
	for i := 0; i < 10; i++ {
		preDDL, commitDDL := getLatestDDLBinlog(c, pump, ddlQuery)
		if preDDL.DdlJobId == commitDDL.DdlJobId {
			c.Assert(commitDDL.StartTs, Equals, preDDL.StartTs)
			c.Assert(commitDDL.CommitTs, Greater, commitDDL.StartTs)
			matched = true
			break
		}
		time.Sleep(time.Millisecond * 10)
	}
	c.Assert(matched, IsTrue)

	tk.MustExec("insert local_binlog values (1, 'abc'), (2, 'cde')")
	prewriteVal := getLatestBinlogPrewriteValue(c, pump)
	c.Assert(prewriteVal.SchemaVersion, Greater, int64(0))
	c.Assert(prewriteVal.Mutations[0].TableId, Greater, int64(0))
	expected := [][]types.Datum{
		{types.NewIntDatum(1), types.NewStringDatum("abc")},
		{types.NewIntDatum(2), types.NewStringDatum("cde")},
	}
	gotRows := mutationRowsToRows(c, prewriteVal.Mutations[0].InsertedRows, 0, 2)
	c.Assert(gotRows, DeepEquals, expected)

	tk.MustExec("update local_binlog set name = 'xyz' where id = 2")
	prewriteVal = getLatestBinlogPrewriteValue(c, pump)
	expected = [][]types.Datum{
		{types.NewIntDatum(2), types.NewStringDatum("xyz")},
	}
	gotRows = mutationRowsToRows(c, prewriteVal.Mutations[0].UpdatedRows, 2, 4)
	c.Assert(gotRows, DeepEquals, expected)

	tk.MustExec("delete from local_binlog where id = 1")
	prewriteVal = getLatestBinlogPrewriteValue(c, pump)
	c.Assert(prewriteVal.Mutations[0].DeletedIds, DeepEquals, []int64{1})

	// Test table primary key is not integer.
	tk.MustExec("create table local_binlog2 (name varchar(64) primary key, age int)")
	tk.MustExec("insert local_binlog2 values ('abc', 16), ('def', 18)")
	tk.MustExec("delete from local_binlog2 where name = 'def'")
	prewriteVal = getLatestBinlogPrewriteValue(c, pump)
	_, deletedPK, _ := codec.DecodeOne(prewriteVal.Mutations[0].DeletedPks[0])
	c.Assert(deletedPK.GetString(), Equals, "def")

	// Test Table don't have primary key.
	tk.MustExec("create table local_binlog3 (c1 int, c2 int)")
	tk.MustExec("insert local_binlog3 values (1, 2), (1, 3), (2, 3)")
	tk.MustExec("update local_binlog3 set c1 = 3 where c1 = 2")
	prewriteVal = getLatestBinlogPrewriteValue(c, pump)
	gotRows = mutationRowsToRows(c, prewriteVal.Mutations[0].UpdatedRows, 5, 7)
	expected = [][]types.Datum{
		{types.NewIntDatum(3), types.NewIntDatum(3)},
	}
	c.Assert(gotRows, DeepEquals, expected)

	tk.MustExec("delete from local_binlog3 where c1 = 3 and c2 = 3")
	prewriteVal = getLatestBinlogPrewriteValue(c, pump)
	gotRows = mutationRowsToRows(c, prewriteVal.Mutations[0].DeletedRows, 1, 3)
	expected = [][]types.Datum{
		{types.NewIntDatum(3), types.NewIntDatum(3)},
	}
	c.Assert(gotRows, DeepEquals, expected)

	checkBinlogCount(c, pump)

	pump.mu.Lock()
	originBinlogLen := len(pump.mu.payloads)
	pump.mu.Unlock()
	tk.MustExec("set @@global.autocommit = 0")
	tk.MustExec("set @@global.autocommit = 1")
	pump.mu.Lock()
	newBinlogLen := len(pump.mu.payloads)
	pump.mu.Unlock()
	c.Assert(newBinlogLen, Equals, originBinlogLen)
}

func getLatestBinlogPrewriteValue(c *C, pump *mockBinlogPump) *binlog.PrewriteValue {
	var bin *binlog.Binlog
	pump.mu.Lock()
	for i := len(pump.mu.payloads) - 1; i >= 0; i-- {
		payload := pump.mu.payloads[i]
		bin = new(binlog.Binlog)
		bin.Unmarshal(payload)
		if bin.Tp == binlog.BinlogType_Prewrite {
			break
		}
	}
	pump.mu.Unlock()
	c.Assert(bin, NotNil)
	preVal := new(binlog.PrewriteValue)
	preVal.Unmarshal(bin.PrewriteValue)
	return preVal
}

func getLatestDDLBinlog(c *C, pump *mockBinlogPump, ddlQuery string) (preDDL, commitDDL *binlog.Binlog) {
	pump.mu.Lock()
	for i := len(pump.mu.payloads) - 1; i >= 0; i-- {
		payload := pump.mu.payloads[i]
		bin := new(binlog.Binlog)
		bin.Unmarshal(payload)
		if bin.Tp == binlog.BinlogType_Commit && bin.DdlJobId > 0 {
			commitDDL = bin
		}
		if bin.Tp == binlog.BinlogType_Prewrite && bin.DdlJobId != 0 {
			preDDL = bin
		}
		if preDDL != nil && commitDDL != nil {
			break
		}
	}
	pump.mu.Unlock()
	c.Assert(preDDL.DdlJobId, Greater, int64(0))
	c.Assert(preDDL.StartTs, Greater, int64(0))
	c.Assert(preDDL.CommitTs, Equals, int64(0))
	c.Assert(string(preDDL.DdlQuery), Equals, ddlQuery)
	return
}

func checkBinlogCount(c *C, pump *mockBinlogPump) {
	var bin *binlog.Binlog
	prewriteCount := 0
	ddlCount := 0
	pump.mu.Lock()
	length := len(pump.mu.payloads)
	for i := length - 1; i >= 0; i-- {
		payload := pump.mu.payloads[i]
		bin = new(binlog.Binlog)
		bin.Unmarshal(payload)
		if bin.Tp == binlog.BinlogType_Prewrite {
			if bin.DdlJobId != 0 {
				ddlCount++
			} else {
				prewriteCount++
			}
		}
	}
	pump.mu.Unlock()
	c.Assert(ddlCount, Greater, 0)
	match := false
	for i := 0; i < 10; i++ {
		pump.mu.Lock()
		length = len(pump.mu.payloads)
		pump.mu.Unlock()
		if (prewriteCount+ddlCount)*2 == length {
			match = true
			break
		}
		time.Sleep(time.Millisecond * 10)
	}
	c.Assert(match, IsTrue)
}

func mutationRowsToRows(c *C, mutationRows [][]byte, firstColumn, secondColumn int) [][]types.Datum {
	var rows [][]types.Datum
	for _, mutationRow := range mutationRows {
		datums, err := codec.Decode(mutationRow, 5)
		c.Assert(err, IsNil)
		for i := range datums {
			if i != firstColumn && i != secondColumn {
				// Column ID or handle
				c.Assert(datums[i].GetInt64(), Greater, int64(0))
			}
			if datums[i].Kind() == types.KindBytes {
				datums[i].SetBytesAsString(datums[i].GetBytes())
			}
		}
		row := []types.Datum{datums[firstColumn], datums[secondColumn]}
		rows = append(rows, row)
	}
	return rows
}
<|endoftext|>


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

package mathcat

import (
	"fmt"
	"math"
	"math/rand"
)

type function struct {
	arity int
	fn    func(args []float64) float64
}

type functions map[string]*function

// Functions holds all the function names that are available for use
var Functions []string

var funcs functions = make(functions)

func (f functions) register(name string, function *function) {
	Functions = append(Functions, name)
	f[name] = function
}

func init() {
	funcs.register("abs", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return math.Abs(args[0])
		},
	})
	funcs.register("ceil", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return math.Ceil(args[0])
		},
	})
	funcs.register("floor", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return math.Floor(args[0])
		},
	})
	funcs.register("sin", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return math.Sin(args[0])
		},
	})
	funcs.register("cos", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return math.Cos(args[0])
		},
	})
	funcs.register("tan", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return math.Tan(args[0])
		},
	})
	funcs.register("asin", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return math.Asin(args[0])
		},
	})
	funcs.register("acos", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return math.Acos(args[0])
		},
	})
	funcs.register("atan", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return math.Atan(args[0])
		},
	})
	funcs.register("log", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return math.Log(args[0])
		},
	})
	funcs.register("max", &function{
		arity: 2,
		fn: func(args []float64) float64 {
			return math.Max(args[0], args[1])
		},
	})
	funcs.register("min", &function{
		arity: 2,
		fn: func(args []float64) float64 {
			return math.Min(args[0], args[1])
		},
	})
	funcs.register("sqrt", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return math.Sqrt(args[0])
		},
	})
	funcs.register("rand", &function{
		arity: 0,
		fn: func(_ []float64) float64 {
			return rand.Float64()
		},
	})
	funcs.register("fact", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return factorial(args[0])
		},
	})
	funcs.register("gcd", &function{
		arity: 2,
		fn: func(args []float64) float64 {
			return gcd(args[0], args[1])
		},
	})
	funcs.register("list", &function{
		arity: 0,
		fn: func(_ []float64) float64 {
			for _, name := range Functions {
				fmt.Printf(name + " ")
			}
			fmt.Println()
			return 0
		},
	})
}

func factorial(n float64) float64 {
	if n == 0 {
		return 1
	}

	return n * factorial(n-1)
}

func gcd(x, y float64) float64 {
	for y != 0 {
		x, y = y, math.Mod(x, y)
	}

	return x
}
<commit_msg>Omit type in funcs variable<commit_after>// Copyright 2016 Steven Oud. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be found
// in the LICENSE file.

package mathcat

import (
	"fmt"
	"math"
	"math/rand"
)

type function struct {
	arity int
	fn    func(args []float64) float64
}

type functions map[string]*function

// Functions holds all the function names that are available for use
var Functions []string

var funcs = make(functions)

func (f functions) register(name string, function *function) {
	Functions = append(Functions, name)
	f[name] = function
}

func init() {
	funcs.register("abs", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return math.Abs(args[0])
		},
	})
	funcs.register("ceil", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return math.Ceil(args[0])
		},
	})
	funcs.register("floor", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return math.Floor(args[0])
		},
	})
	funcs.register("sin", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return math.Sin(args[0])
		},
	})
	funcs.register("cos", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return math.Cos(args[0])
		},
	})
	funcs.register("tan", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return math.Tan(args[0])
		},
	})
	funcs.register("asin", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return math.Asin(args[0])
		},
	})
	funcs.register("acos", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return math.Acos(args[0])
		},
	})
	funcs.register("atan", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return math.Atan(args[0])
		},
	})
	funcs.register("log", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return math.Log(args[0])
		},
	})
	funcs.register("max", &function{
		arity: 2,
		fn: func(args []float64) float64 {
			return math.Max(args[0], args[1])
		},
	})
	funcs.register("min", &function{
		arity: 2,
		fn: func(args []float64) float64 {
			return math.Min(args[0], args[1])
		},
	})
	funcs.register("sqrt", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return math.Sqrt(args[0])
		},
	})
	funcs.register("rand", &function{
		arity: 0,
		fn: func(_ []float64) float64 {
			return rand.Float64()
		},
	})
	funcs.register("fact", &function{
		arity: 1,
		fn: func(args []float64) float64 {
			return factorial(args[0])
		},
	})
	funcs.register("gcd", &function{
		arity: 2,
		fn: func(args []float64) float64 {
			return gcd(args[0], args[1])
		},
	})
	funcs.register("list", &function{
		arity: 0,
		fn: func(_ []float64) float64 {
			for _, name := range Functions {
				fmt.Printf(name + " ")
			}
			fmt.Println()
			return 0
		},
	})
}

func factorial(n float64) float64 {
	if n == 0 {
		return 1
	}

	return n * factorial(n-1)
}

func gcd(x, y float64) float64 {
	for y != 0 {
		x, y = y, math.Mod(x, y)
	}

	return x
}
<|endoftext|>


<commit_before>package config

// Rf settings for CC1101
const (
    IOCFG2 = 0x29         // GDO2 Output Pin Configuration
    IOCFG1 = 0x2e         // GDO1 Output Pin Configuration
    IOCFG0 = 0x06         // GDO0 Output Pin Configuration
    FIFOTHR = 0x47        // RX FIFO and TX FIFO Thresholds
    SYNC1 = 0xd3          // Sync Word, High Byte
    SYNC0 = 0x91          // Sync Word, Low Byte
    PKTLEN = 0x3d         // Packet Length
    PKTCTRL1 = 0x04       // Packet Automation Control
    PKTCTRL0 = 0x05       // Packet Automation Control
    ADDR = 0x00           // Device Address
    CHANNR = 0x00         // Channel Number
    FSCTRL1 = 0x06        // Frequency Synthesizer Control
    FSCTRL0 = 0x00        // Frequency Synthesizer Control
    FREQ2 = 0x21          // Frequency Control Word, High Byte
    FREQ1 = 0x65          // Frequency Control Word, Middle Byte
    FREQ0 = 0x44          // Frequency Control Word, Low Byte
    MDMCFG4 = 0xf5        // Modem Configuration
    MDMCFG3 = 0x83        // Modem Configuration
    MDMCFG2 = 0x03        // Modem Configuration
    MDMCFG1 = 0x22        // Modem Configuration
    MDMCFG0 = 0xf8        // Modem Configuration
    DEVIATN = 0x34        // Modem Deviation Setting
    MCSM2 = 0x07          // Main Radio Control State Machine Configuration
    MCSM1 = 0x30          // Main Radio Control State Machine Configuration
    MCSM0 = 0x18          // Main Radio Control State Machine Configuration
    FOCCFG = 0x16         // Frequency Offset Compensation Configuration
    BSCFG = 0x6c          // Bit Synchronization Configuration
    AGCCTRL2 = 0x03       // AGC Control
    AGCCTRL1 = 0x40       // AGC Control
    AGCCTRL0 = 0x91       // AGC Control
    WOREVT1 = 0x87        // High Byte Event0 Timeout
    WOREVT0 = 0x6b        // Low Byte Event0 Timeout
    WORCTRL = 0xfb        // Wake On Radio Control
    FREND1 = 0x56         // Front End RX Configuration
    FREND0 = 0x10         // Front End TX Configuration
    FSCAL3 = 0xe9         // Frequency Synthesizer Calibration
    FSCAL2 = 0x2a         // Frequency Synthesizer Calibration
    FSCAL1 = 0x00         // Frequency Synthesizer Calibration
    FSCAL0 = 0x1f         // Frequency Synthesizer Calibration
    RCCTRL1 = 0x41        // RC Oscillator Configuration
    RCCTRL0 = 0x00        // RC Oscillator Configuration
    FSTEST = 0x59         // Frequency Synthesizer Calibration Control
    PTEST = 0x7f          // Production Test
    AGCTEST = 0x3f        // AGC Test
    TEST2 = 0x81          // Various Test Settings
    TEST1 = 0x35          // Various Test Settings
    TEST0 = 0x09          // Various Test Settings
    PARTNUM = 0x00        // Chip ID
    VERSION = 0x04        // Chip ID
    FREQEST = 0x00        // Frequency Offset Estimate from Demodulator
    LQI = 0x00            // Demodulator Estimate for Link Quality
    RSSI = 0x00           // Received Signal Strength Indication
    MARCSTATE = 0x00      // Main Radio Control State Machine State
    WORTIME1 = 0x00       // High Byte of WOR Time
    WORTIME0 = 0x00       // Low Byte of WOR Time
    PKTSTATUS = 0x00      // Current GDOx Status and Packet Status
    VCO_VC_DAC = 0x00     // Current Setting from PLL Calibration Module
    TXBYTES = 0x00        // Underflow and Number of Bytes
    RXBYTES = 0x00        // Overflow and Number of Bytes
    RCCTRL1_STATUS = 0x00 // Last RC Oscillator Calibration Result
    RCCTRL0_STATUS = 0x00 // Last RC Oscillator Calibration Result
)
<commit_msg>Only interrupt for packets with valid CRC<commit_after>package config

// Rf settings for CC1101
const (
    IOCFG2 = 0x29         // GDO2 Output Pin Configuration
    IOCFG1 = 0x2e         // GDO1 Output Pin Configuration
    IOCFG0 = 0x07         // GDO0 Output Pin Configuration
    FIFOTHR = 0x47        // RX FIFO and TX FIFO Thresholds
    SYNC1 = 0xd3          // Sync Word, High Byte
    SYNC0 = 0x91          // Sync Word, Low Byte
    PKTLEN = 0x3d         // Packet Length
    PKTCTRL1 = 0x04       // Packet Automation Control
    PKTCTRL0 = 0x05       // Packet Automation Control
    ADDR = 0x00           // Device Address
    CHANNR = 0x00         // Channel Number
    FSCTRL1 = 0x06        // Frequency Synthesizer Control
    FSCTRL0 = 0x00        // Frequency Synthesizer Control
    FREQ2 = 0x21          // Frequency Control Word, High Byte
    FREQ1 = 0x65          // Frequency Control Word, Middle Byte
    FREQ0 = 0x44          // Frequency Control Word, Low Byte
    MDMCFG4 = 0xf5        // Modem Configuration
    MDMCFG3 = 0x83        // Modem Configuration
    MDMCFG2 = 0x03        // Modem Configuration
    MDMCFG1 = 0x22        // Modem Configuration
    MDMCFG0 = 0xf8        // Modem Configuration
    DEVIATN = 0x34        // Modem Deviation Setting
    MCSM2 = 0x07          // Main Radio Control State Machine Configuration
    MCSM1 = 0x30          // Main Radio Control State Machine Configuration
    MCSM0 = 0x18          // Main Radio Control State Machine Configuration
    FOCCFG = 0x16         // Frequency Offset Compensation Configuration
    BSCFG = 0x6c          // Bit Synchronization Configuration
    AGCCTRL2 = 0x03       // AGC Control
    AGCCTRL1 = 0x40       // AGC Control
    AGCCTRL0 = 0x91       // AGC Control
    WOREVT1 = 0x87        // High Byte Event0 Timeout
    WOREVT0 = 0x6b        // Low Byte Event0 Timeout
    WORCTRL = 0xfb        // Wake On Radio Control
    FREND1 = 0x56         // Front End RX Configuration
    FREND0 = 0x10         // Front End TX Configuration
    FSCAL3 = 0xe9         // Frequency Synthesizer Calibration
    FSCAL2 = 0x2a         // Frequency Synthesizer Calibration
    FSCAL1 = 0x00         // Frequency Synthesizer Calibration
    FSCAL0 = 0x1f         // Frequency Synthesizer Calibration
    RCCTRL1 = 0x41        // RC Oscillator Configuration
    RCCTRL0 = 0x00        // RC Oscillator Configuration
    FSTEST = 0x59         // Frequency Synthesizer Calibration Control
    PTEST = 0x7f          // Production Test
    AGCTEST = 0x3f        // AGC Test
    TEST2 = 0x81          // Various Test Settings
    TEST1 = 0x35          // Various Test Settings
    TEST0 = 0x09          // Various Test Settings
    PARTNUM = 0x00        // Chip ID
    VERSION = 0x04        // Chip ID
    FREQEST = 0x00        // Frequency Offset Estimate from Demodulator
    LQI = 0x00            // Demodulator Estimate for Link Quality
    RSSI = 0x00           // Received Signal Strength Indication
    MARCSTATE = 0x00      // Main Radio Control State Machine State
    WORTIME1 = 0x00       // High Byte of WOR Time
    WORTIME0 = 0x00       // Low Byte of WOR Time
    PKTSTATUS = 0x00      // Current GDOx Status and Packet Status
    VCO_VC_DAC = 0x00     // Current Setting from PLL Calibration Module
    TXBYTES = 0x00        // Underflow and Number of Bytes
    RXBYTES = 0x00        // Overflow and Number of Bytes
    RCCTRL1_STATUS = 0x00 // Last RC Oscillator Calibration Result
    RCCTRL0_STATUS = 0x00 // Last RC Oscillator Calibration Result
)
<|endoftext|>


<commit_before>package jekyll

import (
	"github.com/parkr/auto-reply/autopull"
	"github.com/parkr/auto-reply/ctx"
	"github.com/parkr/auto-reply/hooks"
	"github.com/parkr/auto-reply/labeler"
	"github.com/parkr/auto-reply/lgtm"

	"github.com/parkr/auto-reply/jekyll/deprecate"
	"github.com/parkr/auto-reply/jekyll/issuecomment"
)

var lgtmEnabledRepos = []lgtm.Repo{{Owner: "jekyll", Name: "import", Quorum: 1}}

var jekyllOrgEventHandlers = map[hooks.EventType][]hooks.EventHandler{
	hooks.IssuesEvent: {deprecate.DeprecateOldRepos},
	hooks.IssueCommentEvent: {
		issuecomment.PendingFeedbackUnlabeler, issuecomment.StaleUnlabeler,
		issuecomment.MergeAndLabel, lgtm.NewIssueCommentHandler(lgtmEnabledRepos),
	},
	hooks.PushEvent: {autopull.AutomaticallyCreatePullRequest("jekyll/jekyll")},
	hooks.PullRequestEvent: {
		labeler.PendingRebaseNeedsWorkPRUnlabeler,
		lgtm.NewPullRequestHandler(lgtmEnabledRepos),
	},
}

func NewJekyllOrgHandler(context *ctx.Context) *hooks.GlobalHandler {
	return &hooks.GlobalHandler{
		Context:       context,
		EventHandlers: jekyllOrgEventHandlers,
	}
}
<commit_msg>Oh, the repo's called 'jekyll-import'.<commit_after>package jekyll

import (
	"github.com/parkr/auto-reply/autopull"
	"github.com/parkr/auto-reply/ctx"
	"github.com/parkr/auto-reply/hooks"
	"github.com/parkr/auto-reply/labeler"
	"github.com/parkr/auto-reply/lgtm"

	"github.com/parkr/auto-reply/jekyll/deprecate"
	"github.com/parkr/auto-reply/jekyll/issuecomment"
)

var lgtmEnabledRepos = []lgtm.Repo{{Owner: "jekyll", Name: "jekyll-import", Quorum: 1}}

var jekyllOrgEventHandlers = map[hooks.EventType][]hooks.EventHandler{
	hooks.IssuesEvent: {deprecate.DeprecateOldRepos},
	hooks.IssueCommentEvent: {
		issuecomment.PendingFeedbackUnlabeler, issuecomment.StaleUnlabeler,
		issuecomment.MergeAndLabel, lgtm.NewIssueCommentHandler(lgtmEnabledRepos),
	},
	hooks.PushEvent: {autopull.AutomaticallyCreatePullRequest("jekyll/jekyll")},
	hooks.PullRequestEvent: {
		labeler.PendingRebaseNeedsWorkPRUnlabeler,
		lgtm.NewPullRequestHandler(lgtmEnabledRepos),
	},
}

func NewJekyllOrgHandler(context *ctx.Context) *hooks.GlobalHandler {
	return &hooks.GlobalHandler{
		Context:       context,
		EventHandlers: jekyllOrgEventHandlers,
	}
}
<|endoftext|>


<commit_before>// Copyright 2010 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 textproto implements generic support for text-based request/response
// protocols in the style of HTTP, NNTP, and SMTP.
//
// The package provides:
//
// Error, which represents a numeric error response from
// a server.
//
// Pipeline, to manage pipelined requests and responses
// in a client.
//
// Reader, to read numeric response code lines,
// key: value headers, lines wrapped with leading spaces
// on continuation lines, and whole text blocks ending
// with a dot on a line by itself.
//
// Writer, to write dot-encoded text blocks.
//
// Conn, a convenient packaging of Reader, Writer, and Pipeline for use
// with a single network connection.
//
package textproto

import (
	"bufio"
	"fmt"
	"io"
	"net"
)

// An Error represents a numeric error response from a server.
type Error struct {
	Code int
	Msg  string
}

func (e *Error) Error() string {
	return fmt.Sprintf("%03d %s", e.Code, e.Msg)
}

// A ProtocolError describes a protocol violation such
// as an invalid response or a hung-up connection.
type ProtocolError string

func (p ProtocolError) Error() string {
	return string(p)
}

// A Conn represents a textual network protocol connection.
// It consists of a Reader and Writer to manage I/O
// and a Pipeline to sequence concurrent requests on the connection.
// These embedded types carry methods with them;
// see the documentation of those types for details.
type Conn struct {
	Reader
	Writer
	Pipeline
	conn io.ReadWriteCloser
}

// NewConn returns a new Conn using conn for I/O.
func NewConn(conn io.ReadWriteCloser) *Conn {
	return &Conn{
		Reader: Reader{R: bufio.NewReader(conn)},
		Writer: Writer{W: bufio.NewWriter(conn)},
		conn:   conn,
	}
}

// Close closes the connection.
func (c *Conn) Close() error {
	return c.conn.Close()
}

// Dial connects to the given address on the given network using net.Dial
// and then returns a new Conn for the connection.
func Dial(network, addr string) (*Conn, error) {
	c, err := net.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	return NewConn(c), nil
}

// Cmd is a convenience method that sends a command after
// waiting its turn in the pipeline.  The command text is the
// result of formatting format with args and appending \r\n.
// Cmd returns the id of the command, for use with StartResponse and EndResponse.
//
// For example, a client might run a HELP command that returns a dot-body
// by using:
//
//	id, err := c.Cmd("HELP")
//	if err != nil {
//		return nil, err
//	}
//
//	c.StartResponse(id)
//	defer c.EndResponse(id)
//
//	if _, _, err = c.ReadCodeLine(110); err != nil {
//		return nil, err
//	}
//	text, err := c.ReadDotBytes()
//	if err != nil {
//		return nil, err
//	}
//	return c.ReadCodeLine(250)
//
func (c *Conn) Cmd(format string, args ...interface{}) (id uint, err error) {
	id = c.Next()
	c.StartRequest(id)
	err = c.PrintfLine(format, args...)
	c.EndRequest(id)
	if err != nil {
		return 0, err
	}
	return id, nil
}

// TrimString returns s without leading and trailing ASCII space.
func TrimString(s string) string {
	for len(s) > 0 && isASCIISpace(s[0]) {
		s = s[1:]
	}
	for len(s) > 0 && isASCIISpace(s[len(s)-1]) {
		s = s[:len(s)-1]
	}
	return s
}

// TrimBytes returns b without leading and trailing ASCII space.
func TrimBytes(b []byte) []byte {
	for len(b) > 0 && isASCIISpace(b[0]) {
		b = b[1:]
	}
	for len(b) > 0 && isASCIISpace(b[len(b)-1]) {
		b = b[:len(b)-1]
	}
	return b
}

func isASCIISpace(b byte) bool {
	return b == ' ' || b == '\t' || b == '\n' || b == '\r'
}

func isASCIILetter(b byte) bool {
	b |= 0x20 // make lower case
	return 'a' <= b && b <= 'z'
}
<commit_msg>net/textproto: Use sync.Pool for bufio.{Reader,Writer}<commit_after>// Copyright 2010 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 textproto implements generic support for text-based request/response
// protocols in the style of HTTP, NNTP, and SMTP.
//
// The package provides:
//
// Error, which represents a numeric error response from
// a server.
//
// Pipeline, to manage pipelined requests and responses
// in a client.
//
// Reader, to read numeric response code lines,
// key: value headers, lines wrapped with leading spaces
// on continuation lines, and whole text blocks ending
// with a dot on a line by itself.
//
// Writer, to write dot-encoded text blocks.
//
// Conn, a convenient packaging of Reader, Writer, and Pipeline for use
// with a single network connection.
//
package textproto

import (
	"bufio"
	"fmt"
	"io"
	"net"
	"sync"
)

var (
	bufioReaderPool sync.Pool
	bufioWriterPool sync.Pool
)

func newBufioReader(r io.Reader) *bufio.Reader {
	if v := bufioReaderPool.Get(); v != nil {
		br := v.(*bufio.Reader)
		br.Reset(r)
		return br
	}
	return bufio.NewReader(r)
}

func putBufioReader(br *bufio.Reader) {
	br.Reset(nil)
	bufioReaderPool.Put(br)
}

func newBufioWriter(w io.Writer) *bufio.Writer {
	if v := bufioWriterPool.Get(); v != nil {
		bw := v.(*bufio.Writer)
		bw.Reset(w)
		return bw
	}
	return bufio.NewWriter(w)
}

func putBufioWriter(bw *bufio.Writer) {
	bw.Reset(nil)
	bufioWriterPool.Put(bw)
}

// An Error represents a numeric error response from a server.
type Error struct {
	Code int
	Msg  string
}

func (e *Error) Error() string {
	return fmt.Sprintf("%03d %s", e.Code, e.Msg)
}

// A ProtocolError describes a protocol violation such
// as an invalid response or a hung-up connection.
type ProtocolError string

func (p ProtocolError) Error() string {
	return string(p)
}

// A Conn represents a textual network protocol connection.
// It consists of a Reader and Writer to manage I/O
// and a Pipeline to sequence concurrent requests on the connection.
// These embedded types carry methods with them;
// see the documentation of those types for details.
type Conn struct {
	Reader
	Writer
	Pipeline
	conn io.ReadWriteCloser
}

// NewConn returns a new Conn using conn for I/O.
func NewConn(conn io.ReadWriteCloser) *Conn {
	return &Conn{
		Reader: Reader{R: newBufioReader(conn)},
		Writer: Writer{W: newBufioWriter(conn)},
		conn:   conn,
	}
}

// Close closes the connection.
func (c *Conn) Close() error {
	err := c.conn.Close()
	putBufioReader(c.Reader.R)
	putBufioWriter(c.Writer.W)
	return err
}

// Dial connects to the given address on the given network using net.Dial
// and then returns a new Conn for the connection.
func Dial(network, addr string) (*Conn, error) {
	c, err := net.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	return NewConn(c), nil
}

// Cmd is a convenience method that sends a command after
// waiting its turn in the pipeline.  The command text is the
// result of formatting format with args and appending \r\n.
// Cmd returns the id of the command, for use with StartResponse and EndResponse.
//
// For example, a client might run a HELP command that returns a dot-body
// by using:
//
//	id, err := c.Cmd("HELP")
//	if err != nil {
//		return nil, err
//	}
//
//	c.StartResponse(id)
//	defer c.EndResponse(id)
//
//	if _, _, err = c.ReadCodeLine(110); err != nil {
//		return nil, err
//	}
//	text, err := c.ReadDotBytes()
//	if err != nil {
//		return nil, err
//	}
//	return c.ReadCodeLine(250)
//
func (c *Conn) Cmd(format string, args ...interface{}) (id uint, err error) {
	id = c.Next()
	c.StartRequest(id)
	err = c.PrintfLine(format, args...)
	c.EndRequest(id)
	if err != nil {
		return 0, err
	}
	return id, nil
}

// TrimString returns s without leading and trailing ASCII space.
func TrimString(s string) string {
	for len(s) > 0 && isASCIISpace(s[0]) {
		s = s[1:]
	}
	for len(s) > 0 && isASCIISpace(s[len(s)-1]) {
		s = s[:len(s)-1]
	}
	return s
}

// TrimBytes returns b without leading and trailing ASCII space.
func TrimBytes(b []byte) []byte {
	for len(b) > 0 && isASCIISpace(b[0]) {
		b = b[1:]
	}
	for len(b) > 0 && isASCIISpace(b[len(b)-1]) {
		b = b[:len(b)-1]
	}
	return b
}

func isASCIISpace(b byte) bool {
	return b == ' ' || b == '\t' || b == '\n' || b == '\r'
}

func isASCIILetter(b byte) bool {
	b |= 0x20 // make lower case
	return 'a' <= b && b <= 'z'
}
<|endoftext|>


<commit_before>// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2015 The Go Authors.  All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

/*
Package jsonpb provides marshalling/unmarshalling functionality between
protocol buffer and JSON objects.

Compared to encoding/json, this library:
 - encodes int64, uint64 as strings
 - optionally encodes enums as strings
*/
package jsonpb

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"reflect"
	"sort"
	"strconv"
	"strings"

	"github.com/golang/protobuf/proto"
)

var (
	byteArrayType = reflect.TypeOf([]byte{})
)

// Marshaller is a configurable object for converting between
// protocol buffer objects and a JSON representation for them
type Marshaller struct {
	// Use string values for enums (as opposed to integer values)
	EnumsAsString bool

	// A string to indent each level by. The presence of this field will
	// also cause a space to appear between the field separator and
	// value, and for newlines to be appear between fields and array
	// elements.
	Indent string
}

// Marshal marshals a protocol buffer into JSON.
func (m *Marshaller) Marshal(out io.Writer, pb proto.Message) error {
	writer := &errWriter{writer: out}
	return m.marshalObject(writer, pb, "")
}

// MarshalToString converts a protocol buffer object to JSON string.
func (m *Marshaller) MarshalToString(pb proto.Message) (string, error) {
	var buf bytes.Buffer
	if err := m.Marshal(&buf, pb); err != nil {
		return "", err
	}
	return buf.String(), nil
}

// marshalObject writes a struct to the Writer.
func (m *Marshaller) marshalObject(out *errWriter, v proto.Message, indent string) error {
	out.write("{")
	if m.Indent != "" {
		out.write("\n")
	}

	s := reflect.ValueOf(v).Elem()
	writeBeforeField := ""
	for i := 0; i < s.NumField(); i++ {
		value := s.Field(i)
		valueField := s.Type().Field(i)
		fieldName, omitFieldIfNil := parseFieldOptions(valueField)

		// Fields which should not be serialized will specify a json tag with '-'
		// TODO: proto3 objects should have default values omitted.
		if fieldName == "-" {
			continue
		} else if omitFieldIfNil {
			// IsNil will panic on most value kinds.
			skip := false
			switch value.Kind() {
			case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
				skip = value.IsNil()
			}
			if skip {
				continue
			}
		}

		out.write(writeBeforeField)
		if m.Indent != "" {
			out.write(indent)
			out.write(m.Indent)
		}
		out.write(`"`)
		out.write(fieldName)
		out.write(`":`)
		if m.Indent != "" {
			out.write(" ")
		}

		if err := m.marshalValue(out, value, valueField, indent); err != nil {
			return err
		}

		if m.Indent != "" {
			writeBeforeField = ",\n"
		} else {
			writeBeforeField = ","
		}
	}

	if m.Indent != "" {
		out.write("\n")
		out.write(indent)
	}
	out.write("}")
	return out.err
}

// marshalValue writes the value to the Writer.
func (m *Marshaller) marshalValue(out *errWriter, v reflect.Value,
	structField reflect.StructField, indent string) error {

	var err error
	v = reflect.Indirect(v)

	// Handle repeated elements.
	if v.Type() != byteArrayType && v.Kind() == reflect.Slice {
		out.write("[")
		comma := ""
		for i := 0; i < v.Len(); i++ {
			sliceVal := v.Index(i)
			out.write(comma)
			if m.Indent != "" {
				out.write("\n")
				out.write(indent)
				out.write(m.Indent)
				out.write(m.Indent)
			}
			m.marshalValue(out, sliceVal, structField, indent+m.Indent)
			comma = ","
		}
		if m.Indent != "" {
			out.write("\n")
			out.write(indent)
			out.write(m.Indent)
		}
		out.write("]")
		return out.err
	}

	// Handle enumerations.
	protoInfo := structField.Tag.Get("protobuf")
	if m.EnumsAsString && strings.Contains(protoInfo, ",enum=") {
		// Unknown enum values will are stringified by the proto library as their
		// value. Such values should _not_ be quoted or they will be intrepreted
		// as an enum string instead of their value.
		enumStr := v.Interface().(fmt.Stringer).String()
		var valStr string
		if v.Kind() == reflect.Ptr {
			valStr = strconv.Itoa(int(v.Elem().Int()))
		} else {
			valStr = strconv.Itoa(int(v.Int()))
		}
		isKnownEnum := enumStr != valStr
		if isKnownEnum {
			out.write(`"`)
		}
		out.write(enumStr)
		if isKnownEnum {
			out.write(`"`)
		}
		return out.err
	}

	// Handle nested messages.
	if v.Kind() == reflect.Struct {
		return m.marshalObject(out, v.Addr().Interface().(proto.Message), indent+m.Indent)
	}

	// Handle maps.
	// NOTE: Since Go randomizes map iteration, we sort keys for stable output.
	if v.Kind() == reflect.Map {
		out.write(`{`)
		keys := v.MapKeys()
		sort.Sort(mapKeys(keys))
		for i, k := range keys {
			if i > 0 {
				out.write(`,`)
			}
			if m.Indent != "" {
				out.write("\n")
				out.write(indent)
				out.write(m.Indent)
				out.write(m.Indent)
			}

			b, err := json.Marshal(k.Interface())
			if err != nil {
				return err
			}
			s := string(b)

			// If the JSON is not a string value, encode it again to make it one.
			if !strings.HasPrefix(s, `"`) {
				b, err := json.Marshal(s)
				if err != nil {
					return err
				}
				s = string(b)
			}

			out.write(s)
			out.write(`:`)
			if m.Indent != "" {
				out.write(` `)
			}

			if err := m.marshalValue(out, v.MapIndex(k), structField, indent+m.Indent); err != nil {
				return err
			}
		}
		if m.Indent != "" {
			out.write("\n")
			out.write(indent)
			out.write(m.Indent)
		}
		out.write(`}`)
		return out.err
	}

	// Default handling defers to the encoding/json library.
	b, err := json.Marshal(v.Interface())
	if err != nil {
		return err
	}
	needToQuote := string(b[0]) != `"` && (v.Kind() == reflect.Int64 || v.Kind() == reflect.Uint64)
	if needToQuote {
		out.write(`"`)
	}
	out.write(string(b))
	if needToQuote {
		out.write(`"`)
	}
	return out.err
}

// Unmarshal unmarshals a JSON object stream into a protocol
// buffer. This function is lenient and will decode any options
// permutations of the related Marshaller.
func Unmarshal(r io.Reader, pb proto.Message) error {
	inputValue := json.RawMessage{}
	if err := json.NewDecoder(r).Decode(&inputValue); err != nil {
		return err
	}
	return unmarshalValue(reflect.ValueOf(pb).Elem(), inputValue)
}

// UnmarshalString will populate the fields of a protocol buffer based
// on a JSON string. This function is lenient and will decode any options
// permutations of the related Marshaller.
func UnmarshalString(str string, pb proto.Message) error {
	return Unmarshal(bytes.NewReader([]byte(str)), pb)
}

// unmarshalValue converts/copies a value into the target.
func unmarshalValue(target reflect.Value, inputValue json.RawMessage) error {
	targetType := target.Type()

	// Allocate memory for pointer fields.
	if targetType.Kind() == reflect.Ptr {
		target.Set(reflect.New(targetType.Elem()))
		return unmarshalValue(target.Elem(), inputValue)
	}

	// Handle nested messages.
	if targetType.Kind() == reflect.Struct {
		var jsonFields map[string]json.RawMessage
		if err := json.Unmarshal(inputValue, &jsonFields); err != nil {
			return err
		}

		for i := 0; i < target.NumField(); i++ {
			fieldName, _ := parseFieldOptions(target.Type().Field(i))

			// Fields which should not be serialized will specify a json tag with '-'
			if fieldName == "-" {
				continue
			}

			if valueForField, ok := jsonFields[fieldName]; ok {
				if err := unmarshalValue(target.Field(i), valueForField); err != nil {
					return err
				}
			}
		}
		return nil
	}

	// Handle arrays (which aren't encoded bytes)
	if targetType != byteArrayType && targetType.Kind() == reflect.Slice {
		var slc []json.RawMessage
		if err := json.Unmarshal(inputValue, &slc); err != nil {
			return err
		}
		len := len(slc)
		target.Set(reflect.MakeSlice(targetType, len, len))
		for i := 0; i < len; i++ {
			if err := unmarshalValue(target.Index(i), slc[i]); err != nil {
				return err
			}
		}
		return nil
	}

	// Handle maps (whose keys are always strings)
	if targetType.Kind() == reflect.Map {
		var mp map[string]json.RawMessage
		if err := json.Unmarshal(inputValue, &mp); err != nil {
			return err
		}
		target.Set(reflect.MakeMap(targetType))
		for ks, raw := range mp {
			// Unmarshal map key. The core json library already decoded the key into a
			// string, so we handle that specially. Other types were quoted post-serialization.
			var k reflect.Value
			if targetType.Key().Kind() == reflect.String {
				k = reflect.ValueOf(ks)
			} else {
				k = reflect.New(targetType.Key()).Elem()
				if err := unmarshalValue(k, json.RawMessage(ks)); err != nil {
					return err
				}
			}

			// Unmarshal map value.
			v := reflect.New(targetType.Elem()).Elem()
			if err := unmarshalValue(v, raw); err != nil {
				return err
			}
			target.SetMapIndex(k, v)
		}
		return nil
	}

	// 64-bit integers can be encoded as strings. In this case we drop
	// the quotes and proceed as normal.
	isNum := targetType.Kind() == reflect.Int64 || targetType.Kind() == reflect.Uint64
	if isNum && strings.HasPrefix(string(inputValue), `"`) {
		inputValue = inputValue[1 : len(inputValue)-1]
	}

	// Use the encoding/json for parsing other value types.
	return json.Unmarshal(inputValue, target.Addr().Interface())
}

// hasUnmarshalJSON is a interface implemented by protocol buffer enums.
type hasUnmarshalJSON interface {
	UnmarshalJSON(data []byte) error
}

// parseFieldOptions returns the field name and if it should be omited.
func parseFieldOptions(f reflect.StructField) (string, bool) {
	name := f.Name
	omitEmpty := false
	tag := f.Tag.Get("json")
	tagParts := strings.Split(tag, ",")
	for i := range tagParts {
		if tagParts[i] == "omitempty" || tagParts[i] == "" {
			omitEmpty = true
		} else {
			name = tagParts[i]
		}
	}
	return name, omitEmpty
}

// Writer wrapper inspired by https://blog.golang.org/errors-are-values
type errWriter struct {
	writer io.Writer
	err    error
}

func (w *errWriter) write(str string) {
	if w.err != nil {
		return
	}
	_, w.err = w.writer.Write([]byte(str))
}

// Map fields may have key types of non-float scalars, strings and enums.
// The easiest way to sort them in some deterministic order is to use fmt.
// If this turns out to be inefficient we can always consider other options,
// such as doing a Schwartzian transform.
type mapKeys []reflect.Value

func (s mapKeys) Len() int      { return len(s) }
func (s mapKeys) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s mapKeys) Less(i, j int) bool {
	return fmt.Sprint(s[i].Interface()) < fmt.Sprint(s[j].Interface())
}
<commit_msg>jsonpb: Reject unknown fields when parsing into a struct.<commit_after>// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2015 The Go Authors.  All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

/*
Package jsonpb provides marshalling/unmarshalling functionality between
protocol buffer and JSON objects.

Compared to encoding/json, this library:
 - encodes int64, uint64 as strings
 - optionally encodes enums as strings
*/
package jsonpb

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"reflect"
	"sort"
	"strconv"
	"strings"

	"github.com/golang/protobuf/proto"
)

var (
	byteArrayType = reflect.TypeOf([]byte{})
)

// Marshaller is a configurable object for converting between
// protocol buffer objects and a JSON representation for them
type Marshaller struct {
	// Use string values for enums (as opposed to integer values)
	EnumsAsString bool

	// A string to indent each level by. The presence of this field will
	// also cause a space to appear between the field separator and
	// value, and for newlines to be appear between fields and array
	// elements.
	Indent string
}

// Marshal marshals a protocol buffer into JSON.
func (m *Marshaller) Marshal(out io.Writer, pb proto.Message) error {
	writer := &errWriter{writer: out}
	return m.marshalObject(writer, pb, "")
}

// MarshalToString converts a protocol buffer object to JSON string.
func (m *Marshaller) MarshalToString(pb proto.Message) (string, error) {
	var buf bytes.Buffer
	if err := m.Marshal(&buf, pb); err != nil {
		return "", err
	}
	return buf.String(), nil
}

// marshalObject writes a struct to the Writer.
func (m *Marshaller) marshalObject(out *errWriter, v proto.Message, indent string) error {
	out.write("{")
	if m.Indent != "" {
		out.write("\n")
	}

	s := reflect.ValueOf(v).Elem()
	writeBeforeField := ""
	for i := 0; i < s.NumField(); i++ {
		value := s.Field(i)
		valueField := s.Type().Field(i)
		fieldName, omitFieldIfNil := parseFieldOptions(valueField)

		// Fields which should not be serialized will specify a json tag with '-'
		// TODO: proto3 objects should have default values omitted.
		if fieldName == "-" {
			continue
		} else if omitFieldIfNil {
			// IsNil will panic on most value kinds.
			skip := false
			switch value.Kind() {
			case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
				skip = value.IsNil()
			}
			if skip {
				continue
			}
		}

		out.write(writeBeforeField)
		if m.Indent != "" {
			out.write(indent)
			out.write(m.Indent)
		}
		out.write(`"`)
		out.write(fieldName)
		out.write(`":`)
		if m.Indent != "" {
			out.write(" ")
		}

		if err := m.marshalValue(out, value, valueField, indent); err != nil {
			return err
		}

		if m.Indent != "" {
			writeBeforeField = ",\n"
		} else {
			writeBeforeField = ","
		}
	}

	if m.Indent != "" {
		out.write("\n")
		out.write(indent)
	}
	out.write("}")
	return out.err
}

// marshalValue writes the value to the Writer.
func (m *Marshaller) marshalValue(out *errWriter, v reflect.Value,
	structField reflect.StructField, indent string) error {

	var err error
	v = reflect.Indirect(v)

	// Handle repeated elements.
	if v.Type() != byteArrayType && v.Kind() == reflect.Slice {
		out.write("[")
		comma := ""
		for i := 0; i < v.Len(); i++ {
			sliceVal := v.Index(i)
			out.write(comma)
			if m.Indent != "" {
				out.write("\n")
				out.write(indent)
				out.write(m.Indent)
				out.write(m.Indent)
			}
			m.marshalValue(out, sliceVal, structField, indent+m.Indent)
			comma = ","
		}
		if m.Indent != "" {
			out.write("\n")
			out.write(indent)
			out.write(m.Indent)
		}
		out.write("]")
		return out.err
	}

	// Handle enumerations.
	protoInfo := structField.Tag.Get("protobuf")
	if m.EnumsAsString && strings.Contains(protoInfo, ",enum=") {
		// Unknown enum values will are stringified by the proto library as their
		// value. Such values should _not_ be quoted or they will be intrepreted
		// as an enum string instead of their value.
		enumStr := v.Interface().(fmt.Stringer).String()
		var valStr string
		if v.Kind() == reflect.Ptr {
			valStr = strconv.Itoa(int(v.Elem().Int()))
		} else {
			valStr = strconv.Itoa(int(v.Int()))
		}
		isKnownEnum := enumStr != valStr
		if isKnownEnum {
			out.write(`"`)
		}
		out.write(enumStr)
		if isKnownEnum {
			out.write(`"`)
		}
		return out.err
	}

	// Handle nested messages.
	if v.Kind() == reflect.Struct {
		return m.marshalObject(out, v.Addr().Interface().(proto.Message), indent+m.Indent)
	}

	// Handle maps.
	// Since Go randomizes map iteration, we sort keys for stable output.
	if v.Kind() == reflect.Map {
		out.write(`{`)
		keys := v.MapKeys()
		sort.Sort(mapKeys(keys))
		for i, k := range keys {
			if i > 0 {
				out.write(`,`)
			}
			if m.Indent != "" {
				out.write("\n")
				out.write(indent)
				out.write(m.Indent)
				out.write(m.Indent)
			}

			b, err := json.Marshal(k.Interface())
			if err != nil {
				return err
			}
			s := string(b)

			// If the JSON is not a string value, encode it again to make it one.
			if !strings.HasPrefix(s, `"`) {
				b, err := json.Marshal(s)
				if err != nil {
					return err
				}
				s = string(b)
			}

			out.write(s)
			out.write(`:`)
			if m.Indent != "" {
				out.write(` `)
			}

			if err := m.marshalValue(out, v.MapIndex(k), structField, indent+m.Indent); err != nil {
				return err
			}
		}
		if m.Indent != "" {
			out.write("\n")
			out.write(indent)
			out.write(m.Indent)
		}
		out.write(`}`)
		return out.err
	}

	// Default handling defers to the encoding/json library.
	b, err := json.Marshal(v.Interface())
	if err != nil {
		return err
	}
	needToQuote := string(b[0]) != `"` && (v.Kind() == reflect.Int64 || v.Kind() == reflect.Uint64)
	if needToQuote {
		out.write(`"`)
	}
	out.write(string(b))
	if needToQuote {
		out.write(`"`)
	}
	return out.err
}

// Unmarshal unmarshals a JSON object stream into a protocol
// buffer. This function is lenient and will decode any options
// permutations of the related Marshaller.
func Unmarshal(r io.Reader, pb proto.Message) error {
	inputValue := json.RawMessage{}
	if err := json.NewDecoder(r).Decode(&inputValue); err != nil {
		return err
	}
	return unmarshalValue(reflect.ValueOf(pb).Elem(), inputValue)
}

// UnmarshalString will populate the fields of a protocol buffer based
// on a JSON string. This function is lenient and will decode any options
// permutations of the related Marshaller.
func UnmarshalString(str string, pb proto.Message) error {
	return Unmarshal(bytes.NewReader([]byte(str)), pb)
}

// unmarshalValue converts/copies a value into the target.
func unmarshalValue(target reflect.Value, inputValue json.RawMessage) error {
	targetType := target.Type()

	// Allocate memory for pointer fields.
	if targetType.Kind() == reflect.Ptr {
		target.Set(reflect.New(targetType.Elem()))
		return unmarshalValue(target.Elem(), inputValue)
	}

	// Handle nested messages.
	if targetType.Kind() == reflect.Struct {
		var jsonFields map[string]json.RawMessage
		if err := json.Unmarshal(inputValue, &jsonFields); err != nil {
			return err
		}

		for i := 0; i < target.NumField(); i++ {
			fieldName, _ := parseFieldOptions(target.Type().Field(i))

			// Fields which should not be serialized will specify a json tag with '-'
			if fieldName == "-" {
				continue
			}

			if valueForField, ok := jsonFields[fieldName]; ok {
				if err := unmarshalValue(target.Field(i), valueForField); err != nil {
					return err
				}
				delete(jsonFields, fieldName)
			}
		}
		if len(jsonFields) > 0 {
			// Pick any field to be the scapegoat.
			var f string
			for fname := range jsonFields {
				f = fname
				break
			}
			return fmt.Errorf("unknown field %q in %v", f, targetType)
		}
		return nil
	}

	// Handle arrays (which aren't encoded bytes)
	if targetType != byteArrayType && targetType.Kind() == reflect.Slice {
		var slc []json.RawMessage
		if err := json.Unmarshal(inputValue, &slc); err != nil {
			return err
		}
		len := len(slc)
		target.Set(reflect.MakeSlice(targetType, len, len))
		for i := 0; i < len; i++ {
			if err := unmarshalValue(target.Index(i), slc[i]); err != nil {
				return err
			}
		}
		return nil
	}

	// Handle maps (whose keys are always strings)
	if targetType.Kind() == reflect.Map {
		var mp map[string]json.RawMessage
		if err := json.Unmarshal(inputValue, &mp); err != nil {
			return err
		}
		target.Set(reflect.MakeMap(targetType))
		for ks, raw := range mp {
			// Unmarshal map key. The core json library already decoded the key into a
			// string, so we handle that specially. Other types were quoted post-serialization.
			var k reflect.Value
			if targetType.Key().Kind() == reflect.String {
				k = reflect.ValueOf(ks)
			} else {
				k = reflect.New(targetType.Key()).Elem()
				if err := unmarshalValue(k, json.RawMessage(ks)); err != nil {
					return err
				}
			}

			// Unmarshal map value.
			v := reflect.New(targetType.Elem()).Elem()
			if err := unmarshalValue(v, raw); err != nil {
				return err
			}
			target.SetMapIndex(k, v)
		}
		return nil
	}

	// 64-bit integers can be encoded as strings. In this case we drop
	// the quotes and proceed as normal.
	isNum := targetType.Kind() == reflect.Int64 || targetType.Kind() == reflect.Uint64
	if isNum && strings.HasPrefix(string(inputValue), `"`) {
		inputValue = inputValue[1 : len(inputValue)-1]
	}

	// Use the encoding/json for parsing other value types.
	return json.Unmarshal(inputValue, target.Addr().Interface())
}

// hasUnmarshalJSON is a interface implemented by protocol buffer enums.
type hasUnmarshalJSON interface {
	UnmarshalJSON(data []byte) error
}

// parseFieldOptions returns the field name and if it should be omited.
func parseFieldOptions(f reflect.StructField) (string, bool) {
	// TODO: Do this without using the "json" field tag.
	name := f.Name
	omitEmpty := false
	tag := f.Tag.Get("json")
	tagParts := strings.Split(tag, ",")
	for i := range tagParts {
		if tagParts[i] == "omitempty" || tagParts[i] == "" {
			omitEmpty = true
		} else {
			name = tagParts[i]
		}
	}
	return name, omitEmpty
}

// Writer wrapper inspired by https://blog.golang.org/errors-are-values
type errWriter struct {
	writer io.Writer
	err    error
}

func (w *errWriter) write(str string) {
	if w.err != nil {
		return
	}
	_, w.err = w.writer.Write([]byte(str))
}

// Map fields may have key types of non-float scalars, strings and enums.
// The easiest way to sort them in some deterministic order is to use fmt.
// If this turns out to be inefficient we can always consider other options,
// such as doing a Schwartzian transform.
type mapKeys []reflect.Value

func (s mapKeys) Len() int      { return len(s) }
func (s mapKeys) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s mapKeys) Less(i, j int) bool {
	return fmt.Sprint(s[i].Interface()) < fmt.Sprint(s[j].Interface())
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/x509"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"syscall"

	"github.com/cloudfoundry-incubator/credhub-cli/credhub"

	"code.cloudfoundry.org/buildpackapplifecycle/databaseuri"
	"code.cloudfoundry.org/dockerapplifecycle/protocol"
)

type PlatformOptions struct {
	CredhubURI string `json:"credhub-uri"`
}

const (
	PlatformOptionsEnvVar  = "VCAP_PLATFORM_OPTIONS"
	CFSystemCertPathEnvVar = "CF_SYSTEM_CERT_PATH"
)

func main() {
	if len(os.Args) < 4 {
		fmt.Fprintf(os.Stderr, "Usage: %s <ignored> <start command> <metadata>", os.Args[0])
		os.Exit(1)
	}

	// os.Args[1] is ignored, but left for backwards compatibility
	startCommand := os.Args[2]
	metadata := os.Args[3]

	platformOptions, err := platformOptions()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Invalid platform options")
		os.Exit(3)
	}

	interpolateVCAPServices(platformOptions)
	setDatabaseURL()

	vcapAppEnv := map[string]interface{}{}

	err = json.Unmarshal([]byte(os.Getenv("VCAP_APPLICATION")), &vcapAppEnv)
	if err == nil {
		vcapAppEnv["host"] = "0.0.0.0"

		vcapAppEnv["instance_id"] = os.Getenv("INSTANCE_GUID")

		port, err := strconv.Atoi(os.Getenv("PORT"))
		if err == nil {
			vcapAppEnv["port"] = port
		}

		index, err := strconv.Atoi(os.Getenv("INSTANCE_INDEX"))
		if err == nil {
			vcapAppEnv["instance_index"] = index
		}

		mungedAppEnv, err := json.Marshal(vcapAppEnv)
		if err == nil {
			os.Setenv("VCAP_APPLICATION", string(mungedAppEnv))
		}
	}

	var executionMetadata protocol.ExecutionMetadata
	err = json.Unmarshal([]byte(metadata), &executionMetadata)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Invalid metadata - %s", err)
		os.Exit(1)
	}

	workdir := "/"
	if executionMetadata.Workdir != "" {
		workdir = executionMetadata.Workdir
	}
	os.Chdir(workdir)

	if len(executionMetadata.Entrypoint) == 0 && len(executionMetadata.Cmd) == 0 && startCommand == "" {
		fmt.Fprintf(os.Stderr, "No start command found or specified")
		os.Exit(1)
	}

	// https://docs.docker.com/reference/builder/#entrypoint and
	// https://docs.docker.com/reference/builder/#cmd dictate how Entrypoint
	// and Cmd are treated by docker; we follow these rules here
	var argv []string
	if startCommand != "" {
		argv = []string{"/bin/sh", "-c", startCommand}
	} else {
		argv = append(executionMetadata.Entrypoint, executionMetadata.Cmd...)
		argv[0], err = exec.LookPath(argv[0])
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to resolve path: %s", err)
			os.Exit(1)
		}
	}

	runtime.GOMAXPROCS(1)
	err = syscall.Exec(argv[0], argv, os.Environ())
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to run: %s", err)
		os.Exit(1)
	}
}

func setDatabaseURL() {
	vcapServices := os.Getenv("VCAP_SERVICES")
	if vcapServices == "" {
		return
	}

	databaseURI := databaseuri.New()
	creds, err := databaseURI.Credentials([]byte(vcapServices))
	if err != nil {
		fmt.Fprintf(os.Stderr, "Cannot parse vcap services: %s", err)
		return
	}
	uri := databaseURI.Uri(creds)
	if uri == "" {
		return
	}
	if err := os.Setenv("DATABASE_URL", uri); err != nil {
		panic(err)
	}
}

func interpolateVCAPServices(platformOptions *PlatformOptions) {
	if platformOptions == nil || platformOptions.CredhubURI == "" {
		return
	}

	vcapServices := os.Getenv("VCAP_SERVICES")
	if !strings.Contains(vcapServices, `"credhub-ref"`) {
		return
	}

	certPath := os.Getenv("CF_INSTANCE_CERT")
	keyPath := os.Getenv("CF_INSTANCE_KEY")
	rootCAs := rootCAs()

	credhubURI := platformOptions.CredhubURI
	_, err := url.ParseRequestURI(credhubURI)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Invalid CredHub URI: '%s'", credhubURI)
		os.Exit(4)
	}

	if certPath == "" || keyPath == "" {
		fmt.Fprintf(os.Stderr, "Unable to load instance identity credentials; CF_INSTANCE_CERT: '%s', CF_INSTANCE_KEY: '%s'", certPath, keyPath)
		os.Exit(4)
	}

	ch, err := credhub.New(credhubURI, credhub.ClientCert(certPath, keyPath), credhub.CaCerts(rootCAs...))
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to create a credhub client: %s", err)
		os.Exit(4)
	}

	interpolatedVcapServices, err := ch.InterpolateString(vcapServices)

	if err != nil {
		fmt.Fprintf(os.Stderr, formatCredHubErrorMessage(err))
		os.Exit(4)
	}

	err = os.Setenv("VCAP_SERVICES", interpolatedVcapServices)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Cannot set environment variable: %s", err)
		os.Exit(4)
	}
}

func rootCAs() []string {
	certsPath := os.Getenv(CFSystemCertPathEnvVar)
	pattern := path.Join(certsPath, "*.crt")
	matches, err := filepath.Glob(pattern)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to locate system certs: %s", err)
		os.Exit(4)
	}
	certs := []string{}
	for _, m := range matches {
		content, err := ioutil.ReadFile(m)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Unable to read system certs: %s", err)
			os.Exit(4)
		}
		certs = append(certs, string(content))
	}
	return certs
}

func platformOptions() (*PlatformOptions, error) {
	jsonPlatformOptions := os.Getenv(PlatformOptionsEnvVar)
	if jsonPlatformOptions == "" {
		return nil, nil
	}
	platformOptions := PlatformOptions{}
	err := json.Unmarshal([]byte(jsonPlatformOptions), &platformOptions)
	if err != nil {
		return nil, err
	}

	return &platformOptions, nil
}

func formatCredHubErrorMessage(err error) string {
	if typeErr, ok := err.(x509.UnknownAuthorityError); ok {
		return fmt.Sprintf("Unable to verify CredHub server: %s", typeErr)
	}

	if typeErr, ok := err.(*url.Error); ok {
		return formatCredHubErrorMessage(typeErr.Err)
	}

	return fmt.Sprintf("Unable to interpolate credhub references: %s", err)
}
<commit_msg>Change credhub-cli's import path<commit_after>package main

import (
	"crypto/x509"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"syscall"

	"code.cloudfoundry.org/credhub-cli/credhub"

	"code.cloudfoundry.org/buildpackapplifecycle/databaseuri"
	"code.cloudfoundry.org/dockerapplifecycle/protocol"
)

type PlatformOptions struct {
	CredhubURI string `json:"credhub-uri"`
}

const (
	PlatformOptionsEnvVar  = "VCAP_PLATFORM_OPTIONS"
	CFSystemCertPathEnvVar = "CF_SYSTEM_CERT_PATH"
)

func main() {
	if len(os.Args) < 4 {
		fmt.Fprintf(os.Stderr, "Usage: %s <ignored> <start command> <metadata>", os.Args[0])
		os.Exit(1)
	}

	// os.Args[1] is ignored, but left for backwards compatibility
	startCommand := os.Args[2]
	metadata := os.Args[3]

	platformOptions, err := platformOptions()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Invalid platform options")
		os.Exit(3)
	}

	interpolateVCAPServices(platformOptions)
	setDatabaseURL()

	vcapAppEnv := map[string]interface{}{}

	err = json.Unmarshal([]byte(os.Getenv("VCAP_APPLICATION")), &vcapAppEnv)
	if err == nil {
		vcapAppEnv["host"] = "0.0.0.0"

		vcapAppEnv["instance_id"] = os.Getenv("INSTANCE_GUID")

		port, err := strconv.Atoi(os.Getenv("PORT"))
		if err == nil {
			vcapAppEnv["port"] = port
		}

		index, err := strconv.Atoi(os.Getenv("INSTANCE_INDEX"))
		if err == nil {
			vcapAppEnv["instance_index"] = index
		}

		mungedAppEnv, err := json.Marshal(vcapAppEnv)
		if err == nil {
			os.Setenv("VCAP_APPLICATION", string(mungedAppEnv))
		}
	}

	var executionMetadata protocol.ExecutionMetadata
	err = json.Unmarshal([]byte(metadata), &executionMetadata)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Invalid metadata - %s", err)
		os.Exit(1)
	}

	workdir := "/"
	if executionMetadata.Workdir != "" {
		workdir = executionMetadata.Workdir
	}
	os.Chdir(workdir)

	if len(executionMetadata.Entrypoint) == 0 && len(executionMetadata.Cmd) == 0 && startCommand == "" {
		fmt.Fprintf(os.Stderr, "No start command found or specified")
		os.Exit(1)
	}

	// https://docs.docker.com/reference/builder/#entrypoint and
	// https://docs.docker.com/reference/builder/#cmd dictate how Entrypoint
	// and Cmd are treated by docker; we follow these rules here
	var argv []string
	if startCommand != "" {
		argv = []string{"/bin/sh", "-c", startCommand}
	} else {
		argv = append(executionMetadata.Entrypoint, executionMetadata.Cmd...)
		argv[0], err = exec.LookPath(argv[0])
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to resolve path: %s", err)
			os.Exit(1)
		}
	}

	runtime.GOMAXPROCS(1)
	err = syscall.Exec(argv[0], argv, os.Environ())
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to run: %s", err)
		os.Exit(1)
	}
}

func setDatabaseURL() {
	vcapServices := os.Getenv("VCAP_SERVICES")
	if vcapServices == "" {
		return
	}

	databaseURI := databaseuri.New()
	creds, err := databaseURI.Credentials([]byte(vcapServices))
	if err != nil {
		fmt.Fprintf(os.Stderr, "Cannot parse vcap services: %s", err)
		return
	}
	uri := databaseURI.Uri(creds)
	if uri == "" {
		return
	}
	if err := os.Setenv("DATABASE_URL", uri); err != nil {
		panic(err)
	}
}

func interpolateVCAPServices(platformOptions *PlatformOptions) {
	if platformOptions == nil || platformOptions.CredhubURI == "" {
		return
	}

	vcapServices := os.Getenv("VCAP_SERVICES")
	if !strings.Contains(vcapServices, `"credhub-ref"`) {
		return
	}

	certPath := os.Getenv("CF_INSTANCE_CERT")
	keyPath := os.Getenv("CF_INSTANCE_KEY")
	rootCAs := rootCAs()

	credhubURI := platformOptions.CredhubURI
	_, err := url.ParseRequestURI(credhubURI)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Invalid CredHub URI: '%s'", credhubURI)
		os.Exit(4)
	}

	if certPath == "" || keyPath == "" {
		fmt.Fprintf(os.Stderr, "Unable to load instance identity credentials; CF_INSTANCE_CERT: '%s', CF_INSTANCE_KEY: '%s'", certPath, keyPath)
		os.Exit(4)
	}

	ch, err := credhub.New(credhubURI, credhub.ClientCert(certPath, keyPath), credhub.CaCerts(rootCAs...))
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to create a credhub client: %s", err)
		os.Exit(4)
	}

	interpolatedVcapServices, err := ch.InterpolateString(vcapServices)

	if err != nil {
		fmt.Fprintf(os.Stderr, formatCredHubErrorMessage(err))
		os.Exit(4)
	}

	err = os.Setenv("VCAP_SERVICES", interpolatedVcapServices)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Cannot set environment variable: %s", err)
		os.Exit(4)
	}
}

func rootCAs() []string {
	certsPath := os.Getenv(CFSystemCertPathEnvVar)
	pattern := path.Join(certsPath, "*.crt")
	matches, err := filepath.Glob(pattern)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to locate system certs: %s", err)
		os.Exit(4)
	}
	certs := []string{}
	for _, m := range matches {
		content, err := ioutil.ReadFile(m)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Unable to read system certs: %s", err)
			os.Exit(4)
		}
		certs = append(certs, string(content))
	}
	return certs
}

func platformOptions() (*PlatformOptions, error) {
	jsonPlatformOptions := os.Getenv(PlatformOptionsEnvVar)
	if jsonPlatformOptions == "" {
		return nil, nil
	}
	platformOptions := PlatformOptions{}
	err := json.Unmarshal([]byte(jsonPlatformOptions), &platformOptions)
	if err != nil {
		return nil, err
	}

	return &platformOptions, nil
}

func formatCredHubErrorMessage(err error) string {
	if typeErr, ok := err.(x509.UnknownAuthorityError); ok {
		return fmt.Sprintf("Unable to verify CredHub server: %s", typeErr)
	}

	if typeErr, ok := err.(*url.Error); ok {
		return formatCredHubErrorMessage(typeErr.Err)
	}

	return fmt.Sprintf("Unable to interpolate credhub references: %s", err)
}
<|endoftext|>


<commit_before>package quiz

import (
	"net/http"

	"github.com/dgraph-io/gru/admin/server"
	"github.com/dgraph-io/gru/dgraph"
)

func Feedback(w http.ResponseWriter, r *http.Request) {
	sr := server.Response{}
	userId, err := validateToken(r)
	if err != nil {
		sr.Write(w, err.Error(), "", http.StatusUnauthorized)
		return
	}

	f := r.PostFormValue("feedback")
	if f == "" {
		sr.Write(w, "", "Feedback can't be empty.", http.StatusBadRequest)
	}

	m := new(dgraph.Mutation)
	m.Set(`<_uid_:` + userId + `> <feedback> "` + f + `" .`)

	if _, err = dgraph.SendMutation(m.String()); err != nil {
		sr.Write(w, "", err.Error(), http.StatusInternalServerError)
		return
	}
}
<commit_msg>Add missing return<commit_after>package quiz

import (
	"net/http"

	"github.com/dgraph-io/gru/admin/server"
	"github.com/dgraph-io/gru/dgraph"
)

func Feedback(w http.ResponseWriter, r *http.Request) {
	sr := server.Response{}
	userId, err := validateToken(r)
	if err != nil {
		sr.Write(w, err.Error(), "", http.StatusUnauthorized)
		return
	}

	f := r.PostFormValue("feedback")
	if f == "" {
		sr.Write(w, "", "Feedback can't be empty.", http.StatusBadRequest)
		return
	}

	m := new(dgraph.Mutation)
	m.Set(`<_uid_:` + userId + `> <feedback> "` + f + `" .`)

	if _, err = dgraph.SendMutation(m.String()); err != nil {
		sr.Write(w, "", err.Error(), http.StatusInternalServerError)
		return
	}
}
<|endoftext|>


<commit_before>package digitalocean

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/pearkes/digitalocean"
)

func resourceDigitalOceanDroplet() *schema.Resource {
	return &schema.Resource{
		Create: resourceDigitalOceanDropletCreate,
		Read:   resourceDigitalOceanDropletRead,
		Update: resourceDigitalOceanDropletUpdate,
		Delete: resourceDigitalOceanDropletDelete,

		Schema: map[string]*schema.Schema{
			"image": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"region": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"size": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"status": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"locked": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"backups": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},

			"ipv6": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
			},

			"ipv6_address": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"ipv6_address_private": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"private_networking": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
			},

			"ipv4_address": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"ipv4_address_private": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"ssh_keys": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
			},

			"user_data": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
		},
	}
}

func resourceDigitalOceanDropletCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*digitalocean.Client)

	// Build up our creation options
	opts := &digitalocean.CreateDroplet{
		Image:  d.Get("image").(string),
		Name:   d.Get("name").(string),
		Region: d.Get("region").(string),
		Size:   d.Get("size").(string),
	}

	if attr, ok := d.GetOk("backups"); ok {
		opts.Backups = attr.(string)
	}

	if attr, ok := d.GetOk("ipv6"); ok && attr.(bool) {
		opts.IPV6 = "true"
	}

	if attr, ok := d.GetOk("private_networking"); ok && attr.(bool) {
		opts.PrivateNetworking = "true"
	}

	if attr, ok := d.GetOk("user_data"); ok {
		opts.UserData = attr.(string)
	}

	// Get configured ssh_keys
	ssh_keys := d.Get("ssh_keys.#").(int)
	if ssh_keys > 0 {
		opts.SSHKeys = make([]string, 0, ssh_keys)
		for i := 0; i < ssh_keys; i++ {
			key := fmt.Sprintf("ssh_keys.%d", i)
			opts.SSHKeys = append(opts.SSHKeys, d.Get(key).(string))
		}
	}

	log.Printf("[DEBUG] Droplet create configuration: %#v", opts)

	id, err := client.CreateDroplet(opts)

	if err != nil {
		return fmt.Errorf("Error creating droplet: %s", err)
	}

	// Assign the droplets id
	d.SetId(id)

	log.Printf("[INFO] Droplet ID: %s", d.Id())

	_, err = WaitForDropletAttribute(d, "active", []string{"new"}, "status", meta)
	if err != nil {
		return fmt.Errorf(
			"Error waiting for droplet (%s) to become ready: %s", d.Id(), err)
	}

	return resourceDigitalOceanDropletRead(d, meta)
}

func resourceDigitalOceanDropletRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*digitalocean.Client)

	// Retrieve the droplet properties for updating the state
	droplet, err := client.RetrieveDroplet(d.Id())
	if err != nil {
		return fmt.Errorf("Error retrieving droplet: %s", err)
	}

	if droplet.ImageSlug() != "" {
		d.Set("image", droplet.ImageSlug())
	} else {
		d.Set("image", droplet.ImageId())
	}

	d.Set("name", droplet.Name)
	d.Set("region", droplet.RegionSlug())
	d.Set("size", droplet.SizeSlug)
	d.Set("status", droplet.Status)
	d.Set("locked", droplet.IsLocked())

	if droplet.IPV6Address("public") != "" {
		d.Set("ipv6", true)
		d.Set("ipv6_address", droplet.IPV6Address("public"))
		d.Set("ipv6_address_private", droplet.IPV6Address("private"))
	}

	d.Set("ipv4_address", droplet.IPV4Address("public"))

	if droplet.NetworkingType() == "private" {
		d.Set("private_networking", true)
		d.Set("ipv4_address_private", droplet.IPV4Address("private"))
	}

	// Initialize the connection info
	d.SetConnInfo(map[string]string{
		"type": "ssh",
		"host": droplet.IPV4Address("public"),
	})

	return nil
}

func resourceDigitalOceanDropletUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*digitalocean.Client)

	if d.HasChange("size") {
		oldSize, newSize := d.GetChange("size")

		err := client.PowerOff(d.Id())

		if err != nil && !strings.Contains(err.Error(), "Droplet is already powered off") {
			return fmt.Errorf(
				"Error powering off droplet (%s): %s", d.Id(), err)
		}

		// Wait for power off
		_, err = WaitForDropletAttribute(d, "off", []string{"active"}, "status", client)
		if err != nil {
			return fmt.Errorf(
				"Error waiting for droplet (%s) to become powered off: %s", d.Id(), err)
		}

		// Resize the droplet
		err = client.Resize(d.Id(), newSize.(string))
		if err != nil {
			newErr := powerOnAndWait(d, meta)
			if newErr != nil {
				return fmt.Errorf(
					"Error powering on droplet (%s) after failed resize: %s", d.Id(), err)
			}
			return fmt.Errorf(
				"Error resizing droplet (%s): %s", d.Id(), err)
		}

		// Wait for the size to change
		_, err = WaitForDropletAttribute(
			d, newSize.(string), []string{"", oldSize.(string)}, "size", meta)

		if err != nil {
			newErr := powerOnAndWait(d, meta)
			if newErr != nil {
				return fmt.Errorf(
					"Error powering on droplet (%s) after waiting for resize to finish: %s", d.Id(), err)
			}
			return fmt.Errorf(
				"Error waiting for resize droplet (%s) to finish: %s", d.Id(), err)
		}

		err = client.PowerOn(d.Id())

		if err != nil {
			return fmt.Errorf(
				"Error powering on droplet (%s) after resize: %s", d.Id(), err)
		}

		// Wait for power off
		_, err = WaitForDropletAttribute(d, "active", []string{"off"}, "status", meta)
		if err != nil {
			return err
		}
	}

	if d.HasChange("name") {
		oldName, newName := d.GetChange("name")

		// Rename the droplet
		err := client.Rename(d.Id(), newName.(string))

		if err != nil {
			return fmt.Errorf(
				"Error renaming droplet (%s): %s", d.Id(), err)
		}

		// Wait for the name to change
		_, err = WaitForDropletAttribute(
			d, newName.(string), []string{"", oldName.(string)}, "name", meta)

		if err != nil {
			return fmt.Errorf(
				"Error waiting for rename droplet (%s) to finish: %s", d.Id(), err)
		}
	}

	// As there is no way to disable private networking,
	// we only check if it needs to be enabled
	if d.HasChange("private_networking") && d.Get("private_networking").(bool) {
		err := client.EnablePrivateNetworking(d.Id())

		if err != nil {
			return fmt.Errorf(
				"Error enabling private networking for droplet (%s): %s", d.Id(), err)
		}

		// Wait for the private_networking to turn on
		_, err = WaitForDropletAttribute(
			d, "true", []string{"", "false"}, "private_networking", meta)

		return fmt.Errorf(
			"Error waiting for private networking to be enabled on for droplet (%s): %s", d.Id(), err)
	}

	// As there is no way to disable IPv6, we only check if it needs to be enabled
	if d.HasChange("ipv6") && d.Get("ipv6").(bool) {
		err := client.EnableIPV6s(d.Id())

		if err != nil {
			return fmt.Errorf(
				"Error turning on ipv6 for droplet (%s): %s", d.Id(), err)
		}

		// Wait for ipv6 to turn on
		_, err = WaitForDropletAttribute(
			d, "true", []string{"", "false"}, "ipv6", meta)

		if err != nil {
			return fmt.Errorf(
				"Error waiting for ipv6 to be turned on for droplet (%s): %s", d.Id(), err)
		}
	}

	return resourceDigitalOceanDropletRead(d, meta)
}

func resourceDigitalOceanDropletDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*digitalocean.Client)

	log.Printf("[INFO] Deleting droplet: %s", d.Id())

	// Destroy the droplet
	err := client.DestroyDroplet(d.Id())

	// Handle remotely destroyed droplets
	if err != nil && strings.Contains(err.Error(), "404 Not Found") {
		return nil
	}

	if err != nil {
		return fmt.Errorf("Error deleting droplet: %s", err)
	}

	return nil
}

func WaitForDropletAttribute(
	d *schema.ResourceData, target string, pending []string, attribute string, meta interface{}) (interface{}, error) {
	// Wait for the droplet so we can get the networking attributes
	// that show up after a while
	log.Printf(
		"[INFO] Waiting for droplet (%s) to have %s of %s",
		d.Id(), attribute, target)

	stateConf := &resource.StateChangeConf{
		Pending:    pending,
		Target:     target,
		Refresh:    newDropletStateRefreshFunc(d, attribute, meta),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	return stateConf.WaitForState()
}

// TODO This function still needs a little more refactoring to make it
// cleaner and more efficient
func newDropletStateRefreshFunc(
	d *schema.ResourceData, attribute string, meta interface{}) resource.StateRefreshFunc {
	client := meta.(*digitalocean.Client)
	return func() (interface{}, string, error) {
		err := resourceDigitalOceanDropletRead(d, meta)
		if err != nil {
			return nil, "", err
		}

		// If the droplet is locked, continue waiting. We can
		// only perform actions on unlocked droplets, so it's
		// pointless to look at that status
		if d.Get("locked").(string) == "true" {
			log.Println("[DEBUG] Droplet is locked, skipping status check and retrying")
			return nil, "", nil
		}

		// See if we can access our attribute
		if attr, ok := d.GetOk(attribute); ok {
			// Retrieve the droplet properties
			droplet, err := client.RetrieveDroplet(d.Id())
			if err != nil {
				return nil, "", fmt.Errorf("Error retrieving droplet: %s", err)
			}

			return &droplet, attr.(string), nil
		}

		return nil, "", nil
	}
}

// Powers on the droplet and waits for it to be active
func powerOnAndWait(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*digitalocean.Client)
	err := client.PowerOn(d.Id())
	if err != nil {
		return err
	}

	// Wait for power on
	_, err = WaitForDropletAttribute(d, "active", []string{"off"}, "status", client)
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>providers/digitalocean: increase timeout for droplet wait to 60 mins<commit_after>package digitalocean

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/pearkes/digitalocean"
)

func resourceDigitalOceanDroplet() *schema.Resource {
	return &schema.Resource{
		Create: resourceDigitalOceanDropletCreate,
		Read:   resourceDigitalOceanDropletRead,
		Update: resourceDigitalOceanDropletUpdate,
		Delete: resourceDigitalOceanDropletDelete,

		Schema: map[string]*schema.Schema{
			"image": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"region": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"size": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"status": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"locked": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"backups": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},

			"ipv6": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
			},

			"ipv6_address": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"ipv6_address_private": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"private_networking": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
			},

			"ipv4_address": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"ipv4_address_private": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"ssh_keys": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
			},

			"user_data": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
		},
	}
}

func resourceDigitalOceanDropletCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*digitalocean.Client)

	// Build up our creation options
	opts := &digitalocean.CreateDroplet{
		Image:  d.Get("image").(string),
		Name:   d.Get("name").(string),
		Region: d.Get("region").(string),
		Size:   d.Get("size").(string),
	}

	if attr, ok := d.GetOk("backups"); ok {
		opts.Backups = attr.(string)
	}

	if attr, ok := d.GetOk("ipv6"); ok && attr.(bool) {
		opts.IPV6 = "true"
	}

	if attr, ok := d.GetOk("private_networking"); ok && attr.(bool) {
		opts.PrivateNetworking = "true"
	}

	if attr, ok := d.GetOk("user_data"); ok {
		opts.UserData = attr.(string)
	}

	// Get configured ssh_keys
	ssh_keys := d.Get("ssh_keys.#").(int)
	if ssh_keys > 0 {
		opts.SSHKeys = make([]string, 0, ssh_keys)
		for i := 0; i < ssh_keys; i++ {
			key := fmt.Sprintf("ssh_keys.%d", i)
			opts.SSHKeys = append(opts.SSHKeys, d.Get(key).(string))
		}
	}

	log.Printf("[DEBUG] Droplet create configuration: %#v", opts)

	id, err := client.CreateDroplet(opts)

	if err != nil {
		return fmt.Errorf("Error creating droplet: %s", err)
	}

	// Assign the droplets id
	d.SetId(id)

	log.Printf("[INFO] Droplet ID: %s", d.Id())

	_, err = WaitForDropletAttribute(d, "active", []string{"new"}, "status", meta)
	if err != nil {
		return fmt.Errorf(
			"Error waiting for droplet (%s) to become ready: %s", d.Id(), err)
	}

	return resourceDigitalOceanDropletRead(d, meta)
}

func resourceDigitalOceanDropletRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*digitalocean.Client)

	// Retrieve the droplet properties for updating the state
	droplet, err := client.RetrieveDroplet(d.Id())
	if err != nil {
		return fmt.Errorf("Error retrieving droplet: %s", err)
	}

	if droplet.ImageSlug() != "" {
		d.Set("image", droplet.ImageSlug())
	} else {
		d.Set("image", droplet.ImageId())
	}

	d.Set("name", droplet.Name)
	d.Set("region", droplet.RegionSlug())
	d.Set("size", droplet.SizeSlug)
	d.Set("status", droplet.Status)
	d.Set("locked", droplet.IsLocked())

	if droplet.IPV6Address("public") != "" {
		d.Set("ipv6", true)
		d.Set("ipv6_address", droplet.IPV6Address("public"))
		d.Set("ipv6_address_private", droplet.IPV6Address("private"))
	}

	d.Set("ipv4_address", droplet.IPV4Address("public"))

	if droplet.NetworkingType() == "private" {
		d.Set("private_networking", true)
		d.Set("ipv4_address_private", droplet.IPV4Address("private"))
	}

	// Initialize the connection info
	d.SetConnInfo(map[string]string{
		"type": "ssh",
		"host": droplet.IPV4Address("public"),
	})

	return nil
}

func resourceDigitalOceanDropletUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*digitalocean.Client)

	if d.HasChange("size") {
		oldSize, newSize := d.GetChange("size")

		err := client.PowerOff(d.Id())

		if err != nil && !strings.Contains(err.Error(), "Droplet is already powered off") {
			return fmt.Errorf(
				"Error powering off droplet (%s): %s", d.Id(), err)
		}

		// Wait for power off
		_, err = WaitForDropletAttribute(d, "off", []string{"active"}, "status", client)
		if err != nil {
			return fmt.Errorf(
				"Error waiting for droplet (%s) to become powered off: %s", d.Id(), err)
		}

		// Resize the droplet
		err = client.Resize(d.Id(), newSize.(string))
		if err != nil {
			newErr := powerOnAndWait(d, meta)
			if newErr != nil {
				return fmt.Errorf(
					"Error powering on droplet (%s) after failed resize: %s", d.Id(), err)
			}
			return fmt.Errorf(
				"Error resizing droplet (%s): %s", d.Id(), err)
		}

		// Wait for the size to change
		_, err = WaitForDropletAttribute(
			d, newSize.(string), []string{"", oldSize.(string)}, "size", meta)

		if err != nil {
			newErr := powerOnAndWait(d, meta)
			if newErr != nil {
				return fmt.Errorf(
					"Error powering on droplet (%s) after waiting for resize to finish: %s", d.Id(), err)
			}
			return fmt.Errorf(
				"Error waiting for resize droplet (%s) to finish: %s", d.Id(), err)
		}

		err = client.PowerOn(d.Id())

		if err != nil {
			return fmt.Errorf(
				"Error powering on droplet (%s) after resize: %s", d.Id(), err)
		}

		// Wait for power off
		_, err = WaitForDropletAttribute(d, "active", []string{"off"}, "status", meta)
		if err != nil {
			return err
		}
	}

	if d.HasChange("name") {
		oldName, newName := d.GetChange("name")

		// Rename the droplet
		err := client.Rename(d.Id(), newName.(string))

		if err != nil {
			return fmt.Errorf(
				"Error renaming droplet (%s): %s", d.Id(), err)
		}

		// Wait for the name to change
		_, err = WaitForDropletAttribute(
			d, newName.(string), []string{"", oldName.(string)}, "name", meta)

		if err != nil {
			return fmt.Errorf(
				"Error waiting for rename droplet (%s) to finish: %s", d.Id(), err)
		}
	}

	// As there is no way to disable private networking,
	// we only check if it needs to be enabled
	if d.HasChange("private_networking") && d.Get("private_networking").(bool) {
		err := client.EnablePrivateNetworking(d.Id())

		if err != nil {
			return fmt.Errorf(
				"Error enabling private networking for droplet (%s): %s", d.Id(), err)
		}

		// Wait for the private_networking to turn on
		_, err = WaitForDropletAttribute(
			d, "true", []string{"", "false"}, "private_networking", meta)

		return fmt.Errorf(
			"Error waiting for private networking to be enabled on for droplet (%s): %s", d.Id(), err)
	}

	// As there is no way to disable IPv6, we only check if it needs to be enabled
	if d.HasChange("ipv6") && d.Get("ipv6").(bool) {
		err := client.EnableIPV6s(d.Id())

		if err != nil {
			return fmt.Errorf(
				"Error turning on ipv6 for droplet (%s): %s", d.Id(), err)
		}

		// Wait for ipv6 to turn on
		_, err = WaitForDropletAttribute(
			d, "true", []string{"", "false"}, "ipv6", meta)

		if err != nil {
			return fmt.Errorf(
				"Error waiting for ipv6 to be turned on for droplet (%s): %s", d.Id(), err)
		}
	}

	return resourceDigitalOceanDropletRead(d, meta)
}

func resourceDigitalOceanDropletDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*digitalocean.Client)

	log.Printf("[INFO] Deleting droplet: %s", d.Id())

	// Destroy the droplet
	err := client.DestroyDroplet(d.Id())

	// Handle remotely destroyed droplets
	if err != nil && strings.Contains(err.Error(), "404 Not Found") {
		return nil
	}

	if err != nil {
		return fmt.Errorf("Error deleting droplet: %s", err)
	}

	return nil
}

func WaitForDropletAttribute(
	d *schema.ResourceData, target string, pending []string, attribute string, meta interface{}) (interface{}, error) {
	// Wait for the droplet so we can get the networking attributes
	// that show up after a while
	log.Printf(
		"[INFO] Waiting for droplet (%s) to have %s of %s",
		d.Id(), attribute, target)

	stateConf := &resource.StateChangeConf{
		Pending:    pending,
		Target:     target,
		Refresh:    newDropletStateRefreshFunc(d, attribute, meta),
		Timeout:    60 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	return stateConf.WaitForState()
}

// TODO This function still needs a little more refactoring to make it
// cleaner and more efficient
func newDropletStateRefreshFunc(
	d *schema.ResourceData, attribute string, meta interface{}) resource.StateRefreshFunc {
	client := meta.(*digitalocean.Client)
	return func() (interface{}, string, error) {
		err := resourceDigitalOceanDropletRead(d, meta)
		if err != nil {
			return nil, "", err
		}

		// If the droplet is locked, continue waiting. We can
		// only perform actions on unlocked droplets, so it's
		// pointless to look at that status
		if d.Get("locked").(string) == "true" {
			log.Println("[DEBUG] Droplet is locked, skipping status check and retrying")
			return nil, "", nil
		}

		// See if we can access our attribute
		if attr, ok := d.GetOk(attribute); ok {
			// Retrieve the droplet properties
			droplet, err := client.RetrieveDroplet(d.Id())
			if err != nil {
				return nil, "", fmt.Errorf("Error retrieving droplet: %s", err)
			}

			return &droplet, attr.(string), nil
		}

		return nil, "", nil
	}
}

// Powers on the droplet and waits for it to be active
func powerOnAndWait(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*digitalocean.Client)
	err := client.PowerOn(d.Id())
	if err != nil {
		return err
	}

	// Wait for power on
	_, err = WaitForDropletAttribute(d, "active", []string{"off"}, "status", client)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>