<commit_before>package xkcd_test

import (
	"encoding/json"
	"github.com/rkoesters/xkcd"
	"io"
	"testing"
)

func TestGet(t *testing.T) {
	comic, err := xkcd.Get(221)
	if err != nil {
		t.Fatal(err)
	}

	expected := &xkcd.Comic{
		Num:       221,
		Title:     "Random Number",
		SafeTitle: "Random Number",
		Img:       "http://imgs.xkcd.com/comics/random_number.png",
		Alt:       "RFC 1149.5 specifies 4 as the standard IEEE-vetted random number.",
		Year:      "2007",
		Month:     "2",
		Day:       "9",
		News:      "",
		Link:      "",
		Transcript: `int getRandomNumber()
{
  return 4;
 chosen by fair dice roll.

 guarenteed to be random.
}
{{title text: RFC 1149.5 specifies 4 as the standard IEEE-vetted random number.}}`,
	}

	if *comic != *expected {
		t.Fail()
	}
}

func TestGetCurrent(t *testing.T) {
	comic1, err := xkcd.GetCurrent()
	if err != nil {
		t.Fatal(err)
	}

	comic2, err := xkcd.Get(comic1.Num)
	if err != nil {
		t.Fatal(err)
	}

	if *comic1 != *comic2 {
		t.Fail()
	}
}

func Test404(t *testing.T) {
	_, err := xkcd.Get(404)
	if err.Error() != "404 Not Found" {
		t.Fatal(err)
	}
}

func TestNew(t *testing.T) {
	comic1, err := xkcd.GetCurrent()
	if err != nil {
		t.Fatal(err)
	}

	r, w := io.Pipe()

	go func() {
		e := json.NewEncoder(w)
		err = e.Encode(comic1)
		if err != nil {
			t.Fatal(err)
		}
	}()

	comic2, err := xkcd.New(r)
	if err != nil {
		t.Fatal(err)
	}

	t.Log("comic1: ", comic1)
	t.Log("comic2: ", comic2)

	if *comic1 != *comic2 {
		t.Fatal("comic1 and comic2 don't match")
	}
}
<commit_msg>Updated tests.<commit_after>package xkcd_test

import (
	"encoding/json"
	"github.com/rkoesters/xkcd"
	"io"
	"testing"
)

func TestGet(t *testing.T) {
	comic, err := xkcd.Get(221)
	if err != nil {
		t.Fatal(err)
	}

	expected := &xkcd.Comic{
		Num:       221,
		Title:     "Random Number",
		SafeTitle: "Random Number",
		Img:       "http://imgs.xkcd.com/comics/random_number.png",
		Alt:       "RFC 1149.5 specifies 4 as the standard IEEE-vetted random number.",
		Year:      "2007",
		Month:     "2",
		Day:       "9",
		News:      "",
		Link:      "",
		Transcript: `int getRandomNumber()
{
  return 4;
 chosen by fair dice roll.

 guarenteed to be random.
}
{{title text: RFC 1149.5 specifies 4 as the standard IEEE-vetted random number.}}`,
	}

	t.Log("comic: ", comic)
	t.Log("expected: ", expected)

	if *comic != *expected {
		t.Fail()
	}
}

func TestGetCurrent(t *testing.T) {
	comic1, err := xkcd.GetCurrent()
	if err != nil {
		t.Fatal(err)
	}

	comic2, err := xkcd.Get(comic1.Num)
	if err != nil {
		t.Fatal(err)
	}

	t.Log("comic1: ", comic1)
	t.Log("comic2: ", comic2)

	if *comic1 != *comic2 {
		t.Fatal("comic1 and comic2 don't match")
	}
}

func Test404(t *testing.T) {
	_, err := xkcd.Get(404)
	if err.Error() != "404 Not Found" {
		t.Fatal(err)
	}
}

func TestNew(t *testing.T) {
	comic1, err := xkcd.GetCurrent()
	if err != nil {
		t.Fatal(err)
	}

	r, w := io.Pipe()

	go func() {
		e := json.NewEncoder(w)
		err = e.Encode(comic1)
		if err != nil {
			t.Fatal(err)
		}
	}()

	comic2, err := xkcd.New(r)
	if err != nil {
		t.Fatal(err)
	}

	t.Log("comic1: ", comic1)
	t.Log("comic2: ", comic2)

	if *comic1 != *comic2 {
		t.Fatal("comic1 and comic2 don't match")
	}
}
<|endoftext|>


<commit_before>package golf

import (
	"encoding/hex"
	"testing"
)

func TestRandomBytes(t *testing.T) {
	randomBytesLengths := []int{0, 32, 64, 1024}
	for length := range randomBytesLengths {
		randomBytes := randomBytes(length)
		if len(randomBytes) != length {
			t.Errorf("Could not create random byte array with length %v", length)
		}
	}
}

func TestDecodeXSRF(t *testing.T) {
	maskedToken := newXSRFToken()
	maskedTokenBytes, _ := hex.DecodeString(maskedToken)
	mask, token, _ := decodeXSRFToken(maskedToken)
	if !compareToken(maskedTokenBytes, append(mask, websocketMask(mask, token)...)) {
		t.Error("Could not genearte correct XSRF token. %v != %v")
	}
}
<commit_msg>[fix] Fix error formatting<commit_after>package golf

import (
	"encoding/hex"
	"testing"
)

func TestRandomBytes(t *testing.T) {
	randomBytesLengths := []int{0, 32, 64, 1024}
	for length := range randomBytesLengths {
		randomBytes := randomBytes(length)
		if len(randomBytes) != length {
			t.Errorf("Could not create random byte array with length %v", length)
		}
	}
}

func TestDecodeXSRF(t *testing.T) {
	maskedToken := newXSRFToken()
	maskedTokenBytes, _ := hex.DecodeString(maskedToken)
	mask, token, _ := decodeXSRFToken(maskedToken)
	result := append(mask, websocketMask(mask, token)...)
	if !compareToken(maskedTokenBytes, result) {
		t.Errorf("Could not genearte correct XSRF token. %v != %v", maskedTokenBytes, result)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Yoshiki Shibata. All rights reserved.

// This package is intended to provide some system calls which are not
// provided the original Go syscall package.

package xusyscall

// Note that some system call such as shmget is not a system call on some
// systems such as 32bit Linux. So we need to implement this package in C
// language

// #include <sys/ipc.h>
// #include <sys/shm.h>
// #include <errno.h>
import "C"

import "unsafe"
import "strconv"

// Flags for fuctions. About details see the output of `man shmget` on Unix.
const (
	// Private key
	IPC_PRIVATE = 0

	// Create key if key does not exist
	IPC_CREAT = 01000
	// Fail if key exists
	IPC_EXCL = 02000
	// Segment is mapped via hugetlb
	SHM_HUGETLB = 04000
	// Don't check for reservations
	SHM_NORESERVE = 010000

	ipc_RMID = 0
	ipc_SET  = 1
	ipc_STAT = 2
	ipc_INFO = 3
)

// Gets a shared memory specified by the key.
// key, size, and shmflg must be equal to or greater than 0.
func Shmget(key int, size int, shmflg int) (shmid int, err error) {
	if key < 0 {
		panic("key is negative value: " + strconv.Itoa(key))
	}
	if size < 0 {
		panic("size is negative value: " + strconv.Itoa(size))
	}
	if shmflg < 0 {
		panic("shmflg is negative value: " + strconv.Itoa(shmflg))
	}

	result, errno := C.shmget(C.key_t(key), C.size_t(size), C.int(shmflg))

	if result == -1 {
		return -1, errno
	}
	return int(result), nil
}

// Attaches the specified shared memory.
// shmflg must be equal to or greater than 0.
func Shmat(shmid int, shmflg int) (data []byte, err error) {
	if shmflg < 0 {
		panic("shmflg is negative value: " + strconv.Itoa(shmflg))
	}

	addr, errno := shmat(shmid, 0, shmflg)

	if errno != nil {
		return nil, errno
	}

	length, errno2 := shmseqsz(shmid)
	if errno2 != nil {
		return nil, errno2
	}

	// Slice memory layout
	var sl = struct {
		addr uintptr
		len  int
		cap  int
	}{addr, length, length}

	data = *(*[]byte)(unsafe.Pointer(&sl))
	return data, nil
}

func shmat(shmid int, shmaddr uintptr, shmflg int) (addr uintptr, err error) {
	result, errno := C.shmat(C.int(shmid), unsafe.Pointer(shmaddr), C.int(shmflg))

	if int(uintptr(result)) == -1 {
		return 0, errno
	}

	return uintptr(result), nil
}

func shmseqsz(shmid int) (segsz int, err error) {
	var shmid_ds C.struct_shmid_ds

	errno := shmctl(shmid, ipc_STAT, &shmid_ds)
	if errno != nil {
		return 0, errno
	}
	return int(shmid_ds.shm_segsz), nil
}

// Detaches the shared memory
func Shmdt(data []byte) error {
	result, errno := C.shmdt(unsafe.Pointer(&data[0]))

	if result == -1 {
		return errno
	}
	return nil
}

// Remove the shared memory specified by shmid
func Shmrm(shmid int) error {
	var shmid_ds C.struct_shmid_ds

	errno := shmctl(shmid, ipc_RMID, &shmid_ds)

	if errno != nil {
		return errno
	}
	return nil
}

// shmctl syscall
func shmctl(shmid int, cmd int, shmid_ds *C.struct_shmid_ds) error {
	result, errno := C.shmctl(C.int(shmid), C.int(cmd),
		(*C.struct_shmid_ds)(unsafe.Pointer(shmid_ds)))

	if result == -1 {
		return errno
	}
	return nil
}
<commit_msg>momodified documentation for this package<commit_after>// Copyright (c) 2013 Yoshiki Shibata. All rights reserved.

// Package xusyscall contains system calls which are not
// provided the original Go syscall package.
package xusyscall

// Note that some system call such as shmget is not a system call on some
// systems such as 32bit Linux. So we need to implement this package in C
// language

// #include <sys/ipc.h>
// #include <sys/shm.h>
// #include <errno.h>
import "C"

import "unsafe"
import "strconv"

// Flags for fuctions. About details see the output of `man shmget` on Unix.
const (
	// Private key
	IPC_PRIVATE = 0

	// Create key if key does not exist
	IPC_CREAT = 01000
	// Fail if key exists
	IPC_EXCL = 02000
	// Segment is mapped via hugetlb
	SHM_HUGETLB = 04000
	// Don't check for reservations
	SHM_NORESERVE = 010000

	ipc_RMID = 0
	ipc_SET  = 1
	ipc_STAT = 2
	ipc_INFO = 3
)

// Gets a shared memory specified by the key.
// key, size, and shmflg must be equal to or greater than 0.
func Shmget(key int, size int, shmflg int) (shmid int, err error) {
	if key < 0 {
		panic("key is negative value: " + strconv.Itoa(key))
	}
	if size < 0 {
		panic("size is negative value: " + strconv.Itoa(size))
	}
	if shmflg < 0 {
		panic("shmflg is negative value: " + strconv.Itoa(shmflg))
	}

	result, errno := C.shmget(C.key_t(key), C.size_t(size), C.int(shmflg))

	if result == -1 {
		return -1, errno
	}
	return int(result), nil
}

// Attaches the specified shared memory.
// shmflg must be equal to or greater than 0.
func Shmat(shmid int, shmflg int) (data []byte, err error) {
	if shmflg < 0 {
		panic("shmflg is negative value: " + strconv.Itoa(shmflg))
	}

	addr, errno := shmat(shmid, 0, shmflg)

	if errno != nil {
		return nil, errno
	}

	length, errno2 := shmseqsz(shmid)
	if errno2 != nil {
		return nil, errno2
	}

	// Slice memory layout
	var sl = struct {
		addr uintptr
		len  int
		cap  int
	}{addr, length, length}

	data = *(*[]byte)(unsafe.Pointer(&sl))
	return data, nil
}

func shmat(shmid int, shmaddr uintptr, shmflg int) (addr uintptr, err error) {
	result, errno := C.shmat(C.int(shmid), unsafe.Pointer(shmaddr), C.int(shmflg))

	if int(uintptr(result)) == -1 {
		return 0, errno
	}

	return uintptr(result), nil
}

func shmseqsz(shmid int) (segsz int, err error) {
	var shmid_ds C.struct_shmid_ds

	errno := shmctl(shmid, ipc_STAT, &shmid_ds)
	if errno != nil {
		return 0, errno
	}
	return int(shmid_ds.shm_segsz), nil
}

// Detaches the shared memory
func Shmdt(data []byte) error {
	result, errno := C.shmdt(unsafe.Pointer(&data[0]))

	if result == -1 {
		return errno
	}
	return nil
}

// Remove the shared memory specified by shmid
func Shmrm(shmid int) error {
	var shmid_ds C.struct_shmid_ds

	errno := shmctl(shmid, ipc_RMID, &shmid_ds)

	if errno != nil {
		return errno
	}
	return nil
}

// shmctl syscall
func shmctl(shmid int, cmd int, shmid_ds *C.struct_shmid_ds) error {
	result, errno := C.shmctl(C.int(shmid), C.int(cmd),
		(*C.struct_shmid_ds)(unsafe.Pointer(shmid_ds)))

	if result == -1 {
		return errno
	}
	return nil
}
<|endoftext|>


<commit_before>package zk

import (
	"strings"
	"time"
)

type Config struct {
	Name           string
	ZkAddrs        string
	SessionTimeout time.Duration
	PanicOnError   bool
}

func DefaultConfig(name, addrs string) *Config {
	return &Config{
		Name:           name,
		ZkAddrs:        addrs,
		SessionTimeout: DefaultZkSessionTimeout(),
		PanicOnError:   false,
	}
}

func (this *Config) ZkServers() []string {
	return strings.Split(this.ZkAddrs, ",")
}

func DefaultZkSessionTimeout() time.Duration {
	return time.Minute
}
<commit_msg>default ZK session will be 5m<commit_after>package zk

import (
	"strings"
	"time"
)

type Config struct {
	Name           string
	ZkAddrs        string
	SessionTimeout time.Duration
	PanicOnError   bool
}

func DefaultConfig(name, addrs string) *Config {
	return &Config{
		Name:           name,
		ZkAddrs:        addrs,
		SessionTimeout: DefaultZkSessionTimeout(),
		PanicOnError:   false,
	}
}

func (this *Config) ZkServers() []string {
	return strings.Split(this.ZkAddrs, ",")
}

func DefaultZkSessionTimeout() time.Duration {
	return time.Minute * 5
}
<|endoftext|>


<commit_before>package zmq2_test

import (
	zmq "github.com/pebbe/zmq2"

	"fmt"
	"runtime"
)

func Example_test_version() {
	major, minor, _ := zmq.Version()
	fmt.Println("Version major:", major)
	fmt.Println("Version minor == 1|2:", minor == 1 || minor == 2)
	// Output:
	// Version major: 2
	// Version minor == 1|2: true
}

func Example_test_hwm() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_pair_inproc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_pair_ipc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_pair_tcp() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_reqrep_inproc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_reqrep_ipc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_reqrep_tcp() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_shutdown_stress() {

	fmt.Println("Done")
	// Output:
	// Done
}

func checkErr(err error) bool {
	if err != nil {
		_, filename, lineno, ok := runtime.Caller(1)
		if ok {
			fmt.Printf("%v:%v: %v\n", filename, lineno, err)
		} else {
			fmt.Println(err)
		}
		return true
	}
	return false
}
<commit_msg>Replaced example by test<commit_after>package zmq2_test

import (
	zmq "github.com/pebbe/zmq2"

	"testing"
)

func TestVersion(t *testing.T) {
	major, _, _ := zmq.Version()
	if major != 2 {
		t.Errorf("Expected major version 2, got %d", major)
	}
}
<|endoftext|>


<commit_before>package zmq3_test

import (
	zmq "github.com/pebbe/zmq3"

	"errors"
	"fmt"
	"runtime"
)

func Example_version() {
	major, _, _ := zmq.Version()
	fmt.Println("Version:", major)
	// Output:
	// Version: 3
}

func Example_test_connect_delay() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_connect_resolve() {

	/*
		copied from zmq4
	*/

	sock, err := zmq.NewSocket(zmq.PUB)
	if checkErr(err) {
		return
	}

	err = sock.Connect("tcp://localhost:1234")
	checkErr(err)

	err = sock.Connect("tcp://localhost:invalid")
	fmt.Println(err)

	err = sock.Connect("tcp://in val id:1234")
	fmt.Println(err)

	err = sock.Connect("invalid://localhost:1234")
	fmt.Println(err)

	err = sock.Close()
	checkErr(err)

	fmt.Println("Done")
	// Output:
	// invalid argument
	// invalid argument
	// protocol not supported
	// Done
}

func Example_test_disconnect_inproc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_hwm() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_invalid_rep() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_last_endpoint() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_monitor() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_msg_flags() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_pair_inproc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_pair_ipc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_pair_tcp() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_reqrep_device() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_reqrep_inproc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_reqrep_ipc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_reqrep_tcp() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_router_mandatory() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_shutdown_stress() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_sub_forward() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_term_endpoint() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_timeo() {

	fmt.Println("Done")
	// Output:
	// Done
}

func bounce(server, client *zmq.Socket) {

	content := "12345678ABCDEFGH12345678abcdefgh"

	//  Send message from client to server
	rc, err := client.Send(content, zmq.SNDMORE)
	if checkErr(err) {
		return
	}
	if rc != 32 {
		checkErr(errors.New("rc != 32"))
	}

	rc, err = client.Send(content, 0)
	if checkErr(err) {
		return
	}
	if rc != 32 {
		checkErr(errors.New("rc != 32"))
	}

	//  Receive message at server side
	msg, err := server.Recv(0)
	if checkErr(err) {
		return
	}

	//  Check that message is still the same
	if msg != content {
		checkErr(errors.New(fmt.Sprintf("%q != %q", msg, content)))
	}

	rcvmore, err := server.GetRcvmore()
	if checkErr(err) {
		return
	}
	if !rcvmore {
		checkErr(errors.New(fmt.Sprint("rcvmore ==", rcvmore)))
		return
	}

	//  Receive message at server side
	msg, err = server.Recv(0)
	if checkErr(err) {
		return
	}

	//  Check that message is still the same
	if msg != content {
		checkErr(errors.New(fmt.Sprintf("%q != %q", msg, content)))
	}

	rcvmore, err = server.GetRcvmore()
	if checkErr(err) {
		return
	}
	if rcvmore {
		checkErr(errors.New(fmt.Sprint("rcvmore == ", rcvmore)))
		return
	}

	// The same, from server back to client

	//  Send message from server to client
	rc, err = server.Send(content, zmq.SNDMORE)
	if checkErr(err) {
		return
	}
	if rc != 32 {
		checkErr(errors.New("rc != 32"))
	}

	rc, err = server.Send(content, 0)
	if checkErr(err) {
		return
	}
	if rc != 32 {
		checkErr(errors.New("rc != 32"))
	}

	//  Receive message at client side
	msg, err = client.Recv(0)
	if checkErr(err) {
		return
	}

	//  Check that message is still the same
	if msg != content {
		checkErr(errors.New(fmt.Sprintf("%q != %q", msg, content)))
	}

	rcvmore, err = client.GetRcvmore()
	if checkErr(err) {
		return
	}
	if !rcvmore {
		checkErr(errors.New(fmt.Sprint("rcvmore ==", rcvmore)))
		return
	}

	//  Receive message at client side
	msg, err = client.Recv(0)
	if checkErr(err) {
		return
	}

	//  Check that message is still the same
	if msg != content {
		checkErr(errors.New(fmt.Sprintf("%q != %q", msg, content)))
	}

	rcvmore, err = client.GetRcvmore()
	if checkErr(err) {
		return
	}
	if rcvmore {
		checkErr(errors.New(fmt.Sprint("rcvmore == ", rcvmore)))
		return
	}

}

func checkErr(err error) bool {
	if err != nil {
		_, filename, lineno, ok := runtime.Caller(1)
		if ok {
			fmt.Printf("%v:%v: %v\n", filename, lineno, err)
		} else {
			fmt.Println(err)
		}
		return true
	}
	return false
}
<commit_msg>Hide version test from godoc examples<commit_after>package zmq3_test

import (
	zmq "github.com/pebbe/zmq3"

	"errors"
	"fmt"
	"runtime"
)

func Example_test_version() {
	major, _, _ := zmq.Version()
	fmt.Println("Version:", major)
	// Output:
	// Version: 3
}

func Example_test_connect_delay() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_connect_resolve() {

	/*
		copied from zmq4
	*/

	sock, err := zmq.NewSocket(zmq.PUB)
	if checkErr(err) {
		return
	}

	err = sock.Connect("tcp://localhost:1234")
	checkErr(err)

	err = sock.Connect("tcp://localhost:invalid")
	fmt.Println(err)

	err = sock.Connect("tcp://in val id:1234")
	fmt.Println(err)

	err = sock.Connect("invalid://localhost:1234")
	fmt.Println(err)

	err = sock.Close()
	checkErr(err)

	fmt.Println("Done")
	// Output:
	// invalid argument
	// invalid argument
	// protocol not supported
	// Done
}

func Example_test_disconnect_inproc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_hwm() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_invalid_rep() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_last_endpoint() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_monitor() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_msg_flags() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_pair_inproc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_pair_ipc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_pair_tcp() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_reqrep_device() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_reqrep_inproc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_reqrep_ipc() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_reqrep_tcp() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_router_mandatory() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_shutdown_stress() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_sub_forward() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_term_endpoint() {

	fmt.Println("Done")
	// Output:
	// Done
}

func Example_test_timeo() {

	fmt.Println("Done")
	// Output:
	// Done
}

func bounce(server, client *zmq.Socket) {

	content := "12345678ABCDEFGH12345678abcdefgh"

	//  Send message from client to server
	rc, err := client.Send(content, zmq.SNDMORE)
	if checkErr(err) {
		return
	}
	if rc != 32 {
		checkErr(errors.New("rc != 32"))
	}

	rc, err = client.Send(content, 0)
	if checkErr(err) {
		return
	}
	if rc != 32 {
		checkErr(errors.New("rc != 32"))
	}

	//  Receive message at server side
	msg, err := server.Recv(0)
	if checkErr(err) {
		return
	}

	//  Check that message is still the same
	if msg != content {
		checkErr(errors.New(fmt.Sprintf("%q != %q", msg, content)))
	}

	rcvmore, err := server.GetRcvmore()
	if checkErr(err) {
		return
	}
	if !rcvmore {
		checkErr(errors.New(fmt.Sprint("rcvmore ==", rcvmore)))
		return
	}

	//  Receive message at server side
	msg, err = server.Recv(0)
	if checkErr(err) {
		return
	}

	//  Check that message is still the same
	if msg != content {
		checkErr(errors.New(fmt.Sprintf("%q != %q", msg, content)))
	}

	rcvmore, err = server.GetRcvmore()
	if checkErr(err) {
		return
	}
	if rcvmore {
		checkErr(errors.New(fmt.Sprint("rcvmore == ", rcvmore)))
		return
	}

	// The same, from server back to client

	//  Send message from server to client
	rc, err = server.Send(content, zmq.SNDMORE)
	if checkErr(err) {
		return
	}
	if rc != 32 {
		checkErr(errors.New("rc != 32"))
	}

	rc, err = server.Send(content, 0)
	if checkErr(err) {
		return
	}
	if rc != 32 {
		checkErr(errors.New("rc != 32"))
	}

	//  Receive message at client side
	msg, err = client.Recv(0)
	if checkErr(err) {
		return
	}

	//  Check that message is still the same
	if msg != content {
		checkErr(errors.New(fmt.Sprintf("%q != %q", msg, content)))
	}

	rcvmore, err = client.GetRcvmore()
	if checkErr(err) {
		return
	}
	if !rcvmore {
		checkErr(errors.New(fmt.Sprint("rcvmore ==", rcvmore)))
		return
	}

	//  Receive message at client side
	msg, err = client.Recv(0)
	if checkErr(err) {
		return
	}

	//  Check that message is still the same
	if msg != content {
		checkErr(errors.New(fmt.Sprintf("%q != %q", msg, content)))
	}

	rcvmore, err = client.GetRcvmore()
	if checkErr(err) {
		return
	}
	if rcvmore {
		checkErr(errors.New(fmt.Sprint("rcvmore == ", rcvmore)))
		return
	}

}

func checkErr(err error) bool {
	if err != nil {
		_, filename, lineno, ok := runtime.Caller(1)
		if ok {
			fmt.Printf("%v:%v: %v\n", filename, lineno, err)
		} else {
			fmt.Println(err)
		}
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package pruneCmd

import (
	// Stdlib
	"errors"
	"fmt"
	"os"
	"strings"

	// Internal
	"github.com/salsaflow/salsaflow/app"
	"github.com/salsaflow/salsaflow/app/appflags"
	"github.com/salsaflow/salsaflow/errs"
	"github.com/salsaflow/salsaflow/flag"
	"github.com/salsaflow/salsaflow/git"
	"github.com/salsaflow/salsaflow/git/gitutil"
	"github.com/salsaflow/salsaflow/log"
	"github.com/salsaflow/salsaflow/modules"
	"github.com/salsaflow/salsaflow/modules/common"
	"github.com/salsaflow/salsaflow/prompt"

	// Other
	"gopkg.in/tchap/gocli.v2"
)

const StoryBranchPrefix = "story/"

var stateEnum = []common.StoryState{
	common.StoryStateTested,
	common.StoryStateStaged,
	common.StoryStateAccepted,
	common.StoryStateClosed,
}

var Command = &gocli.Command{
	// UsageLine set below in an init() functions.
	Short: "delete branches that are not needed",
	Long: `
  Delete Git branches that are no longer needed.

  All story branches are checked and the branches that only contain commits
  associated with stories that are in the selected state or further
  are offered to be deleted. Both local and remote branches are affected.

  This commands counts on the fact that all branches starting with story/
  are forked off trunk. In case this is not met, weird things can happen.
	`,
	Action: run,
}

var flagState *flag.StringEnumFlag

func init() {
	states := make([]string, 0, len(stateEnum))
	for _, state := range stateEnum {
		states = append(states, string(state))
	}

	// Finalize Command.
	Command.UsageLine = fmt.Sprintf("prune [-state={%v}]", strings.Join(states, "|"))

	// Register flags.
	flagState = flag.NewStringEnumFlag(states, string(common.StoryStateAccepted))
	Command.Flags.Var(flagState, "state", "set the required story state for branch removal")

	// Register global flags.
	appflags.RegisterGlobalFlags(&Command.Flags)
}

func allowedStoryStates() map[common.StoryState]struct{} {
	var enum []common.StoryState
	v := common.StoryState(flagState.Value())
	switch v {
	case common.StoryStateTested:
		enum = stateEnum
	case common.StoryStateStaged:
		enum = stateEnum[1:]
	case common.StoryStateAccepted:
		enum = stateEnum[2:]
	case common.StoryStateClosed:
		enum = stateEnum[3:]
	default:
		panic("unknown state: " + v)
	}

	m := make(map[common.StoryState]struct{}, len(enum))
	for _, state := range enum {
		m[state] = struct{}{}
	}
	return m
}

func run(cmd *gocli.Command, args []string) {
	if len(args) != 0 {
		cmd.Usage()
		os.Exit(2)
	}

	app.InitOrDie()

	if err := runMain(); err != nil {
		errs.Fatal(err)
	}
}

func runMain() error {
	// Load config.
	config, err := git.LoadConfig()
	if err != nil {
		return err
	}
	var (
		remoteName = config.RemoteName
		trunkName  = config.TrunkBranchName
	)

	// Make sure trunk is up to date.
	task := fmt.Sprintf("Make sure branch '%v' is up to date", trunkName)
	log.Run(task)
	if err := git.CheckOrCreateTrackingBranch(trunkName, remoteName); err != nil {
		return errs.NewError(task, err)
	}

	// Collect the story branches.
	task = "Collect the story branches"
	log.Run(task)
	storyBranches, err := collectStoryBranches(remoteName)
	if err != nil {
		return errs.NewError(task, err)
	}

	// Split the branches that are not up to date.
	task = "Split the branches that are not up to date"
	log.Run(task)
	storyBranches, err = splitBranchesNotInSync(storyBranches)
	if err != nil {
		return errs.NewError(task, err)
	}

	// Filter branches according to the story state.
	task = "Filter branches according to the story state"
	log.Run(task)
	filteredBranches, err := filterBranches(storyBranches, trunkName)
	if err != nil {
		return errs.NewError(task, err)
	}
	if len(storyBranches) == 0 {
		log.Log("No branches left to be deleted")
		return nil
	}

	// Prompt the user to choose what branches to delete.
	task = "Prompt the user to choose what branches to delete"
	localToDelete, remoteToDelete, err := promptUserToChooseBranches(filteredBranches)
	if err != nil {
		return errs.NewError(task, err)
	}

	// Delete chosen local branches.
	if len(localToDelete) != 0 {
		task := "Delete chosen local branches"
		log.Run(task)
		args := make([]string, 1, 1+len(localToDelete))
		args[0] = "-D"
		args = append(args, localToDelete...)
		if ex := git.Branch(args...); ex != nil {
			errs.LogError(task, ex)
			err = errors.New("failed to delete local branches")
		}
	}

	// Delete chosen remote branches.
	if len(remoteToDelete) != 0 {
		task := "Delete chosen remote branches"
		log.Run(task)
		args := make([]string, 1, 1+len(remoteToDelete))
		args[0] = "--delete"
		args = append(args, remoteToDelete...)
		if ex := git.Push(remoteName, args...); ex != nil {
			errs.LogError(task, ex)
			err = errors.New("failed to delete remote branches")
		}
	}

	return err
}

func collectStoryBranches(remoteName string) ([]*git.GitBranch, error) {
	// Load Git branches.
	branches, err := git.Branches()
	if err != nil {
		return nil, err
	}

	// Get the current branch name so that it can be excluded.
	currentBranch, err := gitutil.CurrentBranch()
	if err != nil {
		return nil, err
	}

	// Filter the branches.
	storyBranches := make([]*git.GitBranch, 0, len(branches))
	for _, branch := range branches {
		// Drop branches not corresponding to the project remote.
		if branch.Remote != "" && branch.Remote != remoteName {
			continue
		}

		var (
			isLocalStoryBranch  = strings.HasPrefix(branch.BranchName, StoryBranchPrefix)
			isRemoteStoryBranch = strings.HasPrefix(branch.RemoteBranchName, StoryBranchPrefix)
		)

		// Exclude the current branch.
		if isLocalStoryBranch && branch.BranchName == currentBranch {
			log.Warn(fmt.Sprintf("Branch '%v' is checked out, it cannot be deleted", currentBranch))
			continue
		}

		// Keep the story branches only.
		if isLocalStoryBranch || isRemoteStoryBranch {
			storyBranches = append(storyBranches, branch)
		}
	}

	// Return the result.
	return storyBranches, nil
}

func splitBranchesNotInSync(storyBranches []*git.GitBranch) ([]*git.GitBranch, error) {
	branches := make([]*git.GitBranch, 0, len(storyBranches))
	for _, branch := range storyBranches {
		upToDate, err := branch.IsUpToDate()
		if err != nil {
			return nil, err
		}
		if upToDate {
			branches = append(branches, branch)
			continue
		}

		// In case the branch is not up to date, we split the local and remote
		// reference into their own branch records to treat them separately.
		var (
			branchName       = branch.BranchName
			remoteBranchName = branch.RemoteBranchName
			remote           = branch.Remote
		)
		log.Warn(fmt.Sprintf("Branch '%s' is not up to date", branchName))
		log.NewLine(fmt.Sprintf("Treating '%v' and '%v/%v' as separate branches",
			branchName, remote, remoteBranchName))

		localBranch := &git.GitBranch{
			BranchName: branchName,
		}
		remoteBranch := &git.GitBranch{
			RemoteBranchName: remoteBranchName,
			Remote:           remote,
		}
		branches = append(branches, localBranch, remoteBranch)
	}
	return branches, nil
}

type gitBranch struct {
	tip     *git.GitBranch
	commits []*git.Commit

	// reason contains the reason the branch was included
	// in the branch deletion candidate list.
	reason string
}

func filterBranches(storyBranches []*git.GitBranch, trunkName string) ([]*gitBranch, error) {
	// Pair the branches with commit ranges specified by trunk..story
	task := "Collected commits associated with the story branches"
	branches := make([]*gitBranch, 0, len(storyBranches))
	for _, branch := range storyBranches {
		var revRange string
		if branch.BranchName != "" {
			// Handle branches that exist locally.
			revRange = fmt.Sprintf("%v..%v", trunkName, branch.BranchName)
		} else {
			// Handle branches that exist only in the remote repository.
			// We can use trunkName here since trunk is up to date.
			revRange = fmt.Sprintf("%v..%v/%v", trunkName, branch.Remote, branch.RemoteBranchName)
		}

		commits, err := git.ShowCommitRange(revRange)
		if err != nil {
			return nil, errs.NewError(task, err)
		}
		branches = append(branches, &gitBranch{
			tip:     branch,
			commits: commits,
		})
		continue
	}

	// Collect story tags.
	task = "Collect affected story tags"
	tracker, err := modules.GetIssueTracker()
	if err != nil {
		return nil, errs.NewError(task, err)
	}

	tags := make([]string, 0, len(storyBranches))
BranchLoop:
	for _, branch := range branches {
		for _, commit := range branch.commits {
			commitTag := commit.StoryIdTag

			// Make sure the tag is not in the list already.
			for _, tag := range tags {
				if tag == commitTag {
					continue BranchLoop
				}
			}

			// Drop tags not recognized by the current issue tracker.
			_, err := tracker.StoryTagToReadableStoryId(commitTag)
			if err == nil {
				tags = append(tags, commitTag)
			}
		}
	}

	// Fetch the collected stories.
	task = "Fetch associated stories from the issue tracker"
	log.Run(task)
	stories, err := tracker.ListStoriesByTag(tags)
	if err != nil {
		return nil, errs.NewError(task, err)
	}

	// Filter the branches according to the story state.
	storyByTag := make(map[string]common.Story, len(stories))
	for i, story := range stories {
		// tags[i] corresponds to stories[i]
		tag := tags[i]
		if story != nil {
			storyByTag[tag] = story
		} else {
			log.Warn(fmt.Sprintf("Story for tag '%v' was not found in the issue tracker", tag))
		}
	}

	allowedStates := allowedStoryStates()

	// checkCommits returns whether the commits passed in are ok
	// considering the state of the stories found in these commits,
	// whether the branch containing these commits can be deleted.
	checkCommits := func(commits []*git.Commit) (common.StoryState, bool) {
		var storyFound bool
		for _, commit := range commits {
			// Skip commits with empty Story-Id tag.
			if commit.StoryIdTag == "" {
				continue
			}

			// In case the story is not found, the tag is not recognized
			// by the current issue tracker. In that case we just skip the commit.
			story, ok := storyByTag[commit.StoryIdTag]
			if !ok {
				continue
			}

			// When the story state associated with the commit is not ok,
			// we can return false here to reject the branch.
			storyState := story.State()
			if _, ok := allowedStates[storyState]; !ok {
				return storyState, false
			}

			storyFound = true
		}

		// We went through all the commits and they are fine, check passed.
		return common.StoryStateInvalid, storyFound
	}

	// Go through the branches and only return these that
	// comply with the story state requirements.
	bs := make([]*gitBranch, 0, len(branches))
	for _, branch := range branches {
		tip := branch.tip

		logger := log.V(log.Verbose)
		if logger {
			logger.Log(fmt.Sprintf("Processing branch %v", tip.CanonicalName()))
		}

		// The branch can be for sure deleted in case there are no commits
		// contained in the commit range. That means the branch is merged into trunk.
		if len(branch.commits) == 0 {
			if logger {
				logger.Log("  Include the branch (reason: merged into trunk)")
			}
			branch.reason = "merged"
			bs = append(bs, branch)
			continue
		}

		// In case the commit check passed, we append the branch.
		state, ok := checkCommits(branch.commits)
		if ok {
			if logger {
				logger.Log("  Include the branch (reason: branch check passed)")
			}
			branch.reason = "check passed"
			bs = append(bs, branch)
			continue
		}

		// Otherwise we print the skip warning.
		if logger {
			if state == common.StoryStateInvalid {
				logger.Log(
					"  Exclude the branch (reason: no story commits found on the branch)")
			} else {
				logger.Log(fmt.Sprintf(
					"  Exclude the branch (reason: story state is '%v')", state))
			}
		}
	}

	return bs, nil
}

func promptUserToChooseBranches(branches []*gitBranch) (local, remote []string, err error) {
	// Go through the branches and ask the user for confirmation.
	var (
		localToDelete  = make([]string, 0, len(branches))
		remoteToDelete = make([]string, 0, len(branches))
	)

	defer fmt.Println()

	for _, branch := range branches {
		tip := branch.tip
		isLocal := tip.BranchName != ""
		isRemote := tip.RemoteBranchName != ""

		var msg string
		switch {
		case isLocal && isRemote:
			msg = fmt.Sprintf(
				"Processing local branch '%v' and its remote counterpart", tip.BranchName)
		case isLocal:
			msg = fmt.Sprintf(
				"Processing local branch '%v'", tip.BranchName)
		case isRemote:
			msg = fmt.Sprintf(
				"Processing remote branch '%v'", tip.FullRemoteBranchName())
		default:
			panic("bullshit")
		}
		fmt.Println()
		fmt.Println(msg)

		if branch.reason != "merged" {
			fmt.Println("Careful now, the branch has not been merged into trunk yet.")
		}

		confirmed, err := prompt.Confirm("Are you sure you want to delete the branch?", false)
		if err != nil {
			return nil, nil, err
		}
		if !confirmed {
			continue
		}

		if isLocal {
			localToDelete = append(localToDelete, tip.BranchName)
		}
		if isRemote {
			remoteToDelete = append(remoteToDelete, tip.RemoteBranchName)
		}
	}
	return localToDelete, remoteToDelete, nil
}
<commit_msg>repo prune: Print warning message in yellow<commit_after>package pruneCmd

import (
	// Stdlib
	"errors"
	"fmt"
	"os"
	"strings"

	// Internal
	"github.com/salsaflow/salsaflow/app"
	"github.com/salsaflow/salsaflow/app/appflags"
	"github.com/salsaflow/salsaflow/errs"
	"github.com/salsaflow/salsaflow/flag"
	"github.com/salsaflow/salsaflow/git"
	"github.com/salsaflow/salsaflow/git/gitutil"
	"github.com/salsaflow/salsaflow/log"
	"github.com/salsaflow/salsaflow/modules"
	"github.com/salsaflow/salsaflow/modules/common"
	"github.com/salsaflow/salsaflow/prompt"

	// Other
	"github.com/fatih/color"
	"gopkg.in/tchap/gocli.v2"
)

const StoryBranchPrefix = "story/"

var stateEnum = []common.StoryState{
	common.StoryStateTested,
	common.StoryStateStaged,
	common.StoryStateAccepted,
	common.StoryStateClosed,
}

var Command = &gocli.Command{
	// UsageLine set below in an init() functions.
	Short: "delete branches that are not needed",
	Long: `
  Delete Git branches that are no longer needed.

  All story branches are checked and the branches that only contain commits
  associated with stories that are in the selected state or further
  are offered to be deleted. Both local and remote branches are affected.

  This commands counts on the fact that all branches starting with story/
  are forked off trunk. In case this is not met, weird things can happen.
	`,
	Action: run,
}

var flagState *flag.StringEnumFlag

func init() {
	states := make([]string, 0, len(stateEnum))
	for _, state := range stateEnum {
		states = append(states, string(state))
	}

	// Finalize Command.
	Command.UsageLine = fmt.Sprintf("prune [-state={%v}]", strings.Join(states, "|"))

	// Register flags.
	flagState = flag.NewStringEnumFlag(states, string(common.StoryStateAccepted))
	Command.Flags.Var(flagState, "state", "set the required story state for branch removal")

	// Register global flags.
	appflags.RegisterGlobalFlags(&Command.Flags)
}

func allowedStoryStates() map[common.StoryState]struct{} {
	var enum []common.StoryState
	v := common.StoryState(flagState.Value())
	switch v {
	case common.StoryStateTested:
		enum = stateEnum
	case common.StoryStateStaged:
		enum = stateEnum[1:]
	case common.StoryStateAccepted:
		enum = stateEnum[2:]
	case common.StoryStateClosed:
		enum = stateEnum[3:]
	default:
		panic("unknown state: " + v)
	}

	m := make(map[common.StoryState]struct{}, len(enum))
	for _, state := range enum {
		m[state] = struct{}{}
	}
	return m
}

func run(cmd *gocli.Command, args []string) {
	if len(args) != 0 {
		cmd.Usage()
		os.Exit(2)
	}

	app.InitOrDie()

	if err := runMain(); err != nil {
		errs.Fatal(err)
	}
}

func runMain() error {
	// Load config.
	config, err := git.LoadConfig()
	if err != nil {
		return err
	}
	var (
		remoteName = config.RemoteName
		trunkName  = config.TrunkBranchName
	)

	// Make sure trunk is up to date.
	task := fmt.Sprintf("Make sure branch '%v' is up to date", trunkName)
	log.Run(task)
	if err := git.CheckOrCreateTrackingBranch(trunkName, remoteName); err != nil {
		return errs.NewError(task, err)
	}

	// Collect the story branches.
	task = "Collect the story branches"
	log.Run(task)
	storyBranches, err := collectStoryBranches(remoteName)
	if err != nil {
		return errs.NewError(task, err)
	}

	// Split the branches that are not up to date.
	task = "Split the branches that are not up to date"
	log.Run(task)
	storyBranches, err = splitBranchesNotInSync(storyBranches)
	if err != nil {
		return errs.NewError(task, err)
	}

	// Filter branches according to the story state.
	task = "Filter branches according to the story state"
	log.Run(task)
	filteredBranches, err := filterBranches(storyBranches, trunkName)
	if err != nil {
		return errs.NewError(task, err)
	}
	if len(storyBranches) == 0 {
		log.Log("No branches left to be deleted")
		return nil
	}

	// Prompt the user to choose what branches to delete.
	task = "Prompt the user to choose what branches to delete"
	localToDelete, remoteToDelete, err := promptUserToChooseBranches(filteredBranches)
	if err != nil {
		return errs.NewError(task, err)
	}

	// Delete chosen local branches.
	if len(localToDelete) != 0 {
		task := "Delete chosen local branches"
		log.Run(task)
		args := make([]string, 1, 1+len(localToDelete))
		args[0] = "-D"
		args = append(args, localToDelete...)
		if ex := git.Branch(args...); ex != nil {
			errs.LogError(task, ex)
			err = errors.New("failed to delete local branches")
		}
	}

	// Delete chosen remote branches.
	if len(remoteToDelete) != 0 {
		task := "Delete chosen remote branches"
		log.Run(task)
		args := make([]string, 1, 1+len(remoteToDelete))
		args[0] = "--delete"
		args = append(args, remoteToDelete...)
		if ex := git.Push(remoteName, args...); ex != nil {
			errs.LogError(task, ex)
			err = errors.New("failed to delete remote branches")
		}
	}

	return err
}

func collectStoryBranches(remoteName string) ([]*git.GitBranch, error) {
	// Load Git branches.
	branches, err := git.Branches()
	if err != nil {
		return nil, err
	}

	// Get the current branch name so that it can be excluded.
	currentBranch, err := gitutil.CurrentBranch()
	if err != nil {
		return nil, err
	}

	// Filter the branches.
	storyBranches := make([]*git.GitBranch, 0, len(branches))
	for _, branch := range branches {
		// Drop branches not corresponding to the project remote.
		if branch.Remote != "" && branch.Remote != remoteName {
			continue
		}

		var (
			isLocalStoryBranch  = strings.HasPrefix(branch.BranchName, StoryBranchPrefix)
			isRemoteStoryBranch = strings.HasPrefix(branch.RemoteBranchName, StoryBranchPrefix)
		)

		// Exclude the current branch.
		if isLocalStoryBranch && branch.BranchName == currentBranch {
			log.Warn(fmt.Sprintf("Branch '%v' is checked out, it cannot be deleted", currentBranch))
			continue
		}

		// Keep the story branches only.
		if isLocalStoryBranch || isRemoteStoryBranch {
			storyBranches = append(storyBranches, branch)
		}
	}

	// Return the result.
	return storyBranches, nil
}

func splitBranchesNotInSync(storyBranches []*git.GitBranch) ([]*git.GitBranch, error) {
	branches := make([]*git.GitBranch, 0, len(storyBranches))
	for _, branch := range storyBranches {
		upToDate, err := branch.IsUpToDate()
		if err != nil {
			return nil, err
		}
		if upToDate {
			branches = append(branches, branch)
			continue
		}

		// In case the branch is not up to date, we split the local and remote
		// reference into their own branch records to treat them separately.
		var (
			branchName       = branch.BranchName
			remoteBranchName = branch.RemoteBranchName
			remote           = branch.Remote
		)
		log.Warn(fmt.Sprintf("Branch '%s' is not up to date", branchName))
		log.NewLine(fmt.Sprintf("Treating '%v' and '%v/%v' as separate branches",
			branchName, remote, remoteBranchName))

		localBranch := &git.GitBranch{
			BranchName: branchName,
		}
		remoteBranch := &git.GitBranch{
			RemoteBranchName: remoteBranchName,
			Remote:           remote,
		}
		branches = append(branches, localBranch, remoteBranch)
	}
	return branches, nil
}

type gitBranch struct {
	tip     *git.GitBranch
	commits []*git.Commit

	// reason contains the reason the branch was included
	// in the branch deletion candidate list.
	reason string
}

func filterBranches(storyBranches []*git.GitBranch, trunkName string) ([]*gitBranch, error) {
	// Pair the branches with commit ranges specified by trunk..story
	task := "Collected commits associated with the story branches"
	branches := make([]*gitBranch, 0, len(storyBranches))
	for _, branch := range storyBranches {
		var revRange string
		if branch.BranchName != "" {
			// Handle branches that exist locally.
			revRange = fmt.Sprintf("%v..%v", trunkName, branch.BranchName)
		} else {
			// Handle branches that exist only in the remote repository.
			// We can use trunkName here since trunk is up to date.
			revRange = fmt.Sprintf("%v..%v/%v", trunkName, branch.Remote, branch.RemoteBranchName)
		}

		commits, err := git.ShowCommitRange(revRange)
		if err != nil {
			return nil, errs.NewError(task, err)
		}
		branches = append(branches, &gitBranch{
			tip:     branch,
			commits: commits,
		})
		continue
	}

	// Collect story tags.
	task = "Collect affected story tags"
	tracker, err := modules.GetIssueTracker()
	if err != nil {
		return nil, errs.NewError(task, err)
	}

	tags := make([]string, 0, len(storyBranches))
BranchLoop:
	for _, branch := range branches {
		for _, commit := range branch.commits {
			commitTag := commit.StoryIdTag

			// Make sure the tag is not in the list already.
			for _, tag := range tags {
				if tag == commitTag {
					continue BranchLoop
				}
			}

			// Drop tags not recognized by the current issue tracker.
			_, err := tracker.StoryTagToReadableStoryId(commitTag)
			if err == nil {
				tags = append(tags, commitTag)
			}
		}
	}

	// Fetch the collected stories.
	task = "Fetch associated stories from the issue tracker"
	log.Run(task)
	stories, err := tracker.ListStoriesByTag(tags)
	if err != nil {
		return nil, errs.NewError(task, err)
	}

	// Filter the branches according to the story state.
	storyByTag := make(map[string]common.Story, len(stories))
	for i, story := range stories {
		// tags[i] corresponds to stories[i]
		tag := tags[i]
		if story != nil {
			storyByTag[tag] = story
		} else {
			log.Warn(fmt.Sprintf("Story for tag '%v' was not found in the issue tracker", tag))
		}
	}

	allowedStates := allowedStoryStates()

	// checkCommits returns whether the commits passed in are ok
	// considering the state of the stories found in these commits,
	// whether the branch containing these commits can be deleted.
	checkCommits := func(commits []*git.Commit) (common.StoryState, bool) {
		var storyFound bool
		for _, commit := range commits {
			// Skip commits with empty Story-Id tag.
			if commit.StoryIdTag == "" {
				continue
			}

			// In case the story is not found, the tag is not recognized
			// by the current issue tracker. In that case we just skip the commit.
			story, ok := storyByTag[commit.StoryIdTag]
			if !ok {
				continue
			}

			// When the story state associated with the commit is not ok,
			// we can return false here to reject the branch.
			storyState := story.State()
			if _, ok := allowedStates[storyState]; !ok {
				return storyState, false
			}

			storyFound = true
		}

		// We went through all the commits and they are fine, check passed.
		return common.StoryStateInvalid, storyFound
	}

	// Go through the branches and only return these that
	// comply with the story state requirements.
	bs := make([]*gitBranch, 0, len(branches))
	for _, branch := range branches {
		tip := branch.tip

		logger := log.V(log.Verbose)
		if logger {
			logger.Log(fmt.Sprintf("Processing branch %v", tip.CanonicalName()))
		}

		// The branch can be for sure deleted in case there are no commits
		// contained in the commit range. That means the branch is merged into trunk.
		if len(branch.commits) == 0 {
			if logger {
				logger.Log("  Include the branch (reason: merged into trunk)")
			}
			branch.reason = "merged"
			bs = append(bs, branch)
			continue
		}

		// In case the commit check passed, we append the branch.
		state, ok := checkCommits(branch.commits)
		if ok {
			if logger {
				logger.Log("  Include the branch (reason: branch check passed)")
			}
			branch.reason = "check passed"
			bs = append(bs, branch)
			continue
		}

		// Otherwise we print the skip warning.
		if logger {
			if state == common.StoryStateInvalid {
				logger.Log(
					"  Exclude the branch (reason: no story commits found on the branch)")
			} else {
				logger.Log(fmt.Sprintf(
					"  Exclude the branch (reason: story state is '%v')", state))
			}
		}
	}

	return bs, nil
}

func promptUserToChooseBranches(branches []*gitBranch) (local, remote []string, err error) {
	// Go through the branches and ask the user for confirmation.
	var (
		localToDelete  = make([]string, 0, len(branches))
		remoteToDelete = make([]string, 0, len(branches))
	)

	defer fmt.Println()

	for _, branch := range branches {
		tip := branch.tip
		isLocal := tip.BranchName != ""
		isRemote := tip.RemoteBranchName != ""

		var msg string
		switch {
		case isLocal && isRemote:
			msg = fmt.Sprintf(
				"Processing local branch '%v' and its remote counterpart", tip.BranchName)
		case isLocal:
			msg = fmt.Sprintf(
				"Processing local branch '%v'", tip.BranchName)
		case isRemote:
			msg = fmt.Sprintf(
				"Processing remote branch '%v'", tip.FullRemoteBranchName())
		default:
			panic("bullshit")
		}
		fmt.Println()
		fmt.Println(msg)

		if branch.reason != "merged" {
			color.Yellow("Careful now, the branch has not been merged into trunk yet.")
		}

		confirmed, err := prompt.Confirm("Are you sure you want to delete the branch?", false)
		if err != nil {
			return nil, nil, err
		}
		if !confirmed {
			continue
		}

		if isLocal {
			localToDelete = append(localToDelete, tip.BranchName)
		}
		if isRemote {
			remoteToDelete = append(remoteToDelete, tip.RemoteBranchName)
		}
	}
	return localToDelete, remoteToDelete, nil
}
<|endoftext|>


<commit_before>package controlapi

import (
	"github.com/docker/engine-api/types/reference"
	"github.com/docker/swarmkit/api"
	"github.com/docker/swarmkit/identity"
	"github.com/docker/swarmkit/manager/state/store"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
)

func validateResources(r *api.Resources) error {
	if r == nil {
		return nil
	}

	if r.NanoCPUs != 0 && r.NanoCPUs < 1e6 {
		return grpc.Errorf(codes.InvalidArgument, "invalid cpu value %d: Must be at least %d", r.NanoCPUs, 1e6)
	}

	if r.MemoryBytes != 0 && r.MemoryBytes < 4*1024*1024 {
		return grpc.Errorf(codes.InvalidArgument, "invalid memory value %d: Must be at least 4MiB", r.MemoryBytes)
	}
	return nil
}

func validateResourceRequirements(r *api.ResourceRequirements) error {
	if r == nil {
		return nil
	}
	if err := validateResources(r.Limits); err != nil {
		return err
	}
	if err := validateResources(r.Reservations); err != nil {
		return err
	}
	return nil
}

func validateServiceSpecTemplate(spec *api.ServiceSpec) error {
	if err := validateResourceRequirements(spec.Task.Resources); err != nil {
		return err
	}

	if spec.Task.GetRuntime() == nil {
		return grpc.Errorf(codes.InvalidArgument, "TaskSpec: missing runtime")
	}

	_, ok := spec.Task.GetRuntime().(*api.TaskSpec_Container)
	if !ok {
		return grpc.Errorf(codes.Unimplemented, "RuntimeSpec: unimplemented runtime in service spec")
	}

	container := spec.Task.GetContainer()
	if container == nil {
		return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: missing in service spec")
	}

	if container.Image == "" {
		return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: image reference must be provided")
	}

	if _, _, err := reference.Parse(container.Image); err != nil {
		return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: %q is not a valid repository/tag", container.Image)
	}
	return nil
}

func validateServiceSpec(spec *api.ServiceSpec) error {
	if spec == nil {
		return grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
	}
	if err := validateAnnotations(spec.Annotations); err != nil {
		return err
	}
	if err := validateServiceSpecTemplate(spec); err != nil {
		return err
	}
	return nil
}

// CreateService creates and return a Service based on the provided ServiceSpec.
// - Returns `InvalidArgument` if the ServiceSpec is malformed.
// - Returns `Unimplemented` if the ServiceSpec references unimplemented features.
// - Returns `AlreadyExists` if the ServiceID conflicts.
// - Returns an error if the creation fails.
func (s *Server) CreateService(ctx context.Context, request *api.CreateServiceRequest) (*api.CreateServiceResponse, error) {
	if err := validateServiceSpec(request.Spec); err != nil {
		return nil, err
	}

	// TODO(aluzzardi): Consider using `Name` as a primary key to handle
	// duplicate creations. See #65
	service := &api.Service{
		ID:   identity.NewID(),
		Spec: *request.Spec,
	}

	err := s.store.Update(func(tx store.Tx) error {
		return store.CreateService(tx, service)
	})
	if err != nil {
		return nil, err
	}

	return &api.CreateServiceResponse{
		Service: service,
	}, nil
}

// GetService returns a Service given a ServiceID.
// - Returns `InvalidArgument` if ServiceID is not provided.
// - Returns `NotFound` if the Service is not found.
func (s *Server) GetService(ctx context.Context, request *api.GetServiceRequest) (*api.GetServiceResponse, error) {
	if request.ServiceID == "" {
		return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
	}

	var service *api.Service
	s.store.View(func(tx store.ReadTx) {
		service = store.GetService(tx, request.ServiceID)
	})
	if service == nil {
		return nil, grpc.Errorf(codes.NotFound, "service %s not found", request.ServiceID)
	}

	return &api.GetServiceResponse{
		Service: service,
	}, nil
}

// UpdateService updates a Service referenced by ServiceID with the given ServiceSpec.
// - Returns `NotFound` if the Service is not found.
// - Returns `InvalidArgument` if the ServiceSpec is malformed.
// - Returns `Unimplemented` if the ServiceSpec references unimplemented features.
// - Returns an error if the update fails.
func (s *Server) UpdateService(ctx context.Context, request *api.UpdateServiceRequest) (*api.UpdateServiceResponse, error) {
	if request.ServiceID == "" || request.ServiceVersion == nil {
		return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
	}
	if err := validateServiceSpec(request.Spec); err != nil {
		return nil, err
	}

	var service *api.Service
	err := s.store.Update(func(tx store.Tx) error {
		service = store.GetService(tx, request.ServiceID)
		if service == nil {
			return nil
		}
		service.Meta.Version = *request.ServiceVersion
		service.Spec = *request.Spec.Copy()
		return store.UpdateService(tx, service)
	})
	if err != nil {
		return nil, err
	}
	if service == nil {
		return nil, grpc.Errorf(codes.NotFound, "service %s not found", request.ServiceID)
	}
	return &api.UpdateServiceResponse{
		Service: service,
	}, nil
}

// RemoveService removes a Service referenced by ServiceID.
// - Returns `InvalidArgument` if ServiceID is not provided.
// - Returns `NotFound` if the Service is not found.
// - Returns an error if the deletion fails.
func (s *Server) RemoveService(ctx context.Context, request *api.RemoveServiceRequest) (*api.RemoveServiceResponse, error) {
	if request.ServiceID == "" {
		return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
	}

	err := s.store.Update(func(tx store.Tx) error {
		return store.DeleteService(tx, request.ServiceID)
	})
	if err != nil {
		if err == store.ErrNotExist {
			return nil, grpc.Errorf(codes.NotFound, "service %s not found", request.ServiceID)
		}
		return nil, err
	}
	return &api.RemoveServiceResponse{}, nil
}

func filterServices(candidates []*api.Service, filters ...func(*api.Service) bool) []*api.Service {
	result := []*api.Service{}

	for _, c := range candidates {
		match := true
		for _, f := range filters {
			if !f(c) {
				match = false
				break
			}
		}
		if match {
			result = append(result, c)
		}
	}

	return result
}

// ListServices returns a list of all services.
func (s *Server) ListServices(ctx context.Context, request *api.ListServicesRequest) (*api.ListServicesResponse, error) {
	var (
		services []*api.Service
		err      error
	)

	s.store.View(func(tx store.ReadTx) {
		switch {
		case request.Filters != nil && len(request.Filters.Names) > 0:
			services, err = store.FindServices(tx, buildFilters(store.ByName, request.Filters.Names))
		case request.Filters != nil && len(request.Filters.IDPrefixes) > 0:
			services, err = store.FindServices(tx, buildFilters(store.ByIDPrefix, request.Filters.IDPrefixes))
		default:
			services, err = store.FindServices(tx, store.All)
		}
	})
	if err != nil {
		return nil, err
	}

	if request.Filters != nil {
		services = filterServices(services,
			func(e *api.Service) bool {
				return filterContains(e.Spec.Annotations.Name, request.Filters.Names)
			},
			func(e *api.Service) bool {
				return filterContainsPrefix(e.ID, request.Filters.IDPrefixes)
			},
			func(e *api.Service) bool {
				return filterMatchLabels(e.Spec.Annotations.Labels, request.Filters.Labels)
			},
		)
	}

	return &api.ListServicesResponse{
		Services: services,
	}, nil
}
<commit_msg>fix cpu error msg<commit_after>package controlapi

import (
	"github.com/docker/engine-api/types/reference"
	"github.com/docker/swarmkit/api"
	"github.com/docker/swarmkit/identity"
	"github.com/docker/swarmkit/manager/state/store"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
)

func validateResources(r *api.Resources) error {
	if r == nil {
		return nil
	}

	if r.NanoCPUs != 0 && r.NanoCPUs < 1e6 {
		return grpc.Errorf(codes.InvalidArgument, "invalid cpu value %g: Must be at least %g", float64(r.NanoCPUs)/1e9, 1e6/1e9)
	}

	if r.MemoryBytes != 0 && r.MemoryBytes < 4*1024*1024 {
		return grpc.Errorf(codes.InvalidArgument, "invalid memory value %d: Must be at least 4MiB", r.MemoryBytes)
	}
	return nil
}

func validateResourceRequirements(r *api.ResourceRequirements) error {
	if r == nil {
		return nil
	}
	if err := validateResources(r.Limits); err != nil {
		return err
	}
	if err := validateResources(r.Reservations); err != nil {
		return err
	}
	return nil
}

func validateServiceSpecTemplate(spec *api.ServiceSpec) error {
	if err := validateResourceRequirements(spec.Task.Resources); err != nil {
		return err
	}

	if spec.Task.GetRuntime() == nil {
		return grpc.Errorf(codes.InvalidArgument, "TaskSpec: missing runtime")
	}

	_, ok := spec.Task.GetRuntime().(*api.TaskSpec_Container)
	if !ok {
		return grpc.Errorf(codes.Unimplemented, "RuntimeSpec: unimplemented runtime in service spec")
	}

	container := spec.Task.GetContainer()
	if container == nil {
		return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: missing in service spec")
	}

	if container.Image == "" {
		return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: image reference must be provided")
	}

	if _, _, err := reference.Parse(container.Image); err != nil {
		return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: %q is not a valid repository/tag", container.Image)
	}
	return nil
}

func validateServiceSpec(spec *api.ServiceSpec) error {
	if spec == nil {
		return grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
	}
	if err := validateAnnotations(spec.Annotations); err != nil {
		return err
	}
	if err := validateServiceSpecTemplate(spec); err != nil {
		return err
	}
	return nil
}

// CreateService creates and return a Service based on the provided ServiceSpec.
// - Returns `InvalidArgument` if the ServiceSpec is malformed.
// - Returns `Unimplemented` if the ServiceSpec references unimplemented features.
// - Returns `AlreadyExists` if the ServiceID conflicts.
// - Returns an error if the creation fails.
func (s *Server) CreateService(ctx context.Context, request *api.CreateServiceRequest) (*api.CreateServiceResponse, error) {
	if err := validateServiceSpec(request.Spec); err != nil {
		return nil, err
	}

	// TODO(aluzzardi): Consider using `Name` as a primary key to handle
	// duplicate creations. See #65
	service := &api.Service{
		ID:   identity.NewID(),
		Spec: *request.Spec,
	}

	err := s.store.Update(func(tx store.Tx) error {
		return store.CreateService(tx, service)
	})
	if err != nil {
		return nil, err
	}

	return &api.CreateServiceResponse{
		Service: service,
	}, nil
}

// GetService returns a Service given a ServiceID.
// - Returns `InvalidArgument` if ServiceID is not provided.
// - Returns `NotFound` if the Service is not found.
func (s *Server) GetService(ctx context.Context, request *api.GetServiceRequest) (*api.GetServiceResponse, error) {
	if request.ServiceID == "" {
		return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
	}

	var service *api.Service
	s.store.View(func(tx store.ReadTx) {
		service = store.GetService(tx, request.ServiceID)
	})
	if service == nil {
		return nil, grpc.Errorf(codes.NotFound, "service %s not found", request.ServiceID)
	}

	return &api.GetServiceResponse{
		Service: service,
	}, nil
}

// UpdateService updates a Service referenced by ServiceID with the given ServiceSpec.
// - Returns `NotFound` if the Service is not found.
// - Returns `InvalidArgument` if the ServiceSpec is malformed.
// - Returns `Unimplemented` if the ServiceSpec references unimplemented features.
// - Returns an error if the update fails.
func (s *Server) UpdateService(ctx context.Context, request *api.UpdateServiceRequest) (*api.UpdateServiceResponse, error) {
	if request.ServiceID == "" || request.ServiceVersion == nil {
		return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
	}
	if err := validateServiceSpec(request.Spec); err != nil {
		return nil, err
	}

	var service *api.Service
	err := s.store.Update(func(tx store.Tx) error {
		service = store.GetService(tx, request.ServiceID)
		if service == nil {
			return nil
		}
		service.Meta.Version = *request.ServiceVersion
		service.Spec = *request.Spec.Copy()
		return store.UpdateService(tx, service)
	})
	if err != nil {
		return nil, err
	}
	if service == nil {
		return nil, grpc.Errorf(codes.NotFound, "service %s not found", request.ServiceID)
	}
	return &api.UpdateServiceResponse{
		Service: service,
	}, nil
}

// RemoveService removes a Service referenced by ServiceID.
// - Returns `InvalidArgument` if ServiceID is not provided.
// - Returns `NotFound` if the Service is not found.
// - Returns an error if the deletion fails.
func (s *Server) RemoveService(ctx context.Context, request *api.RemoveServiceRequest) (*api.RemoveServiceResponse, error) {
	if request.ServiceID == "" {
		return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
	}

	err := s.store.Update(func(tx store.Tx) error {
		return store.DeleteService(tx, request.ServiceID)
	})
	if err != nil {
		if err == store.ErrNotExist {
			return nil, grpc.Errorf(codes.NotFound, "service %s not found", request.ServiceID)
		}
		return nil, err
	}
	return &api.RemoveServiceResponse{}, nil
}

func filterServices(candidates []*api.Service, filters ...func(*api.Service) bool) []*api.Service {
	result := []*api.Service{}

	for _, c := range candidates {
		match := true
		for _, f := range filters {
			if !f(c) {
				match = false
				break
			}
		}
		if match {
			result = append(result, c)
		}
	}

	return result
}

// ListServices returns a list of all services.
func (s *Server) ListServices(ctx context.Context, request *api.ListServicesRequest) (*api.ListServicesResponse, error) {
	var (
		services []*api.Service
		err      error
	)

	s.store.View(func(tx store.ReadTx) {
		switch {
		case request.Filters != nil && len(request.Filters.Names) > 0:
			services, err = store.FindServices(tx, buildFilters(store.ByName, request.Filters.Names))
		case request.Filters != nil && len(request.Filters.IDPrefixes) > 0:
			services, err = store.FindServices(tx, buildFilters(store.ByIDPrefix, request.Filters.IDPrefixes))
		default:
			services, err = store.FindServices(tx, store.All)
		}
	})
	if err != nil {
		return nil, err
	}

	if request.Filters != nil {
		services = filterServices(services,
			func(e *api.Service) bool {
				return filterContains(e.Spec.Annotations.Name, request.Filters.Names)
			},
			func(e *api.Service) bool {
				return filterContainsPrefix(e.ID, request.Filters.IDPrefixes)
			},
			func(e *api.Service) bool {
				return filterMatchLabels(e.Spec.Annotations.Labels, request.Filters.Labels)
			},
		)
	}

	return &api.ListServicesResponse{
		Services: services,
	}, nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.

/*
Package codec provides a
High Performance, Feature-Rich Idiomatic Go 1.4+ codec/encoding library
for binc, msgpack, cbor, json.

Supported Serialization formats are:

  - msgpack: https://github.com/msgpack/msgpack
  - binc:    http://github.com/ugorji/binc
  - cbor:    http://cbor.io http://tools.ietf.org/html/rfc7049
  - json:    http://json.org http://tools.ietf.org/html/rfc7159
  - simple:

To install:

    go get github.com/ugorji/go/codec

This package will carefully use 'unsafe' for performance reasons in specific places.
You can build without unsafe use by passing the safe or appengine tag
i.e. 'go install -tags=safe ...'. Note that unsafe is only supported for the last 3
go sdk versions e.g. current go release is go 1.9, so we support unsafe use only from
go 1.7+ . This is because supporting unsafe requires knowledge of implementation details.

For detailed usage information, read the primer at http://ugorji.net/blog/go-codec-primer .

The idiomatic Go support is as seen in other encoding packages in
the standard library (ie json, xml, gob, etc).

Rich Feature Set includes:

  - Simple but extremely powerful and feature-rich API
  - Support for go1.4 and above, while selectively using newer APIs for later releases
  - Excellent code coverage ( > 90% )
  - Very High Performance.
    Our extensive benchmarks show us outperforming Gob, Json, Bson, etc by 2-4X.
  - Careful selected use of 'unsafe' for targeted performance gains.
    100% mode exists where 'unsafe' is not used at all.
  - Lock-free (sans mutex) concurrency for scaling to 100's of cores
  - In-place updates during decode, with option to zero value in maps and slices prior to decode
  - Coerce types where appropriate
    e.g. decode an int in the stream into a float, decode numbers from formatted strings, etc
  - Corner Cases:
    Overflows, nil maps/slices, nil values in streams are handled correctly
  - Standard field renaming via tags
  - Support for omitting empty fields during an encoding
  - Encoding from any value and decoding into pointer to any value
    (struct, slice, map, primitives, pointers, interface{}, etc)
  - Extensions to support efficient encoding/decoding of any named types
  - Support encoding.(Binary|Text)(M|Unm)arshaler interfaces
  - Support IsZero() bool to determine if a value is a zero value.
    Analogous to time.Time.IsZero() bool.
  - Decoding without a schema (into a interface{}).
    Includes Options to configure what specific map or slice type to use
    when decoding an encoded list or map into a nil interface{}
  - Mapping a non-interface type to an interface, so we can decode appropriately
    into any interface type with a correctly configured non-interface value.
  - Encode a struct as an array, and decode struct from an array in the data stream
  - Option to encode struct keys as numbers (instead of strings)
    (to support structured streams with fields encoded as numeric codes)
  - Comprehensive support for anonymous fields
  - Fast (no-reflection) encoding/decoding of common maps and slices
  - Code-generation for faster performance.
  - Support binary (e.g. messagepack, cbor) and text (e.g. json) formats
  - Support indefinite-length formats to enable true streaming
    (for formats which support it e.g. json, cbor)
  - Support canonical encoding, where a value is ALWAYS encoded as same sequence of bytes.
    This mostly applies to maps, where iteration order is non-deterministic.
  - NIL in data stream decoded as zero value
  - Never silently skip data when decoding.
    User decides whether to return an error or silently skip data when keys or indexes
    in the data stream do not map to fields in the struct.
  - Detect and error when encoding a cyclic reference (instead of stack overflow shutdown)
  - Encode/Decode from/to chan types (for iterative streaming support)
  - Drop-in replacement for encoding/json. `json:` key in struct tag supported.
  - Provides a RPC Server and Client Codec for net/rpc communication protocol.
  - Handle unique idiosyncrasies of codecs e.g.
    - For messagepack, configure how ambiguities in handling raw bytes are resolved
    - For messagepack, provide rpc server/client codec to support
      msgpack-rpc protocol defined at:
      https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md

Extension Support

Users can register a function to handle the encoding or decoding of
their custom types.

There are no restrictions on what the custom type can be. Some examples:

    type BisSet   []int
    type BitSet64 uint64
    type UUID     string
    type MyStructWithUnexportedFields struct { a int; b bool; c []int; }
    type GifImage struct { ... }

As an illustration, MyStructWithUnexportedFields would normally be
encoded as an empty map because it has no exported fields, while UUID
would be encoded as a string. However, with extension support, you can
encode any of these however you like.

Custom Encoding and Decoding

This package maintains symmetry in the encoding and decoding halfs.
We determine how to encode or decode by walking this decision tree

  - is type a codec.Selfer?
  - is there an extension registered for the type?
  - is format binary, and is type a encoding.BinaryMarshaler and BinaryUnmarshaler?
  - is format specifically json, and is type a encoding/json.Marshaler and Unmarshaler?
  - is format text-based, and type an encoding.TextMarshaler?
  - else we use a pair of functions based on the "kind" of the type e.g. map, slice, int64, etc

This symmetry is important to reduce chances of issues happening because the
encoding and decoding sides are out of sync e.g. decoded via very specific
encoding.TextUnmarshaler but encoded via kind-specific generalized mode.

Consequently, if a type only defines one-half of the symmetry
(e.g. it implements UnmarshalJSON() but not MarshalJSON() ),
then that type doesn't satisfy the check and we will continue walking down the
decision tree.

RPC

RPC Client and Server Codecs are implemented, so the codecs can be used
with the standard net/rpc package.

Usage

The Handle is SAFE for concurrent READ, but NOT SAFE for concurrent modification.

The Encoder and Decoder are NOT safe for concurrent use.

Consequently, the usage model is basically:

    - Create and initialize the Handle before any use.
      Once created, DO NOT modify it.
    - Multiple Encoders or Decoders can now use the Handle concurrently.
      They only read information off the Handle (never write).
    - However, each Encoder or Decoder MUST not be used concurrently
    - To re-use an Encoder/Decoder, call Reset(...) on it first.
      This allows you use state maintained on the Encoder/Decoder.

Sample usage model:

    // create and configure Handle
    var (
      bh codec.BincHandle
      mh codec.MsgpackHandle
      ch codec.CborHandle
    )

    mh.MapType = reflect.TypeOf(map[string]interface{}(nil))

    // configure extensions
    // e.g. for msgpack, define functions and enable Time support for tag 1
    // mh.SetExt(reflect.TypeOf(time.Time{}), 1, myExt)

    // create and use decoder/encoder
    var (
      r io.Reader
      w io.Writer
      b []byte
      h = &bh // or mh to use msgpack
    )

    dec = codec.NewDecoder(r, h)
    dec = codec.NewDecoderBytes(b, h)
    err = dec.Decode(&v)

    enc = codec.NewEncoder(w, h)
    enc = codec.NewEncoderBytes(&b, h)
    err = enc.Encode(v)

    //RPC Server
    go func() {
        for {
            conn, err := listener.Accept()
            rpcCodec := codec.GoRpc.ServerCodec(conn, h)
            //OR rpcCodec := codec.MsgpackSpecRpc.ServerCodec(conn, h)
            rpc.ServeCodec(rpcCodec)
        }
    }()

    //RPC Communication (client side)
    conn, err = net.Dial("tcp", "localhost:5555")
    rpcCodec := codec.GoRpc.ClientCodec(conn, h)
    //OR rpcCodec := codec.MsgpackSpecRpc.ClientCodec(conn, h)
    client := rpc.NewClientWithCodec(rpcCodec)

Running Tests

To run tests, use the following:

    go test

To run the full suite of tests, use the following:

    go test -tags alltests -run Suite

You can run the tag 'safe' to run tests or build in safe mode. e.g.

    go test -tags safe -run Json
    go test -tags "alltests safe" -run Suite

Running Benchmarks

Please see http://github.com/ugorji/go-codec-bench .

Caveats

Struct fields matching the following are ignored during encoding and decoding
    - struct tag value set to -
    - func, complex numbers, unsafe pointers
    - unexported and not embedded
    - unexported and embedded and not struct kind
    - unexported and embedded pointers (from go1.10)

Every other field in a struct will be encoded/decoded.

Embedded fields are encoded as if they exist in the top-level struct,
with some caveats. See Encode documentation.

*/
package codec

/*
MID-STACK INLINING:
  - The code currently works optimally with fully enabled mid-stack inlining.
    This way, when enabled, we are already performant.
  - To see how well inlining is working, use the following scripts below:

    myblanklines 20
    zf=7; go build -gcflags "-m=2 -l=4" > $TMPDIR/a$zf.txt 2>&1
    for i in decReaderSwitch bytesDecReader bufioDecReader ioDecReader \
        encWriterSwitch bytesEncAppender bufioEncWriter ioEncWriter
    do echo ; grep -E "cannot inline \(\*${i}\)." $TMPDIR/a7.txt; done

  - When mid-stack inlining is enabled, consider doing the following:
    - if 41<=inlineExtraCallCost<=56,
      make (buf)ioEncWriter.{writen1,writen2,writestr,writeb,atEndOfEncode} go:noinline
    - if <=40,
      do nothing (no go:inline)

TODO:
  - remove Deprecated APIs,
    especially those only used by files generated by old versions of codecgen.
    this is ok, as we have updated the GenVersion, ensuring that old ones break anyway.

PUNTED:
  - To make Handle comparable, make extHandle in BasicHandle a non-embedded pointer,
    and use overlay methods on *BasicHandle to call through to extHandle after initializing
    the "xh *extHandle" to point to a real slice.

BEFORE EACH RELEASE:
  - Look through and fix padding for each type, to eliminate false sharing
    - critical shared objects that are read many times
      TypeInfos
    - pooled objects:
      decNaked, decNakedContainers, codecFner, typeInfoLoadArray,
    - small objects allocated independently, that we read/use much across threads:
      codecFn, typeInfo
    - Objects allocated independently and used a lot
      Decoder, Encoder,
      xxxHandle, xxxEncDriver, xxxDecDriver (xxx = json, msgpack, cbor, binc, simple)
    - In all above, arrange values modified together to be close to each other.
    For all of these, either ensure that they occupy full cache lines,
    or ensure that the things just past the cache line boundary are hardly read/written
    e.g. JsonHandle.RawBytesExt - which is copied into json(En|De)cDriver at init

    Occupying full cache lines means they occupy 8*N words (where N is an integer).
    Check this out by running: ./run.sh -z
    - look at those tagged ****, meaning they are not occupying full cache lines
    - look at those tagged <<<<, meaning they are larger than 32 words (something to watch)
    - Run "golint -min_confidence 0.81"
*/
<commit_msg>codec: move development notes from 0doc.go into private scratchpad (notes.md)<commit_after>// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.

/*
Package codec provides a
High Performance, Feature-Rich Idiomatic Go 1.4+ codec/encoding library
for binc, msgpack, cbor, json.

Supported Serialization formats are:

  - msgpack: https://github.com/msgpack/msgpack
  - binc:    http://github.com/ugorji/binc
  - cbor:    http://cbor.io http://tools.ietf.org/html/rfc7049
  - json:    http://json.org http://tools.ietf.org/html/rfc7159
  - simple:

To install:

    go get github.com/ugorji/go/codec

This package will carefully use 'unsafe' for performance reasons in specific places.
You can build without unsafe use by passing the safe or appengine tag
i.e. 'go install -tags=safe ...'. Note that unsafe is only supported for the last 3
go sdk versions e.g. current go release is go 1.9, so we support unsafe use only from
go 1.7+ . This is because supporting unsafe requires knowledge of implementation details.

For detailed usage information, read the primer at http://ugorji.net/blog/go-codec-primer .

The idiomatic Go support is as seen in other encoding packages in
the standard library (ie json, xml, gob, etc).

Rich Feature Set includes:

  - Simple but extremely powerful and feature-rich API
  - Support for go1.4 and above, while selectively using newer APIs for later releases
  - Excellent code coverage ( > 90% )
  - Very High Performance.
    Our extensive benchmarks show us outperforming Gob, Json, Bson, etc by 2-4X.
  - Careful selected use of 'unsafe' for targeted performance gains.
    100% mode exists where 'unsafe' is not used at all.
  - Lock-free (sans mutex) concurrency for scaling to 100's of cores
  - In-place updates during decode, with option to zero value in maps and slices prior to decode
  - Coerce types where appropriate
    e.g. decode an int in the stream into a float, decode numbers from formatted strings, etc
  - Corner Cases:
    Overflows, nil maps/slices, nil values in streams are handled correctly
  - Standard field renaming via tags
  - Support for omitting empty fields during an encoding
  - Encoding from any value and decoding into pointer to any value
    (struct, slice, map, primitives, pointers, interface{}, etc)
  - Extensions to support efficient encoding/decoding of any named types
  - Support encoding.(Binary|Text)(M|Unm)arshaler interfaces
  - Support IsZero() bool to determine if a value is a zero value.
    Analogous to time.Time.IsZero() bool.
  - Decoding without a schema (into a interface{}).
    Includes Options to configure what specific map or slice type to use
    when decoding an encoded list or map into a nil interface{}
  - Mapping a non-interface type to an interface, so we can decode appropriately
    into any interface type with a correctly configured non-interface value.
  - Encode a struct as an array, and decode struct from an array in the data stream
  - Option to encode struct keys as numbers (instead of strings)
    (to support structured streams with fields encoded as numeric codes)
  - Comprehensive support for anonymous fields
  - Fast (no-reflection) encoding/decoding of common maps and slices
  - Code-generation for faster performance.
  - Support binary (e.g. messagepack, cbor) and text (e.g. json) formats
  - Support indefinite-length formats to enable true streaming
    (for formats which support it e.g. json, cbor)
  - Support canonical encoding, where a value is ALWAYS encoded as same sequence of bytes.
    This mostly applies to maps, where iteration order is non-deterministic.
  - NIL in data stream decoded as zero value
  - Never silently skip data when decoding.
    User decides whether to return an error or silently skip data when keys or indexes
    in the data stream do not map to fields in the struct.
  - Detect and error when encoding a cyclic reference (instead of stack overflow shutdown)
  - Encode/Decode from/to chan types (for iterative streaming support)
  - Drop-in replacement for encoding/json. `json:` key in struct tag supported.
  - Provides a RPC Server and Client Codec for net/rpc communication protocol.
  - Handle unique idiosyncrasies of codecs e.g.
    - For messagepack, configure how ambiguities in handling raw bytes are resolved
    - For messagepack, provide rpc server/client codec to support
      msgpack-rpc protocol defined at:
      https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md

Extension Support

Users can register a function to handle the encoding or decoding of
their custom types.

There are no restrictions on what the custom type can be. Some examples:

    type BisSet   []int
    type BitSet64 uint64
    type UUID     string
    type MyStructWithUnexportedFields struct { a int; b bool; c []int; }
    type GifImage struct { ... }

As an illustration, MyStructWithUnexportedFields would normally be
encoded as an empty map because it has no exported fields, while UUID
would be encoded as a string. However, with extension support, you can
encode any of these however you like.

Custom Encoding and Decoding

This package maintains symmetry in the encoding and decoding halfs.
We determine how to encode or decode by walking this decision tree

  - is type a codec.Selfer?
  - is there an extension registered for the type?
  - is format binary, and is type a encoding.BinaryMarshaler and BinaryUnmarshaler?
  - is format specifically json, and is type a encoding/json.Marshaler and Unmarshaler?
  - is format text-based, and type an encoding.TextMarshaler?
  - else we use a pair of functions based on the "kind" of the type e.g. map, slice, int64, etc

This symmetry is important to reduce chances of issues happening because the
encoding and decoding sides are out of sync e.g. decoded via very specific
encoding.TextUnmarshaler but encoded via kind-specific generalized mode.

Consequently, if a type only defines one-half of the symmetry
(e.g. it implements UnmarshalJSON() but not MarshalJSON() ),
then that type doesn't satisfy the check and we will continue walking down the
decision tree.

RPC

RPC Client and Server Codecs are implemented, so the codecs can be used
with the standard net/rpc package.

Usage

The Handle is SAFE for concurrent READ, but NOT SAFE for concurrent modification.

The Encoder and Decoder are NOT safe for concurrent use.

Consequently, the usage model is basically:

    - Create and initialize the Handle before any use.
      Once created, DO NOT modify it.
    - Multiple Encoders or Decoders can now use the Handle concurrently.
      They only read information off the Handle (never write).
    - However, each Encoder or Decoder MUST not be used concurrently
    - To re-use an Encoder/Decoder, call Reset(...) on it first.
      This allows you use state maintained on the Encoder/Decoder.

Sample usage model:

    // create and configure Handle
    var (
      bh codec.BincHandle
      mh codec.MsgpackHandle
      ch codec.CborHandle
    )

    mh.MapType = reflect.TypeOf(map[string]interface{}(nil))

    // configure extensions
    // e.g. for msgpack, define functions and enable Time support for tag 1
    // mh.SetExt(reflect.TypeOf(time.Time{}), 1, myExt)

    // create and use decoder/encoder
    var (
      r io.Reader
      w io.Writer
      b []byte
      h = &bh // or mh to use msgpack
    )

    dec = codec.NewDecoder(r, h)
    dec = codec.NewDecoderBytes(b, h)
    err = dec.Decode(&v)

    enc = codec.NewEncoder(w, h)
    enc = codec.NewEncoderBytes(&b, h)
    err = enc.Encode(v)

    //RPC Server
    go func() {
        for {
            conn, err := listener.Accept()
            rpcCodec := codec.GoRpc.ServerCodec(conn, h)
            //OR rpcCodec := codec.MsgpackSpecRpc.ServerCodec(conn, h)
            rpc.ServeCodec(rpcCodec)
        }
    }()

    //RPC Communication (client side)
    conn, err = net.Dial("tcp", "localhost:5555")
    rpcCodec := codec.GoRpc.ClientCodec(conn, h)
    //OR rpcCodec := codec.MsgpackSpecRpc.ClientCodec(conn, h)
    client := rpc.NewClientWithCodec(rpcCodec)

Running Tests

To run tests, use the following:

    go test

To run the full suite of tests, use the following:

    go test -tags alltests -run Suite

You can run the tag 'safe' to run tests or build in safe mode. e.g.

    go test -tags safe -run Json
    go test -tags "alltests safe" -run Suite

Running Benchmarks

Please see http://github.com/ugorji/go-codec-bench .

Caveats

Struct fields matching the following are ignored during encoding and decoding
    - struct tag value set to -
    - func, complex numbers, unsafe pointers
    - unexported and not embedded
    - unexported and embedded and not struct kind
    - unexported and embedded pointers (from go1.10)

Every other field in a struct will be encoded/decoded.

Embedded fields are encoded as if they exist in the top-level struct,
with some caveats. See Encode documentation.

*/
package codec

<|endoftext|>