<commit_before>package maxminddb

import (
	"bytes"
	"errors"
	"fmt"
	"net"
	"reflect"
)

const (
	// NotFound is returned by LookupOffset when a matched root record offset
	// cannot be found.
	NotFound = ^uintptr(0)

	dataSectionSeparatorSize = 16
)

var metadataStartMarker = []byte("\xAB\xCD\xEFMaxMind.com")

// Reader holds the data corresponding to the MaxMind DB file. Its only public
// field is Metadata, which contains the metadata from the MaxMind DB file.
type Reader struct {
	hasMappedFile     bool
	buffer            []byte
	decoder           decoder
	Metadata          Metadata
	ipv4Start         uint
	ipv4StartBitDepth int
}

// Metadata holds the metadata decoded from the MaxMind DB file. In particular
// in has the format version, the build time as Unix epoch time, the database
// type and description, the IP version supported, and a slice of the natural
// languages included.
type Metadata struct {
	BinaryFormatMajorVersion uint              `maxminddb:"binary_format_major_version"`
	BinaryFormatMinorVersion uint              `maxminddb:"binary_format_minor_version"`
	BuildEpoch               uint              `maxminddb:"build_epoch"`
	DatabaseType             string            `maxminddb:"database_type"`
	Description              map[string]string `maxminddb:"description"`
	IPVersion                uint              `maxminddb:"ip_version"`
	Languages                []string          `maxminddb:"languages"`
	NodeCount                uint              `maxminddb:"node_count"`
	RecordSize               uint              `maxminddb:"record_size"`
}

// FromBytes takes a byte slice corresponding to a MaxMind DB file and returns
// a Reader structure or an error.
func FromBytes(buffer []byte) (*Reader, error) {
	metadataStart := bytes.LastIndex(buffer, metadataStartMarker)

	if metadataStart == -1 {
		return nil, newInvalidDatabaseError("error opening database: invalid MaxMind DB file")
	}

	metadataStart += len(metadataStartMarker)
	metadataDecoder := decoder{buffer[metadataStart:]}

	var metadata Metadata

	rvMetdata := reflect.ValueOf(&metadata)
	_, err := metadataDecoder.decode(0, rvMetdata, 0)
	if err != nil {
		return nil, err
	}

	searchTreeSize := metadata.NodeCount * metadata.RecordSize / 4
	dataSectionStart := searchTreeSize + dataSectionSeparatorSize
	dataSectionEnd := uint(metadataStart - len(metadataStartMarker))
	if dataSectionStart > dataSectionEnd {
		return nil, newInvalidDatabaseError("the MaxMind DB contains invalid metadata")
	}
	d := decoder{
		buffer[searchTreeSize+dataSectionSeparatorSize : metadataStart-len(metadataStartMarker)],
	}

	reader := &Reader{
		buffer:    buffer,
		decoder:   d,
		Metadata:  metadata,
		ipv4Start: 0,
	}

	err = reader.setIPv4Start()

	return reader, err
}

func (r *Reader) setIPv4Start() error {
	if r.Metadata.IPVersion != 6 {
		return nil
	}

	nodeCount := r.Metadata.NodeCount

	node := uint(0)
	var err error
	i := 0
	for ; i < 96 && node < nodeCount; i++ {
		node, err = r.readNode(node, 0)
		if err != nil {
			return err
		}
	}
	r.ipv4Start = node
	r.ipv4StartBitDepth = i
	return err
}

// Lookup retrieves the database record for ip and stores it in the value
// pointed to be result. If result is nil or not a pointer, an error is
// returned. If the data in the database record cannot be stored in result
// because of type differences, an UnmarshalTypeError is returned. If the
// database is invalid or otherwise cannot be read, an InvalidDatabaseError
// is returned.
func (r *Reader) Lookup(ip net.IP, result interface{}) error {
	if r.buffer == nil {
		return errors.New("cannot call Lookup on a closed database")
	}
	pointer, _, _, err := r.lookupPointer(ip)
	if pointer == 0 || err != nil {
		return err
	}
	return r.retrieveData(pointer, result)
}

// LookupNetwork retrieves the database record for ip and stores it in the
// value pointed to be result. The network returned is the network associated
// with the data record in the database. The ok return value indicates whether
// the database contained a record for the ip.
//
// If result is nil or not a pointer, an error is returned. If the data in the
// database record cannot be stored in result because of type differences, an
// UnmarshalTypeError is returned. If the database is invalid or otherwise
// cannot be read, an InvalidDatabaseError is returned.
func (r *Reader) LookupNetwork(ip net.IP, result interface{}) (network *net.IPNet, ok bool, err error) {
	if r.buffer == nil {
		return nil, false, errors.New("cannot call Lookup on a closed database")
	}
	pointer, prefixLength, ip, err := r.lookupPointer(ip)

	network = r.cidr(ip, prefixLength)
	if pointer == 0 || err != nil {
		return network, false, err
	}

	return network, true, r.retrieveData(pointer, result)
}

// LookupOffset maps an argument net.IP to a corresponding record offset in the
// database. NotFound is returned if no such record is found, and a record may
// otherwise be extracted by passing the returned offset to Decode. LookupOffset
// is an advanced API, which exists to provide clients with a means to cache
// previously-decoded records.
func (r *Reader) LookupOffset(ip net.IP) (uintptr, error) {
	if r.buffer == nil {
		return 0, errors.New("cannot call LookupOffset on a closed database")
	}
	pointer, _, _, err := r.lookupPointer(ip)
	if pointer == 0 || err != nil {
		return NotFound, err
	}
	return r.resolveDataPointer(pointer)
}

func (r *Reader) cidr(ip net.IP, prefixLength int) *net.IPNet {
	// This is necessary as the node that the IPv4 start is at may
	// be at a bit depth that is less that 96, i.e., ipv4Start points
	// to a leaf node.
	if r.Metadata.IPVersion == 6 &&
		len(ip) == net.IPv4len &&
		r.ipv4StartBitDepth != 96 {
		return &net.IPNet{IP: net.ParseIP("::"), Mask: net.CIDRMask(r.ipv4StartBitDepth, 128)}
	}

	mask := net.CIDRMask(prefixLength, len(ip)*8)
	return &net.IPNet{IP: ip.Mask(mask), Mask: mask}
}

// Decode the record at |offset| into |result|. The result value pointed to
// must be a data value that corresponds to a record in the database. This may
// include a struct representation of the data, a map capable of holding the
// data or an empty interface{} value.
//
// If result is a pointer to a struct, the struct need not include a field
// for every value that may be in the database. If a field is not present in
// the structure, the decoder will not decode that field, reducing the time
// required to decode the record.
//
// As a special case, a struct field of type uintptr will be used to capture
// the offset of the value. Decode may later be used to extract the stored
// value from the offset. MaxMind DBs are highly normalized: for example in
// the City database, all records of the same country will reference a
// single representative record for that country. This uintptr behavior allows
// clients to leverage this normalization in their own sub-record caching.
func (r *Reader) Decode(offset uintptr, result interface{}) error {
	if r.buffer == nil {
		return errors.New("cannot call Decode on a closed database")
	}
	return r.decode(offset, result)
}

func (r *Reader) decode(offset uintptr, result interface{}) error {
	rv := reflect.ValueOf(result)
	if rv.Kind() != reflect.Ptr || rv.IsNil() {
		return errors.New("result param must be a pointer")
	}

	_, err := r.decoder.decode(uint(offset), rv, 0)
	return err
}

func (r *Reader) lookupPointer(ip net.IP) (uint, int, net.IP, error) {
	if ip == nil {
		return 0, 0, ip, errors.New("IP passed to Lookup cannot be nil")
	}

	ipV4Address := ip.To4()
	if ipV4Address != nil {
		ip = ipV4Address
	}
	if len(ip) == 16 && r.Metadata.IPVersion == 4 {
		return 0, 0, ip, fmt.Errorf("error looking up '%s': you attempted to look up an IPv6 address in an IPv4-only database", ip.String())
	}

	bitCount := uint(len(ip) * 8)

	var node uint
	if bitCount == 32 {
		node = r.ipv4Start
	}

	nodeCount := r.Metadata.NodeCount

	i := uint(0)
	for ; i < bitCount && node < nodeCount; i++ {
		bit := uint(1) & (uint(ip[i>>3]) >> (7 - (i % 8)))

		var err error
		node, err = r.readNode(node, bit)
		if err != nil {
			return 0, int(i), ip, err
		}
	}
	if node == nodeCount {
		// Record is empty
		return 0, int(i), ip, nil
	} else if node > nodeCount {
		return node, int(i), ip, nil
	}

	return 0, int(i), ip, newInvalidDatabaseError("invalid node in search tree")
}

func (r *Reader) readNode(nodeNumber uint, index uint) (uint, error) {
	RecordSize := r.Metadata.RecordSize

	baseOffset := nodeNumber * RecordSize / 4

	var nodeBytes []byte
	var prefix uint
	switch RecordSize {
	case 24:
		offset := baseOffset + index*3
		nodeBytes = r.buffer[offset : offset+3]
	case 28:
		prefix = uint(r.buffer[baseOffset+3])
		if index != 0 {
			prefix &= 0x0F
		} else {
			prefix = (0xF0 & prefix) >> 4
		}
		offset := baseOffset + index*4
		nodeBytes = r.buffer[offset : offset+3]
	case 32:
		offset := baseOffset + index*4
		nodeBytes = r.buffer[offset : offset+4]
	default:
		return 0, newInvalidDatabaseError("unknown record size: %d", RecordSize)
	}
	return uintFromBytes(prefix, nodeBytes), nil
}

func (r *Reader) retrieveData(pointer uint, result interface{}) error {
	offset, err := r.resolveDataPointer(pointer)
	if err != nil {
		return err
	}
	return r.decode(offset, result)
}

func (r *Reader) resolveDataPointer(pointer uint) (uintptr, error) {
	var resolved = uintptr(pointer - r.Metadata.NodeCount - dataSectionSeparatorSize)

	if resolved > uintptr(len(r.buffer)) {
		return 0, newInvalidDatabaseError("the MaxMind DB file's search tree is corrupt")
	}
	return resolved, nil
}
<commit_msg>Fix typo<commit_after>package maxminddb

import (
	"bytes"
	"errors"
	"fmt"
	"net"
	"reflect"
)

const (
	// NotFound is returned by LookupOffset when a matched root record offset
	// cannot be found.
	NotFound = ^uintptr(0)

	dataSectionSeparatorSize = 16
)

var metadataStartMarker = []byte("\xAB\xCD\xEFMaxMind.com")

// Reader holds the data corresponding to the MaxMind DB file. Its only public
// field is Metadata, which contains the metadata from the MaxMind DB file.
type Reader struct {
	hasMappedFile     bool
	buffer            []byte
	decoder           decoder
	Metadata          Metadata
	ipv4Start         uint
	ipv4StartBitDepth int
}

// Metadata holds the metadata decoded from the MaxMind DB file. In particular
// in has the format version, the build time as Unix epoch time, the database
// type and description, the IP version supported, and a slice of the natural
// languages included.
type Metadata struct {
	BinaryFormatMajorVersion uint              `maxminddb:"binary_format_major_version"`
	BinaryFormatMinorVersion uint              `maxminddb:"binary_format_minor_version"`
	BuildEpoch               uint              `maxminddb:"build_epoch"`
	DatabaseType             string            `maxminddb:"database_type"`
	Description              map[string]string `maxminddb:"description"`
	IPVersion                uint              `maxminddb:"ip_version"`
	Languages                []string          `maxminddb:"languages"`
	NodeCount                uint              `maxminddb:"node_count"`
	RecordSize               uint              `maxminddb:"record_size"`
}

// FromBytes takes a byte slice corresponding to a MaxMind DB file and returns
// a Reader structure or an error.
func FromBytes(buffer []byte) (*Reader, error) {
	metadataStart := bytes.LastIndex(buffer, metadataStartMarker)

	if metadataStart == -1 {
		return nil, newInvalidDatabaseError("error opening database: invalid MaxMind DB file")
	}

	metadataStart += len(metadataStartMarker)
	metadataDecoder := decoder{buffer[metadataStart:]}

	var metadata Metadata

	rvMetdata := reflect.ValueOf(&metadata)
	_, err := metadataDecoder.decode(0, rvMetdata, 0)
	if err != nil {
		return nil, err
	}

	searchTreeSize := metadata.NodeCount * metadata.RecordSize / 4
	dataSectionStart := searchTreeSize + dataSectionSeparatorSize
	dataSectionEnd := uint(metadataStart - len(metadataStartMarker))
	if dataSectionStart > dataSectionEnd {
		return nil, newInvalidDatabaseError("the MaxMind DB contains invalid metadata")
	}
	d := decoder{
		buffer[searchTreeSize+dataSectionSeparatorSize : metadataStart-len(metadataStartMarker)],
	}

	reader := &Reader{
		buffer:    buffer,
		decoder:   d,
		Metadata:  metadata,
		ipv4Start: 0,
	}

	err = reader.setIPv4Start()

	return reader, err
}

func (r *Reader) setIPv4Start() error {
	if r.Metadata.IPVersion != 6 {
		return nil
	}

	nodeCount := r.Metadata.NodeCount

	node := uint(0)
	var err error
	i := 0
	for ; i < 96 && node < nodeCount; i++ {
		node, err = r.readNode(node, 0)
		if err != nil {
			return err
		}
	}
	r.ipv4Start = node
	r.ipv4StartBitDepth = i
	return err
}

// Lookup retrieves the database record for ip and stores it in the value
// pointed to by result. If result is nil or not a pointer, an error is
// returned. If the data in the database record cannot be stored in result
// because of type differences, an UnmarshalTypeError is returned. If the
// database is invalid or otherwise cannot be read, an InvalidDatabaseError
// is returned.
func (r *Reader) Lookup(ip net.IP, result interface{}) error {
	if r.buffer == nil {
		return errors.New("cannot call Lookup on a closed database")
	}
	pointer, _, _, err := r.lookupPointer(ip)
	if pointer == 0 || err != nil {
		return err
	}
	return r.retrieveData(pointer, result)
}

// LookupNetwork retrieves the database record for ip and stores it in the
// value pointed to by result. The network returned is the network associated
// with the data record in the database. The ok return value indicates whether
// the database contained a record for the ip.
//
// If result is nil or not a pointer, an error is returned. If the data in the
// database record cannot be stored in result because of type differences, an
// UnmarshalTypeError is returned. If the database is invalid or otherwise
// cannot be read, an InvalidDatabaseError is returned.
func (r *Reader) LookupNetwork(ip net.IP, result interface{}) (network *net.IPNet, ok bool, err error) {
	if r.buffer == nil {
		return nil, false, errors.New("cannot call Lookup on a closed database")
	}
	pointer, prefixLength, ip, err := r.lookupPointer(ip)

	network = r.cidr(ip, prefixLength)
	if pointer == 0 || err != nil {
		return network, false, err
	}

	return network, true, r.retrieveData(pointer, result)
}

// LookupOffset maps an argument net.IP to a corresponding record offset in the
// database. NotFound is returned if no such record is found, and a record may
// otherwise be extracted by passing the returned offset to Decode. LookupOffset
// is an advanced API, which exists to provide clients with a means to cache
// previously-decoded records.
func (r *Reader) LookupOffset(ip net.IP) (uintptr, error) {
	if r.buffer == nil {
		return 0, errors.New("cannot call LookupOffset on a closed database")
	}
	pointer, _, _, err := r.lookupPointer(ip)
	if pointer == 0 || err != nil {
		return NotFound, err
	}
	return r.resolveDataPointer(pointer)
}

func (r *Reader) cidr(ip net.IP, prefixLength int) *net.IPNet {
	// This is necessary as the node that the IPv4 start is at may
	// be at a bit depth that is less that 96, i.e., ipv4Start points
	// to a leaf node.
	if r.Metadata.IPVersion == 6 &&
		len(ip) == net.IPv4len &&
		r.ipv4StartBitDepth != 96 {
		return &net.IPNet{IP: net.ParseIP("::"), Mask: net.CIDRMask(r.ipv4StartBitDepth, 128)}
	}

	mask := net.CIDRMask(prefixLength, len(ip)*8)
	return &net.IPNet{IP: ip.Mask(mask), Mask: mask}
}

// Decode the record at |offset| into |result|. The result value pointed to
// must be a data value that corresponds to a record in the database. This may
// include a struct representation of the data, a map capable of holding the
// data or an empty interface{} value.
//
// If result is a pointer to a struct, the struct need not include a field
// for every value that may be in the database. If a field is not present in
// the structure, the decoder will not decode that field, reducing the time
// required to decode the record.
//
// As a special case, a struct field of type uintptr will be used to capture
// the offset of the value. Decode may later be used to extract the stored
// value from the offset. MaxMind DBs are highly normalized: for example in
// the City database, all records of the same country will reference a
// single representative record for that country. This uintptr behavior allows
// clients to leverage this normalization in their own sub-record caching.
func (r *Reader) Decode(offset uintptr, result interface{}) error {
	if r.buffer == nil {
		return errors.New("cannot call Decode on a closed database")
	}
	return r.decode(offset, result)
}

func (r *Reader) decode(offset uintptr, result interface{}) error {
	rv := reflect.ValueOf(result)
	if rv.Kind() != reflect.Ptr || rv.IsNil() {
		return errors.New("result param must be a pointer")
	}

	_, err := r.decoder.decode(uint(offset), rv, 0)
	return err
}

func (r *Reader) lookupPointer(ip net.IP) (uint, int, net.IP, error) {
	if ip == nil {
		return 0, 0, ip, errors.New("IP passed to Lookup cannot be nil")
	}

	ipV4Address := ip.To4()
	if ipV4Address != nil {
		ip = ipV4Address
	}
	if len(ip) == 16 && r.Metadata.IPVersion == 4 {
		return 0, 0, ip, fmt.Errorf("error looking up '%s': you attempted to look up an IPv6 address in an IPv4-only database", ip.String())
	}

	bitCount := uint(len(ip) * 8)

	var node uint
	if bitCount == 32 {
		node = r.ipv4Start
	}

	nodeCount := r.Metadata.NodeCount

	i := uint(0)
	for ; i < bitCount && node < nodeCount; i++ {
		bit := uint(1) & (uint(ip[i>>3]) >> (7 - (i % 8)))

		var err error
		node, err = r.readNode(node, bit)
		if err != nil {
			return 0, int(i), ip, err
		}
	}
	if node == nodeCount {
		// Record is empty
		return 0, int(i), ip, nil
	} else if node > nodeCount {
		return node, int(i), ip, nil
	}

	return 0, int(i), ip, newInvalidDatabaseError("invalid node in search tree")
}

func (r *Reader) readNode(nodeNumber uint, index uint) (uint, error) {
	RecordSize := r.Metadata.RecordSize

	baseOffset := nodeNumber * RecordSize / 4

	var nodeBytes []byte
	var prefix uint
	switch RecordSize {
	case 24:
		offset := baseOffset + index*3
		nodeBytes = r.buffer[offset : offset+3]
	case 28:
		prefix = uint(r.buffer[baseOffset+3])
		if index != 0 {
			prefix &= 0x0F
		} else {
			prefix = (0xF0 & prefix) >> 4
		}
		offset := baseOffset + index*4
		nodeBytes = r.buffer[offset : offset+3]
	case 32:
		offset := baseOffset + index*4
		nodeBytes = r.buffer[offset : offset+4]
	default:
		return 0, newInvalidDatabaseError("unknown record size: %d", RecordSize)
	}
	return uintFromBytes(prefix, nodeBytes), nil
}

func (r *Reader) retrieveData(pointer uint, result interface{}) error {
	offset, err := r.resolveDataPointer(pointer)
	if err != nil {
		return err
	}
	return r.decode(offset, result)
}

func (r *Reader) resolveDataPointer(pointer uint) (uintptr, error) {
	var resolved = uintptr(pointer - r.Metadata.NodeCount - dataSectionSeparatorSize)

	if resolved > uintptr(len(r.buffer)) {
		return 0, newInvalidDatabaseError("the MaxMind DB file's search tree is corrupt")
	}
	return resolved, nil
}
<|endoftext|>


<commit_before>package manta

import (
	"encoding/binary"
	"math"
)

var (
	bigEndian    = binary.BigEndian
	littleEndian = binary.LittleEndian
)

// A reader holds a buffer and performs read operations against it.
type Reader struct {
	buf  []byte
	size int
	pos  int
}

// Creates a new reader object with a given buffer.
func NewReader(buf []byte) *Reader {
	return &Reader{buf, len(buf) * 8, 0}
}

// Calculates our byte position.
func (r *Reader) bytePos() int {
	return r.pos / 8
}

// Calculates how many bits are remaining.
func (r *Reader) remBits() int {
	return r.size - r.pos
}

// Calculates how many bytes are remaining.
func (r *Reader) remBytes() int {
	return r.remBits() / 8
}

// Seeks a given number of bits (may be negative).
func (r *Reader) seekBits(n int) {
	if r.pos+n >= r.size || r.pos+n < 0 {
		_panicf("seek overflow: %d bits requested, only %d remaining", n, r.size-r.pos)
	}
	r.pos += n
}

// Seeks a given number of bytes (may be negative).
func (r *Reader) seekBytes(n int) {
	r.seekBits(n * 8)
}

// Reads a little-endian uint16.
func (r *Reader) readLeUint16() uint16 {
	return littleEndian.Uint16(r.readBytes(2))
}

// Reads a little-endian uint32.
func (r *Reader) readLeUint32() uint32 {
	return littleEndian.Uint32(r.readBytes(4))
}

// Reads a little-endian uint64.
func (r *Reader) readLeUint64() uint64 {
	return littleEndian.Uint64(r.readBytes(8))
}

// Reads a big-endian uint16.
func (r *Reader) readBeUint16() uint16 {
	return bigEndian.Uint16(r.readBytes(2))
}

// Reads a big-endian uint32.
func (r *Reader) readBeUint32() uint32 {
	return bigEndian.Uint32(r.readBytes(4))
}

// Reads a big-endian uint64.
func (r *Reader) readBeUint64() uint64 {
	return bigEndian.Uint64(r.readBytes(8))
}

// Reads an unsigned 32-bit varint.
func (r *Reader) readVarUint32() uint32 {
	var x uint
	var s uint
	for {
		b := uint(r.readByte())
		x |= (b & 0x7F) << s
		s += 7
		if ((b & 0x80) == 0) || (s == 35) {
			break
		}
	}

	return uint32(x)
}

// Reads a signed 32-bit varint.
func (r *Reader) readVarInt32() int32 {
	ux := r.readVarUint32()
	x := int32(ux >> 1)
	if ux&1 != 0 {
		x = ^x
	}
	return x
}

// Reads an unsigned 64-bit varint.
func (r *Reader) readVarUint64() uint64 {
	var x uint64
	var s uint
	for i := 0; ; i++ {
		b := r.readByte()
		if b < 0x80 {
			if i > 9 || i == 9 && b > 1 {
				_panicf("read overflow: varint overflows uint64")
			}
			return x | uint64(b)<<s
		}
		x |= uint64(b&0x7f) << s
		s += 7
	}
}

// Reads a signed 64-bit varint.
func (r *Reader) readVarInt64() int64 {
	ux := r.readVarUint64()
	x := int64(ux >> 1)
	if ux&1 != 0 {
		x = ^x
	}
	return x
}

// Reads a boolean value.
func (r *Reader) readBoolean() bool {
	if r.remBits() < 1 {
		_panicf("read overflow: no bits left")
	}

	b := r.buf[r.pos/8]&(1<<uint(r.pos%8)) != 0
	r.pos += 1
	return b
}

// Reads a bit varint, encoding in last to bits of 6 bit group
func (r *Reader) readUBitVar() uint32 {
	ret := r.readBits(6)

	switch ret & 0x30 {
	case 16:
		ret = (ret & 15) | (r.readBits(4) << 4)
		break
	case 32:
		ret = (ret & 15) | (r.readBits(8) << 4)
		break
	case 48:
		ret = (ret & 15) | (r.readBits(28) << 4)
		break
	}

	return ret
}

// Another ubitvar variant, encoding in first 2 bits of 6 bit group
func (r *Reader) readUBitVar2() uint32 {
	ret := r.readBits(6)
	enc := uint32(ret & 3)

	if enc != 0 {
		r.pos -= 4
		return r.readBits(int(4 + enc*4 + (((2 - enc) >> 31) & 16)))
	} else {
		return (ret >> 2)
	}
}

// Reads the next byte (8 bits) in the buffer.
func (r *Reader) readByte() byte {
	// Fast path if our position is byte-aligned.
	if r.pos%8 == 0 && r.pos+8 <= r.size {
		bpos := r.pos / 8
		r.pos += 8
		return r.buf[bpos]
	}

	// Slow path if our position isn't byte aligned.
	return byte(r.readBits(8))
}

// Reads the given number of bytes from the buffer.
func (r *Reader) readBytes(n int) []byte {
	if r.remBits() < (n * 8) {
		_panicf("read overflow: %d bits requested, only %d remaining", n*8, r.remBits())
	}

	// Fast path if our position is byte-aligned.
	if r.pos%8 == 0 {
		bpos := r.pos / 8
		r.pos += (n * 8)
		return r.buf[bpos : bpos+n]
	}

	// Slow path if our position isn't byte aligned.
	buf := make([]byte, n)
	for i := 0; i < n; i++ {
		buf[i] = byte(r.readBits(8))
	}
	return buf
}

// Reads a string of a given length.
func (r *Reader) readStringN(n int) string {
	return string(r.readBytes(n))
}

// Read a null terminated string.
func (r *Reader) readString() string {
	buf := make([]byte, 0)
	for {
		b := r.readByte()
		if b == 0 {
			break
		}
		buf = append(buf, b)
	}

	return string(buf)
}

// Reads a float32 as the IEEE 754 binary representation of the next 4 bytes.
func (r *Reader) readFloat32() float32 {
	return math.Float32frombits(r.readLeUint32())
}

// Reads a float32 with props
func (r *Reader) readFloat32Bits(b int32, lP *float32, hP *float32) float32 {
	bits := int(b)
	lV, hV := float32(0.0), float32(0.0)
	if lP != nil {
		lV = *lP
	}
	if hP != nil {
		hV = *hP
	}

	dividend := r.readBits(bits)
	divisor := (1 << uint(bits)) - 1
	base := float32(dividend) / float32(divisor)
	diff := hV - lV
	return (base * diff) - lV
}

// Read a coord
func (r *Reader) readCoord() float32 {
	value := float32(0.0)

	intval := r.readBits(1)
	fractval := r.readBits(1)
	signbit := false

	if intval != 0 || fractval != 0 {
		signbit = r.readBoolean()

		if intval != 0 {
			intval = r.readBits(14) + 1
		}

		if fractval != 0 {
			fractval = r.readBits(5)
		}

		value = float32(intval) + float32(fractval)*(1.0/(1<<5))

		// Fixup the sign if negative.
		if signbit {
			value = -value
		}
	}

	return value
}

// Reads bits as bytes.
func (r *Reader) readBitsAsBytes(n int) []byte {
	tmp := make([]byte, 0)
	for n >= 8 {
		tmp = append(tmp, r.readByte())
		n -= 8
	}
	if n > 0 {
		tmp = append(tmp, byte(r.readBits(n)))
	}
	return tmp
}

// Read bits of a given length as a uint, may or may not be byte-aligned.
func (r *Reader) readBits(n int) uint32 {
	if r.remBits() < n {
		_panicf("read overflow: %d bits requested, only %d remaining", n, r.remBits())
	}

	if n > 32 {
		_panicf("invalid read: %d is greater than maximum read of 32 bits", n)
	}

	bitOffset := r.pos % 8
	nBitsToRead := bitOffset + n
	nBytesToRead := nBitsToRead / 8
	if nBitsToRead%8 != 0 {
		nBytesToRead += 1
	}

	var val uint64
	for i := 0; i < nBytesToRead; i++ {
		m := r.buf[(r.pos/8)+i]
		val += (uint64(m) << uint32(i*8))
	}
	val >>= uint32(bitOffset)
	val &= ((1 << uint32(n)) - 1)
	r.pos += n

	return uint32(val)
}
<commit_msg>Added reader.readBitNormal<commit_after>package manta

import (
	"encoding/binary"
	"math"
)

var (
	bigEndian    = binary.BigEndian
	littleEndian = binary.LittleEndian
)

// A reader holds a buffer and performs read operations against it.
type Reader struct {
	buf  []byte
	size int
	pos  int
}

// Creates a new reader object with a given buffer.
func NewReader(buf []byte) *Reader {
	return &Reader{buf, len(buf) * 8, 0}
}

// Calculates our byte position.
func (r *Reader) bytePos() int {
	return r.pos / 8
}

// Calculates how many bits are remaining.
func (r *Reader) remBits() int {
	return r.size - r.pos
}

// Calculates how many bytes are remaining.
func (r *Reader) remBytes() int {
	return r.remBits() / 8
}

// Seeks a given number of bits (may be negative).
func (r *Reader) seekBits(n int) {
	if r.pos+n >= r.size || r.pos+n < 0 {
		_panicf("seek overflow: %d bits requested, only %d remaining", n, r.size-r.pos)
	}
	r.pos += n
}

// Seeks a given number of bytes (may be negative).
func (r *Reader) seekBytes(n int) {
	r.seekBits(n * 8)
}

// Reads a little-endian uint16.
func (r *Reader) readLeUint16() uint16 {
	return littleEndian.Uint16(r.readBytes(2))
}

// Reads a little-endian uint32.
func (r *Reader) readLeUint32() uint32 {
	return littleEndian.Uint32(r.readBytes(4))
}

// Reads a little-endian uint64.
func (r *Reader) readLeUint64() uint64 {
	return littleEndian.Uint64(r.readBytes(8))
}

// Reads a big-endian uint16.
func (r *Reader) readBeUint16() uint16 {
	return bigEndian.Uint16(r.readBytes(2))
}

// Reads a big-endian uint32.
func (r *Reader) readBeUint32() uint32 {
	return bigEndian.Uint32(r.readBytes(4))
}

// Reads a big-endian uint64.
func (r *Reader) readBeUint64() uint64 {
	return bigEndian.Uint64(r.readBytes(8))
}

// Reads an unsigned 32-bit varint.
func (r *Reader) readVarUint32() uint32 {
	var x uint
	var s uint
	for {
		b := uint(r.readByte())
		x |= (b & 0x7F) << s
		s += 7
		if ((b & 0x80) == 0) || (s == 35) {
			break
		}
	}

	return uint32(x)
}

// Reads a signed 32-bit varint.
func (r *Reader) readVarInt32() int32 {
	ux := r.readVarUint32()
	x := int32(ux >> 1)
	if ux&1 != 0 {
		x = ^x
	}
	return x
}

// Reads an unsigned 64-bit varint.
func (r *Reader) readVarUint64() uint64 {
	var x uint64
	var s uint
	for i := 0; ; i++ {
		b := r.readByte()
		if b < 0x80 {
			if i > 9 || i == 9 && b > 1 {
				_panicf("read overflow: varint overflows uint64")
			}
			return x | uint64(b)<<s
		}
		x |= uint64(b&0x7f) << s
		s += 7
	}
}

// Reads a signed 64-bit varint.
func (r *Reader) readVarInt64() int64 {
	ux := r.readVarUint64()
	x := int64(ux >> 1)
	if ux&1 != 0 {
		x = ^x
	}
	return x
}

// Reads a boolean value.
func (r *Reader) readBoolean() bool {
	if r.remBits() < 1 {
		_panicf("read overflow: no bits left")
	}

	b := r.buf[r.pos/8]&(1<<uint(r.pos%8)) != 0
	r.pos += 1
	return b
}

// Reads a bit varint, encoding in last to bits of 6 bit group
func (r *Reader) readUBitVar() uint32 {
	ret := r.readBits(6)

	switch ret & 0x30 {
	case 16:
		ret = (ret & 15) | (r.readBits(4) << 4)
		break
	case 32:
		ret = (ret & 15) | (r.readBits(8) << 4)
		break
	case 48:
		ret = (ret & 15) | (r.readBits(28) << 4)
		break
	}

	return ret
}

// Another ubitvar variant, encoding in first 2 bits of 6 bit group
func (r *Reader) readUBitVar2() uint32 {
	ret := r.readBits(6)
	enc := uint32(ret & 3)

	if enc != 0 {
		r.pos -= 4
		return r.readBits(int(4 + enc*4 + (((2 - enc) >> 31) & 16)))
	} else {
		return (ret >> 2)
	}
}

// Reads the next byte (8 bits) in the buffer.
func (r *Reader) readByte() byte {
	// Fast path if our position is byte-aligned.
	if r.pos%8 == 0 && r.pos+8 <= r.size {
		bpos := r.pos / 8
		r.pos += 8
		return r.buf[bpos]
	}

	// Slow path if our position isn't byte aligned.
	return byte(r.readBits(8))
}

// Reads the given number of bytes from the buffer.
func (r *Reader) readBytes(n int) []byte {
	if r.remBits() < (n * 8) {
		_panicf("read overflow: %d bits requested, only %d remaining", n*8, r.remBits())
	}

	// Fast path if our position is byte-aligned.
	if r.pos%8 == 0 {
		bpos := r.pos / 8
		r.pos += (n * 8)
		return r.buf[bpos : bpos+n]
	}

	// Slow path if our position isn't byte aligned.
	buf := make([]byte, n)
	for i := 0; i < n; i++ {
		buf[i] = byte(r.readBits(8))
	}
	return buf
}

// Reads a string of a given length.
func (r *Reader) readStringN(n int) string {
	return string(r.readBytes(n))
}

// Read a null terminated string.
func (r *Reader) readString() string {
	buf := make([]byte, 0)
	for {
		b := r.readByte()
		if b == 0 {
			break
		}
		buf = append(buf, b)
	}

	return string(buf)
}

// Reads a float32 as the IEEE 754 binary representation of the next 4 bytes.
func (r *Reader) readFloat32() float32 {
	return math.Float32frombits(r.readLeUint32())
}

// Reads a float32 with props
func (r *Reader) readFloat32Bits(b int32, lP *float32, hP *float32) float32 {
	bits := int(b)
	lV, hV := float32(0.0), float32(0.0)
	if lP != nil {
		lV = *lP
	}
	if hP != nil {
		hV = *hP
	}

	dividend := r.readBits(bits)
	divisor := (1 << uint(bits)) - 1
	base := float32(dividend) / float32(divisor)
	diff := hV - lV
	return (base * diff) - lV
}

// Read a coord
func (r *Reader) readCoord() float32 {
	value := float32(0.0)

	intval := r.readBits(1)
	fractval := r.readBits(1)
	signbit := false

	if intval != 0 || fractval != 0 {
		signbit = r.readBoolean()

		if intval != 0 {
			intval = r.readBits(14) + 1
		}

		if fractval != 0 {
			fractval = r.readBits(5)
		}

		value = float32(intval) + float32(fractval)*(1.0/(1<<5))

		// Fixup the sign if negative.
		if signbit {
			value = -value
		}
	}

	return value
}

// Read normalized float
func (r *Reader) readNormal() float32 {
	isNeg := r.readBoolean()
	len := r.readBits(11)
	ret := float32(len) * float32(1.0/(float32(1<<11)-1.0))

	if isNeg {
		return -ret
	} else {
		return ret
	}
}

// Reads bits as bytes.
func (r *Reader) readBitsAsBytes(n int) []byte {
	tmp := make([]byte, 0)
	for n >= 8 {
		tmp = append(tmp, r.readByte())
		n -= 8
	}
	if n > 0 {
		tmp = append(tmp, byte(r.readBits(n)))
	}
	return tmp
}

// Read bits of a given length as a uint, may or may not be byte-aligned.
func (r *Reader) readBits(n int) uint32 {
	if r.remBits() < n {
		_panicf("read overflow: %d bits requested, only %d remaining", n, r.remBits())
	}

	if n > 32 {
		_panicf("invalid read: %d is greater than maximum read of 32 bits", n)
	}

	bitOffset := r.pos % 8
	nBitsToRead := bitOffset + n
	nBytesToRead := nBitsToRead / 8
	if nBitsToRead%8 != 0 {
		nBytesToRead += 1
	}

	var val uint64
	for i := 0; i < nBytesToRead; i++ {
		m := r.buf[(r.pos/8)+i]
		val += (uint64(m) << uint32(i*8))
	}
	val >>= uint32(bitOffset)
	val &= ((1 << uint32(n)) - 1)
	r.pos += n

	return uint32(val)
}
<|endoftext|>


<commit_before>// +build windows

package godirwalk

import (
	"fmt"
	"os"
)

// Scanner is an iterator to enumerate the contents of a directory.
type Scanner struct {
	osDirname string
	dh        *os.File // dh is handle to open directory
	de        *Dirent
	err       error // err is the error associated with scanning directory
}

// NewScanner returns a new directory Scanner.
func NewScanner(osDirname string) (*Scanner, error) {
	dh, err := os.Open(osDirname)
	if err != nil {
		return nil, err
	}
	scanner := &Scanner{
		osDirname: osDirname,
		dh:        dh,
	}
	return scanner, nil
}

// Dirent returns the current directory entry while scanning a directory.
func (s *Scanner) Dirent() (*Dirent, error) { return s.de, nil }

// done is called when directory scanner unable to continue, with either the
// triggering error, or nil when there are simply no more entries to read from
// the directory.
func (s *Scanner) done(err error) {
	if s.dh == nil {
		return
	}
	cerr := s.dh.Close()
	s.dh = nil

	if err == nil {
		s.err = cerr
	} else {
		s.err = err
	}

	s.osDirname = ""
	s.de = nil
}

// Err returns the error associated with scanning a directory.
func (s *Scanner) Err() error {
	s.done(s.err)
	return s.err
}

// Name returns the name of the current directory entry while scanning a
// directory.
func (s *Scanner) Name() string { return s.de.name }

// Scan potentially reads and then decodes the next directory entry from the
// file system.
func (s *Scanner) Scan() bool {
	if s.err != nil {
		return false
	}

	fileinfos, err := s.dh.Readdir(1)
	if err != nil {
		s.err = err
		return false
	}

	if l := len(fileinfos); l != 1 {
		s.err = fmt.Errorf("expected a single entry rather than %d", l)
		return false
	}

	fi := fileinfos[0]
	s.de = &Dirent{
		name:     fi.Name(),
		modeType: fi.Mode() & os.ModeType,
	}
	return true
}
<commit_msg>Scanner.Err returns nil on directory EOF<commit_after>// +build windows

package godirwalk

import (
	"fmt"
	"io"
	"os"
)

// Scanner is an iterator to enumerate the contents of a directory.
type Scanner struct {
	osDirname string
	dh        *os.File // dh is handle to open directory
	de        *Dirent
	err       error // err is the error associated with scanning directory
}

// NewScanner returns a new directory Scanner.
func NewScanner(osDirname string) (*Scanner, error) {
	dh, err := os.Open(osDirname)
	if err != nil {
		return nil, err
	}
	scanner := &Scanner{
		osDirname: osDirname,
		dh:        dh,
	}
	return scanner, nil
}

// Dirent returns the current directory entry while scanning a directory.
func (s *Scanner) Dirent() (*Dirent, error) { return s.de, nil }

// done is called when directory scanner unable to continue, with either the
// triggering error, or nil when there are simply no more entries to read from
// the directory.
func (s *Scanner) done(err error) {
	if s.dh == nil {
		return
	}
	cerr := s.dh.Close()
	s.dh = nil

	if err == nil {
		s.err = cerr
	} else {
		s.err = err
	}

	s.osDirname = ""
	s.de = nil
}

// Err returns the error associated with scanning a directory.
func (s *Scanner) Err() error {
	s.done(s.err)
	if s.err == io.EOF {
		return nil
	}
	return s.err
}

// Name returns the name of the current directory entry while scanning a
// directory.
func (s *Scanner) Name() string { return s.de.name }

// Scan potentially reads and then decodes the next directory entry from the
// file system.
func (s *Scanner) Scan() bool {
	if s.err != nil {
		return false
	}

	fileinfos, err := s.dh.Readdir(1)
	if err != nil {
		s.err = err
		return false
	}

	if l := len(fileinfos); l != 1 {
		s.err = fmt.Errorf("expected a single entry rather than %d", l)
		return false
	}

	fi := fileinfos[0]
	s.de = &Dirent{
		name:     fi.Name(),
		modeType: fi.Mode() & os.ModeType,
	}
	return true
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/api/types/versions"
	"github.com/docker/docker/cli"
	"github.com/docker/docker/cli/command"
	"github.com/docker/docker/cli/command/commands"
	cliflags "github.com/docker/docker/cli/flags"
	"github.com/docker/docker/cliconfig"
	"github.com/docker/docker/dockerversion"
	"github.com/docker/docker/pkg/term"
	"github.com/docker/docker/utils"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

func newDockerCommand(dockerCli *command.DockerCli) *cobra.Command {
	opts := cliflags.NewClientOptions()
	var flags *pflag.FlagSet

	cmd := &cobra.Command{
		Use:              "docker [OPTIONS] COMMAND [ARG...]",
		Short:            "A self-sufficient runtime for containers",
		SilenceUsage:     true,
		SilenceErrors:    true,
		TraverseChildren: true,
		Args:             noArgs,
		RunE: func(cmd *cobra.Command, args []string) error {
			if opts.Version {
				showVersion()
				return nil
			}
			cmd.SetOutput(dockerCli.Err())
			cmd.HelpFunc()(cmd, args)
			return nil
		},
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			// daemon command is special, we redirect directly to another binary
			if cmd.Name() == "daemon" {
				return nil
			}
			// flags must be the top-level command flags, not cmd.Flags()
			opts.Common.SetDefaultOptions(flags)
			dockerPreRun(opts)
			return dockerCli.Initialize(opts)
		},
	}
	cli.SetupRootCommand(cmd)

	cmd.SetHelpFunc(func(ccmd *cobra.Command, args []string) {
		if dockerCli.Client() == nil {
			// flags must be the top-level command flags, not cmd.Flags()
			opts.Common.SetDefaultOptions(flags)
			dockerPreRun(opts)
			dockerCli.Initialize(opts)
		}

		hideUnsupportedFeatures(ccmd, dockerCli.Client().ClientVersion(), dockerCli.HasExperimental())

		if err := ccmd.Help(); err != nil {
			ccmd.Println(err)
		}
	})

	flags = cmd.Flags()
	flags.BoolVarP(&opts.Version, "version", "v", false, "Print version information and quit")
	flags.StringVar(&opts.ConfigDir, "config", cliconfig.ConfigDir(), "Location of client config files")
	opts.Common.InstallFlags(flags)

	cmd.SetOutput(dockerCli.Out())
	cmd.AddCommand(newDaemonCommand())
	commands.AddCommands(cmd, dockerCli)

	return cmd
}

func noArgs(cmd *cobra.Command, args []string) error {
	if len(args) == 0 {
		return nil
	}
	return fmt.Errorf(
		"docker: '%s' is not a docker command.\nSee 'docker --help'.", args[0])
}

func main() {
	// Set terminal emulation based on platform as required.
	stdin, stdout, stderr := term.StdStreams()
	logrus.SetOutput(stderr)

	dockerCli := command.NewDockerCli(stdin, stdout, stderr)
	cmd := newDockerCommand(dockerCli)

	if err := cmd.Execute(); err != nil {
		if sterr, ok := err.(cli.StatusError); ok {
			if sterr.Status != "" {
				fmt.Fprintln(stderr, sterr.Status)
			}
			// StatusError should only be used for errors, and all errors should
			// have a non-zero exit status, so never exit with 0
			if sterr.StatusCode == 0 {
				os.Exit(1)
			}
			os.Exit(sterr.StatusCode)
		}
		fmt.Fprintln(stderr, err)
		os.Exit(1)
	}
}

func showVersion() {
	fmt.Printf("Docker version %s, build %s\n", dockerversion.Version, dockerversion.GitCommit)
}

func dockerPreRun(opts *cliflags.ClientOptions) {
	cliflags.SetLogLevel(opts.Common.LogLevel)

	if opts.ConfigDir != "" {
		cliconfig.SetConfigDir(opts.ConfigDir)
	}

	if opts.Common.Debug {
		utils.EnableDebug()
	}
}

func hideUnsupportedFeatures(cmd *cobra.Command, clientVersion string, hasExperimental bool) {
	cmd.Flags().VisitAll(func(f *pflag.Flag) {
		// hide experimental flags
		if !hasExperimental {
			if _, ok := f.Annotations["experimental"]; ok {
				f.Hidden = true
			}
		}

		// hide flags not supported by the server
		if flagVersion, ok := f.Annotations["version"]; ok && len(flagVersion) == 1 && versions.LessThan(clientVersion, flagVersion[0]) {
			f.Hidden = true
		}

	})

	for _, subcmd := range cmd.Commands() {
		// hide experimental subcommands
		if !hasExperimental {
			if _, ok := subcmd.Tags["experimental"]; ok {
				subcmd.Hidden = true
			}
		}

		// hide subcommands not supported by the server
		if subcmdVersion, ok := subcmd.Tags["version"]; ok && versions.LessThan(clientVersion, subcmdVersion) {
			subcmd.Hidden = true
		}
	}
}
<commit_msg>refactor help func in CLI<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/api/types/versions"
	"github.com/docker/docker/cli"
	"github.com/docker/docker/cli/command"
	"github.com/docker/docker/cli/command/commands"
	cliflags "github.com/docker/docker/cli/flags"
	"github.com/docker/docker/cliconfig"
	"github.com/docker/docker/dockerversion"
	"github.com/docker/docker/pkg/term"
	"github.com/docker/docker/utils"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

func newDockerCommand(dockerCli *command.DockerCli) *cobra.Command {
	opts := cliflags.NewClientOptions()
	var flags *pflag.FlagSet

	cmd := &cobra.Command{
		Use:              "docker [OPTIONS] COMMAND [ARG...]",
		Short:            "A self-sufficient runtime for containers",
		SilenceUsage:     true,
		SilenceErrors:    true,
		TraverseChildren: true,
		Args:             noArgs,
		RunE: func(cmd *cobra.Command, args []string) error {
			if opts.Version {
				showVersion()
				return nil
			}
			return dockerCli.ShowHelp(cmd, args)
		},
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			// daemon command is special, we redirect directly to another binary
			if cmd.Name() == "daemon" {
				return nil
			}
			// flags must be the top-level command flags, not cmd.Flags()
			opts.Common.SetDefaultOptions(flags)
			dockerPreRun(opts)
			return dockerCli.Initialize(opts)
		},
	}
	cli.SetupRootCommand(cmd)

	cmd.SetHelpFunc(func(ccmd *cobra.Command, args []string) {
		if dockerCli.Client() == nil {
			// flags must be the top-level command flags, not cmd.Flags()
			opts.Common.SetDefaultOptions(flags)
			dockerPreRun(opts)
			dockerCli.Initialize(opts)
		}

		hideUnsupportedFeatures(ccmd, dockerCli.Client().ClientVersion(), dockerCli.HasExperimental())

		if err := ccmd.Help(); err != nil {
			ccmd.Println(err)
		}
	})

	flags = cmd.Flags()
	flags.BoolVarP(&opts.Version, "version", "v", false, "Print version information and quit")
	flags.StringVar(&opts.ConfigDir, "config", cliconfig.ConfigDir(), "Location of client config files")
	opts.Common.InstallFlags(flags)

	cmd.SetOutput(dockerCli.Out())
	cmd.AddCommand(newDaemonCommand())
	commands.AddCommands(cmd, dockerCli)

	return cmd
}

func noArgs(cmd *cobra.Command, args []string) error {
	if len(args) == 0 {
		return nil
	}
	return fmt.Errorf(
		"docker: '%s' is not a docker command.\nSee 'docker --help'.", args[0])
}

func main() {
	// Set terminal emulation based on platform as required.
	stdin, stdout, stderr := term.StdStreams()
	logrus.SetOutput(stderr)

	dockerCli := command.NewDockerCli(stdin, stdout, stderr)
	cmd := newDockerCommand(dockerCli)

	if err := cmd.Execute(); err != nil {
		if sterr, ok := err.(cli.StatusError); ok {
			if sterr.Status != "" {
				fmt.Fprintln(stderr, sterr.Status)
			}
			// StatusError should only be used for errors, and all errors should
			// have a non-zero exit status, so never exit with 0
			if sterr.StatusCode == 0 {
				os.Exit(1)
			}
			os.Exit(sterr.StatusCode)
		}
		fmt.Fprintln(stderr, err)
		os.Exit(1)
	}
}

func showVersion() {
	fmt.Printf("Docker version %s, build %s\n", dockerversion.Version, dockerversion.GitCommit)
}

func dockerPreRun(opts *cliflags.ClientOptions) {
	cliflags.SetLogLevel(opts.Common.LogLevel)

	if opts.ConfigDir != "" {
		cliconfig.SetConfigDir(opts.ConfigDir)
	}

	if opts.Common.Debug {
		utils.EnableDebug()
	}
}

func hideUnsupportedFeatures(cmd *cobra.Command, clientVersion string, hasExperimental bool) {
	cmd.Flags().VisitAll(func(f *pflag.Flag) {
		// hide experimental flags
		if !hasExperimental {
			if _, ok := f.Annotations["experimental"]; ok {
				f.Hidden = true
			}
		}

		// hide flags not supported by the server
		if flagVersion, ok := f.Annotations["version"]; ok && len(flagVersion) == 1 && versions.LessThan(clientVersion, flagVersion[0]) {
			f.Hidden = true
		}

	})

	for _, subcmd := range cmd.Commands() {
		// hide experimental subcommands
		if !hasExperimental {
			if _, ok := subcmd.Tags["experimental"]; ok {
				subcmd.Hidden = true
			}
		}

		// hide subcommands not supported by the server
		if subcmdVersion, ok := subcmd.Tags["version"]; ok && versions.LessThan(clientVersion, subcmdVersion) {
			subcmd.Hidden = true
		}
	}
}
<|endoftext|>


<commit_before>package gobucket

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
)

// APIClient that holds the required objects for API interaction
type APIClient struct {
	Key  string
	Pass string
	HTTP *http.Client
}

// StatusCode wraps HTTP status codes returned by the BitBucket API
type StatusCode int

// APIResponse holds the HTTP response from a call to the BitBucket API
type APIResponse struct {
	Header     http.Header
	StatusCode StatusCode
	Body       string
}

// Repository contains the desireds repository properties
type Repository struct {
	FullName    string `json:"full_name"`
	Description string
}

// RepositoryResponse contains the support information returned by the API
type RepositoryResponse struct {
	PageLen      int
	Size         int
	Repositories []Repository `json:"values"`
}

// DeployKey contains the desired deploy key properties
type DeployKey struct {
	ID    int `json:"pk"`
	Key   string
	Label string
}

// Service contains properties for service hooks on a repository
type Service struct {
	ID      int
	Service struct {
		Fields []struct {
			Name  string
			Value string
		}
		Type string
	}
}

type restrictionUser struct {
	Username string `json:"username"`
}

type restrictionGroup struct {
	Slug  string          `json:"slug"`
	Owner restrictionUser `json:"owner"`
}

type branchRestriction struct {
	Kind    string             `json:"kind"`
	Pattern string             `json:"pattern"`
	Groups  []restrictionGroup `json:"groups"`
	Users   []restrictionUser  `json:"users"`
}

const baseURL string = "https://bitbucket.org/api"

// New returns an API client for BitBucket
func New(key string, pass string) *APIClient {
	client := &APIClient{}

	client.Key = key
	client.Pass = pass
	client.HTTP = &http.Client{}

	return client
}

func (c *APIClient) callFormEnc(version string, endpoint string, method string, params url.Values) (*APIResponse, error) {
	if params == nil {
		params = url.Values{}
	}

	payload := params.Encode()

	return c.call(version, endpoint, method, "application/x-www-form-urlencoded", bytes.NewBufferString(payload))
}

func (c *APIClient) callJSONEnc(version string, endpoint string, method string, params interface{}) (*APIResponse, error) {
	payload, _ := json.Marshal(params)

	return c.call(version, endpoint, method, "application/json", bytes.NewBuffer(payload))
}

func (c *APIClient) callStringBody(version string, endpoint string, method string, payload string) (*APIResponse, error) {
	return c.call(version, endpoint, method, "text/plain", bytes.NewBufferString(payload))
}

func (c *APIClient) call(version string, endpoint string, method string, contentType string, payload *bytes.Buffer) (*APIResponse, error) {
	apiurl := fmt.Sprintf("%s/%s/%s", baseURL, version, endpoint)

	req, err := http.NewRequest(method, apiurl, payload)

	if err != nil {
		return nil, err
	}

	req.Close = true

	if method != "GET" {
		req.Header.Add("Content-Type", contentType+"; charset=utf-8")
		req.Header.Add("Content-Length", strconv.Itoa(payload.Len()))
	}

	req.SetBasicAuth(c.Key, c.Pass)
	resp, err := c.HTTP.Do(req)

	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return nil, err
	}

	apiresp := &APIResponse{resp.Header, StatusCode(resp.StatusCode), string(body)}

	return apiresp, nil
}

// GetRepositories returns a list of all repositories owned by `owner`
func (c *APIClient) GetRepositories(owner string) ([]Repository, error) {
	var repos []Repository

	page := 1
	for {
		apiresp, err := c.call("2.0", fmt.Sprintf("repositories/%s?page=%d", owner, page), "GET", "", &bytes.Buffer{})
		if err != nil {
			return []Repository{}, err
		}

		var reporesp RepositoryResponse
		json.Unmarshal([]byte(apiresp.Body), &reporesp)

		repos = append(repos, reporesp.Repositories...)

		if page*reporesp.PageLen > reporesp.Size {
			break
		}

		page++
	}

	return repos, nil
}

// RepositoriesChanged returns whether or not the repositories for an account has changed
// as well as the latest ETag returned by the web server.
func (c *APIClient) RepositoriesChanged(owner string, etag string) (bool, string, error) {
	apiresp, err := c.callFormEnc("2.0", fmt.Sprintf("repositories/%s", owner), "HEAD", nil)

	if err != nil {
		return false, etag, err
	}

	if apiresp.StatusCode != 200 {
		return false, etag, fmt.Errorf("%s", apiresp.Body)
	}

	currentEtag := apiresp.Header.Get("Etag")

	return etag != currentEtag, currentEtag, nil
}

// AddBranchRestriction adds a new branch restriction to a repository
func (c *APIClient) AddBranchRestriction(owner string, repo string, kind string, branchpattern string, users []string, groups []string) error {
	restriction := branchRestriction{}
	restriction.Kind = kind
	restriction.Pattern = branchpattern

	if users != nil {
		for _, username := range users {
			restriction.Users = append(restriction.Users, restrictionUser{username})
		}
	}

	if groups != nil {
		for _, groupname := range groups {
			restriction.Groups = append(restriction.Groups, restrictionGroup{groupname, restrictionUser{owner}})
		}
	}

	apiresp, err := c.callJSONEnc("2.0", fmt.Sprintf("repositories/%s/%s/branch-restrictions", owner, repo), "POST", restriction)

	if err != nil {
		return err
	}

	if apiresp.StatusCode == 200 || apiresp.StatusCode == 409 {
		return nil
	}

	return fmt.Errorf("[%d]: %s", apiresp.StatusCode, apiresp.Body)
}

// AddUserPrivilege adds a privilege for a user on a repository
func (c *APIClient) AddUserPrivilege(owner string, repo string, privilegeUser string, privilege string) error {
	return c.addPrivilege(owner, repo, "privileges", privilegeUser, privilege)
}

// AddGroupPrivilege adds a privilege for a group on a repository
func (c *APIClient) AddGroupPrivilege(owner string, repo string, privilegeGroup string, privilege string) error {
	group := fmt.Sprintf("%s/%s", owner, privilegeGroup)
	return c.addPrivilege(owner, repo, "group-privileges", group, privilege)
}

func (c *APIClient) addPrivilege(owner string, repo string, privilegeURL string, privilegeEntity string, privilege string) error {
	endpoint := fmt.Sprintf("%s/%s/%s/%s", privilegeURL, owner, repo, privilegeEntity)

	if !(privilege == "read" || privilege == "write" || privilege == "admin") {
		return fmt.Errorf("Wrong privilege ('%s'). One of 'read', 'write' or 'admin' required.", privilege)
	}

	apiresp, err := c.callStringBody("1.0", endpoint, "PUT", privilege)

	if err != nil {
		return err
	}

	if apiresp.StatusCode == 200 {
		return nil
	}

	return fmt.Errorf("[%d]: %s", apiresp.StatusCode, apiresp.Body)
}

// GetServices returns a list of the service hooks attached to a repository
func (c *APIClient) GetServices(owner string, repository string) ([]Service, error) {
	resp, err := c.callFormEnc("1.0", fmt.Sprintf("repositories/%s/%s/services", owner, repository), "GET", nil)

	if err != nil {
		return nil, err
	}

	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("[%d]: %s", resp.StatusCode, resp.Body)
	}

	var serviceResponse []Service

	json.Unmarshal([]byte(resp.Body), &serviceResponse)

	return serviceResponse, nil
}

// AddService attaches a new service hook to the repository
func (c *APIClient) AddService(owner string, repository string, servicetype string, parameters map[string]string) error {
	data := url.Values{}
	data.Set("type", servicetype)

	for key, value := range parameters {
		data.Set(key, value)
	}

	resp, err := c.callFormEnc("1.0", fmt.Sprintf("repositories/%s/%s/services", owner, repository), "POST", data)

	if err != nil {
		return err
	}

	if resp.StatusCode == 200 {
		return nil
	}

	return fmt.Errorf("[%d]: %s", resp.StatusCode, resp.Body)
}

// GetDeployKeys returns a list of all deploy keys attached to a repository
func (c *APIClient) GetDeployKeys(owner string, repo string) ([]DeployKey, error) {
	apiresp, err := c.callFormEnc("1.0", fmt.Sprintf("repositories/%s/%s/deploy-keys", owner, repo), "GET", nil)

	if err != nil {
		return nil, err
	}

	if apiresp.StatusCode != 200 {
		return nil, fmt.Errorf("%s", apiresp.Body)
	}

	var keys []DeployKey

	json.Unmarshal([]byte(apiresp.Body), &keys)

	return keys, nil
}

// AddDeployKey attaches a new deploy key to a repository
func (c *APIClient) AddDeployKey(owner string, repository string, name string, key string) error {
	data := url.Values{}
	data.Set("label", name)
	data.Set("key", key)

	resp, err := c.callFormEnc("1.0", fmt.Sprintf("repositories/%s/%s/deploy-keys", owner, repository), "POST", data)

	if err != nil {
		return err
	}

	if resp.StatusCode == 200 {
		return nil
	}

	return fmt.Errorf("[%d]: %s", resp.StatusCode, resp.Body)
}

// DeleteDeployKey removes a deploy key from a repository
func (c *APIClient) DeleteDeployKey(owner string, repository string, keyID int) error {
	resp, err := c.callFormEnc("1.0", fmt.Sprintf("repositories/%s/%s/deploy-keys/%d", owner, repository, keyID), "DELETE", nil)

	if err != nil {
		return err
	}

	if resp.StatusCode == 204 {
		return nil
	}

	return fmt.Errorf("[%d]: %s", resp.StatusCode, resp.Body)
}

// Used when updating properties on repositories
func (c *APIClient) putV1RepoProp(owner string, repository string, data url.Values) (*APIResponse, error) {
	return c.callFormEnc("1.0", fmt.Sprintf("repositories/%s/%s", owner, repository), "PUT", data)
}

func (c *APIClient) getV1Error(resp *APIResponse, err error) error {
	if err != nil {
		return err
	}

	if resp.StatusCode == 200 {
		return nil
	}

	return fmt.Errorf("[%d]: %s", resp.StatusCode, resp.Body)
}

// SetLandingPage sets the landing page for a repository: "branches", "commits",
// "downloads", "overview", "pull_requests" or "source".
func (c *APIClient) SetLandingPage(owner string, repository string, landingpage string) error {
	data := url.Values{}
	data.Set("landing_page", landingpage)

	res, err := c.putV1RepoProp(owner, repository, data)
	return c.getV1Error(res, err)
}

// SetPrivacy set the repository privacy/visibility
func (c *APIClient) SetPrivacy(owner string, repository string, isPrivate bool) error {
	data := url.Values{}
	data.Set("is_private", fmt.Sprintf("%t", isPrivate))

	res, err := c.putV1RepoProp(owner, repository, data)
	return c.getV1Error(res, err)
}

// SetIssueTracker sets whether the repository has PUBLIC or NO issue tracker
// (Private issue trackers doesn't seem to be supported by the API)
func (c *APIClient) SetIssueTracker(owner string, repository string, issueTracker string) error {
	data := url.Values{}

	if issueTracker == "none" {
		data.Set("has_issues", "false")
	} else if issueTracker == "public" {
		data.Set("has_issues", "true")
	} else {
		return fmt.Errorf("Issue tracker setting '%s' not valid. 'none' or 'public' required", issueTracker)
	}

	res, err := c.putV1RepoProp(owner, repository, data)
	return c.getV1Error(res, err)
}

// SetMainBranch sets the main branch for the repository
func (c *APIClient) SetMainBranch(owner string, repository string, mainBranch string) error {
	data := url.Values{}
	data.Set("main_branch", mainBranch)

	res, err := c.putV1RepoProp(owner, repository, data)
	return c.getV1Error(res, err)
}

// SetDescription sets the main branch for the repository
func (c *APIClient) SetDescription(owner string, repository string, description string) error {
	data := url.Values{}
	data.Set("description", description)

	res, err := c.putV1RepoProp(owner, repository, data)
	return c.getV1Error(res, err)
}

// SetForks set the forking policy for the repository: "none", "private" or "public"
func (c *APIClient) SetForks(owner string, repository string, forks string) error {
	data := url.Values{}

	if forks == "none" {
		data.Set("no_forks", "True")
		data.Set("no_public_forks", "True")
	} else if forks == "private" {
		data.Set("no_forks", "False")
		data.Set("no_public_forks", "True")
	} else if forks == "public" {
		data.Set("no_forks", "False")
		data.Set("no_public_forks", "False")
	}

	res, err := c.putV1RepoProp(owner, repository, data)
	return c.getV1Error(res, err)
}
<commit_msg>FIX: No longer has endless loop if repository list is a multiple of PageLen long<commit_after>package gobucket

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
)

// APIClient that holds the required objects for API interaction
type APIClient struct {
	Key  string
	Pass string
	HTTP *http.Client
}

// StatusCode wraps HTTP status codes returned by the BitBucket API
type StatusCode int

// APIResponse holds the HTTP response from a call to the BitBucket API
type APIResponse struct {
	Header     http.Header
	StatusCode StatusCode
	Body       string
}

// Repository contains the desireds repository properties
type Repository struct {
	FullName    string `json:"full_name"`
	Description string
}

// RepositoryResponse contains the support information returned by the API
type RepositoryResponse struct {
	PageLen      int
	Size         int
	Repositories []Repository `json:"values"`
}

// DeployKey contains the desired deploy key properties
type DeployKey struct {
	ID    int `json:"pk"`
	Key   string
	Label string
}

// Service contains properties for service hooks on a repository
type Service struct {
	ID      int
	Service struct {
		Fields []struct {
			Name  string
			Value string
		}
		Type string
	}
}

type restrictionUser struct {
	Username string `json:"username"`
}

type restrictionGroup struct {
	Slug  string          `json:"slug"`
	Owner restrictionUser `json:"owner"`
}

type branchRestriction struct {
	Kind    string             `json:"kind"`
	Pattern string             `json:"pattern"`
	Groups  []restrictionGroup `json:"groups"`
	Users   []restrictionUser  `json:"users"`
}

const baseURL string = "https://bitbucket.org/api"

// New returns an API client for BitBucket
func New(key string, pass string) *APIClient {
	client := &APIClient{}

	client.Key = key
	client.Pass = pass
	client.HTTP = &http.Client{}

	return client
}

func (c *APIClient) callFormEnc(version string, endpoint string, method string, params url.Values) (*APIResponse, error) {
	if params == nil {
		params = url.Values{}
	}

	payload := params.Encode()

	return c.call(version, endpoint, method, "application/x-www-form-urlencoded", bytes.NewBufferString(payload))
}

func (c *APIClient) callJSONEnc(version string, endpoint string, method string, params interface{}) (*APIResponse, error) {
	payload, _ := json.Marshal(params)

	return c.call(version, endpoint, method, "application/json", bytes.NewBuffer(payload))
}

func (c *APIClient) callStringBody(version string, endpoint string, method string, payload string) (*APIResponse, error) {
	return c.call(version, endpoint, method, "text/plain", bytes.NewBufferString(payload))
}

func (c *APIClient) call(version string, endpoint string, method string, contentType string, payload *bytes.Buffer) (*APIResponse, error) {
	apiurl := fmt.Sprintf("%s/%s/%s", baseURL, version, endpoint)

	req, err := http.NewRequest(method, apiurl, payload)

	if err != nil {
		return nil, err
	}

	req.Close = true

	if method != "GET" {
		req.Header.Add("Content-Type", contentType+"; charset=utf-8")
		req.Header.Add("Content-Length", strconv.Itoa(payload.Len()))
	}

	req.SetBasicAuth(c.Key, c.Pass)
	resp, err := c.HTTP.Do(req)

	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return nil, err
	}

	apiresp := &APIResponse{resp.Header, StatusCode(resp.StatusCode), string(body)}

	return apiresp, nil
}

// GetRepositories returns a list of all repositories owned by `owner`
func (c *APIClient) GetRepositories(owner string) ([]Repository, error) {
	var repos []Repository

	page := 1
	for {
		apiresp, err := c.call("2.0", fmt.Sprintf("repositories/%s?page=%d", owner, page), "GET", "", &bytes.Buffer{})
		if err != nil {
			return []Repository{}, err
		}

		var reporesp RepositoryResponse
		json.Unmarshal([]byte(apiresp.Body), &reporesp)

		repos = append(repos, reporesp.Repositories...)

		if page*reporesp.PageLen >= reporesp.Size {
			break
		}

		page++
	}

	return repos, nil
}

// RepositoriesChanged returns whether or not the repositories for an account has changed
// as well as the latest ETag returned by the web server.
func (c *APIClient) RepositoriesChanged(owner string, etag string) (bool, string, error) {
	apiresp, err := c.callFormEnc("2.0", fmt.Sprintf("repositories/%s", owner), "HEAD", nil)

	if err != nil {
		return false, etag, err
	}

	if apiresp.StatusCode != 200 {
		return false, etag, fmt.Errorf("%s", apiresp.Body)
	}

	currentEtag := apiresp.Header.Get("Etag")

	return etag != currentEtag, currentEtag, nil
}

// AddBranchRestriction adds a new branch restriction to a repository
func (c *APIClient) AddBranchRestriction(owner string, repo string, kind string, branchpattern string, users []string, groups []string) error {
	restriction := branchRestriction{}
	restriction.Kind = kind
	restriction.Pattern = branchpattern

	if users != nil {
		for _, username := range users {
			restriction.Users = append(restriction.Users, restrictionUser{username})
		}
	}

	if groups != nil {
		for _, groupname := range groups {
			restriction.Groups = append(restriction.Groups, restrictionGroup{groupname, restrictionUser{owner}})
		}
	}

	apiresp, err := c.callJSONEnc("2.0", fmt.Sprintf("repositories/%s/%s/branch-restrictions", owner, repo), "POST", restriction)

	if err != nil {
		return err
	}

	if apiresp.StatusCode == 200 || apiresp.StatusCode == 409 {
		return nil
	}

	return fmt.Errorf("[%d]: %s", apiresp.StatusCode, apiresp.Body)
}

// AddUserPrivilege adds a privilege for a user on a repository
func (c *APIClient) AddUserPrivilege(owner string, repo string, privilegeUser string, privilege string) error {
	return c.addPrivilege(owner, repo, "privileges", privilegeUser, privilege)
}

// AddGroupPrivilege adds a privilege for a group on a repository
func (c *APIClient) AddGroupPrivilege(owner string, repo string, privilegeGroup string, privilege string) error {
	group := fmt.Sprintf("%s/%s", owner, privilegeGroup)
	return c.addPrivilege(owner, repo, "group-privileges", group, privilege)
}

func (c *APIClient) addPrivilege(owner string, repo string, privilegeURL string, privilegeEntity string, privilege string) error {
	endpoint := fmt.Sprintf("%s/%s/%s/%s", privilegeURL, owner, repo, privilegeEntity)

	if !(privilege == "read" || privilege == "write" || privilege == "admin") {
		return fmt.Errorf("Wrong privilege ('%s'). One of 'read', 'write' or 'admin' required.", privilege)
	}

	apiresp, err := c.callStringBody("1.0", endpoint, "PUT", privilege)

	if err != nil {
		return err
	}

	if apiresp.StatusCode == 200 {
		return nil
	}

	return fmt.Errorf("[%d]: %s", apiresp.StatusCode, apiresp.Body)
}

// GetServices returns a list of the service hooks attached to a repository
func (c *APIClient) GetServices(owner string, repository string) ([]Service, error) {
	resp, err := c.callFormEnc("1.0", fmt.Sprintf("repositories/%s/%s/services", owner, repository), "GET", nil)

	if err != nil {
		return nil, err
	}

	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("[%d]: %s", resp.StatusCode, resp.Body)
	}

	var serviceResponse []Service

	json.Unmarshal([]byte(resp.Body), &serviceResponse)

	return serviceResponse, nil
}

// AddService attaches a new service hook to the repository
func (c *APIClient) AddService(owner string, repository string, servicetype string, parameters map[string]string) error {
	data := url.Values{}
	data.Set("type", servicetype)

	for key, value := range parameters {
		data.Set(key, value)
	}

	resp, err := c.callFormEnc("1.0", fmt.Sprintf("repositories/%s/%s/services", owner, repository), "POST", data)

	if err != nil {
		return err
	}

	if resp.StatusCode == 200 {
		return nil
	}

	return fmt.Errorf("[%d]: %s", resp.StatusCode, resp.Body)
}

// GetDeployKeys returns a list of all deploy keys attached to a repository
func (c *APIClient) GetDeployKeys(owner string, repo string) ([]DeployKey, error) {
	apiresp, err := c.callFormEnc("1.0", fmt.Sprintf("repositories/%s/%s/deploy-keys", owner, repo), "GET", nil)

	if err != nil {
		return nil, err
	}

	if apiresp.StatusCode != 200 {
		return nil, fmt.Errorf("%s", apiresp.Body)
	}

	var keys []DeployKey

	json.Unmarshal([]byte(apiresp.Body), &keys)

	return keys, nil
}

// AddDeployKey attaches a new deploy key to a repository
func (c *APIClient) AddDeployKey(owner string, repository string, name string, key string) error {
	data := url.Values{}
	data.Set("label", name)
	data.Set("key", key)

	resp, err := c.callFormEnc("1.0", fmt.Sprintf("repositories/%s/%s/deploy-keys", owner, repository), "POST", data)

	if err != nil {
		return err
	}

	if resp.StatusCode == 200 {
		return nil
	}

	return fmt.Errorf("[%d]: %s", resp.StatusCode, resp.Body)
}

// DeleteDeployKey removes a deploy key from a repository
func (c *APIClient) DeleteDeployKey(owner string, repository string, keyID int) error {
	resp, err := c.callFormEnc("1.0", fmt.Sprintf("repositories/%s/%s/deploy-keys/%d", owner, repository, keyID), "DELETE", nil)

	if err != nil {
		return err
	}

	if resp.StatusCode == 204 {
		return nil
	}

	return fmt.Errorf("[%d]: %s", resp.StatusCode, resp.Body)
}

// Used when updating properties on repositories
func (c *APIClient) putV1RepoProp(owner string, repository string, data url.Values) (*APIResponse, error) {
	return c.callFormEnc("1.0", fmt.Sprintf("repositories/%s/%s", owner, repository), "PUT", data)
}

func (c *APIClient) getV1Error(resp *APIResponse, err error) error {
	if err != nil {
		return err
	}

	if resp.StatusCode == 200 {
		return nil
	}

	return fmt.Errorf("[%d]: %s", resp.StatusCode, resp.Body)
}

// SetLandingPage sets the landing page for a repository: "branches", "commits",
// "downloads", "overview", "pull_requests" or "source".
func (c *APIClient) SetLandingPage(owner string, repository string, landingpage string) error {
	data := url.Values{}
	data.Set("landing_page", landingpage)

	res, err := c.putV1RepoProp(owner, repository, data)
	return c.getV1Error(res, err)
}

// SetPrivacy set the repository privacy/visibility
func (c *APIClient) SetPrivacy(owner string, repository string, isPrivate bool) error {
	data := url.Values{}
	data.Set("is_private", fmt.Sprintf("%t", isPrivate))

	res, err := c.putV1RepoProp(owner, repository, data)
	return c.getV1Error(res, err)
}

// SetIssueTracker sets whether the repository has PUBLIC or NO issue tracker
// (Private issue trackers doesn't seem to be supported by the API)
func (c *APIClient) SetIssueTracker(owner string, repository string, issueTracker string) error {
	data := url.Values{}

	if issueTracker == "none" {
		data.Set("has_issues", "false")
	} else if issueTracker == "public" {
		data.Set("has_issues", "true")
	} else {
		return fmt.Errorf("Issue tracker setting '%s' not valid. 'none' or 'public' required", issueTracker)
	}

	res, err := c.putV1RepoProp(owner, repository, data)
	return c.getV1Error(res, err)
}

// SetMainBranch sets the main branch for the repository
func (c *APIClient) SetMainBranch(owner string, repository string, mainBranch string) error {
	data := url.Values{}
	data.Set("main_branch", mainBranch)

	res, err := c.putV1RepoProp(owner, repository, data)
	return c.getV1Error(res, err)
}

// SetDescription sets the main branch for the repository
func (c *APIClient) SetDescription(owner string, repository string, description string) error {
	data := url.Values{}
	data.Set("description", description)

	res, err := c.putV1RepoProp(owner, repository, data)
	return c.getV1Error(res, err)
}

// SetForks set the forking policy for the repository: "none", "private" or "public"
func (c *APIClient) SetForks(owner string, repository string, forks string) error {
	data := url.Values{}

	if forks == "none" {
		data.Set("no_forks", "True")
		data.Set("no_public_forks", "True")
	} else if forks == "private" {
		data.Set("no_forks", "False")
		data.Set("no_public_forks", "True")
	} else if forks == "public" {
		data.Set("no_forks", "False")
		data.Set("no_public_forks", "False")
	}

	res, err := c.putV1RepoProp(owner, repository, data)
	return c.getV1Error(res, err)
}
<|endoftext|>


<commit_before>// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
//
// Copyright 2012 Julien Schmidt. All rights reserved.
// http://www.julienschmidt.com
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

package mysql

import (
	"bufio"
	"database/sql"
	"database/sql/driver"
	"errors"
	"net"
)

type mysqlDriver struct{}

// Open new Connection.
// See http://code.google.com/p/go-mysql-driver/#DSN_(Data_Source_Name) for how
// the DSN string is formated
func (d *mysqlDriver) Open(dsn string) (driver.Conn, error) {
	var e error

	// New mysqlConn
	mc := new(mysqlConn)
	mc.cfg = parseDSN(dsn)

	if mc.cfg.dbname == "" {
		e = errors.New("Incomplete or invalid DSN")
		return nil, e
	}

	// Connect to Server
	mc.netConn, e = net.Dial(mc.cfg.net, mc.cfg.addr)
	if e != nil {
		return nil, e
	}
	mc.bufReader = bufio.NewReader(mc.netConn)

	// Reading Handshake Initialization Packet
	e = mc.readInitPacket()
	if e != nil {
		return nil, e
	}

	// Send Client Authentication Packet
	e = mc.writeAuthPacket()
	if e != nil {
		return nil, e
	}

	// Read Result Packet
	e = mc.readResultOK()
	if e != nil {
		return nil, e
	}

	// Handle DSN Params
	e = mc.handleParams()
	if e != nil {
		return nil, e
	}

	return mc, e
}

func init() {
	sql.Register("mysql", &mysqlDriver{})
}
<commit_msg>Fix doc header<commit_after>// Copyright 2012 Julien Schmidt. All rights reserved.
// http://www.julienschmidt.com
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
package mysql

import (
	"bufio"
	"database/sql"
	"database/sql/driver"
	"errors"
	"net"
)

type mysqlDriver struct{}

// Open new Connection.
// See http://code.google.com/p/go-mysql-driver/#DSN_(Data_Source_Name) for how
// the DSN string is formated
func (d *mysqlDriver) Open(dsn string) (driver.Conn, error) {
	var e error

	// New mysqlConn
	mc := new(mysqlConn)
	mc.cfg = parseDSN(dsn)

	if mc.cfg.dbname == "" {
		e = errors.New("Incomplete or invalid DSN")
		return nil, e
	}

	// Connect to Server
	mc.netConn, e = net.Dial(mc.cfg.net, mc.cfg.addr)
	if e != nil {
		return nil, e
	}
	mc.bufReader = bufio.NewReader(mc.netConn)

	// Reading Handshake Initialization Packet
	e = mc.readInitPacket()
	if e != nil {
		return nil, e
	}

	// Send Client Authentication Packet
	e = mc.writeAuthPacket()
	if e != nil {
		return nil, e
	}

	// Read Result Packet
	e = mc.readResultOK()
	if e != nil {
		return nil, e
	}

	// Handle DSN Params
	e = mc.handleParams()
	if e != nil {
		return nil, e
	}

	return mc, e
}

func init() {
	sql.Register("mysql", &mysqlDriver{})
}
<|endoftext|>


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

package checkmgr

import (
	"reflect"
	"testing"

	"github.com/circonus-labs/circonus-gometrics/api"
)

func TestIsMetricActive(t *testing.T) {

	cm := &CheckManager{}

	cm.availableMetrics = map[string]bool{
		"foo": true,
	}

	t.Log("'foo' in active metric list")
	{
		if !cm.IsMetricActive("foo") {
			t.Error("Expected true")
		}
	}

	t.Log("'bar' not in active metric list")
	{
		if cm.IsMetricActive("bar") {
			t.Error("Expected false")
		}
	}
}

func TestActivateMetric(t *testing.T) {
	cm := &CheckManager{}
	cm.checkBundle = &api.CheckBundle{}
	cm.checkBundle.Metrics = []api.CheckBundleMetric{
		api.CheckBundleMetric{
			Name:   "foo",
			Type:   "numeric",
			Status: "active",
		},
		api.CheckBundleMetric{
			Name:   "bar",
			Type:   "numeric",
			Status: "available",
		},
	}

	cm.availableMetrics = make(map[string]bool)
	cm.forceMetricActivation = false

	cm.inventoryMetrics()

	t.Log("'foo' already active")
	{
		if cm.ActivateMetric("foo") {
			t.Error("Expected false")
		}
	}

	t.Log("'bar' in list but not active [force=false]")
	{
		if cm.ActivateMetric("bar") {
			t.Error("Expected false")
		}
	}

	t.Log("'baz' not in list")
	{
		if !cm.ActivateMetric("baz") {
			t.Error("Expected true")
		}
	}

	cm.forceMetricActivation = true

	t.Log("'bar' in list but not active [force=true]")
	{
		if !cm.ActivateMetric("bar") {
			t.Error("Expected true")
		}
	}
}

func TestInventoryMetrics(t *testing.T) {
	cm := &CheckManager{}
	cm.checkBundle = &api.CheckBundle{}
	cm.checkBundle.Metrics = []api.CheckBundleMetric{
		api.CheckBundleMetric{
			Name:   "foo",
			Type:   "numeric",
			Status: "active",
		},
		api.CheckBundleMetric{
			Name:   "bar",
			Type:   "numeric",
			Status: "available",
		},
	}

	cm.availableMetrics = make(map[string]bool)
	cm.inventoryMetrics()

	expectedMetrics := make(map[string]bool)
	expectedMetrics["foo"] = true
	expectedMetrics["bar"] = false

	t.Log("'foo', in inventory and active")
	{
		active, exists := cm.availableMetrics["foo"]
		if !active {
			t.Fatalf("Expected active")
		}
		if !exists {
			t.Fatalf("Expected exists")
		}
	}

	t.Log("'bar', in inventory and not active")
	{
		active, exists := cm.availableMetrics["bar"]
		if active {
			t.Fatalf("Expected not active")
		}
		if !exists {
			t.Fatalf("Expected exists")
		}
	}

	t.Log("'baz', not in inventory and not active")
	{
		active, exists := cm.availableMetrics["baz"]
		if active {
			t.Fatalf("Expected not active")
		}
		if exists {
			t.Fatalf("Expected not exists")
		}
	}
}

func TestAddMetricTags(t *testing.T) {
	cm := &CheckManager{}
	cm.checkBundle = &api.CheckBundle{}
	cm.metricTags = make(map[string][]string)

	t.Log("no tags")
	{
		if cm.AddMetricTags("foo", []string{}, false) {
			t.Fatalf("Expected false")
		}
	}

	t.Log("no metric named 'foo'")
	{
		if !cm.AddMetricTags("foo", []string{"cat:tag"}, false) {
			t.Fatalf("Expected true")
		}
	}

	cm.checkBundle.Metrics = []api.CheckBundleMetric{
		api.CheckBundleMetric{
			Name:   "bar",
			Type:   "numeric",
			Status: "active",
		},
		api.CheckBundleMetric{
			Name:   "foo",
			Type:   "numeric",
			Status: "active",
		},
		api.CheckBundleMetric{
			Name:   "baz",
			Type:   "numeric",
			Status: "active",
			Tags:   []string{"cat1:tag1"},
		},
	}

	t.Log("metric named 'bar', add tag")
	{

		cm.metricTags = make(map[string][]string)
		// append, zero current
		if !cm.AddMetricTags("bar", []string{"cat:tag"}, true) {
			t.Fatalf("Expected true")
		}
		expected := make(map[string][]string)
		expected["bar"] = []string{"cat:tag"}

		if !reflect.DeepEqual(cm.metricTags, expected) {
			t.Fatalf("expected %v got %+v", expected, cm.metricTags)
		}

		// tag already exists, no need to add
		if cm.AddMetricTags("bar", []string{"cat:tag"}, true) {
			t.Fatalf("Expected false")
		}

		if !reflect.DeepEqual(cm.metricTags, expected) {
			t.Fatalf("expected %v got %+v", expected, cm.metricTags)
		}

		// append, zero tags
		if cm.AddMetricTags("bar", []string{}, true) {
			t.Fatalf("Expected false")
		}

		if !reflect.DeepEqual(cm.metricTags, expected) {
			t.Fatalf("expected %v got %+v", expected, cm.metricTags)
		}
	}

	t.Log("metric named 'baz', add tag")
	{
		cm.metricTags = make(map[string][]string)

		// append, current tag, should be noupdate
		if cm.AddMetricTags("baz", []string{"cat1:tag1"}, true) {
			t.Fatalf("Expected false")
		}

		if _, found := cm.metricTags["baz"]; found {
			t.Fatalf("expected not found")
		}

		// append, one current
		if !cm.AddMetricTags("baz", []string{"cat2:tag2"}, true) {
			t.Fatalf("Expected true")
		}
		expected := make(map[string][]string)
		expected["baz"] = []string{"cat1:tag1", "cat2:tag2"}

		if !reflect.DeepEqual(cm.metricTags, expected) {
			t.Fatalf("expected %v got %+v", expected, cm.metricTags)
		}

		// append, tag already exists (should be noupdate)
		if cm.AddMetricTags("baz", []string{"cat2:tag2"}, true) {
			t.Fatalf("Expected false")
		}
	}

	t.Log("metric named 'foo', set tag")
	{
		expected := make(map[string][]string)
		cm.metricTags = make(map[string][]string)

		// set tag
		if !cm.AddMetricTags("foo", []string{"cat:tag"}, false) {
			t.Fatalf("Expected true")
		}
		expected["foo"] = []string{"cat:tag"}
		if !reflect.DeepEqual(cm.metricTags, expected) {
			t.Fatalf("expected %v got %+v", expected, cm.metricTags)
		}

		// set, reset (pass 0 tags)
		if !cm.AddMetricTags("foo", []string{}, false) {
			t.Fatalf("Expected true")
		}

		if _, found := cm.metricTags["foo"]; found {
			t.Fatal("expected not found")
		}

		// set tag
		if !cm.AddMetricTags("foo", []string{"cat:tag"}, false) {
			t.Fatalf("Expected true")
		}

		expected["foo"] = []string{"cat:tag"}
		if !reflect.DeepEqual(cm.metricTags, expected) {
			t.Fatalf("expected %v got %+v", expected, cm.metricTags)
		}

		// set, no update (same tag)
		if cm.AddMetricTags("foo", []string{"cat:tag"}, false) {
			t.Fatalf("Expected false")
		}

		expected["foo"] = []string{"cat:tag"}
		if !reflect.DeepEqual(cm.metricTags, expected) {
			t.Fatalf("expected %v got %+v", expected, cm.metricTags)
		}

		// replace any existing
		if !cm.AddMetricTags("foo", []string{"cat:newtag"}, false) {
			t.Fatalf("Expected true")
		}

		expected["foo"] = []string{"cat:newtag"}
		if !reflect.DeepEqual(cm.metricTags, expected) {
			t.Fatalf("expected %v got %+v", expected, cm.metricTags)
		}

	}
}

func TestAddNewMetrics(t *testing.T) {
	cm := &CheckManager{}

	newMetrics := make(map[string]*api.CheckBundleMetric)

	newMetrics["foo"] = &api.CheckBundleMetric{
		Name:   "foo",
		Type:   "numeric",
		Status: "active",
	}

	t.Log("no check bundle")
	{
		if cm.addNewMetrics(newMetrics) {
			t.Fatalf("Expected false")
		}
	}

	cm.checkBundle = &api.CheckBundle{}
	t.Log("no check bundle metrics")
	{
		if !cm.addNewMetrics(newMetrics) {
			t.Fatalf("Expected true")
		}
		if !cm.forceCheckUpdate {
			t.Fatal("Expected forceCheckUpdate to be true")
		}
	}
}
<commit_msg>fix: tag reset/clear<commit_after>// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package checkmgr

import (
	"reflect"
	"testing"

	"github.com/circonus-labs/circonus-gometrics/api"
)

func TestIsMetricActive(t *testing.T) {

	cm := &CheckManager{}

	cm.availableMetrics = map[string]bool{
		"foo": true,
	}

	t.Log("'foo' in active metric list")
	{
		if !cm.IsMetricActive("foo") {
			t.Error("Expected true")
		}
	}

	t.Log("'bar' not in active metric list")
	{
		if cm.IsMetricActive("bar") {
			t.Error("Expected false")
		}
	}
}

func TestActivateMetric(t *testing.T) {
	cm := &CheckManager{}
	cm.checkBundle = &api.CheckBundle{}
	cm.checkBundle.Metrics = []api.CheckBundleMetric{
		api.CheckBundleMetric{
			Name:   "foo",
			Type:   "numeric",
			Status: "active",
		},
		api.CheckBundleMetric{
			Name:   "bar",
			Type:   "numeric",
			Status: "available",
		},
	}

	cm.availableMetrics = make(map[string]bool)
	cm.forceMetricActivation = false

	cm.inventoryMetrics()

	t.Log("'foo' already active")
	{
		if cm.ActivateMetric("foo") {
			t.Error("Expected false")
		}
	}

	t.Log("'bar' in list but not active [force=false]")
	{
		if cm.ActivateMetric("bar") {
			t.Error("Expected false")
		}
	}

	t.Log("'baz' not in list")
	{
		if !cm.ActivateMetric("baz") {
			t.Error("Expected true")
		}
	}

	cm.forceMetricActivation = true

	t.Log("'bar' in list but not active [force=true]")
	{
		if !cm.ActivateMetric("bar") {
			t.Error("Expected true")
		}
	}
}

func TestInventoryMetrics(t *testing.T) {
	cm := &CheckManager{}
	cm.checkBundle = &api.CheckBundle{}
	cm.checkBundle.Metrics = []api.CheckBundleMetric{
		api.CheckBundleMetric{
			Name:   "foo",
			Type:   "numeric",
			Status: "active",
		},
		api.CheckBundleMetric{
			Name:   "bar",
			Type:   "numeric",
			Status: "available",
		},
	}

	cm.availableMetrics = make(map[string]bool)
	cm.inventoryMetrics()

	expectedMetrics := make(map[string]bool)
	expectedMetrics["foo"] = true
	expectedMetrics["bar"] = false

	t.Log("'foo', in inventory and active")
	{
		active, exists := cm.availableMetrics["foo"]
		if !active {
			t.Fatalf("Expected active")
		}
		if !exists {
			t.Fatalf("Expected exists")
		}
	}

	t.Log("'bar', in inventory and not active")
	{
		active, exists := cm.availableMetrics["bar"]
		if active {
			t.Fatalf("Expected not active")
		}
		if !exists {
			t.Fatalf("Expected exists")
		}
	}

	t.Log("'baz', not in inventory and not active")
	{
		active, exists := cm.availableMetrics["baz"]
		if active {
			t.Fatalf("Expected not active")
		}
		if exists {
			t.Fatalf("Expected not exists")
		}
	}
}

func TestAddMetricTags(t *testing.T) {
	cm := &CheckManager{}
	cm.checkBundle = &api.CheckBundle{}
	cm.metricTags = make(map[string][]string)

	t.Log("no tags")
	{
		if cm.AddMetricTags("foo", []string{}, false) {
			t.Fatalf("Expected false")
		}
	}

	t.Log("no metric named 'foo'")
	{
		if !cm.AddMetricTags("foo", []string{"cat:tag"}, false) {
			t.Fatalf("Expected true")
		}
	}

	cm.checkBundle.Metrics = []api.CheckBundleMetric{
		api.CheckBundleMetric{
			Name:   "bar",
			Type:   "numeric",
			Status: "active",
		},
		api.CheckBundleMetric{
			Name:   "foo",
			Type:   "numeric",
			Status: "active",
		},
		api.CheckBundleMetric{
			Name:   "baz",
			Type:   "numeric",
			Status: "active",
			Tags:   []string{"cat1:tag1"},
		},
	}

	t.Log("metric named 'bar', add tag")
	{

		cm.metricTags = make(map[string][]string)
		// append, zero current
		if !cm.AddMetricTags("bar", []string{"cat:tag"}, true) {
			t.Fatalf("Expected true")
		}
		expected := make(map[string][]string)
		expected["bar"] = []string{"cat:tag"}

		if !reflect.DeepEqual(cm.metricTags, expected) {
			t.Fatalf("expected %v got %+v", expected, cm.metricTags)
		}

		// tag already exists, no need to add
		if cm.AddMetricTags("bar", []string{"cat:tag"}, true) {
			t.Fatalf("Expected false")
		}

		if !reflect.DeepEqual(cm.metricTags, expected) {
			t.Fatalf("expected %v got %+v", expected, cm.metricTags)
		}

		// append, zero tags
		if cm.AddMetricTags("bar", []string{}, true) {
			t.Fatalf("Expected false")
		}

		if !reflect.DeepEqual(cm.metricTags, expected) {
			t.Fatalf("expected %v got %+v", expected, cm.metricTags)
		}
	}

	t.Log("metric named 'baz', add tag")
	{
		cm.metricTags = make(map[string][]string)

		// append, current tag, should be noupdate
		if cm.AddMetricTags("baz", []string{"cat1:tag1"}, true) {
			t.Fatalf("Expected false")
		}

		if _, found := cm.metricTags["baz"]; found {
			t.Fatalf("expected not found")
		}

		// append, one current
		if !cm.AddMetricTags("baz", []string{"cat2:tag2"}, true) {
			t.Fatalf("Expected true")
		}
		expected := make(map[string][]string)
		expected["baz"] = []string{"cat1:tag1", "cat2:tag2"}

		if !reflect.DeepEqual(cm.metricTags, expected) {
			t.Fatalf("expected %v got %+v", expected, cm.metricTags)
		}

		// append, tag already exists (should be noupdate)
		if cm.AddMetricTags("baz", []string{"cat2:tag2"}, true) {
			t.Fatalf("Expected false")
		}
	}

	t.Log("metric named 'foo', set tag")
	{
		expected := make(map[string][]string)
		cm.metricTags = make(map[string][]string)

		// set tag
		if !cm.AddMetricTags("foo", []string{"cat:tag"}, false) {
			t.Fatalf("Expected true")
		}
		expected["foo"] = []string{"cat:tag"}
		if !reflect.DeepEqual(cm.metricTags, expected) {
			t.Fatalf("expected %v got %+v", expected, cm.metricTags)
		}

		// set, reset (pass 0 tags)
		if !cm.AddMetricTags("foo", []string{}, false) {
			t.Fatalf("Expected true")
		}

		if _, found := cm.metricTags["foo"]; !found {
			t.Fatal("expected found")
		}

		expected["foo"] = []string{}
		if !reflect.DeepEqual(cm.metricTags, expected) {
			t.Fatalf("expected %v got %+v", expected, cm.metricTags)
		}

		// set tag
		if !cm.AddMetricTags("foo", []string{"cat:tag"}, false) {
			t.Fatalf("Expected true")
		}

		expected["foo"] = []string{"cat:tag"}
		if !reflect.DeepEqual(cm.metricTags, expected) {
			t.Fatalf("expected %v got %+v", expected, cm.metricTags)
		}

		// set, no update (same tag)
		if cm.AddMetricTags("foo", []string{"cat:tag"}, false) {
			t.Fatalf("Expected false")
		}

		expected["foo"] = []string{"cat:tag"}
		if !reflect.DeepEqual(cm.metricTags, expected) {
			t.Fatalf("expected %v got %+v", expected, cm.metricTags)
		}

		// replace any existing
		if !cm.AddMetricTags("foo", []string{"cat:newtag"}, false) {
			t.Fatalf("Expected true")
		}

		expected["foo"] = []string{"cat:newtag"}
		if !reflect.DeepEqual(cm.metricTags, expected) {
			t.Fatalf("expected %v got %+v", expected, cm.metricTags)
		}

	}
}

func TestAddNewMetrics(t *testing.T) {
	cm := &CheckManager{}

	newMetrics := make(map[string]*api.CheckBundleMetric)

	newMetrics["foo"] = &api.CheckBundleMetric{
		Name:   "foo",
		Type:   "numeric",
		Status: "active",
	}

	t.Log("no check bundle")
	{
		if cm.addNewMetrics(newMetrics) {
			t.Fatalf("Expected false")
		}
	}

	cm.checkBundle = &api.CheckBundle{}
	t.Log("no check bundle metrics")
	{
		if !cm.addNewMetrics(newMetrics) {
			t.Fatalf("Expected true")
		}
		if !cm.forceCheckUpdate {
			t.Fatal("Expected forceCheckUpdate to be true")
		}
	}
}
<|endoftext|>