<commit_before>package null

import (
	"database/sql/driver"
	"encoding/binary"
	"reflect"
	"strconv"
)

type NullInt struct{ Int *int }
type NullInt8 struct{ Int8 *int8 }
type NullUint8 struct{ Uint8 *uint8 }
type NullInt16 struct{ Int16 *int16 }
type NullUint16 struct{ Uint16 *uint16 }
type NullInt32 struct{ Int32 *int32 }
type NullUint32 struct{ Uint32 *uint32 }
type NullInt64 struct{ Int64 *int64 }
type NullUint64 struct{ Uint64 *uint64 }

func (n *NullInt) IsEmpty() bool    { return isEmpty(n.Int) }
func (n *NullInt8) IsEmpty() bool   { return isEmpty(n.Int8) }
func (n *NullUint8) IsEmpty() bool  { return isEmpty(n.Uint8) }
func (n *NullInt16) IsEmpty() bool  { return isEmpty(n.Int16) }
func (n *NullUint16) IsEmpty() bool { return isEmpty(n.Uint16) }
func (n *NullInt32) IsEmpty() bool  { return isEmpty(n.Int32) }
func (n *NullUint32) IsEmpty() bool { return isEmpty(n.Uint32) }
func (n *NullInt64) IsEmpty() bool  { return isEmpty(n.Int64) }
func (n *NullUint64) IsEmpty() bool { return isEmpty(n.Uint64) }

func (n *NullInt) MarshalJSON() ([]byte, error)    { return marshalJSON(n.Int) }
func (n *NullInt8) MarshalJSON() ([]byte, error)   { return marshalJSON(n.Int8) }
func (n *NullUint8) MarshalJSON() ([]byte, error)  { return marshalJSON(n.Uint8) }
func (n *NullInt16) MarshalJSON() ([]byte, error)  { return marshalJSON(n.Int16) }
func (n *NullUint16) MarshalJSON() ([]byte, error) { return marshalJSON(n.Uint16) }
func (n *NullInt32) MarshalJSON() ([]byte, error)  { return marshalJSON(n.Int32) }
func (n *NullUint32) MarshalJSON() ([]byte, error) { return marshalJSON(n.Uint32) }
func (n *NullInt64) MarshalJSON() ([]byte, error)  { return marshalJSON(n.Int64) }
func (n *NullUint64) MarshalJSON() ([]byte, error) { return marshalJSON(n.Uint64) }

func (n *NullInt) UnmarshalJSON(data []byte) error    { return unmarshalJSON(n.Int, data) }
func (n *NullInt8) UnmarshalJSON(data []byte) error   { return unmarshalJSON(n.Int8, data) }
func (n *NullUint8) UnmarshalJSON(data []byte) error  { return unmarshalJSON(n.Uint8, data) }
func (n *NullInt16) UnmarshalJSON(data []byte) error  { return unmarshalJSON(n.Int16, data) }
func (n *NullUint16) UnmarshalJSON(data []byte) error { return unmarshalJSON(n.Uint16, data) }
func (n *NullInt32) UnmarshalJSON(data []byte) error  { return unmarshalJSON(n.Int32, data) }
func (n *NullUint32) UnmarshalJSON(data []byte) error { return unmarshalJSON(n.Uint32, data) }
func (n *NullInt64) UnmarshalJSON(data []byte) error  { return unmarshalJSON(n.Int64, data) }
func (n *NullUint64) UnmarshalJSON(data []byte) error { return unmarshalJSON(n.Uint64, data) }

func (n *NullInt) String() string    { return toString(n.Int) }
func (n *NullInt8) String() string   { return toString(n.Int8) }
func (n *NullUint8) String() string  { return toString(n.Uint8) }
func (n *NullInt16) String() string  { return toString(n.Int16) }
func (n *NullUint16) String() string { return toString(n.Uint16) }
func (n *NullInt32) String() string  { return toString(n.Int32) }
func (n *NullUint32) String() string { return toString(n.Uint32) }
func (n *NullInt64) String() string  { return toString(n.Int64) }
func (n *NullUint64) String() string { return toString(n.Uint64) }

func (n *NullInt) Scan(value interface{}) error    { return scan(n.Int, value) }
func (n *NullInt8) Scan(value interface{}) error   { return scan(n.Int8, value) }
func (n *NullUint8) Scan(value interface{}) error  { return scan(n.Uint8, value) }
func (n *NullInt16) Scan(value interface{}) error  { return scan(n.Int16, value) }
func (n *NullUint16) Scan(value interface{}) error { return scan(n.Uint16, value) }
func (n *NullInt32) Scan(value interface{}) error  { return scan(n.Int32, value) }
func (n *NullUint32) Scan(value interface{}) error { return scan(n.Uint32, value) }
func (n *NullInt64) Scan(value interface{}) error  { return scan(n.Int64, value) }
func (n *NullUint64) Scan(value interface{}) error { return scan(n.Uint64, value) }

func (n NullInt) Value() (driver.Value, error)    { return value(n.Int) }
func (n NullInt8) Value() (driver.Value, error)   { return value(n.Int8) }
func (n NullUint8) Value() (driver.Value, error)  { return value(n.Uint8) }
func (n NullInt16) Value() (driver.Value, error)  { return value(n.Int16) }
func (n NullUint16) Value() (driver.Value, error) { return value(n.Uint16) }
func (n NullInt32) Value() (driver.Value, error)  { return value(n.Int32) }
func (n NullUint32) Value() (driver.Value, error) { return value(n.Uint32) }
func (n NullInt64) Value() (driver.Value, error)  { return value(n.Int64) }
func (n NullUint64) Value() (driver.Value, error) { return value(n.Uint64) }

func toString(ptr interface{}) string {
	if ptr == nil {
		return "nil"
	}

	i64 := toInt64(ptr)
	if i64 == 0 {
		return "nil"
	}

	return strconv.FormatInt(i64, 10)
}

func value(ptr interface{}) (driver.Value, error) {
	if ptr == nil {
		return nil, nil
	}

	i64 := toInt64(ptr)
	if i64 == 0 {
		return nil, nil
	}
	return i64, nil
}

func toInt64(ptr interface{}) (i64 int64) {
	switch v := ptr.(type) {
	case *int8:
		i64 = int64(*v)
	case *uint8:
		i64 = int64(*v)
	// case *byte:
	// 	i64 = int64(*v)
	case *int16:
		i64 = int64(*v)
	case *uint16:
		i64 = int64(*v)
	case *int32:
		i64 = int64(*v)
	case *uint32:
		i64 = int64(*v)
	case *int:
		i64 = int64(*v)
	// case *rune:
	// 	i64 = int64(*v)
	case *int64:
		i64 = *v
	case *uint64:
		i64 = int64(*v)

	default:
		panic("unsupported type " + reflect.TypeOf(v).String())
	}
	return
}

func scan(ptr, value interface{}) error {
	if value == nil {
		return nil
	}

	var i64 int64
	switch v := value.(type) {
	case int64:
		i64 = v
	case *int64:
		i64 = *v
	case []uint8:
		i64 = int64(binary.BigEndian.Uint64(v))
	default:
		panic("unsupported type " + reflect.TypeOf(v).String())
	}

	fromI64(ptr, i64)

	return nil
}

func isEmpty(ptr interface{}) bool {
	if ptr == nil {
		return true
	}
	return toInt64(ptr) == 0
}

func marshalJSON(ptr interface{}) ([]byte, error) {
	if ptr == nil {
		return []byte{'0'}, nil
	}
	i64 := toInt64(ptr)
	return []byte(strconv.FormatInt(i64, 10)), nil
}

func unmarshalJSON(ptr interface{}, data []byte) error {
	if data == nil {
		return nil
	}
	i64, err := strconv.ParseInt(string(data), 10, 64)
	if err != nil {
		return err
	}

	fromI64(ptr, i64)
	return nil
}

func fromI64(ptr interface{}, i64 int64) {
	switch v := ptr.(type) {
	case *int8:
		*v = int8(i64)
	case *uint8:
		*v = uint8(i64)
	// case *byte:
	// 	*v = byte(i64)
	case *int16:
		*v = int16(i64)
	case *uint16:
		*v = uint16(i64)
	case *int32:
		*v = int32(i64)
	case *uint32:
		*v = uint32(i64)
	case *int:
		*v = int(i64)
	// case *rune:
	// 	*v = rune(i64)
	case *int64:
		*v = i64
	case *uint64:
		*v = uint64(i64)

	default:
		panic("unsupported type " + reflect.TypeOf(v).String())
	}
}
<commit_msg>fix int return []uint8 convert error<commit_after>package null

import (
	"database/sql/driver"
	"reflect"
	"strconv"
)

type NullInt struct{ Int *int }
type NullInt8 struct{ Int8 *int8 }
type NullUint8 struct{ Uint8 *uint8 }
type NullInt16 struct{ Int16 *int16 }
type NullUint16 struct{ Uint16 *uint16 }
type NullInt32 struct{ Int32 *int32 }
type NullUint32 struct{ Uint32 *uint32 }
type NullInt64 struct{ Int64 *int64 }
type NullUint64 struct{ Uint64 *uint64 }

func (n *NullInt) IsEmpty() bool    { return isEmpty(n.Int) }
func (n *NullInt8) IsEmpty() bool   { return isEmpty(n.Int8) }
func (n *NullUint8) IsEmpty() bool  { return isEmpty(n.Uint8) }
func (n *NullInt16) IsEmpty() bool  { return isEmpty(n.Int16) }
func (n *NullUint16) IsEmpty() bool { return isEmpty(n.Uint16) }
func (n *NullInt32) IsEmpty() bool  { return isEmpty(n.Int32) }
func (n *NullUint32) IsEmpty() bool { return isEmpty(n.Uint32) }
func (n *NullInt64) IsEmpty() bool  { return isEmpty(n.Int64) }
func (n *NullUint64) IsEmpty() bool { return isEmpty(n.Uint64) }

func (n *NullInt) MarshalJSON() ([]byte, error)    { return marshalJSON(n.Int) }
func (n *NullInt8) MarshalJSON() ([]byte, error)   { return marshalJSON(n.Int8) }
func (n *NullUint8) MarshalJSON() ([]byte, error)  { return marshalJSON(n.Uint8) }
func (n *NullInt16) MarshalJSON() ([]byte, error)  { return marshalJSON(n.Int16) }
func (n *NullUint16) MarshalJSON() ([]byte, error) { return marshalJSON(n.Uint16) }
func (n *NullInt32) MarshalJSON() ([]byte, error)  { return marshalJSON(n.Int32) }
func (n *NullUint32) MarshalJSON() ([]byte, error) { return marshalJSON(n.Uint32) }
func (n *NullInt64) MarshalJSON() ([]byte, error)  { return marshalJSON(n.Int64) }
func (n *NullUint64) MarshalJSON() ([]byte, error) { return marshalJSON(n.Uint64) }

func (n *NullInt) UnmarshalJSON(data []byte) error    { return unmarshalJSON(n.Int, data) }
func (n *NullInt8) UnmarshalJSON(data []byte) error   { return unmarshalJSON(n.Int8, data) }
func (n *NullUint8) UnmarshalJSON(data []byte) error  { return unmarshalJSON(n.Uint8, data) }
func (n *NullInt16) UnmarshalJSON(data []byte) error  { return unmarshalJSON(n.Int16, data) }
func (n *NullUint16) UnmarshalJSON(data []byte) error { return unmarshalJSON(n.Uint16, data) }
func (n *NullInt32) UnmarshalJSON(data []byte) error  { return unmarshalJSON(n.Int32, data) }
func (n *NullUint32) UnmarshalJSON(data []byte) error { return unmarshalJSON(n.Uint32, data) }
func (n *NullInt64) UnmarshalJSON(data []byte) error  { return unmarshalJSON(n.Int64, data) }
func (n *NullUint64) UnmarshalJSON(data []byte) error { return unmarshalJSON(n.Uint64, data) }

func (n *NullInt) String() string    { return toString(n.Int) }
func (n *NullInt8) String() string   { return toString(n.Int8) }
func (n *NullUint8) String() string  { return toString(n.Uint8) }
func (n *NullInt16) String() string  { return toString(n.Int16) }
func (n *NullUint16) String() string { return toString(n.Uint16) }
func (n *NullInt32) String() string  { return toString(n.Int32) }
func (n *NullUint32) String() string { return toString(n.Uint32) }
func (n *NullInt64) String() string  { return toString(n.Int64) }
func (n *NullUint64) String() string { return toString(n.Uint64) }

func (n *NullInt) Scan(value interface{}) error    { return scan(n.Int, value) }
func (n *NullInt8) Scan(value interface{}) error   { return scan(n.Int8, value) }
func (n *NullUint8) Scan(value interface{}) error  { return scan(n.Uint8, value) }
func (n *NullInt16) Scan(value interface{}) error  { return scan(n.Int16, value) }
func (n *NullUint16) Scan(value interface{}) error { return scan(n.Uint16, value) }
func (n *NullInt32) Scan(value interface{}) error  { return scan(n.Int32, value) }
func (n *NullUint32) Scan(value interface{}) error { return scan(n.Uint32, value) }
func (n *NullInt64) Scan(value interface{}) error  { return scan(n.Int64, value) }
func (n *NullUint64) Scan(value interface{}) error { return scan(n.Uint64, value) }

func (n NullInt) Value() (driver.Value, error)    { return value(n.Int) }
func (n NullInt8) Value() (driver.Value, error)   { return value(n.Int8) }
func (n NullUint8) Value() (driver.Value, error)  { return value(n.Uint8) }
func (n NullInt16) Value() (driver.Value, error)  { return value(n.Int16) }
func (n NullUint16) Value() (driver.Value, error) { return value(n.Uint16) }
func (n NullInt32) Value() (driver.Value, error)  { return value(n.Int32) }
func (n NullUint32) Value() (driver.Value, error) { return value(n.Uint32) }
func (n NullInt64) Value() (driver.Value, error)  { return value(n.Int64) }
func (n NullUint64) Value() (driver.Value, error) { return value(n.Uint64) }

func toString(ptr interface{}) string {
	if ptr == nil {
		return "nil"
	}

	i64 := toInt64(ptr)
	if i64 == 0 {
		return "nil"
	}

	return strconv.FormatInt(i64, 10)
}

func value(ptr interface{}) (driver.Value, error) {
	if ptr == nil {
		return nil, nil
	}

	i64 := toInt64(ptr)
	if i64 == 0 {
		return nil, nil
	}
	return i64, nil
}

func toInt64(ptr interface{}) (i64 int64) {
	switch v := ptr.(type) {
	case *int8:
		i64 = int64(*v)
	case *uint8:
		i64 = int64(*v)
	// case *byte:
	// 	i64 = int64(*v)
	case *int16:
		i64 = int64(*v)
	case *uint16:
		i64 = int64(*v)
	case *int32:
		i64 = int64(*v)
	case *uint32:
		i64 = int64(*v)
	case *int:
		i64 = int64(*v)
	// case *rune:
	// 	i64 = int64(*v)
	case *int64:
		i64 = *v
	case *uint64:
		i64 = int64(*v)

	default:
		panic("unsupported type " + reflect.TypeOf(v).String())
	}
	return
}

func scan(ptr, value interface{}) error {
	if value == nil {
		return nil
	}

	var i64 int64
	switch v := value.(type) {
	case int64:
		i64 = v
	case *int64:
		i64 = *v
	case []uint8:
		var err error
		i64, err = strconv.ParseInt(string(v), 10, 64)
		if err != nil {
			return err
		}
	default:
		panic("unsupported type " + reflect.TypeOf(v).String())
	}

	fromI64(ptr, i64)

	return nil
}

func isEmpty(ptr interface{}) bool {
	if ptr == nil {
		return true
	}
	return toInt64(ptr) == 0
}

func marshalJSON(ptr interface{}) ([]byte, error) {
	if ptr == nil {
		return []byte{'0'}, nil
	}
	i64 := toInt64(ptr)
	return []byte(strconv.FormatInt(i64, 10)), nil
}

func unmarshalJSON(ptr interface{}, data []byte) error {
	if data == nil {
		return nil
	}
	i64, err := strconv.ParseInt(string(data), 10, 64)
	if err != nil {
		return err
	}

	fromI64(ptr, i64)
	return nil
}

func fromI64(ptr interface{}, i64 int64) {
	switch v := ptr.(type) {
	case *int8:
		*v = int8(i64)
	case *uint8:
		*v = uint8(i64)
	// case *byte:
	// 	*v = byte(i64)
	case *int16:
		*v = int16(i64)
	case *uint16:
		*v = uint16(i64)
	case *int32:
		*v = int32(i64)
	case *uint32:
		*v = uint32(i64)
	case *int:
		*v = int(i64)
	// case *rune:
	// 	*v = rune(i64)
	case *int64:
		*v = i64
	case *uint64:
		*v = uint64(i64)

	default:
		panic("unsupported type " + reflect.TypeOf(v).String())
	}
}
<|endoftext|>


<commit_before>package nv

import (
	"encoding/binary"
	"io"
	"reflect"
)

//go:generate stringer -type=flag
type flag uint32

const (
	_ flag = iota
	UNIQUE_NAME
	UNIQUE_NAME_TYPE
)

//go:generate stringer -type=dataType
type dataType uint32

const (
	UNKNOWN dataType = iota
	BOOLEAN
	BYTE
	INT16
	UINT16
	INT32
	UINT32
	INT64
	UINT64
	STRING
	BYTE_ARRAY
	INT16_ARRAY
	UINT16_ARRAY
	INT32_ARRAY
	UINT32_ARRAY
	INT64_ARRAY
	UINT64_ARRAY // 0x10
	STRING_ARRAY
	HRTIME
	NVLIST
	NVLIST_ARRAY
	BOOLEAN_VALUE
	INT8
	UINT8
	BOOLEAN_ARRAY
	INT8_ARRAY
	UINT8_ARRAY
	DOUBLE
)

var goToNV = map[string]dataType{
	"bool":          BOOLEAN_VALUE,
	"boolean_array": BOOLEAN_ARRAY,
	"byte":          BYTE,
	"byte_array":    BYTE_ARRAY,
	"float64":       DOUBLE,
	"int16":         INT16,
	"int16_array":   INT16_ARRAY,
	"int32":         INT32,
	"int32_array":   INT32_ARRAY,
	"int64":         INT64,
	"int64_array":   INT64_ARRAY,
	"int8":          INT8,
	"int8_array":    INT8_ARRAY,
	"nv.List":       NVLIST,
	"nvlist_array":  NVLIST_ARRAY,
	"string":        STRING,
	"string_array":  STRING_ARRAY,
	"time.Time":     HRTIME,
	"uint16":        UINT16,
	"uint16_array":  UINT16_ARRAY,
	"uint32":        UINT32,
	"uint32_array":  UINT32_ARRAY,
	"uint64":        UINT64,
	"uint64_array":  UINT64_ARRAY,
	"uint8":         UINT8,
	"uint8_array":   UINT8_ARRAY,
}

type List struct {
	header
	Pairs []Pair
}

type encoding struct {
	Encoding  uint8
	Endianess uint8
	Reserved1 uint8
	Reserved2 uint8
}

type header struct {
	Version uint32
	Flag    flag
}

type pair struct {
	EncodedSize uint32
	DecodedSize uint32
	Name        string
	Type        dataType
	NElements   uint32
	data        interface{}
}

type Pair struct {
	pair
	Value interface{}
}

func align4(n int) int {
	return (n + 3) & ^3
}

func align8(n int) int {
	return (n + 7) & ^7
}

func (p pair) headerSize() int {
	return 4 + 4 + 4 + align4(len(p.Name)) + 4 + 4
}

func (p pair) encodedSize() int {
	valSize := 0
	switch p.Type {
	case BYTE, INT8, UINT8, INT16, UINT16, BOOLEAN_VALUE, INT32, UINT32:
		valSize = 4
	case INT64, UINT64, HRTIME, DOUBLE:
		valSize = 8
	case BYTE_ARRAY:
		valSize = int(p.NElements * 1)
	case BOOLEAN_ARRAY, INT8_ARRAY, UINT8_ARRAY, INT16_ARRAY, UINT16_ARRAY, INT32_ARRAY, UINT32_ARRAY:
		valSize = 4 + int(p.NElements*4)
	case INT64_ARRAY, UINT64_ARRAY:
		valSize = 4 + int(p.NElements*8)
	case STRING:
		valSize = 4 + len(p.data.(string))
	case NVLIST, NVLIST_ARRAY:
		valSize = len(p.data.([]byte))
	case STRING_ARRAY:
		slice := p.data.([]string)
		for i := range slice {
			valSize += align4(4 + len(slice[i]))
		}
	}
	return p.headerSize() + align4(valSize)
}

func (p pair) decodedSize() int {
	// typedef struct nvpair {
	// 	int32_t nvp_size;	/* size of this nvpair */
	// 	int16_t	nvp_name_sz;	/* length of name string */
	// 	int16_t	nvp_reserve;	/* not used */
	// 	int32_t	nvp_value_elem;	/* number of elements for array types */
	// 	data_type_t nvp_type;	/* type of value */
	// 	/* name string */
	// 	/* aligned ptr array for string arrays */
	// 	/* aligned array of data for value */
	// } nvpair_t;
	nvpair_tSize := 4 + 2 + 2 + 4 + 4 + len(p.Name) + 1

	valSize := 0
	switch p.Type {
	case BYTE, INT8, UINT8:
		valSize = 1
	case INT16, UINT16:
		valSize = 2
	case BOOLEAN_VALUE, INT32, UINT32:
		valSize = 4
	case INT64, UINT64, HRTIME, DOUBLE:
		valSize = 8
	case BYTE_ARRAY, INT8_ARRAY, UINT8_ARRAY:
		valSize = int(p.NElements * 1)
	case INT16_ARRAY, UINT16_ARRAY:
		valSize = int(p.NElements * 2)
	case INT32_ARRAY, UINT32_ARRAY:
		valSize = int(p.NElements * 4)
	case INT64_ARRAY, UINT64_ARRAY:
		valSize = int(p.NElements * 8)
	case STRING:
		valSize = len(p.data.(string)) + 1
	case NVLIST:
		// /* nvlist header */
		// typedef struct nvlist {
		// 	int32_t		nvl_version;
		// 	uint32_t	nvl_nvflag;	/* persistent flags */
		// 	uint64_t	nvl_priv;	/* ptr to private data if not packed */
		// 	uint32_t	nvl_flag;
		// 	int32_t		nvl_pad;	/* currently not used, for alignment */
		// } nvlist_t;
		valSize = 4 + 4 + 8 + 4 + 4
	case NVLIST_ARRAY:
		// value_sz = (uint64_t)nelem * sizeof (uint64_t) +
		//	      (uint64_t)nelem * NV_ALIGN(sizeof (nvlist_t));
		valSize = int(p.NElements) * (8 + align8(4+4+8+4+4))
	case BOOLEAN_ARRAY:
		valSize = 4 + int(p.NElements*4)
	case STRING_ARRAY:
		valSize = int(p.NElements * 8)
		slice := p.data.([]string)
		for i := range slice {
			valSize += len(slice[i]) + 1
		}
	}
	return align8(nvpair_tSize) + align8(valSize)
}

func deref(v reflect.Value) reflect.Value {
	for v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	return v
}

func writeHeader(w io.Writer) error {

	return nil
}

type mVal struct {
	Name  string
	Type  dataType
	Value interface{}
}
type mList map[string]mVal

func isEnd(r io.ReadSeeker) (bool, error) {
	var end uint64
	err := binary.Read(r, binary.BigEndian, &end)
	if err != nil {
		return false, err
	}
	if end == 0 {
		return true, nil
	}
	_, err = r.Seek(-8, 1)
	return false, err
}
<commit_msg>nv: add String and GoString methods to pair<commit_after>package nv

import (
	"encoding/binary"
	"fmt"
	"io"
	"reflect"
)

//go:generate stringer -type=flag
type flag uint32

const (
	_ flag = iota
	UNIQUE_NAME
	UNIQUE_NAME_TYPE
)

//go:generate stringer -type=dataType
type dataType uint32

const (
	UNKNOWN dataType = iota
	BOOLEAN
	BYTE
	INT16
	UINT16
	INT32
	UINT32
	INT64
	UINT64
	STRING
	BYTE_ARRAY
	INT16_ARRAY
	UINT16_ARRAY
	INT32_ARRAY
	UINT32_ARRAY
	INT64_ARRAY
	UINT64_ARRAY // 0x10
	STRING_ARRAY
	HRTIME
	NVLIST
	NVLIST_ARRAY
	BOOLEAN_VALUE
	INT8
	UINT8
	BOOLEAN_ARRAY
	INT8_ARRAY
	UINT8_ARRAY
	DOUBLE
)

var goToNV = map[string]dataType{
	"bool":          BOOLEAN_VALUE,
	"boolean_array": BOOLEAN_ARRAY,
	"byte":          BYTE,
	"byte_array":    BYTE_ARRAY,
	"float64":       DOUBLE,
	"int16":         INT16,
	"int16_array":   INT16_ARRAY,
	"int32":         INT32,
	"int32_array":   INT32_ARRAY,
	"int64":         INT64,
	"int64_array":   INT64_ARRAY,
	"int8":          INT8,
	"int8_array":    INT8_ARRAY,
	"nv.List":       NVLIST,
	"nvlist_array":  NVLIST_ARRAY,
	"string":        STRING,
	"string_array":  STRING_ARRAY,
	"time.Time":     HRTIME,
	"uint16":        UINT16,
	"uint16_array":  UINT16_ARRAY,
	"uint32":        UINT32,
	"uint32_array":  UINT32_ARRAY,
	"uint64":        UINT64,
	"uint64_array":  UINT64_ARRAY,
	"uint8":         UINT8,
	"uint8_array":   UINT8_ARRAY,
}

type List struct {
	header
	Pairs []Pair
}

type encoding struct {
	Encoding  uint8
	Endianess uint8
	Reserved1 uint8
	Reserved2 uint8
}

type header struct {
	Version uint32
	Flag    flag
}

type pair struct {
	EncodedSize uint32
	DecodedSize uint32
	Name        string
	Type        dataType
	NElements   uint32
	data        interface{}
}

func (p pair) String() string {
	return fmt.Sprintf("{%d, %d, \"%s\", %s, %d, %#v}",
		p.EncodedSize, p.DecodedSize, p.Name, p.Type, p.NElements, p.data)
}

func (p pair) GoString() string {
	return fmt.Sprintf("{EncodedSize:%d, DecodedSize:%d, Name:\"%s\", Type:%s, NElements:%d, data:%#v}",
		p.EncodedSize, p.DecodedSize, p.Name, p.Type, p.NElements, p.data)
}

type Pair struct {
	pair
	Value interface{}
}

func align4(n int) int {
	return (n + 3) & ^3
}

func align8(n int) int {
	return (n + 7) & ^7
}

func (p pair) headerSize() int {
	return 4 + 4 + 4 + align4(len(p.Name)) + 4 + 4
}

func (p pair) encodedSize() int {
	valSize := 0
	switch p.Type {
	case BYTE, INT8, UINT8, INT16, UINT16, BOOLEAN_VALUE, INT32, UINT32:
		valSize = 4
	case INT64, UINT64, HRTIME, DOUBLE:
		valSize = 8
	case BYTE_ARRAY:
		valSize = int(p.NElements * 1)
	case BOOLEAN_ARRAY, INT8_ARRAY, UINT8_ARRAY, INT16_ARRAY, UINT16_ARRAY, INT32_ARRAY, UINT32_ARRAY:
		valSize = 4 + int(p.NElements*4)
	case INT64_ARRAY, UINT64_ARRAY:
		valSize = 4 + int(p.NElements*8)
	case STRING:
		valSize = 4 + len(p.data.(string))
	case NVLIST, NVLIST_ARRAY:
		valSize = len(p.data.([]byte))
	case STRING_ARRAY:
		slice := p.data.([]string)
		for i := range slice {
			valSize += align4(4 + len(slice[i]))
		}
	}
	return p.headerSize() + align4(valSize)
}

func (p pair) decodedSize() int {
	// typedef struct nvpair {
	// 	int32_t nvp_size;	/* size of this nvpair */
	// 	int16_t	nvp_name_sz;	/* length of name string */
	// 	int16_t	nvp_reserve;	/* not used */
	// 	int32_t	nvp_value_elem;	/* number of elements for array types */
	// 	data_type_t nvp_type;	/* type of value */
	// 	/* name string */
	// 	/* aligned ptr array for string arrays */
	// 	/* aligned array of data for value */
	// } nvpair_t;
	nvpair_tSize := 4 + 2 + 2 + 4 + 4 + len(p.Name) + 1

	valSize := 0
	switch p.Type {
	case BYTE, INT8, UINT8:
		valSize = 1
	case INT16, UINT16:
		valSize = 2
	case BOOLEAN_VALUE, INT32, UINT32:
		valSize = 4
	case INT64, UINT64, HRTIME, DOUBLE:
		valSize = 8
	case BYTE_ARRAY, INT8_ARRAY, UINT8_ARRAY:
		valSize = int(p.NElements * 1)
	case INT16_ARRAY, UINT16_ARRAY:
		valSize = int(p.NElements * 2)
	case INT32_ARRAY, UINT32_ARRAY:
		valSize = int(p.NElements * 4)
	case INT64_ARRAY, UINT64_ARRAY:
		valSize = int(p.NElements * 8)
	case STRING:
		valSize = len(p.data.(string)) + 1
	case NVLIST:
		// /* nvlist header */
		// typedef struct nvlist {
		// 	int32_t		nvl_version;
		// 	uint32_t	nvl_nvflag;	/* persistent flags */
		// 	uint64_t	nvl_priv;	/* ptr to private data if not packed */
		// 	uint32_t	nvl_flag;
		// 	int32_t		nvl_pad;	/* currently not used, for alignment */
		// } nvlist_t;
		valSize = 4 + 4 + 8 + 4 + 4
	case NVLIST_ARRAY:
		// value_sz = (uint64_t)nelem * sizeof (uint64_t) +
		//	      (uint64_t)nelem * NV_ALIGN(sizeof (nvlist_t));
		valSize = int(p.NElements) * (8 + align8(4+4+8+4+4))
	case BOOLEAN_ARRAY:
		valSize = 4 + int(p.NElements*4)
	case STRING_ARRAY:
		valSize = int(p.NElements * 8)
		slice := p.data.([]string)
		for i := range slice {
			valSize += len(slice[i]) + 1
		}
	}
	return align8(nvpair_tSize) + align8(valSize)
}

func deref(v reflect.Value) reflect.Value {
	for v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	return v
}

func writeHeader(w io.Writer) error {

	return nil
}

type mVal struct {
	Name  string
	Type  dataType
	Value interface{}
}
type mList map[string]mVal

func isEnd(r io.ReadSeeker) (bool, error) {
	var end uint64
	err := binary.Read(r, binary.BigEndian, &end)
	if err != nil {
		return false, err
	}
	if end == 0 {
		return true, nil
	}
	_, err = r.Seek(-8, 1)
	return false, err
}
<|endoftext|>


<commit_before>package main

import (
	cryptorand "crypto/rand"
	"crypto/sha512"
	"flag"
	"fmt"
	//	"math/rand"
	"os"
	"runtime"
	"time"
)

const (
	BSIZE = 65536
)

var (
	narg   = int(0)
	phrase = ""
)

// randomSeed produces a int64 seed based on crypto/rand and time.
func randomSeed() int64 {
	var seed int64

	urandom := make([]byte, 8)
	cryptorand.Reader.Read(urandom)

	for key, value := range urandom {
		seed ^= (int64(value) ^ time.Now().UTC().UnixNano()) << (uint(key) * 8)
	}

	return seed
}

func init() {
	flag.StringVar(&phrase, "phrase", "", "the Garble phrase, by default random")
	flag.Parse()

	narg = flag.NArg()

	if narg <= 0 {
		flag.Usage()
		os.Exit(1)
	}

	if phrase == "" {
		phrase = fmt.Sprintf("%016x", uint64(randomSeed()))
	}
}

func garble(index int, f *os.File, c chan []byte) {
	fmt.Println("garble(", index, f, c, ")")
	<-c
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	channels := make([]chan []byte, narg)
	files := make([]*os.File, narg)

	for i, arg := range flag.Args() {
		f, err := os.OpenFile(arg, os.O_RDWR, 0666)
		if err != nil {
			panic(err)
		}
		defer f.Close()
		files[i] = f
		channels[i] = make(chan []byte, 8)
		go garble(i, files[i], channels[i])
	}

	hash := sha512.New()
	seed := []byte(phrase)
	b := make([]byte, hash.Size())
	for i := 0; i < 2; i++ {
		hash.Write(seed)
		hash.Sum(b[:0])
		fmt.Println(b)
	}
}
<commit_msg>stupid randomBytes<commit_after>package main

import (
	cryptorand "crypto/rand"
	"crypto/sha512"
	"flag"
	"fmt"
	"math/rand"
	"os"
	"runtime"
	"time"
)

const (
	BSIZE    = 65536
	BSIZEMOD = BSIZE % 7
	BSIZE7   = BSIZE - BSIZEMOD
	SRC      = 8
)

var (
	narg    = int(0)
	phrase  = ""
	sources [8]rand.Source
)

// randomSeed produces a int64 seed based on crypto/rand and time.
func randomSeed() int64 {
	var seed int64

	urandom := make([]byte, 8)
	cryptorand.Reader.Read(urandom)

	for key, value := range urandom {
		seed ^= (int64(value) ^ time.Now().UTC().UnixNano()) << (uint(key) * 8)
	}

	return seed
}

func randomBytes(src rand.Source) []byte {
	buf := make([]byte, BSIZE)

	for i := 0; i < BSIZE7; i += 7 {
		r := src.Int63()
		buf[i] = byte(r)
		buf[i+1] = byte(r << 8)
		buf[i+2] = byte(r << 16)
		buf[i+3] = byte(r << 24)
		buf[i+4] = byte(r << 32)
		buf[i+5] = byte(r << 40)
		buf[i+6] = byte(r << 48)
	}

	r := src.Int63()

	for i := BSIZE - BSIZE7; i < BSIZE; i++ {
		buf[i] = byte(r)
		r = r << 8
	}

	return buf
}

func init() {
	flag.StringVar(&phrase, "phrase", "", "the Garble phrase, by default random")
	flag.Parse()

	narg = flag.NArg()

	if narg <= 0 {
		flag.Usage()
		os.Exit(1)
	}

	if phrase == "" {
		phrase = fmt.Sprintf("%016x", uint64(randomSeed()))
	}
}

func garble(index int, f *os.File, c chan []byte) {
	fmt.Println("garble(", index, f, c, ")")
	<-c
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	channels := make([]chan []byte, narg)
	files := make([]*os.File, narg)

	for i, arg := range flag.Args() {
		f, err := os.OpenFile(arg, os.O_RDWR, 0666)
		if err != nil {
			panic(err)
		}
		defer f.Close()
		files[i] = f
		channels[i] = make(chan []byte, 8)
		go garble(i, files[i], channels[i])
	}

	hash := sha512.New()
	seed := []byte(phrase)
	b := make([]byte, hash.Size())
	for i := 0; i < 2; i++ {
		hash.Write(seed)
		hash.Sum(b[:0])
		fmt.Println(b)
	}
}
<|endoftext|>


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

package flow

import (
	"database/sql"
	"testing"

	_ "github.com/go-sql-driver/mysql"
)

var (
	states = []string{"DRAFT", "REQ_PENDING", "APPROVED", "REJECTED"}
)

// Driver test function.
func TestDocStates01(t *testing.T) {
	var dtypeStorReqID DocTypeID
	var dtypeStorRelID DocTypeID

	// Connect to the database.
	driver, connStr := "mysql", "travis@/flow"
	db, err := sql.Open(driver, connStr)
	if err != nil {
		t.Fatalf("could not connect to database : %v\n", err)
	}
	defer db.Close()
	err = db.Ping()
	if err != nil {
		t.Fatalf("could not ping the database : %v\n", err)
	}
	RegisterDB(db)

	// Tear down.
	defer func() {
		tx, err := db.Begin()
		if err != nil {
			t.Fatalf("error starting transaction : %v\n", err)
		}
		defer tx.Rollback()

		_, err = tx.Exec(`DELETE FROM wf_docstates_master WHERE id > 1`)
		if err != nil {
			t.Fatalf("error running transaction : %v\n", err)
		}

		_, err = tx.Exec(`DELETE FROM wf_doctypes_master`)
		if err != nil {
			t.Fatalf("error running transaction : %v\n", err)
		}

		err = tx.Commit()
		if err != nil {
			t.Fatalf("error committing transaction : %v\n", err)
		}
	}()

	// Test life cycle.
	t.Run("CRUL", func(t *testing.T) {
		// Insert the required document types.
		tx, err := db.Begin()
		if err != nil {
			t.Fatalf("error starting transaction : %v\n", err)
		}
		defer tx.Rollback()

		dtypeStorReqID, err = DocTypes.New(tx, dtypeStorReq)
		if err != nil {
			t.Fatalf("error creating document type '%s' : %v\n", dtypeStorReq, err)
		}
		dtypeStorRelID, err = DocTypes.New(tx, dtypeStorRel)
		if err != nil {
			t.Fatalf("error creating document type '%s' : %v\n", dtypeStorRel, err)
		}

		// Add document states.
		var ds DocStateID
		for _, name := range states {
			ds, err = DocStates.New(tx, name)
			if err != nil {
				t.Fatalf("error creating document state '%s' : %v\n", name, err)
			}
		}

		err = tx.Commit()
		if err != nil {
			t.Fatalf("error committing transaction : %v\n", err)
		}

		// Test reading.
		_, err = DocStates.Get(ds)
		if err != nil {
			t.Fatalf("error getting document state '1' : %v\n", err)
		}

		_, err = DocStates.GetByName(states[1])
		if err != nil {
			t.Fatalf("error getting document type:state '%s' : %v\n", states[1], err)
		}

		_, err = DocStates.List(0, 0)
		if err != nil {
			t.Fatalf("error listing document types : %v\n", err)
		}

		// Rename the given document state to the specified new name.
		tx, err = db.Begin()
		if err != nil {
			t.Fatalf("error starting transaction : %v\n", err)
		}
		defer tx.Rollback()

		err = DocStates.Rename(tx, ds, "INITIAL")
		if err != nil {
			t.Fatalf("error renaming document state '1' : %v\n", err)
		}

		err = tx.Commit()
		if err != nil {
			t.Fatalf("error committing transaction : %v\n", err)
		}

		tx, err = db.Begin()
		if err != nil {
			t.Fatalf("error starting transaction : %v\n", err)
		}
		defer tx.Rollback()

		err = DocStates.Rename(tx, ds, states[len(states)-1])
		if err != nil {
			t.Fatalf("error renaming document state '1' : %v\n", err)
		}

		err = tx.Commit()
		if err != nil {
			t.Fatalf("error committing transaction : %v\n", err)
		}
	})
}
<commit_msg>Remove `docstate_test.go`; tests migrated to `flow_test.go`<commit_after><|endoftext|>


<commit_before>package gui

import (
	"github.com/andlabs/ui"
	"image"
	"image/draw"
)

var area ui.Area
var window ui.Window

func mainGraphics(title string, handler Interface) error {
	go goGraphics(title, handler)

	return ui.Go()
}

func goGraphics(title string, handler Interface) {
	ui.Do(func() {
		w, h := handler.SpriteSize()
		w *= 80
		h *= 25
		area = ui.NewArea(w, h, &graphicsHandler{handler, w, h})
		window = ui.NewWindow(title, w, h, area)

		window.OnClosing(func() bool {
			if handler.Closing() {
				select {
				case <-exitch:
				default:
					close(exitch)
				}
				return true
			}
			return false
		})

		window.Show()
	})

	for {
		select {
		case <-redrawch:
			ui.Do(area.RepaintAll)

		case <-exitch:
			ui.Stop()
			return
		}
	}
}

type graphicsHandler struct {
	handler Interface
	w, h    int
}

func (g *graphicsHandler) Paint(cliprect image.Rectangle) *image.RGBA {
	img := image.NewRGBA(cliprect)

	w, h := g.handler.SpriteSize()
	r := image.Rect(0, 0, w, h)

	g.w = (cliprect.Max.X + w - 1) / w
	g.h = (cliprect.Max.Y + h - 1) / h

	for x := cliprect.Min.X / w; x <= cliprect.Max.X/w; x++ {
		for y := cliprect.Min.Y / h; y <= cliprect.Max.Y/h; y++ {
			s := g.handler.SpriteAt(x, y, (cliprect.Max.X+w-1)/w, (cliprect.Max.Y+h-1)/h)
			for _, i := range s.Images {
				draw.Draw(img, r.Add(image.Pt(x*w, y*h)), i, i.Bounds().Min, draw.Over)
			}
		}
	}

	return img
}

func (g *graphicsHandler) Mouse(e ui.MouseEvent) {
	defer area.RepaintAll()

	x, y := e.Pos.X, e.Pos.Y
	w, h := g.handler.SpriteSize()
	x /= w
	y /= h

	g.handler.Mouse(x, y, (g.w+w-1)/w, (g.h+h-1)/h)
}

func (g *graphicsHandler) Key(e ui.KeyEvent) (handled bool) {
	defer area.RepaintAll()

	if e.Up {
		return false
	}
	if e.Modifier != 0 {
		return false
	}
	if e.Modifiers&^ui.Shift != 0 {
		return false
	}

	if e.Key == '\b' {
		return g.handler.Key(Backspace)
	}
	if e.Key == 0 {
		if k, ok := graphicsKeys[e.ExtKey]; ok {
			return g.handler.Key(k)
		}
	}

	if e.Key != 0 && e.Modifiers&ui.Shift == ui.Shift {
		if k, ok := graphicsShift[e.Key]; ok {
			return g.handler.Rune(k)
		}
	}
	if k := e.EffectiveKey(); k != 0 {
		return g.handler.Rune(rune(k))
	}
	return false
}

var graphicsShift = map[byte]rune{
	'`':  '~',
	'1':  '!',
	'2':  '@',
	'3':  '#',
	'4':  '$',
	'5':  '%',
	'6':  '^',
	'7':  '&',
	'8':  '*',
	'9':  '(',
	'0':  ')',
	'-':  '_',
	'=':  '+',
	'q':  'Q',
	'w':  'W',
	'e':  'E',
	'r':  'R',
	't':  'T',
	'y':  'Y',
	'u':  'U',
	'i':  'I',
	'o':  'O',
	'p':  'P',
	'[':  '{',
	']':  '}',
	'\\': '|',
	'a':  'A',
	's':  'S',
	'd':  'D',
	'f':  'F',
	'g':  'G',
	'h':  'H',
	'j':  'J',
	'k':  'K',
	'l':  'L',
	';':  ':',
	'\'': '"',
	'z':  'Z',
	'x':  'X',
	'c':  'C',
	'v':  'V',
	'b':  'B',
	'n':  'N',
	'm':  'M',
	',':  '<',
	'.':  '>',
	'/':  '?',
}
<commit_msg>fix a few issues with graphical gui<commit_after>package gui

import (
	"github.com/andlabs/ui"
	"image"
	"image/draw"
)

var area ui.Area
var window ui.Window

func mainGraphics(title string, handler Interface) error {
	go goGraphics(title, handler)

	return ui.Go()
}

func goGraphics(title string, handler Interface) {
	ui.Do(func() {
		w, h := handler.SpriteSize()
		w *= 80
		h *= 25
		area = ui.NewArea(w, h, &graphicsHandler{handler, w, h})
		window = ui.NewWindow(title, w, h, area)

		window.OnClosing(func() bool {
			if handler.Closing() {
				select {
				case <-exitch:
				default:
					close(exitch)
				}
				return true
			}
			return false
		})

		window.Show()
	})

	for {
		select {
		case <-redrawch:
			ui.Do(area.RepaintAll)

		case <-exitch:
			ui.Stop()
			return
		}
	}
}

type graphicsHandler struct {
	handler Interface
	w, h    int
}

func (g *graphicsHandler) Paint(cliprect image.Rectangle) *image.RGBA {
	img := image.NewRGBA(cliprect)

	w, h := g.handler.SpriteSize()
	r := image.Rect(0, 0, w, h)

	g.w = (cliprect.Max.X + w - 1) / w
	g.h = (cliprect.Max.Y + h - 1) / h

	for x := cliprect.Min.X / w; x < (cliprect.Max.X+w-1)/w; x++ {
		for y := cliprect.Min.Y / h; y < (cliprect.Max.Y+h-1)/h; y++ {
			s := g.handler.SpriteAt(x, y, g.w, g.h)
			for _, i := range s.Images {
				draw.Draw(img, r.Add(image.Pt(x*w, y*h)), i, i.Bounds().Min, draw.Over)
			}
		}
	}

	return img
}

func (g *graphicsHandler) Mouse(e ui.MouseEvent) {
	defer area.RepaintAll()

	x, y := e.Pos.X, e.Pos.Y
	w, h := g.handler.SpriteSize()
	x /= w
	y /= h

	g.handler.Mouse(x, y, g.w, g.h)
}

func (g *graphicsHandler) Key(e ui.KeyEvent) (handled bool) {
	defer area.RepaintAll()

	if e.Up {
		return false
	}
	if e.Modifier != 0 {
		return false
	}
	if e.Modifiers&^ui.Shift != 0 {
		return false
	}

	if e.Key == '\b' {
		return g.handler.Key(Backspace)
	}
	if e.Key == 0 {
		if k, ok := graphicsKeys[e.ExtKey]; ok {
			return g.handler.Key(k)
		}
	}

	if e.Key != 0 && e.Modifiers&ui.Shift == ui.Shift {
		if k, ok := graphicsShift[e.Key]; ok {
			return g.handler.Rune(k)
		}
	}
	if k := e.EffectiveKey(); k != 0 {
		return g.handler.Rune(rune(k))
	}
	return false
}

var graphicsShift = map[byte]rune{
	'`':  '~',
	'1':  '!',
	'2':  '@',
	'3':  '#',
	'4':  '$',
	'5':  '%',
	'6':  '^',
	'7':  '&',
	'8':  '*',
	'9':  '(',
	'0':  ')',
	'-':  '_',
	'=':  '+',
	'q':  'Q',
	'w':  'W',
	'e':  'E',
	'r':  'R',
	't':  'T',
	'y':  'Y',
	'u':  'U',
	'i':  'I',
	'o':  'O',
	'p':  'P',
	'[':  '{',
	']':  '}',
	'\\': '|',
	'a':  'A',
	's':  'S',
	'd':  'D',
	'f':  'F',
	'g':  'G',
	'h':  'H',
	'j':  'J',
	'k':  'K',
	'l':  'L',
	';':  ':',
	'\'': '"',
	'z':  'Z',
	'x':  'X',
	'c':  'C',
	'v':  'V',
	'b':  'B',
	'n':  'N',
	'm':  'M',
	',':  '<',
	'.':  '>',
	'/':  '?',
}
<|endoftext|>


<commit_before>package krpc

import (
	"testing"

	"github.com/anacrolix/torrent/bencode"
	"github.com/stretchr/testify/require"
)

// https://github.com/anacrolix/torrent/issues/166
func TestUnmarshalBadError(t *testing.T) {
	var e Error
	err := bencode.Unmarshal([]byte(`l5:helloe`), &e)
	require.Error(t, err)
	t.Log(err)
}
<commit_msg>Don't log expected error in test<commit_after>package krpc

import (
	"testing"

	"github.com/anacrolix/torrent/bencode"
	"github.com/stretchr/testify/require"
)

// https://github.com/anacrolix/torrent/issues/166
func TestUnmarshalBadError(t *testing.T) {
	var e Error
	err := bencode.Unmarshal([]byte(`l5:helloe`), &e)
	require.Error(t, err)
}
<|endoftext|>


<commit_before>package csv

import (
	"bytes"
	"encoding/csv"
	"errors"
	"fmt"
	"reflect"
	"strconv"
)

// Marshaler is an interface for objects which can Marshal themselves into CSV.
type Marshaler interface {
	MarshalCSV() ([]byte, error)
}

type encoder struct {
	*csv.Writer
	buffer *bytes.Buffer
}

// Marshal returns the CSV encoding of i, which must be a slice of struct types.
//
// Marshal traverses the slice and encodes the primative values.
//
// The first row of the CSV output is a header row. The column names are based
// on the field name.  If a different name is required a struct tag can be used
// to define a new name.
//
//   Field string `csv:"Column Name"`
//
// To skip encoding a field use the "-" as the tag value.
//
//   Field string `csv:"-"`
//
// Boolean fields can use string values to define true or false.
//   Bool bool `true:"Yes" false:"No"`
func Marshal(i interface{}) ([]byte, error) {
	// validate the interface
	// create a new encoder
	//   assing the cfields
	// get the headers
	// encoder each row

	data := reflect.ValueOf(i)
	if data.IsNil()  {
		return []byte{}, nil
	}

	if data.Kind() != reflect.Slice {
		return []byte{}, errors.New("only slices can be marshalled")
	}

	el := data.Index(0)
	if el.Kind() == reflect.Interface {
		el = el.Elem()
	}
	enc, err := newEncoder(el)

	if err != nil {
		return []byte{}, err
	}

	err = enc.encodeAll(data)

	if err != nil {
		return []byte{}, err
	}

	enc.Flush()
	return enc.buffer.Bytes(), nil
}

func newEncoder(el reflect.Value) (*encoder, error) {
	b := bytes.NewBuffer([]byte{})

	enc := &encoder{
		buffer: b,
		Writer: csv.NewWriter(b),
	}

	err := enc.Write(colNames(el.Type()))

	return enc, err
}

// colNames takes a struct and returns the computed columns names for each
// field.
func colNames(t reflect.Type) (out []string) {
	l := t.NumField()

	for x := 0; x < l; x++ {
		f := t.Field(x)
		h, ok := fieldHeaderName(f)
		if ok {
			out = append(out, h)
		}
	}

	return
}

// encodeAll iterates over each item in data, encoder it then writes it
func (enc *encoder) encodeAll(data reflect.Value) error {
	n := data.Len()
	for c := 0; c < n; c++ {
		row, err := enc.encodeRow(data.Index(c))

		if err != nil {
			return err
		}

		err = enc.Write(row)

		if err != nil {
			return err
		}
	}

	return nil
}

// encodes a struct into a CSV row
func (enc *encoder) encodeRow(v reflect.Value) ([]string, error) {

	var row []string
	// TODO env.columns should map to a cfield
	// iterate over each cfield and encode with it

	if v.Kind() == reflect.Interface {
		v = v.Elem()
	}
	l := v.Type().NumField()

	for x := 0; x < l; x++ {
		fv := v.Field(x)
		st := v.Type().Field(x).Tag

		if st.Get("csv") == "-" {
			continue
		}
		o := enc.encodeCol(fv, st)
		row = append(row, o)
	}

	return row, nil
}

// Returns the string representation of the field value
func (enc *encoder) encodeCol(fv reflect.Value, st reflect.StructTag) string {
	switch fv.Kind() {
	case reflect.String:
		return fv.String()
	case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int8:
		return fmt.Sprintf("%v", fv.Int())
	case reflect.Float32:
		return encodeFloat(32, fv)
	case reflect.Float64:
		return encodeFloat(64, fv)
	case reflect.Bool:
		return encodeBool(fv.Bool(), st)
	case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint8:
		return fmt.Sprintf("%v", fv.Uint())
	case reflect.Complex64, reflect.Complex128:
		return fmt.Sprintf("%+.3g", fv.Complex())
	case reflect.Interface:
		return encodeInterface(fv, st)
	case reflect.Struct:
		return encodeInterface(fv, st)
	default:
		panic(fmt.Sprintf("Unsupported type %s", fv.Kind()))
	}

	return ""
}

func encodeFloat(bits int, f reflect.Value) string {
	return strconv.FormatFloat(f.Float(), 'g', -1, bits)
}

func encodeBool(b bool, st reflect.StructTag) string {
	v := strconv.FormatBool(b)
	tv := st.Get(v)

	if tv != "" {
		return tv
	}
	return v
}

func encodeInterface(fv reflect.Value, st reflect.StructTag) string {
	marshalerType := reflect.TypeOf(new(Marshaler)).Elem()

	if fv.Type().Implements(marshalerType) {
		m := fv.Interface().(Marshaler)
		b, err := m.MarshalCSV()
		if err != nil {
			return ""
		}
		return string(b)
	}

	return ""
}
<commit_msg>fixes failing tests<commit_after>package csv

import (
	"bytes"
	"encoding/csv"
	"errors"
	"fmt"
	"reflect"
	"strconv"
)

// Marshaler is an interface for objects which can Marshal themselves into CSV.
type Marshaler interface {
	MarshalCSV() ([]byte, error)
}

type encoder struct {
	*csv.Writer
	buffer *bytes.Buffer
}

// Marshal returns the CSV encoding of i, which must be a slice of struct types.
//
// Marshal traverses the slice and encodes the primative values.
//
// The first row of the CSV output is a header row. The column names are based
// on the field name.  If a different name is required a struct tag can be used
// to define a new name.
//
//   Field string `csv:"Column Name"`
//
// To skip encoding a field use the "-" as the tag value.
//
//   Field string `csv:"-"`
//
// Boolean fields can use string values to define true or false.
//   Bool bool `true:"Yes" false:"No"`
func Marshal(i interface{}) ([]byte, error) {
	// validate the interface
	// create a new encoder
	//   assing the cfields
	// get the headers
	// encoder each row

	data := reflect.ValueOf(i)

	if data.Kind() != reflect.Slice {
		return []byte{}, errors.New("only slices can be marshalled")
	}
	if data.IsNil()  {
		return []byte{}, nil
	}

	el := data.Index(0)
	if el.Kind() == reflect.Interface {
		el = el.Elem()
	}
	enc, err := newEncoder(el)

	if err != nil {
		return []byte{}, err
	}

	err = enc.encodeAll(data)

	if err != nil {
		return []byte{}, err
	}

	enc.Flush()
	return enc.buffer.Bytes(), nil
}

func newEncoder(el reflect.Value) (*encoder, error) {
	b := bytes.NewBuffer([]byte{})

	enc := &encoder{
		buffer: b,
		Writer: csv.NewWriter(b),
	}

	err := enc.Write(colNames(el.Type()))

	return enc, err
}

// colNames takes a struct and returns the computed columns names for each
// field.
func colNames(t reflect.Type) (out []string) {
	l := t.NumField()

	for x := 0; x < l; x++ {
		f := t.Field(x)
		h, ok := fieldHeaderName(f)
		if ok {
			out = append(out, h)
		}
	}

	return
}

// encodeAll iterates over each item in data, encoder it then writes it
func (enc *encoder) encodeAll(data reflect.Value) error {
	n := data.Len()
	for c := 0; c < n; c++ {
		row, err := enc.encodeRow(data.Index(c))

		if err != nil {
			return err
		}

		err = enc.Write(row)

		if err != nil {
			return err
		}
	}

	return nil
}

// encodes a struct into a CSV row
func (enc *encoder) encodeRow(v reflect.Value) ([]string, error) {

	var row []string
	// TODO env.columns should map to a cfield
	// iterate over each cfield and encode with it

	if v.Kind() == reflect.Interface {
		v = v.Elem()
	}
	l := v.Type().NumField()

	for x := 0; x < l; x++ {
		fv := v.Field(x)
		st := v.Type().Field(x).Tag

		if st.Get("csv") == "-" {
			continue
		}
		o := enc.encodeCol(fv, st)
		row = append(row, o)
	}

	return row, nil
}

// Returns the string representation of the field value
func (enc *encoder) encodeCol(fv reflect.Value, st reflect.StructTag) string {
	switch fv.Kind() {
	case reflect.String:
		return fv.String()
	case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int8:
		return fmt.Sprintf("%v", fv.Int())
	case reflect.Float32:
		return encodeFloat(32, fv)
	case reflect.Float64:
		return encodeFloat(64, fv)
	case reflect.Bool:
		return encodeBool(fv.Bool(), st)
	case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint8:
		return fmt.Sprintf("%v", fv.Uint())
	case reflect.Complex64, reflect.Complex128:
		return fmt.Sprintf("%+.3g", fv.Complex())
	case reflect.Interface:
		return encodeInterface(fv, st)
	case reflect.Struct:
		return encodeInterface(fv, st)
	default:
		panic(fmt.Sprintf("Unsupported type %s", fv.Kind()))
	}

	return ""
}

func encodeFloat(bits int, f reflect.Value) string {
	return strconv.FormatFloat(f.Float(), 'g', -1, bits)
}

func encodeBool(b bool, st reflect.StructTag) string {
	v := strconv.FormatBool(b)
	tv := st.Get(v)

	if tv != "" {
		return tv
	}
	return v
}

func encodeInterface(fv reflect.Value, st reflect.StructTag) string {
	marshalerType := reflect.TypeOf(new(Marshaler)).Elem()

	if fv.Type().Implements(marshalerType) {
		m := fv.Interface().(Marshaler)
		b, err := m.MarshalCSV()
		if err != nil {
			return ""
		}
		return string(b)
	}

	return ""
}
<|endoftext|>


<commit_before>package eda

import (
	"encoding/json"
	"errors"
	"sync"

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

// Encoders are the set of built-in data encMap.
var (
	encMux = &sync.Mutex{}

	encMap = map[string]Encoder{
		"bytes": &bytesEncoder{},
		"json":  &jsonEncoder{},
		"proto": &protoEncoder{},
		"nil":   &nilEncoder{},
	}
)

// Encoder is an interface for encoding and decoding native types
// into event data.
type Encoder interface {
	Encode(v interface{}) ([]byte, error)
	Decode(b []byte, v interface{}) error
}

// Bytes returns Data that encodes and decodes the raw bytes.
func Bytes(b []byte) Data {
	return &decodable{
		t:   "bytes",
		v:   b,
		enc: encMap["bytes"],
	}
}

// JSON returns Data that encodes and decodes the JSON-encodable value.
func JSON(v interface{}) Data {
	return &decodable{
		t:   "json",
		v:   v,
		enc: encMap["json"],
	}
}

// Proto returns Data that encodes and decodes the proto message.
func Proto(m proto.Message) Data {
	return &decodable{
		t:   "proto",
		v:   m,
		enc: encMap["proto"],
	}
}

type nilEncoder struct{}

func (n *nilEncoder) Type() string {
	return "nil"
}

func (n *nilEncoder) Encode(interface{}) ([]byte, error) {
	return nil, nil
}

func (n *nilEncoder) Decode([]byte, interface{}) error {
	return nil
}

type bytesEncoder struct{}

func (e *bytesEncoder) Encode(v interface{}) ([]byte, error) {
	if b, ok := v.([]byte); ok {
		return b, nil
	}

	return nil, errors.New("byte slice required")
}

func (e *bytesEncoder) Decode(b []byte, v interface{}) error {
	x, ok := v.(*[]byte)
	if !ok {
		return errors.New("pointer to []byte required")
	}
	*x = b
	return nil
}

type jsonEncoder struct{}

func (e *jsonEncoder) Encode(v interface{}) ([]byte, error) {
	return json.Marshal(v)
}

func (e *jsonEncoder) Decode(b []byte, v interface{}) error {
	return json.Unmarshal(b, v)
}

type protoEncoder struct{}

func (e *protoEncoder) Encode(v interface{}) ([]byte, error) {
	if m, ok := v.(proto.Message); ok {
		return proto.Marshal(m)
	}

	return nil, errors.New("proto message required")
}

func (e *protoEncoder) Decode(b []byte, v interface{}) error {
	x, ok := v.(proto.Message)
	if !ok {
		return errors.New("proto.Message required")
	}

	return proto.Unmarshal(b, x)
}

// Data encapsulates a value with a known encoding scheme.
type Data interface {
	// Type returns the encoding type used to encode the data to bytes.
	Type() string

	// Decodes the underlying bytes into the passed value pointer.
	Decode(v interface{}) error

	// Encode encodes the underlying type into bytes.
	Encode() ([]byte, error)
}

// decodable wraps the encoding and raw bytes.
type decodable struct {
	v   interface{}
	b   []byte
	t   string
	e   bool
	enc Encoder
}

func (r *decodable) Type() string {
	return r.t
}

// Encode "re-encodes" the bytes without copying.
func (r *decodable) Encode() ([]byte, error) {
	if r.e {
		return r.b, nil
	}

	if r.enc != nil {
		return r.enc.Encode(r.v)
	}

	return nil, errors.New("unknown encoding: " + r.t)
}

func (r *decodable) Decode(v interface{}) error {
	if r.e {
		if r.enc != nil {
			return r.enc.Decode(r.b, v)
		}

		return errors.New("unknown encoding: " + r.t)
	}

	return errors.New("cannot decode non-encoded data")
}
<commit_msg>Make Encoder a private interface<commit_after>package eda

import (
	"encoding/json"
	"errors"
	"sync"

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

// Encoders are the set of built-in data encMap.
var (
	encMux = &sync.Mutex{}

	encMap = map[string]encoder{
		"bytes": &bytesEncoder{},
		"json":  &jsonEncoder{},
		"proto": &protoEncoder{},
		"nil":   &nilEncoder{},
	}
)

// Encoder is an interface for encoding and decoding native types
// into event data.
type encoder interface {
	Encode(v interface{}) ([]byte, error)
	Decode(b []byte, v interface{}) error
}

// Bytes returns Data that encodes and decodes the raw bytes.
func Bytes(b []byte) Data {
	return &decodable{
		t:   "bytes",
		v:   b,
		enc: encMap["bytes"],
	}
}

// JSON returns Data that encodes and decodes the JSON-encodable value.
func JSON(v interface{}) Data {
	return &decodable{
		t:   "json",
		v:   v,
		enc: encMap["json"],
	}
}

// Proto returns Data that encodes and decodes the proto message.
func Proto(m proto.Message) Data {
	return &decodable{
		t:   "proto",
		v:   m,
		enc: encMap["proto"],
	}
}

type nilEncoder struct{}

func (n *nilEncoder) Type() string {
	return "nil"
}

func (n *nilEncoder) Encode(interface{}) ([]byte, error) {
	return nil, nil
}

func (n *nilEncoder) Decode([]byte, interface{}) error {
	return nil
}

type bytesEncoder struct{}

func (e *bytesEncoder) Encode(v interface{}) ([]byte, error) {
	if b, ok := v.([]byte); ok {
		return b, nil
	}

	return nil, errors.New("byte slice required")
}

func (e *bytesEncoder) Decode(b []byte, v interface{}) error {
	x, ok := v.(*[]byte)
	if !ok {
		return errors.New("pointer to []byte required")
	}
	*x = b
	return nil
}

type jsonEncoder struct{}

func (e *jsonEncoder) Encode(v interface{}) ([]byte, error) {
	return json.Marshal(v)
}

func (e *jsonEncoder) Decode(b []byte, v interface{}) error {
	return json.Unmarshal(b, v)
}

type protoEncoder struct{}

func (e *protoEncoder) Encode(v interface{}) ([]byte, error) {
	if m, ok := v.(proto.Message); ok {
		return proto.Marshal(m)
	}

	return nil, errors.New("proto message required")
}

func (e *protoEncoder) Decode(b []byte, v interface{}) error {
	x, ok := v.(proto.Message)
	if !ok {
		return errors.New("proto.Message required")
	}

	return proto.Unmarshal(b, x)
}

// Data encapsulates a value with a known encoding scheme.
type Data interface {
	// Type returns the encoding type used to encode the data to bytes.
	Type() string

	// Decodes the underlying bytes into the passed value pointer.
	Decode(v interface{}) error

	// Encode encodes the underlying type into bytes.
	Encode() ([]byte, error)
}

// decodable wraps the encoding and raw bytes.
type decodable struct {
	v   interface{}
	b   []byte
	t   string
	e   bool
	enc encoder
}

func (r *decodable) Type() string {
	return r.t
}

// Encode "re-encodes" the bytes without copying.
func (r *decodable) Encode() ([]byte, error) {
	if r.e {
		return r.b, nil
	}

	if r.enc != nil {
		return r.enc.Encode(r.v)
	}

	return nil, errors.New("unknown encoding: " + r.t)
}

func (r *decodable) Decode(v interface{}) error {
	if r.e {
		if r.enc != nil {
			return r.enc.Decode(r.b, v)
		}

		return errors.New("unknown encoding: " + r.t)
	}

	return errors.New("cannot decode non-encoded data")
}
<|endoftext|>


<commit_before>package runner

import (
	"os"
	"path/filepath"
	"sync"
)

const (
	STATUS_QUEUED      = "queued"
	STATUS_IN_PROGRESS = "in_progress"
	STATUS_FINISHED    = "finished"
)

func publishArtifacts(reporter *Reporter, cID string, artifacts []string) {
	if len(artifacts) == 0 {
		return
	}

	var matches []string
	for _, pattern := range artifacts {
		m, err := filepath.Glob(pattern)
		if err != nil {
			panic("Invalid artifact pattern" + err.Error())
		}
		matches = append(matches, m...)
	}

	reporter.PushArtifacts(cID, matches)
}

func RunAllCmds(reporter *Reporter, config *Config, result string, logsource *LogSource) {
	wg := sync.WaitGroup{}

	for _, cmd := range config.Cmds {
		reporter.PushStatus(cmd.Id, STATUS_IN_PROGRESS, -1)
		wc, err := NewWrappedScriptCommand(cmd.Script, cmd.Id)
		if err != nil {
			reporter.PushStatus(cmd.Id, STATUS_FINISHED, 255)
			result = "failed"
			break
		}

		env := os.Environ()
		for k, v := range cmd.Env {
			env = append(env, k+"="+v)
		}
		wc.Cmd.Env = env

		if len(cmd.Cwd) > 0 {
			wc.Cmd.Dir = cmd.Cwd
		}

		wg.Add(1)
		go func() {
			logsource.reportChunks(wc.ChunkChan)
			wg.Done()
		}()

		pState, err := wc.Run()
		if err != nil {
			reporter.PushStatus(cmd.Id, STATUS_FINISHED, 255)
			result = "failed"
			break
		} else {
			if pState.Success() {
				reporter.PushStatus(cmd.Id, STATUS_FINISHED, 0)
			} else {
				reporter.PushStatus(cmd.Id, STATUS_FINISHED, 1)
				result = "failed"
				break
			}
		}

		wg.Add(1)
		go func(artifacts []string) {
			publishArtifacts(reporter, config.JobstepID, artifacts)
			wg.Done()
		}(cmd.Artifacts)
	}

	wg.Wait()
}

func RunBuildPlan(reporter *Reporter, config *Config) {
	result := "passed"

	logsource := &LogSource{
		Name:      "console",
		JobstepID: config.JobstepID,
		Reporter:  reporter,
	}

	reporter.PushJobStatus(config.JobstepID, STATUS_IN_PROGRESS, "")

	RunAllCmds(reporter, config, result, logsource)

	reporter.PushJobStatus(config.JobstepID, STATUS_FINISHED, result)
}
<commit_msg>Correctly propagate result<commit_after>package runner

import (
	"os"
	"path/filepath"
	"sync"
)

const (
	STATUS_QUEUED      = "queued"
	STATUS_IN_PROGRESS = "in_progress"
	STATUS_FINISHED    = "finished"
)

func publishArtifacts(reporter *Reporter, cID string, artifacts []string) {
	if len(artifacts) == 0 {
		return
	}

	var matches []string
	for _, pattern := range artifacts {
		m, err := filepath.Glob(pattern)
		if err != nil {
			panic("Invalid artifact pattern" + err.Error())
		}
		matches = append(matches, m...)
	}

	reporter.PushArtifacts(cID, matches)
}

func RunAllCmds(reporter *Reporter, config *Config, logsource *LogSource) string {
	result := "passed"

	wg := sync.WaitGroup{}

	for _, cmd := range config.Cmds {
		reporter.PushStatus(cmd.Id, STATUS_IN_PROGRESS, -1)
		wc, err := NewWrappedScriptCommand(cmd.Script, cmd.Id)
		if err != nil {
			reporter.PushStatus(cmd.Id, STATUS_FINISHED, 255)
			result = "failed"
			break
		}

		env := os.Environ()
		for k, v := range cmd.Env {
			env = append(env, k+"="+v)
		}
		wc.Cmd.Env = env

		if len(cmd.Cwd) > 0 {
			wc.Cmd.Dir = cmd.Cwd
		}

		wg.Add(1)
		go func() {
			logsource.reportChunks(wc.ChunkChan)
			wg.Done()
		}()

		pState, err := wc.Run()
		if err != nil {
			reporter.PushStatus(cmd.Id, STATUS_FINISHED, 255)
			result = "failed"
			break
		} else {
			if pState.Success() {
				reporter.PushStatus(cmd.Id, STATUS_FINISHED, 0)
			} else {
				reporter.PushStatus(cmd.Id, STATUS_FINISHED, 1)
				result = "failed"
				break
			}
		}

		wg.Add(1)
		go func(artifacts []string) {
			publishArtifacts(reporter, config.JobstepID, artifacts)
			wg.Done()
		}(cmd.Artifacts)
	}

	wg.Wait()

	return result
}

func RunBuildPlan(reporter *Reporter, config *Config) {
	logsource := &LogSource{
		Name:      "console",
		JobstepID: config.JobstepID,
		Reporter:  reporter,
	}

	reporter.PushJobStatus(config.JobstepID, STATUS_IN_PROGRESS, "")

	result := RunAllCmds(reporter, config, logsource)

	reporter.PushJobStatus(config.JobstepID, STATUS_FINISHED, result)
}
<|endoftext|>


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

// Package main is the main entry point for the app.
package main

import (
	"context"
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"

	"go.chromium.org/luci/common/data/rand/mathrand"
	"go.chromium.org/luci/common/logging"
	"go.chromium.org/luci/common/proto/access"
	"go.chromium.org/luci/grpc/prpc"
	"go.chromium.org/luci/server"
	"go.chromium.org/luci/server/gaeemulation"
	"go.chromium.org/luci/server/module"
	"go.chromium.org/luci/server/router"
	"go.chromium.org/luci/server/tq"

	// Enable datastore transactional tasks support.
	_ "go.chromium.org/luci/server/tq/txn/datastore"

	"go.chromium.org/luci/buildbucket/appengine/rpc"
	pb "go.chromium.org/luci/buildbucket/proto"
)

// isBeefy returns whether the request was intended for the beefy service.
func isBeefy(req *http.Request) bool {
	return strings.Contains(req.Host, "beefy")
}

// isDev returns whether the request was intended for the dev instance.
func isDev(req *http.Request) bool {
	return strings.HasSuffix(req.Host, "-dev.appspot.com")
}

func main() {
	mods := []module.Module{
		gaeemulation.NewModuleFromFlags(),
		tq.NewModuleFromFlags(),
	}

	server.Main(nil, mods, func(srv *server.Server) error {
		// Proxy buildbucket.v2.Builds pRPC requests back to the Python
		// service in order to achieve a programmatic traffic split.
		// Because of the way dispatch routes work, requests are proxied
		// to a copy of the Python service hosted at a different path.
		// TODO(crbug/1042991): Remove the proxy once the go service handles all traffic.
		pythonURL, err := url.Parse(fmt.Sprintf("https://default-dot-%s.appspot.com/python", srv.Options.CloudProject))
		if err != nil {
			panic(err)
		}
		beefyURL, err := url.Parse(fmt.Sprintf("https://beefy-dot-%s.appspot.com/python", srv.Options.CloudProject))
		if err != nil {
			panic(err)
		}
		prx := httputil.NewSingleHostReverseProxy(pythonURL)
		prx.Director = func(req *http.Request) {
			target := pythonURL
			if isBeefy(req) {
				target = beefyURL
			}
			// According to net.Request documentation, setting Host is unnecessary
			// because URL.Host is supposed to be used for outbound requests.
			// However, on GAE, it seems that req.Host is incorrectly used.
			req.Host = target.Host
			req.URL.Scheme = target.Scheme
			req.URL.Host = target.Host
			req.URL.Path = fmt.Sprintf("%s%s", target.Path, req.URL.Path)
		}
		// makeOverride returns a prpc.Override which allows the given percentage of requests
		// through to this service, proxying the remainder to Python.
		makeOverride := func(prodPct, devPct int) func(*router.Context) bool {
			return func(ctx *router.Context) bool {
				// TODO(crbug/1090540): remove env k-v
				ctx.Context = context.WithValue(ctx.Context, "env", "Prod")
				pct := prodPct
				if isDev(ctx.Request) {
					pct = devPct
					// TODO(crbug/1090540): remove env k-v
					ctx.Context = context.WithValue(ctx.Context, "env", "Dev")
				}
				switch val := ctx.Request.Header.Get("Should-Proxy"); val {
				case "true":
					pct = 0
					logging.Debugf(ctx.Context, "request demanded to be proxied")
				case "false":
					pct = 100
					logging.Debugf(ctx.Context, "request demanded not to be proxied")
				}
				if mathrand.Intn(ctx.Context, 100) < pct {
					return false
				}
				target := pythonURL
				if isBeefy(ctx.Request) {
					target = beefyURL
				}
				logging.Debugf(ctx.Context, "proxying request to %s", target)
				prx.ServeHTTP(ctx.Writer, ctx.Request)
				return true
			}
		}

		srv.PRPC.AccessControl = prpc.AllowOriginAll
		access.RegisterAccessServer(srv.PRPC, &access.UnimplementedAccessServer{})
		pb.RegisterBuildsServer(srv.PRPC, rpc.NewBuilds())
		pb.RegisterBuildersServer(srv.PRPC, rpc.NewBuilders())
		// TODO(crbug/1082369): Remove this workaround once field masks can be decoded.
		srv.PRPC.HackFixFieldMasksForJSON = true

		// makeOverride(prod % -> Go, dev % -> Go).
		srv.PRPC.RegisterOverride("buildbucket.v2.Builds", "Batch", makeOverride(100, 100))
		srv.PRPC.RegisterOverride("buildbucket.v2.Builds", "CancelBuild", makeOverride(0, 0))
		srv.PRPC.RegisterOverride("buildbucket.v2.Builds", "ScheduleBuild", makeOverride(0, 0))
		srv.PRPC.RegisterOverride("buildbucket.v2.Builds", "UpdateBuild", makeOverride(0, 100))
		return nil
	})
}
<commit_msg>[buildbucket] bump up % of UpdateBuild by Go to 5<commit_after>// Copyright 2020 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package main is the main entry point for the app.
package main

import (
	"context"
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"

	"go.chromium.org/luci/common/data/rand/mathrand"
	"go.chromium.org/luci/common/logging"
	"go.chromium.org/luci/common/proto/access"
	"go.chromium.org/luci/grpc/prpc"
	"go.chromium.org/luci/server"
	"go.chromium.org/luci/server/gaeemulation"
	"go.chromium.org/luci/server/module"
	"go.chromium.org/luci/server/router"
	"go.chromium.org/luci/server/tq"

	// Enable datastore transactional tasks support.
	_ "go.chromium.org/luci/server/tq/txn/datastore"

	"go.chromium.org/luci/buildbucket/appengine/rpc"
	pb "go.chromium.org/luci/buildbucket/proto"
)

// isBeefy returns whether the request was intended for the beefy service.
func isBeefy(req *http.Request) bool {
	return strings.Contains(req.Host, "beefy")
}

// isDev returns whether the request was intended for the dev instance.
func isDev(req *http.Request) bool {
	return strings.HasSuffix(req.Host, "-dev.appspot.com")
}

func main() {
	mods := []module.Module{
		gaeemulation.NewModuleFromFlags(),
		tq.NewModuleFromFlags(),
	}

	server.Main(nil, mods, func(srv *server.Server) error {
		// Proxy buildbucket.v2.Builds pRPC requests back to the Python
		// service in order to achieve a programmatic traffic split.
		// Because of the way dispatch routes work, requests are proxied
		// to a copy of the Python service hosted at a different path.
		// TODO(crbug/1042991): Remove the proxy once the go service handles all traffic.
		pythonURL, err := url.Parse(fmt.Sprintf("https://default-dot-%s.appspot.com/python", srv.Options.CloudProject))
		if err != nil {
			panic(err)
		}
		beefyURL, err := url.Parse(fmt.Sprintf("https://beefy-dot-%s.appspot.com/python", srv.Options.CloudProject))
		if err != nil {
			panic(err)
		}
		prx := httputil.NewSingleHostReverseProxy(pythonURL)
		prx.Director = func(req *http.Request) {
			target := pythonURL
			if isBeefy(req) {
				target = beefyURL
			}
			// According to net.Request documentation, setting Host is unnecessary
			// because URL.Host is supposed to be used for outbound requests.
			// However, on GAE, it seems that req.Host is incorrectly used.
			req.Host = target.Host
			req.URL.Scheme = target.Scheme
			req.URL.Host = target.Host
			req.URL.Path = fmt.Sprintf("%s%s", target.Path, req.URL.Path)
		}
		// makeOverride returns a prpc.Override which allows the given percentage of requests
		// through to this service, proxying the remainder to Python.
		makeOverride := func(prodPct, devPct int) func(*router.Context) bool {
			return func(ctx *router.Context) bool {
				// TODO(crbug/1090540): remove env k-v
				ctx.Context = context.WithValue(ctx.Context, "env", "Prod")
				pct := prodPct
				if isDev(ctx.Request) {
					pct = devPct
					// TODO(crbug/1090540): remove env k-v
					ctx.Context = context.WithValue(ctx.Context, "env", "Dev")
				}
				switch val := ctx.Request.Header.Get("Should-Proxy"); val {
				case "true":
					pct = 0
					logging.Debugf(ctx.Context, "request demanded to be proxied")
				case "false":
					pct = 100
					logging.Debugf(ctx.Context, "request demanded not to be proxied")
				}
				if mathrand.Intn(ctx.Context, 100) < pct {
					return false
				}
				target := pythonURL
				if isBeefy(ctx.Request) {
					target = beefyURL
				}
				logging.Debugf(ctx.Context, "proxying request to %s", target)
				prx.ServeHTTP(ctx.Writer, ctx.Request)
				return true
			}
		}

		srv.PRPC.AccessControl = prpc.AllowOriginAll
		access.RegisterAccessServer(srv.PRPC, &access.UnimplementedAccessServer{})
		pb.RegisterBuildsServer(srv.PRPC, rpc.NewBuilds())
		pb.RegisterBuildersServer(srv.PRPC, rpc.NewBuilders())
		// TODO(crbug/1082369): Remove this workaround once field masks can be decoded.
		srv.PRPC.HackFixFieldMasksForJSON = true

		// makeOverride(prod % -> Go, dev % -> Go).
		srv.PRPC.RegisterOverride("buildbucket.v2.Builds", "Batch", makeOverride(100, 100))
		srv.PRPC.RegisterOverride("buildbucket.v2.Builds", "CancelBuild", makeOverride(0, 0))
		srv.PRPC.RegisterOverride("buildbucket.v2.Builds", "ScheduleBuild", makeOverride(0, 0))
		srv.PRPC.RegisterOverride("buildbucket.v2.Builds", "UpdateBuild", makeOverride(5, 100))
		return nil
	})
}
<|endoftext|>


<commit_before>package dynago

import (
	"fmt"
	"net/http"
	"strings"
)

// Encapsulates errors coming from amazon/dynamodb
type Error struct {
	Type          AmazonError    // Parsed and mapped down type
	AmazonRawType string         // Raw error type from amazon
	Exception     string         // Exception from amazon
	Message       string         // Raw message from amazon
	Response      *http.Response // If available, HTTP response
	ResponseBody  []byte         // If available, raw response body bytes
}

func (e *Error) Error() string {
	exception := e.Exception
	if exception == "" {
		exception = e.AmazonRawType
	}
	return fmt.Sprintf("dynago.Error(%d): %s: %s", e.Type, exception, e.Message)
}

// Parse and create the error
func (e *Error) parse(input *inputError) {
	e.AmazonRawType = input.AmazonRawType
	e.Message = input.Message
	parts := strings.Split(e.AmazonRawType, "#")
	if len(parts) >= 2 {
		e.Exception = parts[1]
		if conf, ok := amazonErrorMap[e.Exception]; ok {
			e.Type = conf.mappedError
		}
	}
}

type inputError struct {
	AmazonRawType string `json:"__type"`
	Message       string `json:"message"`
}

type AmazonError int

const (
	ErrorUnknown AmazonError = iota

	ErrorConditionFailed        // When a conditional put/update fails due to condition not being met
	ErrorCollectionSizeExceeded // Item collection (local secondary index) too large
	ErrorThroughputExceeded     // We exceeded our provisioned throughput for this table or shard
	ErrorNotFound               // Resource referenced by key not found
	ErrorInternalFailure        // Internal server error
	ErrorAuth                   // Encapsulates various authorization errors
	ErrorInvalidParameter       // Encapsulates many forms of invalid input errors
	ErrorServiceUnavailable     // Amazon service unavailable
	ErrorThrottling             // Amazon is throttling us, try later
	ErrorResourceInUse          // Tried to create a table already created, delete a table in CREATING state, etc.
)

type amazonErrorConfig struct {
	amazonCode     string
	expectedStatus int
	mappedError    AmazonError
}

// This variable is mostly exposed so that we can document how errors are mapped
var AmazonErrors = []amazonErrorConfig{
	{"ConditionalCheckFailedException", 400, ErrorConditionFailed},
	{"ResourceNotFoundException", 400, ErrorNotFound},
	{"InternalFailure", 500, ErrorInternalFailure},
	{"InternalServerError", 500, ErrorInternalFailure},
	{"IncompleteSignature", 400, ErrorAuth},
	{"InvalidParameterCombination", 400, ErrorInvalidParameter},
	{"InvalidParameterValue", 400, ErrorInvalidParameter},
	{"InvalidQueryParameter", 400, ErrorInvalidParameter},
	{"ItemCollectionSizeLimitExceededException", 400, ErrorCollectionSizeExceeded},
	{"MalformedQueryString", 404, ErrorInvalidParameter},
	{"MissingAction", 400, ErrorInvalidParameter},
	{"MissingAuthenticationToken", 403, ErrorAuth},
	{"MissingParameter", 400, ErrorInvalidParameter},
	{"OptInRequired", 403, ErrorAuth},
	{"ProvisionedThroughputExceededException", 400, ErrorThroughputExceeded},
	{"RequestExpired", 400, ErrorAuth},
	{"ResourceInUseException", 400, ErrorResourceInUse},
	{"ServiceUnavailable", 503, ErrorServiceUnavailable},
	{"ValidationError", 400, ErrorInvalidParameter},
}

var amazonErrorMap map[string]*amazonErrorConfig

func init() {
	amazonErrorMap = make(map[string]*amazonErrorConfig, len(AmazonErrors))
	for i, conf := range AmazonErrors {
		amazonErrorMap[conf.amazonCode] = &AmazonErrors[i]
	}
}
<commit_msg>Add support for ValidationException<commit_after>package dynago

import (
	"fmt"
	"net/http"
	"strings"
)

// Encapsulates errors coming from amazon/dynamodb
type Error struct {
	Type          AmazonError    // Parsed and mapped down type
	AmazonRawType string         // Raw error type from amazon
	Exception     string         // Exception from amazon
	Message       string         // Raw message from amazon
	Response      *http.Response // If available, HTTP response
	ResponseBody  []byte         // If available, raw response body bytes
}

func (e *Error) Error() string {
	exception := e.Exception
	if exception == "" {
		exception = e.AmazonRawType
	}
	return fmt.Sprintf("dynago.Error(%d): %s: %s", e.Type, exception, e.Message)
}

// Parse and create the error
func (e *Error) parse(input *inputError) {
	e.AmazonRawType = input.AmazonRawType
	e.Message = input.Message
	parts := strings.Split(e.AmazonRawType, "#")
	if len(parts) >= 2 {
		e.Exception = parts[1]
		if conf, ok := amazonErrorMap[e.Exception]; ok {
			e.Type = conf.mappedError
		}
	}
}

type inputError struct {
	AmazonRawType string `json:"__type"`
	Message       string `json:"message"`
}

type AmazonError int

const (
	ErrorUnknown AmazonError = iota

	ErrorConditionFailed        // When a conditional put/update fails due to condition not being met
	ErrorCollectionSizeExceeded // Item collection (local secondary index) too large
	ErrorThroughputExceeded     // We exceeded our provisioned throughput for this table or shard
	ErrorNotFound               // Resource referenced by key not found
	ErrorInternalFailure        // Internal server error
	ErrorAuth                   // Encapsulates various authorization errors
	ErrorInvalidParameter       // Encapsulates many forms of invalid input errors
	ErrorServiceUnavailable     // Amazon service unavailable
	ErrorThrottling             // Amazon is throttling us, try later
	ErrorResourceInUse          // Tried to create a table already created, delete a table in CREATING state, etc.
)

type amazonErrorConfig struct {
	amazonCode     string
	expectedStatus int
	mappedError    AmazonError
}

// This variable is mostly exposed so that we can document how errors are mapped
var AmazonErrors = []amazonErrorConfig{
	{"ConditionalCheckFailedException", 400, ErrorConditionFailed},
	{"ResourceNotFoundException", 400, ErrorNotFound},
	{"InternalFailure", 500, ErrorInternalFailure},
	{"InternalServerError", 500, ErrorInternalFailure},
	{"IncompleteSignature", 400, ErrorAuth},
	{"InvalidParameterCombination", 400, ErrorInvalidParameter},
	{"InvalidParameterValue", 400, ErrorInvalidParameter},
	{"InvalidQueryParameter", 400, ErrorInvalidParameter},
	{"ItemCollectionSizeLimitExceededException", 400, ErrorCollectionSizeExceeded},
	{"MalformedQueryString", 404, ErrorInvalidParameter},
	{"MissingAction", 400, ErrorInvalidParameter},
	{"MissingAuthenticationToken", 403, ErrorAuth},
	{"MissingParameter", 400, ErrorInvalidParameter},
	{"OptInRequired", 403, ErrorAuth},
	{"ProvisionedThroughputExceededException", 400, ErrorThroughputExceeded},
	{"RequestExpired", 400, ErrorAuth},
	{"ResourceInUseException", 400, ErrorResourceInUse},
	{"ServiceUnavailable", 503, ErrorServiceUnavailable},
	{"ValidationError", 400, ErrorInvalidParameter},
	{"ValidationException", 400, ErrorInvalidParameter},
}

var amazonErrorMap map[string]*amazonErrorConfig

func init() {
	amazonErrorMap = make(map[string]*amazonErrorConfig, len(AmazonErrors))
	for i, conf := range AmazonErrors {
		amazonErrorMap[conf.amazonCode] = &AmazonErrors[i]
	}
}
<|endoftext|>


<commit_before>package arangolite

type errUnique interface {
	error
	IsErrUnique()
}

type errUniqueBehavior struct{}

func (err errUniqueBehavior) IsErrUnique() {}

func withErrUnique(err error) error {
	return struct {
		error
		errUniqueBehavior
	}{
		err,
		errUniqueBehavior{},
	}
}

// IsErrUnique returns true when error message contains "unique constraint violated" string.
func IsErrUnique(err error) bool {
	_, ok := err.(errUniqueBehavior)
	return ok
}

type errNotFound interface {
	error
	IsErrNotFound()
}

type errNotFoundBehavior struct{}

func (err errNotFound) IsErrNotFound() {}

func withErrNotFound(err error) error {
	return struct {
		error
		errNotFoundBehavior
	}{
		err,
		errNotFoundBehavior{},
	}
}

// IsErrNotFound returns true when error message contains "not found" or "unknown collection" string.
func IsErrNotFound(err error) bool {
	_, ok := err.(errNotFoundBehavior)
	return ok
}

type errDuplicate interface {
	error
	IsErrDuplicate()
}

type errDuplicateBehavior struct{}

func (err errDuplicate) IsErrDuplicate() {}

func withErrDuplicate(err error) error {
	return struct {
		error
		errDuplicateBehavior
	}{
		err,
		errDuplicateBehavior{},
	}
}

// IsErrDuplicate returns true when error message contains "duplicate name" string.
func IsErrDuplicate(err error) bool {
	_, ok := err.(errDuplicateBehavior)
	return ok
}
<commit_msg>Errors refactored<commit_after>package arangolite

type errUniqueBehavior interface {
	error
	IsErrUnique()
}

type errUnique struct{ error }

func (err errUnique) IsErrUnique() {}

func withErrUnique(err error) error {
	return errUnique{err}
}

// IsErrUnique returns true when error message contains "unique constraint violated" string.
func IsErrUnique(err error) bool {
	_, ok := err.(errUniqueBehavior)
	return ok
}

type errNotFoundBehavior interface {
	error
	IsErrNotFound()
}

type errNotFound struct{ error }

func (err errNotFound) IsErrNotFound() {}

func withErrNotFound(err error) error {
	return errNotFound{err}
}

// IsErrNotFound returns true when error message contains "not found" or "unknown collection" string.
func IsErrNotFound(err error) bool {
	_, ok := err.(errNotFoundBehavior)
	return ok
}

type errDuplicateBehavior interface {
	error
	IsErrDuplicate()
}

type errDuplicate struct{ error }

func (err errDuplicate) IsErrDuplicate() {}

func withErrDuplicate(err error) error {
	return errDuplicate{err}
}

// IsErrDuplicate returns true when error message contains "duplicate name" string.
func IsErrDuplicate(err error) bool {
	_, ok := err.(errDuplicateBehavior)
	return ok
}
<|endoftext|>


<commit_before>package main

import (
	"strings"
)

type (
	RetryableError interface {
		Retryable() bool
	}
)

type (
	InvalidJobError struct {
		msg string
	}
)

func (e InvalidJobError) Error() string {
	return e.msg
}

func (e InvalidJobError) Retryable() bool {
	return false
}

type (
	CompositeError struct {
		errors []error
	}
)

func (e *CompositeError) Error() string {
	msgs := []string{}
	for _, err := range e.errors {
		msgs = append(msgs, err.Error())
	}
	return strings.Join(msgs, "\n")
}

func (e CompositeError) Retryable() bool {
	for _, err := range e.errors {
		switch err.(type) {
		case RetryableError:
			e := err.(RetryableError)
			if !e.Retryable() {
				return false
			}
		}
	}
	return true
}
<commit_msg>:bug: Fix the method definitions<commit_after>package main

import (
	"strings"
)

type (
	RetryableError interface {
		Retryable() bool
	}
)

type (
	InvalidJobError struct {
		msg string
	}
)

func (e *InvalidJobError) Error() string {
	return e.msg
}

func (e *InvalidJobError) Retryable() bool {
	return false
}

type (
	CompositeError struct {
		errors []error
	}
)

func (e *CompositeError) Error() string {
	msgs := []string{}
	for _, err := range e.errors {
		msgs = append(msgs, err.Error())
	}
	return strings.Join(msgs, "\n")
}

func (e *CompositeError) Retryable() bool {
	for _, err := range e.errors {
		switch err.(type) {
		case RetryableError:
			e := err.(RetryableError)
			if !e.Retryable() {
				return false
			}
		}
	}
	return true
}

func (e *CompositeError) Any(f func(error) bool) bool {
	for _, err := range e.errors {
		if f(err) {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>// Copyright 2014 The gocui 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 gocui

import (
	"errors"
	"strconv"
)

type escapeInterpreter struct {
	state                          escapeState
	curch                          rune
	csiParam                       []string
	curFgColor, curBgColor         Attribute
	defaultFgColor, defaultBgColor Attribute
}

type escapeState int

const (
	stateNone escapeState = iota
	stateEscape
	stateCSI
	stateParams
)

var (
	errNotCSI        = errors.New("Not a CSI escape sequence")
	errCSINotANumber = errors.New("CSI escape sequence was expecting a number or a ;")
	errCSIParseError = errors.New("CSI escape sequence parsing error")
	errCSITooLong    = errors.New("CSI escape sequence is too long")
)

// runes in case of error will output the non-parsed runes as a string.
func (ei *escapeInterpreter) runes() []rune {
	switch ei.state {
	case stateNone:
		return []rune{0x1b}
	case stateEscape:
		return []rune{0x1b, ei.curch}
	case stateCSI:
		return []rune{0x1b, '[', ei.curch}
	case stateParams:
		ret := []rune{0x1b, '['}
		for _, s := range ei.csiParam {
			ret = append(ret, []rune(s)...)
			ret = append(ret, ';')
		}
		return append(ret, ei.curch)
	}
	return nil
}

// newEscapeInterpreter returns an escapeInterpreter that will be able to parse
// terminal escape sequences.
func newEscapeInterpreter() *escapeInterpreter {
	ei := &escapeInterpreter{
		defaultFgColor: ColorWhite,
		defaultBgColor: ColorBlack,
		state:          stateNone,
		curFgColor:     ColorWhite,
		curBgColor:     ColorBlack,
	}
	return ei
}

// reset sets the escapeInterpreter in inital state.
func (ei *escapeInterpreter) reset() {
	ei.state = stateNone
	ei.curFgColor = ei.defaultFgColor
	ei.curBgColor = ei.defaultBgColor
	ei.csiParam = nil
}

// paramToColor returns an attribute given a terminfo coloring.
func paramToColor(p int) Attribute {
	switch p {
	case 0:
		return ColorBlack
	case 1:
		return ColorRed
	case 2:
		return ColorGreen
	case 3:
		return ColorYellow
	case 4:
		return ColorBlue
	case 5:
		return ColorMagenta
	case 6:
		return ColorCyan
	case 7:
		return ColorWhite
	}
	return ColorDefault
}

// parseOne parses a rune. If isEscape is true, it means that the rune is part
// of an scape sequence, and as such should not be printed verbatim. Otherwise,
// it's not an escape sequence.
func (ei *escapeInterpreter) parseOne(ch rune) (isEscape bool, err error) {
	// Sanity checks to make sure we're not parsing something totally bogus.
	if len(ei.csiParam) > 20 {
		return false, errCSITooLong
	}
	if len(ei.csiParam) > 0 && len(ei.csiParam[len(ei.csiParam)-1]) > 255 {
		return false, errCSITooLong
	}
	ei.curch = ch
	switch ei.state {
	case stateNone:
		if ch == 0x1b {
			ei.state = stateEscape
			return true, nil
		}
		return false, nil
	case stateEscape:
		if ch == '[' {
			ei.state = stateCSI
			return true, nil
		}
		return false, errNotCSI
	case stateCSI:
		if ch >= '0' && ch <= '9' {
			ei.state = stateParams
			ei.csiParam = append(ei.csiParam, string(ch))
			return true, nil
		}
		return false, errCSINotANumber
	case stateParams:
		switch {
		case ch >= '0' && ch <= '9':
			ei.csiParam[len(ei.csiParam)-1] += string(ch)
			return true, nil
		case ch == ';':
			ei.csiParam = append(ei.csiParam, "")
			return true, nil
		case ch == 'm':
			if len(ei.csiParam) < 1 {
				return false, errCSIParseError
			}
			for _, param := range ei.csiParam {
				p, err := strconv.Atoi(param)
				if err != nil {
					return false, errCSIParseError
				}
				switch {
				case p >= 30 && p <= 37:
					ei.curFgColor = paramToColor(p - 30)
				case p >= 40 && p <= 47:
					ei.curBgColor = paramToColor(p - 40)
				case p == 1:
					ei.curFgColor |= AttrBold
				case p == 4:
					ei.curFgColor |= AttrUnderline
				case p == 7:
					ei.curFgColor |= AttrReverse
				case p == 0 || p == 39:
					ei.curFgColor = ei.defaultFgColor
					ei.curBgColor = ei.defaultBgColor
				}
			}
			ei.state = stateNone
			ei.csiParam = nil
			return true, nil
		}
	}
	return false, nil
}
<commit_msg>Fix minor typo<commit_after>// Copyright 2014 The gocui 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 gocui

import (
	"errors"
	"strconv"
)

type escapeInterpreter struct {
	state                          escapeState
	curch                          rune
	csiParam                       []string
	curFgColor, curBgColor         Attribute
	defaultFgColor, defaultBgColor Attribute
}

type escapeState int

const (
	stateNone escapeState = iota
	stateEscape
	stateCSI
	stateParams
)

var (
	errNotCSI        = errors.New("Not a CSI escape sequence")
	errCSINotANumber = errors.New("CSI escape sequence was expecting a number or a ;")
	errCSIParseError = errors.New("CSI escape sequence parsing error")
	errCSITooLong    = errors.New("CSI escape sequence is too long")
)

// runes in case of error will output the non-parsed runes as a string.
func (ei *escapeInterpreter) runes() []rune {
	switch ei.state {
	case stateNone:
		return []rune{0x1b}
	case stateEscape:
		return []rune{0x1b, ei.curch}
	case stateCSI:
		return []rune{0x1b, '[', ei.curch}
	case stateParams:
		ret := []rune{0x1b, '['}
		for _, s := range ei.csiParam {
			ret = append(ret, []rune(s)...)
			ret = append(ret, ';')
		}
		return append(ret, ei.curch)
	}
	return nil
}

// newEscapeInterpreter returns an escapeInterpreter that will be able to parse
// terminal escape sequences.
func newEscapeInterpreter() *escapeInterpreter {
	ei := &escapeInterpreter{
		defaultFgColor: ColorWhite,
		defaultBgColor: ColorBlack,
		state:          stateNone,
		curFgColor:     ColorWhite,
		curBgColor:     ColorBlack,
	}
	return ei
}

// reset sets the escapeInterpreter in inital state.
func (ei *escapeInterpreter) reset() {
	ei.state = stateNone
	ei.curFgColor = ei.defaultFgColor
	ei.curBgColor = ei.defaultBgColor
	ei.csiParam = nil
}

// paramToColor returns an attribute given a terminfo coloring.
func paramToColor(p int) Attribute {
	switch p {
	case 0:
		return ColorBlack
	case 1:
		return ColorRed
	case 2:
		return ColorGreen
	case 3:
		return ColorYellow
	case 4:
		return ColorBlue
	case 5:
		return ColorMagenta
	case 6:
		return ColorCyan
	case 7:
		return ColorWhite
	}
	return ColorDefault
}

// parseOne parses a rune. If isEscape is true, it means that the rune is part
// of an escape sequence, and as such should not be printed verbatim. Otherwise,
// it's not an escape sequence.
func (ei *escapeInterpreter) parseOne(ch rune) (isEscape bool, err error) {
	// Sanity checks to make sure we're not parsing something totally bogus.
	if len(ei.csiParam) > 20 {
		return false, errCSITooLong
	}
	if len(ei.csiParam) > 0 && len(ei.csiParam[len(ei.csiParam)-1]) > 255 {
		return false, errCSITooLong
	}
	ei.curch = ch
	switch ei.state {
	case stateNone:
		if ch == 0x1b {
			ei.state = stateEscape
			return true, nil
		}
		return false, nil
	case stateEscape:
		if ch == '[' {
			ei.state = stateCSI
			return true, nil
		}
		return false, errNotCSI
	case stateCSI:
		if ch >= '0' && ch <= '9' {
			ei.state = stateParams
			ei.csiParam = append(ei.csiParam, string(ch))
			return true, nil
		}
		return false, errCSINotANumber
	case stateParams:
		switch {
		case ch >= '0' && ch <= '9':
			ei.csiParam[len(ei.csiParam)-1] += string(ch)
			return true, nil
		case ch == ';':
			ei.csiParam = append(ei.csiParam, "")
			return true, nil
		case ch == 'm':
			if len(ei.csiParam) < 1 {
				return false, errCSIParseError
			}
			for _, param := range ei.csiParam {
				p, err := strconv.Atoi(param)
				if err != nil {
					return false, errCSIParseError
				}
				switch {
				case p >= 30 && p <= 37:
					ei.curFgColor = paramToColor(p - 30)
				case p >= 40 && p <= 47:
					ei.curBgColor = paramToColor(p - 40)
				case p == 1:
					ei.curFgColor |= AttrBold
				case p == 4:
					ei.curFgColor |= AttrUnderline
				case p == 7:
					ei.curFgColor |= AttrReverse
				case p == 0 || p == 39:
					ei.curFgColor = ei.defaultFgColor
					ei.curBgColor = ei.defaultBgColor
				}
			}
			ei.state = stateNone
			ei.csiParam = nil
			return true, nil
		}
	}
	return false, nil
}
<|endoftext|>